1use std::collections::{HashMap, HashSet};
16use std::sync::Arc;
17
18use itertools::Itertools;
19use risingwave_common::catalog::{FunctionId, IndexId, StreamJobStatus, TableId};
20use risingwave_common::id::ObjectId;
21use risingwave_common::session_config::{SearchPath, USER_NAME_WILD_CARD};
22use risingwave_common::types::DataType;
23use risingwave_connector::sink::catalog::SinkCatalog;
24use risingwave_pb::catalog::{
25 PbConnection, PbDatabase, PbFunction, PbIndex, PbSchema, PbSecret, PbSink, PbSource,
26 PbSubscription, PbTable, PbView,
27};
28use risingwave_pb::common::PbObjectType;
29use risingwave_pb::hummock::HummockVersionStats;
30use risingwave_pb::meta::ObjectDependency as PbObjectDependency;
31
32use super::function_catalog::FunctionCatalog;
33use super::source_catalog::SourceCatalog;
34use super::subscription_catalog::{SubscriptionCatalog, SubscriptionState};
35use super::view_catalog::ViewCatalog;
36use super::{
37 CatalogError, CatalogResult, ConnectionId, SecretId, SinkId, SourceId, SubscriptionId, ViewId,
38};
39use crate::catalog::connection_catalog::ConnectionCatalog;
40use crate::catalog::database_catalog::DatabaseCatalog;
41use crate::catalog::schema_catalog::SchemaCatalog;
42use crate::catalog::secret_catalog::SecretCatalog;
43use crate::catalog::system_catalog::{
44 SystemTableCatalog, get_sys_tables_in_schema, get_sys_views_in_schema,
45};
46use crate::catalog::table_catalog::TableCatalog;
47use crate::catalog::{DatabaseId, IndexCatalog, SchemaId};
48use crate::expr::{Expr, ExprImpl};
49
50#[derive(Copy, Clone)]
51pub enum SchemaPath<'a> {
52 Name(&'a str),
53 Path(&'a SearchPath, &'a str),
55}
56
57impl<'a> SchemaPath<'a> {
58 pub fn new(
59 schema_name: Option<&'a str>,
60 search_path: &'a SearchPath,
61 user_name: &'a str,
62 ) -> Self {
63 match schema_name {
64 Some(schema_name) => SchemaPath::Name(schema_name),
65 None => SchemaPath::Path(search_path, user_name),
66 }
67 }
68
69 pub fn try_find<T, E>(
71 &self,
72 mut f: impl FnMut(&str) -> Result<Option<T>, E>,
73 ) -> Result<Option<(T, &'a str)>, E> {
74 match self {
75 SchemaPath::Name(schema_name) => Ok(f(schema_name)?.map(|t| (t, *schema_name))),
76 SchemaPath::Path(search_path, user_name) => {
77 for schema_name in search_path.path() {
78 let mut schema_name: &str = schema_name;
79 if schema_name == USER_NAME_WILD_CARD {
80 schema_name = user_name;
81 }
82 if let Ok(Some(res)) = f(schema_name) {
83 return Ok(Some((res, schema_name)));
84 }
85 }
86 Ok(None)
87 }
88 }
89 }
90}
91
92#[derive(Clone, Debug)]
93pub struct ObjectDependency {
94 pub object_id: ObjectId,
95 pub referenced_object_id: ObjectId,
96 pub referenced_object_type: PbObjectType,
97}
98
99impl From<PbObjectDependency> for ObjectDependency {
100 fn from(dependency: PbObjectDependency) -> Self {
101 let referenced_object_type = PbObjectType::try_from(dependency.referenced_object_type)
102 .unwrap_or(PbObjectType::Unspecified);
103 Self {
104 object_id: dependency.object_id,
105 referenced_object_id: dependency.referenced_object_id,
106 referenced_object_type,
107 }
108 }
109}
110
111pub struct Catalog {
123 database_by_name: HashMap<String, DatabaseCatalog>,
124 db_name_by_id: HashMap<DatabaseId, String>,
125 table_by_id: HashMap<TableId, Arc<TableCatalog>>,
127 table_stats: HummockVersionStats,
128 object_dependencies: HashMap<ObjectId, Vec<ObjectDependency>>,
129}
130
131#[expect(clippy::derivable_impls)]
132impl Default for Catalog {
133 fn default() -> Self {
134 Self {
135 database_by_name: HashMap::new(),
136 db_name_by_id: HashMap::new(),
137 table_by_id: HashMap::new(),
138 table_stats: HummockVersionStats::default(),
139 object_dependencies: HashMap::new(),
140 }
141 }
142}
143
144impl Catalog {
145 fn get_database_mut(&mut self, db_id: DatabaseId) -> Option<&mut DatabaseCatalog> {
146 let name = self.db_name_by_id.get(&db_id)?;
147 self.database_by_name.get_mut(name)
148 }
149
150 pub fn clear(&mut self) {
151 self.database_by_name.clear();
152 self.db_name_by_id.clear();
153 self.table_by_id.clear();
154 self.object_dependencies.clear();
155 }
156
157 pub fn create_database(&mut self, db: &PbDatabase) {
158 let name = db.name.clone();
159 let id = db.id;
160
161 self.database_by_name
162 .try_insert(name.clone(), db.into())
163 .unwrap();
164 self.db_name_by_id.try_insert(id, name).unwrap();
165 }
166
167 pub fn create_schema(&mut self, proto: &PbSchema) {
168 let database_id = proto.database_id;
169 let id = proto.id;
170 self.get_database_mut(database_id)
171 .unwrap()
172 .create_schema(proto);
173
174 for sys_table in get_sys_tables_in_schema(proto.name.as_str()) {
175 self.get_database_mut(database_id)
176 .unwrap()
177 .get_schema_mut(id)
178 .unwrap()
179 .create_sys_table(sys_table);
180 }
181 for mut sys_view in get_sys_views_in_schema(proto.name.as_str()) {
182 sys_view.database_id = database_id;
183 sys_view.schema_id = id;
184 self.get_database_mut(database_id)
185 .unwrap()
186 .get_schema_mut(id)
187 .unwrap()
188 .create_sys_view(Arc::new(sys_view));
189 }
190 }
191
192 pub fn create_table(&mut self, proto: &PbTable) {
193 let table = self
194 .get_database_mut(proto.database_id)
195 .unwrap()
196 .get_schema_mut(proto.schema_id)
197 .unwrap()
198 .create_table(proto);
199 self.table_by_id.insert(proto.id, table);
200 }
201
202 pub fn create_index(&mut self, proto: &PbIndex) {
203 self.get_database_mut(proto.database_id)
204 .unwrap()
205 .get_schema_mut(proto.schema_id)
206 .unwrap()
207 .create_index(proto);
208 }
209
210 pub fn create_source(&mut self, proto: &PbSource) {
211 self.get_database_mut(proto.database_id)
212 .unwrap()
213 .get_schema_mut(proto.schema_id)
214 .unwrap()
215 .create_source(proto);
216 }
217
218 pub fn create_sink(&mut self, proto: &PbSink) {
219 self.get_database_mut(proto.database_id)
220 .unwrap()
221 .get_schema_mut(proto.schema_id)
222 .unwrap()
223 .create_sink(proto);
224 }
225
226 pub fn create_subscription(&mut self, proto: &PbSubscription) {
227 self.get_database_mut(proto.database_id)
228 .unwrap()
229 .get_schema_mut(proto.schema_id)
230 .unwrap()
231 .create_subscription(proto);
232 }
233
234 pub fn create_secret(&mut self, proto: &PbSecret) {
235 self.get_database_mut(proto.database_id)
236 .unwrap()
237 .get_schema_mut(proto.schema_id)
238 .unwrap()
239 .create_secret(proto);
240 }
241
242 pub fn create_view(&mut self, proto: &PbView) {
243 self.get_database_mut(proto.database_id)
244 .unwrap()
245 .get_schema_mut(proto.schema_id)
246 .unwrap()
247 .create_view(proto);
248 }
249
250 pub fn create_function(&mut self, proto: &PbFunction) {
251 self.get_database_mut(proto.database_id)
252 .unwrap()
253 .get_schema_mut(proto.schema_id)
254 .unwrap()
255 .create_function(proto);
256 }
257
258 pub fn create_connection(&mut self, proto: &PbConnection) {
259 self.get_database_mut(proto.database_id)
260 .unwrap()
261 .get_schema_mut(proto.schema_id)
262 .unwrap()
263 .create_connection(proto);
264 }
265
266 pub fn drop_connection(
267 &mut self,
268 db_id: DatabaseId,
269 schema_id: SchemaId,
270 connection_id: ConnectionId,
271 ) {
272 self.get_database_mut(db_id)
273 .unwrap()
274 .get_schema_mut(schema_id)
275 .unwrap()
276 .drop_connection(connection_id);
277 }
278
279 pub fn update_connection(&mut self, proto: &PbConnection) {
280 let database = self.get_database_mut(proto.database_id).unwrap();
281 let schema = database.get_schema_mut(proto.schema_id).unwrap();
282 if schema.get_connection_by_id(proto.id).is_some() {
283 schema.update_connection(proto);
284 } else {
285 schema.create_connection(proto);
287 database
288 .iter_schemas_mut()
289 .find(|schema| {
290 schema.id() != proto.schema_id
291 && schema.get_connection_by_id(proto.id).is_some()
292 })
293 .unwrap()
294 .drop_connection(proto.id);
295 }
296 }
297
298 pub fn update_secret(&mut self, proto: &PbSecret) {
299 let database = self.get_database_mut(proto.database_id).unwrap();
300 let schema = database.get_schema_mut(proto.schema_id).unwrap();
301 let secret_id = proto.id;
302 if schema.get_secret_by_id(secret_id).is_some() {
303 schema.update_secret(proto);
304 } else {
305 schema.create_secret(proto);
307 database
308 .iter_schemas_mut()
309 .find(|schema| {
310 schema.id() != proto.schema_id && schema.get_secret_by_id(secret_id).is_some()
311 })
312 .unwrap()
313 .drop_secret(secret_id);
314 }
315 }
316
317 pub fn drop_database(&mut self, db_id: DatabaseId) {
318 let name = self.db_name_by_id.remove(&db_id).unwrap();
319 let database = self.database_by_name.remove(&name).unwrap();
320 let object_ids: HashSet<ObjectId> = database.iter_object_ids().collect();
321 self.remove_object_dependencies_for_objects(&object_ids);
322 database.iter_all_table_ids().for_each(|table| {
323 self.table_by_id.remove(&table);
324 });
325 }
326
327 pub fn drop_schema(&mut self, db_id: DatabaseId, schema_id: SchemaId) {
328 let object_ids = self
329 .get_database_by_id(db_id)
330 .ok()
331 .and_then(|db| db.get_schema_by_id(schema_id))
332 .map(|schema| schema.iter_object_ids().collect::<HashSet<_>>())
333 .unwrap_or_default();
334 self.remove_object_dependencies_for_objects(&object_ids);
335 self.get_database_mut(db_id).unwrap().drop_schema(schema_id);
336 }
337
338 pub fn drop_table(&mut self, db_id: DatabaseId, schema_id: SchemaId, tb_id: TableId) {
339 self.remove_object_dependencies_for_object(tb_id.as_object_id());
340 self.table_by_id.remove(&tb_id);
341 self.get_database_mut(db_id)
342 .unwrap()
343 .get_schema_mut(schema_id)
344 .unwrap()
345 .drop_table(tb_id);
346 }
347
348 pub fn update_table(&mut self, proto: &PbTable) {
349 let database = self.get_database_mut(proto.database_id).unwrap();
350 let schema = database.get_schema_mut(proto.schema_id).unwrap();
351 let table = if schema.get_table_by_id(proto.id).is_some() {
352 schema.update_table(proto)
353 } else {
354 let new_table = schema.create_table(proto);
356 database
357 .iter_schemas_mut()
358 .find(|schema| {
359 schema.id() != proto.schema_id
360 && schema.get_created_table_by_id(proto.id).is_some()
361 })
362 .unwrap()
363 .drop_table(proto.id);
364 new_table
365 };
366
367 self.table_by_id.insert(proto.id, table);
368 }
369
370 pub fn update_database(&mut self, proto: &PbDatabase) {
371 let id = proto.id;
372 let name = proto.name.clone();
373
374 let old_database_name = self.db_name_by_id.get(&id).unwrap().to_owned();
375 if old_database_name != name {
376 let mut database = self.database_by_name.remove(&old_database_name).unwrap();
377 database.name.clone_from(&name);
378 database.owner = proto.owner;
379 database.resource_group.clone_from(&proto.resource_group);
380 database.barrier_interval_ms = proto.barrier_interval_ms;
381 database.checkpoint_frequency = proto.checkpoint_frequency;
382 self.database_by_name.insert(name.clone(), database);
383 self.db_name_by_id.insert(id, name);
384 } else {
385 let database = self.get_database_mut(id).unwrap();
386 database.name = name;
387 database.owner = proto.owner;
388 database.resource_group = proto.resource_group.clone();
389 database.barrier_interval_ms = proto.barrier_interval_ms;
390 database.checkpoint_frequency = proto.checkpoint_frequency;
391 }
392 }
393
394 pub fn update_schema(&mut self, proto: &PbSchema) {
395 self.get_database_mut(proto.database_id)
396 .unwrap()
397 .update_schema(proto);
398 }
399
400 pub fn update_index(&mut self, proto: &PbIndex) {
401 let database = self.get_database_mut(proto.database_id).unwrap();
402 let schema = database.get_schema_mut(proto.schema_id).unwrap();
403 if schema.get_index_by_id(proto.id).is_some() {
404 schema.update_index(proto);
405 } else {
406 schema.create_index(proto);
408 database
409 .iter_schemas_mut()
410 .find(|schema| {
411 schema.id() != proto.schema_id && schema.get_index_by_id(proto.id).is_some()
412 })
413 .unwrap()
414 .drop_index(proto.id);
415 }
416 }
417
418 pub fn drop_source(&mut self, db_id: DatabaseId, schema_id: SchemaId, source_id: SourceId) {
419 self.remove_object_dependencies_for_object(source_id.as_object_id());
420 self.get_database_mut(db_id)
421 .unwrap()
422 .get_schema_mut(schema_id)
423 .unwrap()
424 .drop_source(source_id);
425 }
426
427 pub fn update_source(&mut self, proto: &PbSource) {
428 let database = self.get_database_mut(proto.database_id).unwrap();
429 let schema = database.get_schema_mut(proto.schema_id).unwrap();
430 if schema.get_source_by_id(proto.id).is_some() {
431 schema.update_source(proto);
432 } else {
433 schema.create_source(proto);
435 database
436 .iter_schemas_mut()
437 .find(|schema| {
438 schema.id() != proto.schema_id && schema.get_source_by_id(proto.id).is_some()
439 })
440 .unwrap()
441 .drop_source(proto.id);
442 }
443 }
444
445 pub fn drop_sink(&mut self, db_id: DatabaseId, schema_id: SchemaId, sink_id: SinkId) {
446 self.remove_object_dependencies_for_object(sink_id.as_object_id());
447 self.get_database_mut(db_id)
448 .unwrap()
449 .get_schema_mut(schema_id)
450 .unwrap()
451 .drop_sink(sink_id);
452 }
453
454 pub fn drop_secret(&mut self, db_id: DatabaseId, schema_id: SchemaId, secret_id: SecretId) {
455 self.remove_object_dependencies_for_object(secret_id.as_object_id());
456 self.get_database_mut(db_id)
457 .unwrap()
458 .get_schema_mut(schema_id)
459 .unwrap()
460 .drop_secret(secret_id);
461 }
462
463 pub fn update_sink(&mut self, proto: &PbSink) {
464 let database = self.get_database_mut(proto.database_id).unwrap();
465 let schema = database.get_schema_mut(proto.schema_id).unwrap();
466 if schema.get_sink_by_id(proto.id).is_some() {
467 schema.update_sink(proto);
468 } else {
469 schema.create_sink(proto);
471 database
472 .iter_schemas_mut()
473 .find(|schema| {
474 schema.id() != proto.schema_id && schema.get_sink_by_id(proto.id).is_some()
475 })
476 .unwrap()
477 .drop_sink(proto.id);
478 }
479 }
480
481 pub fn drop_subscription(
482 &mut self,
483 db_id: DatabaseId,
484 schema_id: SchemaId,
485 subscription_id: SubscriptionId,
486 ) {
487 self.remove_object_dependencies_for_object(subscription_id.as_object_id());
488 self.get_database_mut(db_id)
489 .unwrap()
490 .get_schema_mut(schema_id)
491 .unwrap()
492 .drop_subscription(subscription_id);
493 }
494
495 pub fn update_subscription(&mut self, proto: &PbSubscription) {
496 let database = self.get_database_mut(proto.database_id).unwrap();
497 let schema = database.get_schema_mut(proto.schema_id).unwrap();
498 if schema.get_subscription_by_id(proto.id).is_some() {
499 schema.update_subscription(proto);
500 } else {
501 schema.create_subscription(proto);
503 database
504 .iter_schemas_mut()
505 .find(|schema| {
506 schema.id() != proto.schema_id
507 && schema.get_subscription_by_id(proto.id).is_some()
508 })
509 .unwrap()
510 .drop_subscription(proto.id);
511 }
512 }
513
514 pub fn drop_index(&mut self, db_id: DatabaseId, schema_id: SchemaId, index_id: IndexId) {
515 self.remove_object_dependencies_for_object(index_id.as_object_id());
516 self.get_database_mut(db_id)
517 .unwrap()
518 .get_schema_mut(schema_id)
519 .unwrap()
520 .drop_index(index_id);
521 }
522
523 pub fn drop_view(&mut self, db_id: DatabaseId, schema_id: SchemaId, view_id: ViewId) {
524 self.remove_object_dependencies_for_object(view_id.as_object_id());
525 self.get_database_mut(db_id)
526 .unwrap()
527 .get_schema_mut(schema_id)
528 .unwrap()
529 .drop_view(view_id);
530 }
531
532 pub fn update_view(&mut self, proto: &PbView) {
533 let database = self.get_database_mut(proto.database_id).unwrap();
534 let schema = database.get_schema_mut(proto.schema_id).unwrap();
535 if schema.get_view_by_id(proto.id).is_some() {
536 schema.update_view(proto);
537 } else {
538 schema.create_view(proto);
540 database
541 .iter_schemas_mut()
542 .find(|schema| {
543 schema.id() != proto.schema_id && schema.get_view_by_id(proto.id).is_some()
544 })
545 .unwrap()
546 .drop_view(proto.id);
547 }
548 }
549
550 pub fn drop_function(
551 &mut self,
552 db_id: DatabaseId,
553 schema_id: SchemaId,
554 function_id: FunctionId,
555 ) {
556 self.remove_object_dependencies_for_object(function_id.as_object_id());
557 self.get_database_mut(db_id)
558 .unwrap()
559 .get_schema_mut(schema_id)
560 .unwrap()
561 .drop_function(function_id);
562 }
563
564 pub fn update_function(&mut self, proto: &PbFunction) {
565 let database = self.get_database_mut(proto.database_id).unwrap();
566 let schema = database.get_schema_mut(proto.schema_id).unwrap();
567 if schema.get_function_by_id(proto.id).is_some() {
568 schema.update_function(proto);
569 } else {
570 schema.create_function(proto);
572 database
573 .iter_schemas_mut()
574 .find(|schema| {
575 schema.id() != proto.schema_id && schema.get_function_by_id(proto.id).is_some()
576 })
577 .unwrap()
578 .drop_function(proto.id);
579 }
580
581 self.get_database_mut(proto.database_id)
582 .unwrap()
583 .get_schema_mut(proto.schema_id)
584 .unwrap()
585 .update_function(proto);
586 }
587
588 pub fn get_database_by_name(&self, db_name: &str) -> CatalogResult<&DatabaseCatalog> {
589 self.database_by_name
590 .get(db_name)
591 .ok_or_else(|| CatalogError::not_found("database", db_name))
592 }
593
594 pub fn get_database_by_id(&self, db_id: DatabaseId) -> CatalogResult<&DatabaseCatalog> {
595 let db_name = self
596 .db_name_by_id
597 .get(&db_id)
598 .ok_or_else(|| CatalogError::not_found("db_id", db_id.to_string()))?;
599 self.database_by_name
600 .get(db_name)
601 .ok_or_else(|| CatalogError::not_found("database", db_name))
602 }
603
604 pub fn find_schema_secret_by_secret_id(
605 &self,
606 db_name: &str,
607 secret_id: SecretId,
608 ) -> CatalogResult<(String, String)> {
609 let db = self.get_database_by_name(db_name)?;
610 let schema_secret = db
611 .iter_schemas()
612 .find_map(|schema| {
613 schema
614 .get_secret_by_id(secret_id)
615 .map(|secret| (schema.name(), secret.name.clone()))
616 })
617 .ok_or_else(|| CatalogError::not_found("secret", secret_id.to_string()))?;
618 Ok(schema_secret)
619 }
620
621 pub fn get_all_schema_names(&self, db_name: &str) -> CatalogResult<Vec<String>> {
622 Ok(self.get_database_by_name(db_name)?.get_all_schema_names())
623 }
624
625 pub fn iter_schemas(
626 &self,
627 db_name: &str,
628 ) -> CatalogResult<impl Iterator<Item = &SchemaCatalog>> {
629 Ok(self.get_database_by_name(db_name)?.iter_schemas())
630 }
631
632 pub fn get_all_database_names(&self) -> Vec<String> {
633 self.database_by_name.keys().cloned().collect_vec()
634 }
635
636 pub fn iter_databases(&self) -> impl Iterator<Item = &DatabaseCatalog> {
637 self.database_by_name.values()
638 }
639
640 pub fn get_schema_by_name(
641 &self,
642 db_name: &str,
643 schema_name: &str,
644 ) -> CatalogResult<&SchemaCatalog> {
645 self.get_database_by_name(db_name)?
646 .get_schema_by_name(schema_name)
647 .ok_or_else(|| CatalogError::not_found("schema", schema_name))
648 }
649
650 pub fn get_table_name_by_id(&self, table_id: TableId) -> CatalogResult<String> {
651 self.get_any_table_by_id(table_id)
652 .map(|table| table.name.clone())
653 }
654
655 pub fn get_schema_by_id(
656 &self,
657 db_id: DatabaseId,
658 schema_id: SchemaId,
659 ) -> CatalogResult<&SchemaCatalog> {
660 self.get_database_by_id(db_id)?
661 .get_schema_by_id(schema_id)
662 .ok_or_else(|| CatalogError::not_found("schema_id", schema_id.to_string()))
663 }
664
665 pub fn first_valid_schema(
667 &self,
668 db_name: &str,
669 search_path: &SearchPath,
670 user_name: &str,
671 ) -> CatalogResult<&SchemaCatalog> {
672 for path in search_path.real_path() {
673 let mut schema_name: &str = path;
674 if schema_name == USER_NAME_WILD_CARD {
675 schema_name = user_name;
676 }
677
678 if let schema_catalog @ Ok(_) = self.get_schema_by_name(db_name, schema_name) {
679 return schema_catalog;
680 }
681 }
682 Err(CatalogError::not_found(
683 "first valid schema",
684 "no schema has been selected to create in".to_owned(),
685 ))
686 }
687
688 pub fn get_source_by_id<'a>(
689 &self,
690 db_name: &'a str,
691 schema_path: SchemaPath<'a>,
692 source_id: SourceId,
693 ) -> CatalogResult<(&Arc<SourceCatalog>, &'a str)> {
694 schema_path
695 .try_find(|schema_name| -> CatalogResult<_> {
696 Ok(self
697 .get_schema_by_name(db_name, schema_name)?
698 .get_source_by_id(source_id))
699 })?
700 .ok_or_else(|| CatalogError::not_found("source", source_id.to_string()))
701 }
702
703 pub fn get_source_by_id_with_db(
705 &self,
706 db_name: &str,
707 source_id: SourceId,
708 ) -> CatalogResult<&Arc<SourceCatalog>> {
709 for schema in self.get_database_by_name(db_name)?.iter_schemas() {
710 if let Some(source) = schema.get_source_by_id(source_id) {
711 return Ok(source);
712 }
713 }
714 Err(CatalogError::not_found("source", source_id.to_string()))
715 }
716
717 pub fn get_table_by_name<'a>(
718 &self,
719 db_name: &str,
720 schema_path: SchemaPath<'a>,
721 table_name: &str,
722 bind_creating: bool,
723 ) -> CatalogResult<(&Arc<TableCatalog>, &'a str)> {
724 schema_path
725 .try_find(|schema_name| -> CatalogResult<_> {
726 Ok(self
727 .get_schema_by_name(db_name, schema_name)?
728 .get_table_by_name(table_name, bind_creating))
729 })?
730 .ok_or_else(|| CatalogError::not_found("table", table_name))
731 }
732
733 pub fn get_any_table_by_name<'a>(
736 &self,
737 db_name: &str,
738 schema_path: SchemaPath<'a>,
739 table_name: &str,
740 ) -> CatalogResult<(&Arc<TableCatalog>, &'a str)> {
741 self.get_table_by_name(db_name, schema_path, table_name, true)
742 }
743
744 pub fn get_created_table_by_name<'a>(
747 &self,
748 db_name: &str,
749 schema_path: SchemaPath<'a>,
750 table_name: &str,
751 ) -> CatalogResult<(&Arc<TableCatalog>, &'a str)> {
752 self.get_table_by_name(db_name, schema_path, table_name, false)
753 }
754
755 pub fn get_any_table_by_id(&self, table_id: TableId) -> CatalogResult<&Arc<TableCatalog>> {
756 self.table_by_id
757 .get(&table_id)
758 .ok_or_else(|| CatalogError::not_found("table id", table_id.to_string()))
759 }
760
761 pub fn get_created_table_by_id_with_db(
763 &self,
764 db_name: &str,
765 table_id: u32,
766 ) -> CatalogResult<&Arc<TableCatalog>> {
767 let table_id = TableId::from(table_id);
768 for schema in self.get_database_by_name(db_name)?.iter_schemas() {
769 if let Some(table) = schema.get_created_table_by_id(table_id) {
770 return Ok(table);
771 }
772 }
773 Err(CatalogError::not_found("table id", table_id.to_string()))
774 }
775
776 pub fn iter_tables(&self) -> impl Iterator<Item = &Arc<TableCatalog>> {
777 self.table_by_id.values()
778 }
779
780 pub fn iter_backfilling_internal_tables(&self) -> impl Iterator<Item = &Arc<TableCatalog>> {
781 self.table_by_id
782 .values()
783 .filter(|t| t.is_internal_table() && !t.is_created())
784 }
785
786 pub fn alter_table_name_by_id(&mut self, table_id: TableId, table_name: &str) {
788 let mut found = false;
789 for database in self.database_by_name.values() {
790 if !found {
791 for schema in database.iter_schemas() {
792 if schema.iter_user_table().any(|t| t.id() == table_id) {
793 found = true;
794 break;
795 }
796 }
797 }
798 }
799
800 if found {
801 let mut table = self.get_any_table_by_id(table_id).unwrap().to_prost();
802 table.name = table_name.to_owned();
803 self.update_table(&table);
804 }
805 }
806
807 #[cfg(test)]
808 pub fn insert_table_id_mapping(&mut self, table_id: TableId, fragment_id: super::FragmentId) {
809 self.table_by_id.insert(
810 table_id,
811 Arc::new(TableCatalog {
812 fragment_id,
813 ..Default::default()
814 }),
815 );
816 }
817
818 pub fn get_sys_table_by_name(
819 &self,
820 db_name: &str,
821 schema_name: &str,
822 table_name: &str,
823 ) -> CatalogResult<&Arc<SystemTableCatalog>> {
824 self.get_schema_by_name(db_name, schema_name)?
825 .get_system_table_by_name(table_name)
826 .ok_or_else(|| CatalogError::not_found("table", table_name))
827 }
828
829 pub fn get_source_by_name<'a>(
830 &self,
831 db_name: &str,
832 schema_path: SchemaPath<'a>,
833 source_name: &str,
834 ) -> CatalogResult<(&Arc<SourceCatalog>, &'a str)> {
835 schema_path
836 .try_find(|schema_name| -> CatalogResult<_> {
837 Ok(self
838 .get_schema_by_name(db_name, schema_name)?
839 .get_source_by_name(source_name))
840 })?
841 .ok_or_else(|| CatalogError::not_found("source", source_name))
842 }
843
844 pub fn get_sink_by_name<'a>(
845 &self,
846 db_name: &str,
847 schema_path: SchemaPath<'a>,
848 sink_name: &str,
849 bind_creating: bool,
850 ) -> CatalogResult<(&Arc<SinkCatalog>, &'a str)> {
851 schema_path
852 .try_find(|schema_name| -> CatalogResult<_> {
853 Ok(self
854 .get_schema_by_name(db_name, schema_name)?
855 .get_sink_by_name(sink_name, bind_creating))
856 })?
857 .ok_or_else(|| CatalogError::not_found("sink", sink_name))
858 }
859
860 pub fn get_any_sink_by_name<'a>(
861 &self,
862 db_name: &str,
863 schema_path: SchemaPath<'a>,
864 sink_name: &str,
865 ) -> CatalogResult<(&Arc<SinkCatalog>, &'a str)> {
866 self.get_sink_by_name(db_name, schema_path, sink_name, true)
867 }
868
869 pub fn get_created_sink_by_name<'a>(
870 &self,
871 db_name: &str,
872 schema_path: SchemaPath<'a>,
873 sink_name: &str,
874 ) -> CatalogResult<(&Arc<SinkCatalog>, &'a str)> {
875 self.get_sink_by_name(db_name, schema_path, sink_name, false)
876 }
877
878 pub fn get_subscription_by_name<'a>(
879 &self,
880 db_name: &str,
881 schema_path: SchemaPath<'a>,
882 subscription_name: &str,
883 ) -> CatalogResult<(&Arc<SubscriptionCatalog>, &'a str)> {
884 schema_path
885 .try_find(|schema_name| -> CatalogResult<_> {
886 Ok(self
887 .get_schema_by_name(db_name, schema_name)?
888 .get_subscription_by_name(subscription_name))
889 })?
890 .ok_or_else(|| CatalogError::not_found("subscription", subscription_name))
891 }
892
893 pub fn get_index_by_name<'a>(
894 &self,
895 db_name: &str,
896 schema_path: SchemaPath<'a>,
897 index_name: &str,
898 ) -> CatalogResult<(&Arc<IndexCatalog>, &'a str)> {
899 schema_path
900 .try_find(|schema_name| -> CatalogResult<_> {
901 Ok(self
902 .get_schema_by_name(db_name, schema_name)?
903 .get_created_index_by_name(index_name))
904 })?
905 .ok_or_else(|| CatalogError::not_found("index", index_name))
906 }
907
908 pub fn get_any_index_by_name<'a>(
909 &self,
910 db_name: &str,
911 schema_path: SchemaPath<'a>,
912 index_name: &str,
913 ) -> CatalogResult<(&Arc<IndexCatalog>, &'a str)> {
914 schema_path
915 .try_find(|schema_name| -> CatalogResult<_> {
916 Ok(self
917 .get_schema_by_name(db_name, schema_name)?
918 .get_any_index_by_name(index_name))
919 })?
920 .ok_or_else(|| CatalogError::not_found("index", index_name))
921 }
922
923 pub fn get_index_by_id(
924 &self,
925 db_name: &str,
926 index_id: u32,
927 ) -> CatalogResult<&Arc<IndexCatalog>> {
928 let index_id = IndexId::from(index_id);
929 for schema in self.get_database_by_name(db_name)?.iter_schemas() {
930 if let Some(index) = schema.get_index_by_id(index_id) {
931 return Ok(index);
932 }
933 }
934 Err(CatalogError::not_found("index", index_id.to_string()))
935 }
936
937 pub fn get_view_by_name<'a>(
938 &self,
939 db_name: &str,
940 schema_path: SchemaPath<'a>,
941 view_name: &str,
942 ) -> CatalogResult<(&Arc<ViewCatalog>, &'a str)> {
943 schema_path
944 .try_find(|schema_name| -> CatalogResult<_> {
945 Ok(self
946 .get_schema_by_name(db_name, schema_name)?
947 .get_view_by_name(view_name))
948 })?
949 .ok_or_else(|| CatalogError::not_found("view", view_name))
950 }
951
952 pub fn get_view_by_id(&self, db_name: &str, view_id: u32) -> CatalogResult<Arc<ViewCatalog>> {
953 for schema in self.get_database_by_name(db_name)?.iter_schemas() {
954 if let Some(view) = schema.get_view_by_id(ViewId::from(view_id)) {
955 return Ok(view.clone());
956 }
957 }
958 Err(CatalogError::not_found("view", view_id.to_string()))
959 }
960
961 pub fn get_secret_by_name<'a>(
962 &self,
963 db_name: &str,
964 schema_path: SchemaPath<'a>,
965 secret_name: &str,
966 ) -> CatalogResult<(&Arc<SecretCatalog>, &'a str)> {
967 schema_path
968 .try_find(|schema_name| -> CatalogResult<_> {
969 Ok(self
970 .get_schema_by_name(db_name, schema_name)?
971 .get_secret_by_name(secret_name))
972 })?
973 .ok_or_else(|| CatalogError::not_found("secret", secret_name))
974 }
975
976 pub fn get_connection_by_id(
977 &self,
978 db_name: &str,
979 connection_id: ConnectionId,
980 ) -> CatalogResult<&Arc<ConnectionCatalog>> {
981 for schema in self.get_database_by_name(db_name)?.iter_schemas() {
982 if let Some(conn) = schema.get_connection_by_id(connection_id) {
983 return Ok(conn);
984 }
985 }
986 Err(CatalogError::not_found(
987 "connection",
988 connection_id.to_string(),
989 ))
990 }
991
992 pub fn get_connection_by_name<'a>(
993 &self,
994 db_name: &str,
995 schema_path: SchemaPath<'a>,
996 connection_name: &str,
997 ) -> CatalogResult<(&Arc<ConnectionCatalog>, &'a str)> {
998 schema_path
999 .try_find(|schema_name| -> CatalogResult<_> {
1000 Ok(self
1001 .get_schema_by_name(db_name, schema_name)?
1002 .get_connection_by_name(connection_name))
1003 })?
1004 .ok_or_else(|| CatalogError::not_found("connection", connection_name))
1005 }
1006
1007 pub fn get_function_by_name_inputs<'a>(
1008 &self,
1009 db_name: &str,
1010 schema_path: SchemaPath<'a>,
1011 function_name: &str,
1012 inputs: &mut [ExprImpl],
1013 ) -> CatalogResult<(&Arc<FunctionCatalog>, &'a str)> {
1014 schema_path
1015 .try_find(|schema_name| -> CatalogResult<_> {
1016 Ok(self
1017 .get_schema_by_name(db_name, schema_name)?
1018 .get_function_by_name_inputs(function_name, inputs))
1019 })?
1020 .ok_or_else(|| {
1021 CatalogError::not_found(
1022 "function",
1023 format!(
1024 "{}({})",
1025 function_name,
1026 inputs
1027 .iter()
1028 .map(|a| a.return_type().to_string())
1029 .join(", ")
1030 ),
1031 )
1032 })
1033 }
1034
1035 pub fn get_function_by_name_args<'a>(
1036 &self,
1037 db_name: &str,
1038 schema_path: SchemaPath<'a>,
1039 function_name: &str,
1040 args: &[DataType],
1041 ) -> CatalogResult<(&Arc<FunctionCatalog>, &'a str)> {
1042 schema_path
1043 .try_find(|schema_name| -> CatalogResult<_> {
1044 Ok(self
1045 .get_schema_by_name(db_name, schema_name)?
1046 .get_function_by_name_args(function_name, args))
1047 })?
1048 .ok_or_else(|| {
1049 CatalogError::not_found(
1050 "function",
1051 format!(
1052 "{}({})",
1053 function_name,
1054 args.iter().map(|a| a.to_string()).join(", ")
1055 ),
1056 )
1057 })
1058 }
1059
1060 pub fn get_functions_by_name<'a>(
1062 &self,
1063 db_name: &str,
1064 schema_path: SchemaPath<'a>,
1065 function_name: &str,
1066 ) -> CatalogResult<(Vec<&Arc<FunctionCatalog>>, &'a str)> {
1067 schema_path
1068 .try_find(|schema_name| -> CatalogResult<_> {
1069 Ok(self
1070 .get_schema_by_name(db_name, schema_name)?
1071 .get_functions_by_name(function_name))
1072 })?
1073 .ok_or_else(|| CatalogError::not_found("function", function_name))
1074 }
1075
1076 pub fn check_relation_name_duplicated(
1078 &self,
1079 db_name: &str,
1080 schema_name: &str,
1081 relation_name: &str,
1082 ) -> CatalogResult<()> {
1083 let schema = self.get_schema_by_name(db_name, schema_name)?;
1084
1085 if let Some(table) = schema.get_any_table_by_name(relation_name) {
1086 let is_creating = table.stream_job_status == StreamJobStatus::Creating;
1087 if table.is_index() {
1088 Err(CatalogError::duplicated_under_creation(
1089 "index",
1090 relation_name.to_owned(),
1091 is_creating,
1092 ))
1093 } else if table.is_mview() {
1094 Err(CatalogError::duplicated_under_creation(
1095 "materialized view",
1096 relation_name.to_owned(),
1097 is_creating,
1098 ))
1099 } else {
1100 Err(CatalogError::duplicated_under_creation(
1101 "table",
1102 relation_name.to_owned(),
1103 is_creating,
1104 ))
1105 }
1106 } else if schema.get_source_by_name(relation_name).is_some() {
1107 Err(CatalogError::duplicated("source", relation_name))
1108 } else if let Some(sink) = schema.get_any_sink_by_name(relation_name) {
1109 Err(CatalogError::duplicated_under_creation(
1110 "sink",
1111 relation_name.to_owned(),
1112 !sink.is_created(),
1113 ))
1114 } else if schema.get_view_by_name(relation_name).is_some() {
1115 Err(CatalogError::duplicated("view", relation_name))
1116 } else if let Some(subscription) = schema.get_subscription_by_name(relation_name) {
1117 let is_not_created = subscription.subscription_state != SubscriptionState::Created;
1118 Err(CatalogError::duplicated_under_creation(
1119 "subscription",
1120 relation_name.to_owned(),
1121 is_not_created,
1122 ))
1123 } else {
1124 Ok(())
1125 }
1126 }
1127
1128 pub fn check_function_name_duplicated(
1129 &self,
1130 db_name: &str,
1131 schema_name: &str,
1132 function_name: &str,
1133 arg_types: &[DataType],
1134 ) -> CatalogResult<()> {
1135 let schema = self.get_schema_by_name(db_name, schema_name)?;
1136
1137 if schema
1138 .get_function_by_name_args(function_name, arg_types)
1139 .is_some()
1140 {
1141 let name = format!(
1142 "{function_name}({})",
1143 arg_types.iter().map(|t| t.to_string()).join(",")
1144 );
1145 Err(CatalogError::duplicated("function", name))
1146 } else {
1147 Ok(())
1148 }
1149 }
1150
1151 pub fn check_connection_name_duplicated(
1153 &self,
1154 db_name: &str,
1155 schema_name: &str,
1156 connection_name: &str,
1157 ) -> CatalogResult<()> {
1158 let schema = self.get_schema_by_name(db_name, schema_name)?;
1159
1160 if schema.get_connection_by_name(connection_name).is_some() {
1161 Err(CatalogError::duplicated("connection", connection_name))
1162 } else {
1163 Ok(())
1164 }
1165 }
1166
1167 pub fn check_secret_name_duplicated(
1168 &self,
1169 db_name: &str,
1170 schema_name: &str,
1171 secret_name: &str,
1172 ) -> CatalogResult<()> {
1173 let schema = self.get_schema_by_name(db_name, schema_name)?;
1174
1175 if schema.get_secret_by_name(secret_name).is_some() {
1176 Err(CatalogError::duplicated("secret", secret_name))
1177 } else {
1178 Ok(())
1179 }
1180 }
1181
1182 pub fn table_stats(&self) -> &HummockVersionStats {
1183 &self.table_stats
1184 }
1185
1186 pub fn set_table_stats(&mut self, table_stats: HummockVersionStats) {
1187 self.table_stats = table_stats;
1188 }
1189
1190 pub fn set_object_dependencies(&mut self, dependencies: Vec<PbObjectDependency>) {
1191 self.object_dependencies.clear();
1192 self.insert_object_dependencies(dependencies);
1193 }
1194
1195 pub fn insert_object_dependencies(&mut self, dependencies: Vec<PbObjectDependency>) {
1196 let mut grouped: HashMap<ObjectId, Vec<ObjectDependency>> = HashMap::new();
1197 for dependency in dependencies {
1198 let dependency = ObjectDependency::from(dependency);
1199 grouped
1200 .entry(dependency.object_id)
1201 .or_default()
1202 .push(dependency);
1203 }
1204 for (object_id, deps) in grouped {
1205 self.object_dependencies.insert(object_id, deps);
1206 }
1207 }
1208
1209 pub fn iter_object_dependencies(&self) -> impl Iterator<Item = &ObjectDependency> {
1210 self.object_dependencies
1211 .values()
1212 .flat_map(|deps| deps.iter())
1213 }
1214
1215 fn remove_object_dependencies_for_object(&mut self, object_id: ObjectId) {
1216 let mut object_ids = HashSet::new();
1217 object_ids.insert(object_id);
1218 self.remove_object_dependencies_for_objects(&object_ids);
1219 }
1220
1221 fn remove_object_dependencies_for_objects(&mut self, object_ids: &HashSet<ObjectId>) {
1222 if object_ids.is_empty() {
1223 return;
1224 }
1225 self.object_dependencies.retain(|object_id, deps| {
1226 if object_ids.contains(object_id) {
1227 return false;
1228 }
1229 deps.retain(|dep| !object_ids.contains(&dep.referenced_object_id));
1230 !deps.is_empty()
1231 });
1232 }
1233
1234 pub fn get_all_indexes_related_to_object(
1235 &self,
1236 db_id: DatabaseId,
1237 schema_id: SchemaId,
1238 mv_id: TableId,
1239 ) -> Vec<Arc<IndexCatalog>> {
1240 self.get_database_by_id(db_id)
1241 .unwrap()
1242 .get_schema_by_id(schema_id)
1243 .unwrap()
1244 .get_any_indexes_by_table_id(mv_id)
1245 }
1246
1247 pub fn get_id_by_class_name(
1248 &self,
1249 db_name: &str,
1250 schema_path: SchemaPath<'_>,
1251 class_name: &str,
1252 ) -> CatalogResult<ObjectId> {
1253 schema_path
1254 .try_find(|schema_name| -> CatalogResult<_> {
1255 let schema = self.get_schema_by_name(db_name, schema_name)?;
1256
1257 if let Some(item) = schema.get_system_table_by_name(class_name) {
1258 Ok(Some(item.id().as_object_id()))
1259 } else if let Some(item) = schema.get_any_table_by_name(class_name) {
1260 Ok(Some(item.id().as_object_id()))
1261 } else if let Some(item) = schema.get_any_index_by_name(class_name) {
1262 Ok(Some(item.id.as_object_id()))
1263 } else if let Some(item) = schema.get_source_by_name(class_name) {
1264 Ok(Some(item.id.as_object_id()))
1265 } else if let Some(item) = schema.get_view_by_name(class_name) {
1266 Ok(Some(item.id.as_object_id()))
1267 } else if let Some(item) = schema.get_any_sink_by_name(class_name) {
1268 Ok(Some(item.id.as_object_id()))
1269 } else {
1270 Ok(None)
1271 }
1272 })?
1273 .map(|(id, _)| id)
1274 .ok_or_else(|| CatalogError::not_found("class", class_name))
1275 }
1276}
1277
1278#[cfg(test)]
1279mod tests {
1280 use risingwave_pb::catalog::{
1281 PbCreateType, PbDatabase, PbSchema, PbSink, PbSinkType, PbStreamJobStatus,
1282 };
1283
1284 use super::Catalog;
1285
1286 fn test_sink(id: u32, name: &str, database_id: u32, schema_id: u32) -> PbSink {
1287 PbSink {
1288 id: id.into(),
1289 name: name.to_owned(),
1290 database_id: database_id.into(),
1291 schema_id: schema_id.into(),
1292 sink_type: PbSinkType::AppendOnly.into(),
1293 stream_job_status: PbStreamJobStatus::Creating.into(),
1294 create_type: PbCreateType::Background.into(),
1295 ..Default::default()
1296 }
1297 }
1298
1299 #[test]
1300 fn test_update_sink_set_schema_drops_old_catalog() {
1301 let database_id = 1;
1302 let old_schema_id = 2;
1303 let new_schema_id = 3;
1304 let sink_id = 4;
1305 let mut catalog = Catalog::default();
1306 catalog.create_database(&PbDatabase {
1307 id: database_id.into(),
1308 name: "dev".to_owned(),
1309 ..Default::default()
1310 });
1311 catalog.create_schema(&PbSchema {
1312 id: old_schema_id.into(),
1313 database_id: database_id.into(),
1314 name: "public".to_owned(),
1315 ..Default::default()
1316 });
1317 catalog.create_schema(&PbSchema {
1318 id: new_schema_id.into(),
1319 database_id: database_id.into(),
1320 name: "archive".to_owned(),
1321 ..Default::default()
1322 });
1323 catalog.create_sink(&test_sink(
1324 sink_id,
1325 "replace_kafka_sink",
1326 database_id,
1327 old_schema_id,
1328 ));
1329
1330 catalog.update_sink(&test_sink(
1331 sink_id,
1332 "replace_kafka_sink",
1333 database_id,
1334 new_schema_id,
1335 ));
1336
1337 let old_schema = catalog
1338 .get_schema_by_id(database_id.into(), old_schema_id.into())
1339 .unwrap();
1340 assert!(old_schema.get_sink_by_id(sink_id.into()).is_none());
1341 let new_schema = catalog
1342 .get_schema_by_id(database_id.into(), new_schema_id.into())
1343 .unwrap();
1344 assert!(new_schema.get_sink_by_id(sink_id.into()).is_some());
1345 }
1346}