1use std::collections::{BTreeMap, BTreeSet, VecDeque};
14use std::fmt::Debug;
15use std::iter;
16use std::str::FromStr;
17use std::sync::Arc;
18
19use differential_dataflow::consolidation::consolidate_updates;
20use futures::future;
21use itertools::{Either, Itertools};
22use mz_adapter_types::connection::ConnectionId;
23use mz_catalog::SYSTEM_CONN_ID;
24use mz_catalog::builtin::{
25 BUILTIN_LOG_LOOKUP, BUILTIN_LOOKUP, Builtin, BuiltinLog, BuiltinTable, BuiltinView,
26};
27use mz_catalog::durable::objects::{
28 ClusterKey, DatabaseKey, DurableType, ItemKey, NetworkPolicyKey, RoleAuthKey, RoleKey,
29 SchemaKey,
30};
31use mz_catalog::durable::{CatalogError, SystemObjectMapping};
32use mz_catalog::memory::error::{Error, ErrorKind};
33use mz_catalog::memory::objects::{
34 CatalogEntry, CatalogItem, Cluster, ClusterReplica, Database, Func, Index, Log, NetworkPolicy,
35 Role, RoleAuth, Schema, Source, StateDiff, StateUpdate, StateUpdateKind, Table,
36 TableDataSource, TemporaryItem, Type, UpdateFrom,
37};
38use mz_compute_types::config::ComputeReplicaConfig;
39use mz_compute_types::dataflows::DataflowDescription;
40use mz_controller::clusters::{ReplicaConfig, ReplicaLogging};
41use mz_controller_types::ClusterId;
42use mz_expr::MirScalarExpr;
43use mz_ore::collections::CollectionExt;
44use mz_ore::tracing::OpenTelemetryContext;
45use mz_ore::{
46 instrument, soft_assert_eq_or_log, soft_assert_no_log, soft_assert_or_log, soft_panic_or_log,
47};
48use mz_pgrepr::oid::INVALID_OID;
49use mz_repr::adt::mz_acl_item::{MzAclItem, PrivilegeMap};
50use mz_repr::role_id::RoleId;
51use mz_repr::{CatalogItemId, Diff, GlobalId, RelationVersion, Timestamp, VersionedRelationDesc};
52use mz_sql::catalog::CatalogError as SqlCatalogError;
53use mz_sql::catalog::{CatalogItem as SqlCatalogItem, CatalogItemType, CatalogSchema, CatalogType};
54use mz_sql::names::{
55 FullItemName, ItemQualifiers, QualifiedItemName, RawDatabaseSpecifier,
56 ResolvedDatabaseSpecifier, ResolvedIds, SchemaSpecifier,
57};
58use mz_sql::session::user::MZ_SYSTEM_ROLE_ID;
59use mz_sql::session::vars::{VarError, VarInput};
60use mz_sql::{plan, rbac};
61use mz_sql_parser::ast::Expr;
62use mz_storage_types::sources::Timeline;
63use mz_transform::dataflow::DataflowMetainfo;
64use mz_transform::notice::OptimizerNotice;
65use tracing::{info_span, warn};
66
67use crate::AdapterError;
68use crate::catalog::state::LocalExpressionCache;
69use crate::catalog::{BuiltinTableUpdate, CatalogState};
70use crate::coord::catalog_implications::parsed_state_updates::{self, ParsedStateUpdate};
71use crate::util::{index_sql, sort_topological};
72
73#[derive(Debug, Clone, Default)]
85struct InProgressRetractions {
86 roles: BTreeMap<RoleKey, Role>,
87 role_auths: BTreeMap<RoleAuthKey, RoleAuth>,
88 databases: BTreeMap<DatabaseKey, Database>,
89 schemas: BTreeMap<SchemaKey, Schema>,
90 clusters: BTreeMap<ClusterKey, Cluster>,
91 network_policies: BTreeMap<NetworkPolicyKey, NetworkPolicy>,
92 items: BTreeMap<ItemKey, CatalogEntry>,
93 temp_items: BTreeMap<CatalogItemId, CatalogEntry>,
94 introspection_source_indexes: BTreeMap<CatalogItemId, CatalogEntry>,
95 system_object_mappings: BTreeMap<CatalogItemId, CatalogEntry>,
96}
97
98impl CatalogState {
99 #[must_use]
103 #[instrument]
104 pub(crate) async fn apply_updates(
105 &mut self,
106 updates: Vec<StateUpdate>,
107 local_expression_cache: &mut LocalExpressionCache,
108 ) -> (
109 Vec<BuiltinTableUpdate<&'static BuiltinTable>>,
110 Vec<ParsedStateUpdate>,
111 ) {
112 let mut builtin_table_updates = Vec::with_capacity(updates.len());
113 let mut catalog_updates = Vec::with_capacity(updates.len());
114
115 let updates = Self::consolidate_updates(updates);
120
121 let mut groups: Vec<Vec<_>> = Vec::new();
123 for (_, updates) in &updates.into_iter().chunk_by(|update| update.ts) {
124 let updates = sort_updates(updates.collect());
128 groups.push(updates);
129 }
130
131 for updates in groups {
132 let mut apply_state = ApplyState::Updates(Vec::new());
133 let mut retractions = InProgressRetractions::default();
134
135 for update in updates {
136 let (next_apply_state, (builtin_table_update, catalog_update)) = apply_state
137 .step(
138 ApplyState::new(update),
139 self,
140 &mut retractions,
141 local_expression_cache,
142 )
143 .await;
144 apply_state = next_apply_state;
145 builtin_table_updates.extend(builtin_table_update);
146 catalog_updates.extend(catalog_update);
147 }
148
149 let (builtin_table_update, catalog_update) = apply_state
151 .apply(self, &mut retractions, local_expression_cache)
152 .await;
153 builtin_table_updates.extend(builtin_table_update);
154 catalog_updates.extend(catalog_update);
155
156 let dropped_entries: Vec<CatalogEntry> = retractions
159 .items
160 .into_values()
161 .chain(retractions.temp_items.into_values())
162 .collect();
163 if !dropped_entries.is_empty() {
164 let dropped_notices = self.drop_optimizer_notices(dropped_entries);
165 if self.system_config().enable_mz_notices() {
166 self.pack_optimizer_notice_updates(
167 &mut builtin_table_updates,
168 dropped_notices.iter(),
169 Diff::MINUS_ONE,
170 );
171 }
172 }
173 }
174
175 (builtin_table_updates, catalog_updates)
176 }
177
178 fn consolidate_updates(updates: Vec<StateUpdate>) -> Vec<StateUpdate> {
186 let mut updates: Vec<(StateUpdateKind, Timestamp, mz_repr::Diff)> = updates
187 .into_iter()
188 .map(|update| (update.kind, update.ts, update.diff.into()))
189 .collect_vec();
190
191 consolidate_updates(&mut updates);
192
193 updates
194 .into_iter()
195 .map(|(kind, ts, diff)| StateUpdate {
196 kind,
197 ts,
198 diff: diff
199 .try_into()
200 .expect("catalog state cannot have diff other than -1 or 1"),
201 })
202 .collect_vec()
203 }
204
205 #[instrument(level = "debug")]
206 fn apply_updates_inner(
207 &mut self,
208 updates: Vec<StateUpdate>,
209 retractions: &mut InProgressRetractions,
210 local_expression_cache: &mut LocalExpressionCache,
211 ) -> Result<
212 (
213 Vec<BuiltinTableUpdate<&'static BuiltinTable>>,
214 Vec<ParsedStateUpdate>,
215 ),
216 CatalogError,
217 > {
218 soft_assert_no_log!(
219 updates.iter().map(|update| update.ts).all_equal(),
220 "all timestamps should be equal: {updates:?}"
221 );
222
223 let mut update_system_config = false;
224
225 let mut builtin_table_updates = Vec::with_capacity(updates.len());
226 let mut catalog_updates = Vec::new();
227
228 for state_update in updates {
229 if matches!(state_update.kind, StateUpdateKind::SystemConfiguration(_)) {
230 update_system_config = true;
231 }
232
233 match state_update.diff {
234 StateDiff::Retraction => {
235 if let Some(update) =
239 parsed_state_updates::parse_state_update(self, state_update.clone())
240 {
241 catalog_updates.push(update);
242 }
243
244 builtin_table_updates.extend(self.generate_builtin_table_update(
247 state_update.kind.clone(),
248 state_update.diff,
249 ));
250 self.apply_update(
251 state_update.kind,
252 state_update.diff,
253 retractions,
254 local_expression_cache,
255 )?;
256 }
257 StateDiff::Addition => {
258 self.apply_update(
259 state_update.kind.clone(),
260 state_update.diff,
261 retractions,
262 local_expression_cache,
263 )?;
264 builtin_table_updates.extend(self.generate_builtin_table_update(
268 state_update.kind.clone(),
269 state_update.diff,
270 ));
271
272 if let Some(update) =
275 parsed_state_updates::parse_state_update(self, state_update.clone())
276 {
277 catalog_updates.push(update);
278 }
279 }
280 }
281 }
282
283 if update_system_config {
284 self.system_configuration.dyncfg_updates();
285 }
286
287 Ok((builtin_table_updates, catalog_updates))
288 }
289
290 #[instrument(level = "debug")]
291 fn apply_update(
292 &mut self,
293 kind: StateUpdateKind,
294 diff: StateDiff,
295 retractions: &mut InProgressRetractions,
296 local_expression_cache: &mut LocalExpressionCache,
297 ) -> Result<(), CatalogError> {
298 match kind {
299 StateUpdateKind::Role(role) => {
300 self.apply_role_update(role, diff, retractions);
301 }
302 StateUpdateKind::RoleAuth(role_auth) => {
303 self.apply_role_auth_update(role_auth, diff, retractions);
304 }
305 StateUpdateKind::Database(database) => {
306 self.apply_database_update(database, diff, retractions);
307 }
308 StateUpdateKind::Schema(schema) => {
309 self.apply_schema_update(schema, diff, retractions);
310 }
311 StateUpdateKind::DefaultPrivilege(default_privilege) => {
312 self.apply_default_privilege_update(default_privilege, diff, retractions);
313 }
314 StateUpdateKind::SystemPrivilege(system_privilege) => {
315 self.apply_system_privilege_update(system_privilege, diff, retractions);
316 }
317 StateUpdateKind::SystemConfiguration(system_configuration) => {
318 self.apply_system_configuration_update(system_configuration, diff, retractions);
319 }
320 StateUpdateKind::ClusterSystemConfiguration(cfg) => {
321 Self::apply_scoped_system_configuration_update(
322 &mut self.scoped_system_parameters.cluster,
323 cfg.cluster_id,
324 cfg.name,
325 cfg.value,
326 diff,
327 );
328 }
329 StateUpdateKind::ReplicaSystemConfiguration(cfg) => {
330 Self::apply_scoped_system_configuration_update(
331 &mut self.scoped_system_parameters.replica,
332 cfg.replica_id,
333 cfg.name,
334 cfg.value,
335 diff,
336 );
337 }
338 StateUpdateKind::Cluster(cluster) => {
339 self.apply_cluster_update(cluster, diff, retractions);
340 }
341 StateUpdateKind::NetworkPolicy(network_policy) => {
342 self.apply_network_policy_update(network_policy, diff, retractions);
343 }
344 StateUpdateKind::IntrospectionSourceIndex(introspection_source_index) => {
345 self.apply_introspection_source_index_update(
346 introspection_source_index,
347 diff,
348 retractions,
349 );
350 }
351 StateUpdateKind::ClusterReplica(cluster_replica) => {
352 self.apply_cluster_replica_update(cluster_replica, diff, retractions);
353 }
354 StateUpdateKind::SystemObjectMapping(system_object_mapping) => {
355 self.apply_system_object_mapping_update(
356 system_object_mapping,
357 diff,
358 retractions,
359 local_expression_cache,
360 );
361 }
362 StateUpdateKind::TemporaryItem(item) => {
363 self.apply_temporary_item_update(item, diff, retractions, local_expression_cache);
364 }
365 StateUpdateKind::Item(item) => {
366 self.apply_item_update(item, diff, retractions, local_expression_cache)?;
367 }
368 StateUpdateKind::Comment(comment) => {
369 self.apply_comment_update(comment, diff, retractions);
370 }
371 StateUpdateKind::SourceReferences(source_reference) => {
372 self.apply_source_references_update(source_reference, diff, retractions);
373 }
374 StateUpdateKind::AuditLog(_audit_log) => {
375 }
377 StateUpdateKind::StorageCollectionMetadata(storage_collection_metadata) => {
378 self.apply_storage_collection_metadata_update(
379 storage_collection_metadata,
380 diff,
381 retractions,
382 );
383 }
384 StateUpdateKind::UnfinalizedShard(unfinalized_shard) => {
385 self.apply_unfinalized_shard_update(unfinalized_shard, diff, retractions);
386 }
387 }
388
389 Ok(())
390 }
391
392 #[instrument(level = "debug")]
393 fn apply_role_auth_update(
394 &mut self,
395 role_auth: mz_catalog::durable::RoleAuth,
396 diff: StateDiff,
397 retractions: &mut InProgressRetractions,
398 ) {
399 apply_with_update(
400 &mut self.role_auth_by_id,
401 role_auth,
402 |role_auth| role_auth.role_id,
403 diff,
404 &mut retractions.role_auths,
405 );
406 }
407
408 #[instrument(level = "debug")]
409 fn apply_role_update(
410 &mut self,
411 role: mz_catalog::durable::Role,
412 diff: StateDiff,
413 retractions: &mut InProgressRetractions,
414 ) {
415 apply_inverted_lookup(&mut self.roles_by_name, &role.name, role.id, diff);
416 apply_with_update(
417 &mut self.roles_by_id,
418 role,
419 |role| role.id,
420 diff,
421 &mut retractions.roles,
422 );
423 }
424
425 #[instrument(level = "debug")]
426 fn apply_database_update(
427 &mut self,
428 database: mz_catalog::durable::Database,
429 diff: StateDiff,
430 retractions: &mut InProgressRetractions,
431 ) {
432 apply_inverted_lookup(
433 &mut self.database_by_name,
434 &database.name,
435 database.id,
436 diff,
437 );
438 apply_with_update(
439 &mut self.database_by_id,
440 database,
441 |database| database.id,
442 diff,
443 &mut retractions.databases,
444 );
445 }
446
447 #[instrument(level = "debug")]
448 fn apply_schema_update(
449 &mut self,
450 schema: mz_catalog::durable::Schema,
451 diff: StateDiff,
452 retractions: &mut InProgressRetractions,
453 ) {
454 match &schema.database_id {
455 Some(database_id) => {
456 let db = self
457 .database_by_id
458 .get_mut(database_id)
459 .expect("catalog out of sync");
460 apply_inverted_lookup(&mut db.schemas_by_name, &schema.name, schema.id, diff);
461 apply_with_update(
462 &mut db.schemas_by_id,
463 schema,
464 |schema| schema.id,
465 diff,
466 &mut retractions.schemas,
467 );
468 }
469 None => {
470 apply_inverted_lookup(
471 &mut self.ambient_schemas_by_name,
472 &schema.name,
473 schema.id,
474 diff,
475 );
476 apply_with_update(
477 &mut self.ambient_schemas_by_id,
478 schema,
479 |schema| schema.id,
480 diff,
481 &mut retractions.schemas,
482 );
483 }
484 }
485 }
486
487 #[instrument(level = "debug")]
488 fn apply_default_privilege_update(
489 &mut self,
490 default_privilege: mz_catalog::durable::DefaultPrivilege,
491 diff: StateDiff,
492 _retractions: &mut InProgressRetractions,
493 ) {
494 match diff {
495 StateDiff::Addition => Arc::make_mut(&mut self.default_privileges)
496 .grant(default_privilege.object, default_privilege.acl_item),
497 StateDiff::Retraction => Arc::make_mut(&mut self.default_privileges)
498 .revoke(&default_privilege.object, &default_privilege.acl_item),
499 }
500 }
501
502 #[instrument(level = "debug")]
503 fn apply_system_privilege_update(
504 &mut self,
505 system_privilege: MzAclItem,
506 diff: StateDiff,
507 _retractions: &mut InProgressRetractions,
508 ) {
509 match diff {
510 StateDiff::Addition => {
511 Arc::make_mut(&mut self.system_privileges).grant(system_privilege)
512 }
513 StateDiff::Retraction => {
514 Arc::make_mut(&mut self.system_privileges).revoke(&system_privilege)
515 }
516 }
517 }
518
519 #[instrument(level = "debug")]
520 fn apply_system_configuration_update(
521 &mut self,
522 system_configuration: mz_catalog::durable::SystemConfiguration,
523 diff: StateDiff,
524 _retractions: &mut InProgressRetractions,
525 ) {
526 let res = match diff {
527 StateDiff::Addition => self.insert_system_configuration(
528 &system_configuration.name,
529 VarInput::Flat(&system_configuration.value),
530 ),
531 StateDiff::Retraction => self.remove_system_configuration(&system_configuration.name),
532 };
533 match res {
534 Ok(_) => (),
535 Err(Error {
539 kind: ErrorKind::VarError(VarError::UnknownParameter(name)),
540 }) => {
541 warn!(%name, "unknown system parameter from catalog storage");
542 }
543 Err(e) => panic!("unable to update system variable: {e:?}"),
544 }
545 }
546
547 fn apply_scoped_system_configuration_update<Id: Ord>(
561 map: &mut BTreeMap<Id, BTreeMap<String, String>>,
562 id: Id,
563 name: String,
564 value: String,
565 diff: StateDiff,
566 ) {
567 match diff {
568 StateDiff::Addition => {
569 map.entry(id).or_default().insert(name, value);
570 }
571 StateDiff::Retraction => {
572 if let Some(values) = map.get_mut(&id) {
573 if values.get(&name) == Some(&value) {
574 values.remove(&name);
575 if values.is_empty() {
576 map.remove(&id);
577 }
578 }
579 }
580 }
581 }
582 }
583
584 #[instrument(level = "debug")]
585 fn apply_cluster_update(
586 &mut self,
587 cluster: mz_catalog::durable::Cluster,
588 diff: StateDiff,
589 retractions: &mut InProgressRetractions,
590 ) {
591 if matches!(diff, StateDiff::Addition) {
598 if let mz_catalog::durable::ClusterVariant::Managed(managed) = &cluster.config.variant {
599 if !self.cluster_replica_sizes.0.contains_key(&managed.size) {
600 soft_panic_or_log!(
601 "managed cluster {} ({}) references unknown replica size {:?}; \
602 mz_clusters.disk will resolve to false",
603 cluster.name,
604 cluster.id,
605 managed.size,
606 );
607 }
608 }
609 }
610 apply_inverted_lookup(&mut self.clusters_by_name, &cluster.name, cluster.id, diff);
611 apply_with_update(
612 &mut self.clusters_by_id,
613 cluster,
614 |cluster| cluster.id,
615 diff,
616 &mut retractions.clusters,
617 );
618 }
619
620 #[instrument(level = "debug")]
621 fn apply_network_policy_update(
622 &mut self,
623 policy: mz_catalog::durable::NetworkPolicy,
624 diff: StateDiff,
625 retractions: &mut InProgressRetractions,
626 ) {
627 apply_inverted_lookup(
628 &mut self.network_policies_by_name,
629 &policy.name,
630 policy.id,
631 diff,
632 );
633 apply_with_update(
634 &mut self.network_policies_by_id,
635 policy,
636 |policy| policy.id,
637 diff,
638 &mut retractions.network_policies,
639 );
640 }
641
642 #[instrument(level = "debug")]
643 fn apply_introspection_source_index_update(
644 &mut self,
645 introspection_source_index: mz_catalog::durable::IntrospectionSourceIndex,
646 diff: StateDiff,
647 retractions: &mut InProgressRetractions,
648 ) {
649 let cluster = self
650 .clusters_by_id
651 .get_mut(&introspection_source_index.cluster_id)
652 .expect("catalog out of sync");
653 let log = BUILTIN_LOG_LOOKUP
654 .get(introspection_source_index.name.as_str())
655 .expect("missing log");
656 apply_inverted_lookup(
657 &mut cluster.log_indexes,
658 &log.variant,
659 introspection_source_index.index_id,
660 diff,
661 );
662
663 match diff {
664 StateDiff::Addition => {
665 if let Some(mut entry) = retractions
666 .introspection_source_indexes
667 .remove(&introspection_source_index.item_id)
668 {
669 let (index_name, index) = self.create_introspection_source_index(
672 introspection_source_index.cluster_id,
673 log,
674 introspection_source_index.index_id,
675 );
676 assert_eq!(entry.id, introspection_source_index.item_id);
677 assert_eq!(entry.oid, introspection_source_index.oid);
678 assert_eq!(entry.name, index_name);
679 entry.item = index;
680 self.insert_entry(entry);
681 } else {
682 self.insert_introspection_source_index(
683 introspection_source_index.cluster_id,
684 log,
685 introspection_source_index.item_id,
686 introspection_source_index.index_id,
687 introspection_source_index.oid,
688 );
689 }
690 }
691 StateDiff::Retraction => {
692 let entry = self.drop_item(introspection_source_index.item_id);
693 retractions
694 .introspection_source_indexes
695 .insert(entry.id, entry);
696 }
697 }
698 }
699
700 #[instrument(level = "debug")]
701 fn apply_cluster_replica_update(
702 &mut self,
703 cluster_replica: mz_catalog::durable::ClusterReplica,
704 diff: StateDiff,
705 _retractions: &mut InProgressRetractions,
706 ) {
707 let cluster = self
708 .clusters_by_id
709 .get(&cluster_replica.cluster_id)
710 .expect("catalog out of sync");
711
712 if let mz_catalog::durable::ReplicaLocation::Managed { size, .. } =
721 &cluster_replica.config.location
722 {
723 if !self.cluster_replica_sizes.0.contains_key(size) {
724 soft_panic_or_log!(
725 "cluster replica {}.{} ({}) references unknown replica size {:?}; \
726 skipping in-memory registration",
727 cluster.name,
728 cluster_replica.name,
729 cluster_replica.replica_id,
730 size,
731 );
732 return;
733 }
734 }
735
736 let location = self
742 .concretize_replica_location(cluster_replica.config.location, &vec![], None, true)
743 .expect("catalog in unexpected state");
744 let cluster = self
745 .clusters_by_id
746 .get_mut(&cluster_replica.cluster_id)
747 .expect("catalog out of sync");
748 apply_inverted_lookup(
749 &mut cluster.replica_id_by_name_,
750 &cluster_replica.name,
751 cluster_replica.replica_id,
752 diff,
753 );
754 match diff {
755 StateDiff::Retraction => {
756 let prev = cluster.replicas_by_id_.remove(&cluster_replica.replica_id);
757 assert!(
758 prev.is_some(),
759 "retraction does not match existing value: {:?}",
760 cluster_replica.replica_id
761 );
762 }
763 StateDiff::Addition => {
764 let logging = ReplicaLogging {
765 log_logging: cluster_replica.config.logging.log_logging,
766 interval: cluster_replica.config.logging.interval,
767 };
768 let config = ReplicaConfig {
769 location,
770 compute: ComputeReplicaConfig { logging },
771 };
772 let mem_cluster_replica = ClusterReplica {
773 name: cluster_replica.name.clone(),
774 cluster_id: cluster_replica.cluster_id,
775 replica_id: cluster_replica.replica_id,
776 config,
777 owner_id: cluster_replica.owner_id,
778 };
779 let prev = cluster
780 .replicas_by_id_
781 .insert(cluster_replica.replica_id, mem_cluster_replica);
782 assert_eq!(
783 prev, None,
784 "values must be explicitly retracted before inserting a new value: {:?}",
785 cluster_replica.replica_id
786 );
787 }
788 }
789 }
790
791 #[instrument(level = "debug")]
792 fn apply_system_object_mapping_update(
793 &mut self,
794 system_object_mapping: mz_catalog::durable::SystemObjectMapping,
795 diff: StateDiff,
796 retractions: &mut InProgressRetractions,
797 local_expression_cache: &mut LocalExpressionCache,
798 ) {
799 let item_id = system_object_mapping.unique_identifier.catalog_id;
800 let global_id = system_object_mapping.unique_identifier.global_id;
801
802 if system_object_mapping.unique_identifier.runtime_alterable() {
803 return;
807 }
808
809 if let StateDiff::Retraction = diff {
810 let entry = self.drop_item(item_id);
811 retractions.system_object_mappings.insert(item_id, entry);
812 return;
813 }
814
815 if let Some(entry) = retractions.system_object_mappings.remove(&item_id) {
816 self.insert_entry(entry);
821 return;
822 }
823
824 let builtin = BUILTIN_LOOKUP
825 .get(&system_object_mapping.description)
826 .expect("missing builtin")
827 .1;
828 let schema_name = builtin.schema();
829 let schema_id = self
830 .ambient_schemas_by_name
831 .get(schema_name)
832 .unwrap_or_else(|| panic!("unknown ambient schema: {schema_name}"));
833 let name = QualifiedItemName {
834 qualifiers: ItemQualifiers {
835 database_spec: ResolvedDatabaseSpecifier::Ambient,
836 schema_spec: SchemaSpecifier::Id(*schema_id),
837 },
838 item: builtin.name().into(),
839 };
840 match builtin {
841 Builtin::Log(log) => {
842 let mut acl_items = vec![rbac::owner_privilege(
843 mz_sql::catalog::ObjectType::Source,
844 MZ_SYSTEM_ROLE_ID,
845 )];
846 acl_items.extend_from_slice(&log.access);
847 self.insert_item(
848 item_id,
849 log.oid,
850 name.clone(),
851 CatalogItem::Log(Log {
852 variant: log.variant,
853 global_id,
854 }),
855 MZ_SYSTEM_ROLE_ID,
856 PrivilegeMap::from_mz_acl_items(acl_items),
857 );
858 }
859
860 Builtin::Table(table) => {
861 let mut acl_items = vec![rbac::owner_privilege(
862 mz_sql::catalog::ObjectType::Table,
863 MZ_SYSTEM_ROLE_ID,
864 )];
865 acl_items.extend_from_slice(&table.access);
866
867 self.insert_item(
868 item_id,
869 table.oid,
870 name.clone(),
871 CatalogItem::Table(Table {
872 create_sql: None,
873 desc: VersionedRelationDesc::new(table.desc.clone()),
874 collections: [(RelationVersion::root(), global_id)].into_iter().collect(),
875 conn_id: None,
876 resolved_ids: ResolvedIds::empty(),
877 custom_logical_compaction_window: table.is_retained_metrics_object.then(
878 || {
879 self.system_config()
880 .metrics_retention()
881 .try_into()
882 .expect("invalid metrics retention")
883 },
884 ),
885 is_retained_metrics_object: table.is_retained_metrics_object,
886 data_source: TableDataSource::TableWrites {
887 defaults: vec![Expr::null(); table.desc.arity()],
888 },
889 }),
890 MZ_SYSTEM_ROLE_ID,
891 PrivilegeMap::from_mz_acl_items(acl_items),
892 );
893 }
894 Builtin::Index(index) => {
895 let custom_logical_compaction_window =
896 index.is_retained_metrics_object.then(|| {
897 self.system_config()
898 .metrics_retention()
899 .try_into()
900 .expect("invalid metrics retention")
901 });
902 let versions = BTreeMap::new();
904
905 let item = self
906 .parse_item(
907 global_id,
908 &index.create_sql(),
909 &versions,
910 None,
911 index.is_retained_metrics_object,
912 custom_logical_compaction_window,
913 local_expression_cache,
914 None,
915 )
916 .unwrap_or_else(|e| {
917 panic!(
918 "internal error: failed to load bootstrap index:\n\
919 {}\n\
920 error:\n\
921 {:?}\n\n\
922 make sure that the schema name is specified in the builtin index's create sql statement.",
923 index.name, e
924 )
925 });
926 let CatalogItem::Index(_) = item else {
927 panic!(
928 "internal error: builtin index {}'s SQL does not begin with \"CREATE INDEX\".",
929 index.name
930 );
931 };
932
933 self.insert_item(
934 item_id,
935 index.oid,
936 name,
937 item,
938 MZ_SYSTEM_ROLE_ID,
939 PrivilegeMap::default(),
940 );
941 }
942 Builtin::View(_) => {
943 unreachable!("views added elsewhere");
945 }
946
947 Builtin::Type(typ) => {
949 let typ = self.resolve_builtin_type_references(typ);
950 if let CatalogType::Array { element_reference } = typ.details.typ {
951 let entry = self.get_entry_mut(&element_reference);
952 let item_type = match &mut entry.item {
953 CatalogItem::Type(item_type) => item_type,
954 _ => unreachable!("types can only reference other types"),
955 };
956 item_type.details.array_id = Some(item_id);
957 }
958
959 let schema_id = self.resolve_system_schema(typ.schema);
960
961 self.insert_item(
962 item_id,
963 typ.oid,
964 QualifiedItemName {
965 qualifiers: ItemQualifiers {
966 database_spec: ResolvedDatabaseSpecifier::Ambient,
967 schema_spec: SchemaSpecifier::Id(schema_id),
968 },
969 item: typ.name.to_owned(),
970 },
971 CatalogItem::Type(Type {
972 create_sql: None,
973 global_id,
974 details: typ.details.clone(),
975 resolved_ids: ResolvedIds::empty(),
976 }),
977 MZ_SYSTEM_ROLE_ID,
978 PrivilegeMap::from_mz_acl_items(vec![
979 rbac::default_builtin_object_privilege(mz_sql::catalog::ObjectType::Type),
980 rbac::owner_privilege(mz_sql::catalog::ObjectType::Type, MZ_SYSTEM_ROLE_ID),
981 ]),
982 );
983 }
984
985 Builtin::Func(func) => {
986 let oid = INVALID_OID;
990 self.insert_item(
991 item_id,
992 oid,
993 name.clone(),
994 CatalogItem::Func(Func {
995 inner: func.inner,
996 global_id,
997 }),
998 MZ_SYSTEM_ROLE_ID,
999 PrivilegeMap::default(),
1000 );
1001 }
1002
1003 Builtin::Source(coll) => {
1004 let mut acl_items = vec![rbac::owner_privilege(
1005 mz_sql::catalog::ObjectType::Source,
1006 MZ_SYSTEM_ROLE_ID,
1007 )];
1008 acl_items.extend_from_slice(&coll.access);
1009
1010 self.insert_item(
1011 item_id,
1012 coll.oid,
1013 name.clone(),
1014 CatalogItem::Source(Source {
1015 create_sql: None,
1016 data_source: coll.data_source.clone(),
1017 desc: coll.desc.clone(),
1018 global_id,
1019 timeline: Timeline::EpochMilliseconds,
1020 resolved_ids: ResolvedIds::empty(),
1021 custom_logical_compaction_window: coll.is_retained_metrics_object.then(
1022 || {
1023 self.system_config()
1024 .metrics_retention()
1025 .try_into()
1026 .expect("invalid metrics retention")
1027 },
1028 ),
1029 is_retained_metrics_object: coll.is_retained_metrics_object,
1030 }),
1031 MZ_SYSTEM_ROLE_ID,
1032 PrivilegeMap::from_mz_acl_items(acl_items),
1033 );
1034 }
1035 Builtin::MaterializedView(mv) => {
1036 let mut acl_items = vec![rbac::owner_privilege(
1037 mz_sql::catalog::ObjectType::MaterializedView,
1038 MZ_SYSTEM_ROLE_ID,
1039 )];
1040 acl_items.extend_from_slice(&mv.access);
1041
1042 let custom_logical_compaction_window = mv.is_retained_metrics_object.then(|| {
1043 self.system_config()
1044 .metrics_retention()
1045 .try_into()
1046 .expect("invalid metrics retention")
1047 });
1048
1049 let versions = BTreeMap::new();
1051
1052 let mut item = self
1053 .parse_item(
1054 global_id,
1055 &mv.create_sql(),
1056 &versions,
1057 None,
1058 mv.is_retained_metrics_object,
1059 custom_logical_compaction_window,
1060 local_expression_cache,
1061 None,
1062 )
1063 .unwrap_or_else(|e| {
1064 panic!(
1065 "internal error: failed to load bootstrap materialized view:\n\
1066 {}\n\
1067 error:\n\
1068 {e:?}\n\n\
1069 make sure that the schema name is specified in the builtin \
1070 materialized view's create sql statement.",
1071 mv.name,
1072 )
1073 });
1074 let CatalogItem::MaterializedView(catalog_mv) = &mut item else {
1075 panic!(
1076 "internal error: builtin materialized view {}'s SQL does not begin \
1077 with \"CREATE MATERIALIZED VIEW\".",
1078 mv.name,
1079 );
1080 };
1081
1082 let mut desc = catalog_mv.desc.latest();
1086 for key in &mv.desc.typ().keys {
1087 desc = desc.with_key(key.clone());
1088 }
1089 catalog_mv.desc = VersionedRelationDesc::new(desc);
1090
1091 self.insert_item(
1092 item_id,
1093 mv.oid,
1094 name,
1095 item,
1096 MZ_SYSTEM_ROLE_ID,
1097 PrivilegeMap::from_mz_acl_items(acl_items),
1098 );
1099 }
1100 Builtin::Connection(connection) => {
1101 let versions = BTreeMap::new();
1103 let mut item = self
1104 .parse_item(
1105 global_id,
1106 connection.sql,
1107 &versions,
1108 None,
1109 false,
1110 None,
1111 local_expression_cache,
1112 None,
1113 )
1114 .unwrap_or_else(|e| {
1115 panic!(
1116 "internal error: failed to load bootstrap connection:\n\
1117 {}\n\
1118 error:\n\
1119 {:?}\n\n\
1120 make sure that the schema name is specified in the builtin connection's create sql statement.",
1121 connection.name, e
1122 )
1123 });
1124 let CatalogItem::Connection(_) = &mut item else {
1125 panic!(
1126 "internal error: builtin connection {}'s SQL does not begin with \"CREATE CONNECTION\".",
1127 connection.name
1128 );
1129 };
1130
1131 let mut acl_items = vec![rbac::owner_privilege(
1132 mz_sql::catalog::ObjectType::Connection,
1133 connection.owner_id.clone(),
1134 )];
1135 acl_items.extend_from_slice(connection.access);
1136
1137 self.insert_item(
1138 item_id,
1139 connection.oid,
1140 name.clone(),
1141 item,
1142 connection.owner_id.clone(),
1143 PrivilegeMap::from_mz_acl_items(acl_items),
1144 );
1145 }
1146 }
1147 }
1148
1149 #[instrument(level = "debug")]
1150 fn apply_temporary_item_update(
1151 &mut self,
1152 temporary_item: TemporaryItem,
1153 diff: StateDiff,
1154 retractions: &mut InProgressRetractions,
1155 local_expression_cache: &mut LocalExpressionCache,
1156 ) {
1157 match diff {
1158 StateDiff::Addition => {
1159 let TemporaryItem {
1160 id,
1161 oid,
1162 global_id,
1163 schema_id,
1164 name,
1165 conn_id,
1166 create_sql,
1167 owner_id,
1168 privileges,
1169 extra_versions,
1170 } = temporary_item;
1171 let temp_conn_id = conn_id
1174 .as_ref()
1175 .expect("temporary items must have a connection id");
1176 if !self.temporary_schemas.contains_key(temp_conn_id) {
1177 self.create_temporary_schema(temp_conn_id, owner_id)
1178 .expect("failed to create temporary schema");
1179 }
1180 let schema = self.find_temp_schema(&schema_id);
1181 let name = QualifiedItemName {
1182 qualifiers: ItemQualifiers {
1183 database_spec: schema.database().clone(),
1184 schema_spec: schema.id().clone(),
1185 },
1186 item: name.clone(),
1187 };
1188
1189 let entry = match retractions.temp_items.remove(&id) {
1190 Some(mut retraction) => {
1191 assert_eq!(retraction.id, id);
1192
1193 if retraction.create_sql() != create_sql {
1198 let mut catalog_item = self
1199 .deserialize_item(
1200 global_id,
1201 &create_sql,
1202 &extra_versions,
1203 local_expression_cache,
1204 Some(retraction.item),
1205 )
1206 .unwrap_or_else(|e| {
1207 panic!("{e:?}: invalid persisted SQL: {create_sql}")
1208 });
1209 catalog_item.set_conn_id(conn_id);
1216 catalog_item.set_create_sql(create_sql);
1227 retraction.item = catalog_item;
1228 }
1229
1230 retraction.id = id;
1231 retraction.oid = oid;
1232 retraction.name = name;
1233 retraction.owner_id = owner_id;
1234 retraction.privileges = PrivilegeMap::from_mz_acl_items(privileges);
1235 retraction
1236 }
1237 None => {
1238 let mut catalog_item = self
1239 .deserialize_item(
1240 global_id,
1241 &create_sql,
1242 &extra_versions,
1243 local_expression_cache,
1244 None,
1245 )
1246 .unwrap_or_else(|e| {
1247 panic!("{e:?}: invalid persisted SQL: {create_sql}")
1248 });
1249
1250 catalog_item.set_conn_id(conn_id);
1256 catalog_item.set_create_sql(create_sql);
1259
1260 CatalogEntry {
1261 item: catalog_item,
1262 referenced_by: Vec::new(),
1263 used_by: Vec::new(),
1264 id,
1265 oid,
1266 name,
1267 owner_id,
1268 privileges: PrivilegeMap::from_mz_acl_items(privileges),
1269 }
1270 }
1271 };
1272 self.insert_entry(entry);
1273 }
1274 StateDiff::Retraction => {
1275 let entry = self.drop_item(temporary_item.id);
1276 retractions.temp_items.insert(temporary_item.id, entry);
1277 }
1278 }
1279 }
1280
1281 #[instrument(level = "debug")]
1282 fn apply_item_update(
1283 &mut self,
1284 item: mz_catalog::durable::Item,
1285 diff: StateDiff,
1286 retractions: &mut InProgressRetractions,
1287 local_expression_cache: &mut LocalExpressionCache,
1288 ) -> Result<(), CatalogError> {
1289 match diff {
1290 StateDiff::Addition => {
1291 let key = item.key();
1292 let mz_catalog::durable::Item {
1293 id,
1294 oid,
1295 global_id,
1296 schema_id,
1297 name,
1298 create_sql,
1299 owner_id,
1300 privileges,
1301 extra_versions,
1302 } = item;
1303 let schema = self.find_non_temp_schema(&schema_id);
1304 let name = QualifiedItemName {
1305 qualifiers: ItemQualifiers {
1306 database_spec: schema.database().clone(),
1307 schema_spec: schema.id().clone(),
1308 },
1309 item: name.clone(),
1310 };
1311 let entry = match retractions.items.remove(&key) {
1312 Some(retraction) => {
1313 assert_eq!(retraction.id, item.id);
1314
1315 let item = self
1316 .deserialize_item(
1317 global_id,
1318 &create_sql,
1319 &extra_versions,
1320 local_expression_cache,
1321 Some(retraction.item),
1322 )
1323 .unwrap_or_else(|e| {
1324 panic!("{e:?}: invalid persisted SQL: {create_sql}")
1325 });
1326
1327 CatalogEntry {
1328 item,
1329 id,
1330 oid,
1331 name,
1332 owner_id,
1333 privileges: PrivilegeMap::from_mz_acl_items(privileges),
1334 referenced_by: retraction.referenced_by,
1335 used_by: retraction.used_by,
1336 }
1337 }
1338 None => {
1339 let catalog_item = self
1340 .deserialize_item(
1341 global_id,
1342 &create_sql,
1343 &extra_versions,
1344 local_expression_cache,
1345 None,
1346 )
1347 .unwrap_or_else(|e| {
1348 panic!("{e:?}: invalid persisted SQL: {create_sql}")
1349 });
1350 CatalogEntry {
1351 item: catalog_item,
1352 referenced_by: Vec::new(),
1353 used_by: Vec::new(),
1354 id,
1355 oid,
1356 name,
1357 owner_id,
1358 privileges: PrivilegeMap::from_mz_acl_items(privileges),
1359 }
1360 }
1361 };
1362
1363 self.insert_entry(entry);
1364 }
1365 StateDiff::Retraction => {
1366 let entry = self.drop_item(item.id);
1367 let key = item.into_key_value().0;
1368 retractions.items.insert(key, entry);
1369 }
1370 }
1371 Ok(())
1372 }
1373
1374 #[instrument(level = "debug")]
1375 fn apply_comment_update(
1376 &mut self,
1377 comment: mz_catalog::durable::Comment,
1378 diff: StateDiff,
1379 _retractions: &mut InProgressRetractions,
1380 ) {
1381 match diff {
1382 StateDiff::Addition => {
1383 let prev = Arc::make_mut(&mut self.comments).update_comment(
1384 comment.object_id,
1385 comment.sub_component,
1386 Some(comment.comment),
1387 );
1388 assert_eq!(
1389 prev, None,
1390 "values must be explicitly retracted before inserting a new value"
1391 );
1392 }
1393 StateDiff::Retraction => {
1394 let prev = Arc::make_mut(&mut self.comments).update_comment(
1395 comment.object_id,
1396 comment.sub_component,
1397 None,
1398 );
1399 assert_eq!(
1400 prev,
1401 Some(comment.comment),
1402 "retraction does not match existing value: ({:?}, {:?})",
1403 comment.object_id,
1404 comment.sub_component,
1405 );
1406 }
1407 }
1408 }
1409
1410 #[instrument(level = "debug")]
1411 fn apply_source_references_update(
1412 &mut self,
1413 source_references: mz_catalog::durable::SourceReferences,
1414 diff: StateDiff,
1415 _retractions: &mut InProgressRetractions,
1416 ) {
1417 match diff {
1418 StateDiff::Addition => {
1419 let prev = self
1420 .source_references
1421 .insert(source_references.source_id, source_references.into());
1422 assert!(
1423 prev.is_none(),
1424 "values must be explicitly retracted before inserting a new value: {prev:?}"
1425 );
1426 }
1427 StateDiff::Retraction => {
1428 let prev = self.source_references.remove(&source_references.source_id);
1429 assert!(
1430 prev.is_some(),
1431 "retraction for a non-existent existing value: {source_references:?}"
1432 );
1433 }
1434 }
1435 }
1436
1437 #[instrument(level = "debug")]
1438 fn apply_storage_collection_metadata_update(
1439 &mut self,
1440 storage_collection_metadata: mz_catalog::durable::StorageCollectionMetadata,
1441 diff: StateDiff,
1442 _retractions: &mut InProgressRetractions,
1443 ) {
1444 apply_inverted_lookup(
1445 &mut Arc::make_mut(&mut self.storage_metadata).collection_metadata,
1446 &storage_collection_metadata.id,
1447 storage_collection_metadata.shard,
1448 diff,
1449 );
1450 }
1451
1452 #[instrument(level = "debug")]
1453 fn apply_unfinalized_shard_update(
1454 &mut self,
1455 unfinalized_shard: mz_catalog::durable::UnfinalizedShard,
1456 diff: StateDiff,
1457 _retractions: &mut InProgressRetractions,
1458 ) {
1459 match diff {
1460 StateDiff::Addition => {
1461 let newly_inserted = Arc::make_mut(&mut self.storage_metadata)
1462 .unfinalized_shards
1463 .insert(unfinalized_shard.shard);
1464 assert!(
1465 newly_inserted,
1466 "values must be explicitly retracted before inserting a new value: {unfinalized_shard:?}",
1467 );
1468 }
1469 StateDiff::Retraction => {
1470 let removed = Arc::make_mut(&mut self.storage_metadata)
1471 .unfinalized_shards
1472 .remove(&unfinalized_shard.shard);
1473 assert!(
1474 removed,
1475 "retraction does not match existing value: {unfinalized_shard:?}"
1476 );
1477 }
1478 }
1479 }
1480
1481 #[instrument(level = "debug")]
1484 pub(crate) fn generate_builtin_table_update(
1485 &self,
1486 kind: StateUpdateKind,
1487 diff: StateDiff,
1488 ) -> Vec<BuiltinTableUpdate<&'static BuiltinTable>> {
1489 let diff = diff.into();
1490 match kind {
1491 StateUpdateKind::Role(_) => Vec::new(),
1495 StateUpdateKind::RoleAuth(role_auth) => {
1496 vec![self.pack_role_auth_update(role_auth.role_id, diff)]
1497 }
1498 StateUpdateKind::DefaultPrivilege(_) => Vec::new(),
1502 StateUpdateKind::SystemPrivilege(_) => Vec::new(),
1503 StateUpdateKind::SystemConfiguration(_) => Vec::new(),
1504 StateUpdateKind::ClusterSystemConfiguration(_) => Vec::new(),
1510 StateUpdateKind::ReplicaSystemConfiguration(_) => Vec::new(),
1511 StateUpdateKind::Cluster(_) => Vec::new(),
1515 StateUpdateKind::IntrospectionSourceIndex(introspection_source_index) => {
1516 self.pack_item_update(introspection_source_index.item_id, diff)
1517 }
1518 StateUpdateKind::ClusterReplica(_) => Vec::new(),
1521 StateUpdateKind::SystemObjectMapping(system_object_mapping) => {
1522 if !system_object_mapping.unique_identifier.runtime_alterable() {
1526 self.pack_item_update(system_object_mapping.unique_identifier.catalog_id, diff)
1527 } else {
1528 vec![]
1529 }
1530 }
1531 StateUpdateKind::TemporaryItem(item) => self.pack_item_update(item.id, diff),
1532 StateUpdateKind::Item(item) => self.pack_item_update(item.id, diff),
1533 StateUpdateKind::Comment(_) => Vec::new(),
1534 StateUpdateKind::SourceReferences(source_references) => {
1535 self.pack_source_references_update(&source_references, diff)
1536 }
1537 StateUpdateKind::AuditLog(_) => Vec::new(),
1541 StateUpdateKind::Database(_)
1542 | StateUpdateKind::Schema(_)
1543 | StateUpdateKind::NetworkPolicy(_)
1544 | StateUpdateKind::StorageCollectionMetadata(_)
1545 | StateUpdateKind::UnfinalizedShard(_) => Vec::new(),
1546 }
1547 }
1548
1549 fn get_entry_mut(&mut self, id: &CatalogItemId) -> &mut CatalogEntry {
1550 self.entry_by_id
1551 .get_mut(id)
1552 .unwrap_or_else(|| panic!("catalog out of sync, missing id {id}"))
1553 }
1554
1555 pub(super) fn set_optimized_plan(
1560 &mut self,
1561 id: GlobalId,
1562 plan: DataflowDescription<mz_expr::OptimizedMirRelationExpr>,
1563 ) {
1564 let item_id = self.entry_by_global_id[&id];
1565 let entry = self.get_entry_mut(&item_id);
1566 match entry.item_mut() {
1567 CatalogItem::Index(idx) => idx.optimized_plan = Some(Arc::new(plan)),
1568 CatalogItem::MaterializedView(mv) => mv.optimized_plan = Some(Arc::new(plan)),
1569 other => panic!("set_optimized_plan called on {} ({:?})", id, other.typ()),
1570 }
1571 }
1572
1573 pub(super) fn set_physical_plan(
1578 &mut self,
1579 id: GlobalId,
1580 plan: DataflowDescription<mz_compute_types::plan::LirRelationExpr>,
1581 ) {
1582 let item_id = self.entry_by_global_id[&id];
1583 let entry = self.get_entry_mut(&item_id);
1584 match entry.item_mut() {
1585 CatalogItem::Index(idx) => idx.physical_plan = Some(Arc::new(plan)),
1586 CatalogItem::MaterializedView(mv) => mv.physical_plan = Some(Arc::new(plan)),
1587 other => panic!("set_physical_plan called on {} ({:?})", id, other.typ()),
1588 }
1589 }
1590
1591 pub(super) fn set_dataflow_metainfo(
1596 &mut self,
1597 id: GlobalId,
1598 metainfo: DataflowMetainfo<Arc<OptimizerNotice>>,
1599 ) {
1600 for notice in metainfo.optimizer_notices.iter() {
1602 for dep_id in notice.dependencies.iter() {
1603 self.notices_by_dep_id
1604 .entry(*dep_id)
1605 .or_default()
1606 .push(Arc::clone(notice));
1607 }
1608 if let Some(item_id) = notice.item_id {
1609 soft_assert_eq_or_log!(
1610 item_id,
1611 id,
1612 "notice.item_id should match the id for whom we are saving the notice"
1613 );
1614 }
1615 }
1616 let item_id = self.entry_by_global_id[&id];
1618 let entry = self.get_entry_mut(&item_id);
1619 match entry.item_mut() {
1620 CatalogItem::Index(idx) => idx.dataflow_metainfo = Some(metainfo),
1621 CatalogItem::MaterializedView(mv) => mv.dataflow_metainfo = Some(metainfo),
1622 other => panic!("set_dataflow_metainfo called on {} ({:?})", id, other.typ()),
1623 }
1624 }
1625
1626 #[mz_ore::instrument(level = "trace")]
1637 pub(super) fn drop_optimizer_notices(
1638 &mut self,
1639 dropped_entries: Vec<CatalogEntry>,
1640 ) -> BTreeSet<Arc<OptimizerNotice>> {
1641 let mut dropped_notices = BTreeSet::new();
1642 let mut drop_ids = BTreeSet::new();
1643
1644 for mut entry in dropped_entries {
1646 drop_ids.extend(entry.global_ids());
1647 let metainfo = match entry.item_mut() {
1648 CatalogItem::Index(idx) => idx.dataflow_metainfo.take(),
1649 CatalogItem::MaterializedView(mv) => mv.dataflow_metainfo.take(),
1650 _ => None,
1651 };
1652 if let Some(mut metainfo) = metainfo {
1653 soft_assert_or_log!(
1654 metainfo.optimizer_notices.iter().all_unique(),
1655 "should have been pushed there by \
1656 `push_optimizer_notice_dedup`"
1657 );
1658 for n in metainfo.optimizer_notices.drain(..) {
1659 for dep_id in n.dependencies.iter() {
1662 if let Some(notices) = self.notices_by_dep_id.get_mut(dep_id) {
1663 notices.retain(|x| &n != x);
1664 if notices.is_empty() {
1665 self.notices_by_dep_id.remove(dep_id);
1666 }
1667 }
1668 }
1669 dropped_notices.insert(n);
1670 }
1671 }
1672 }
1673
1674 for id in &drop_ids {
1678 if let Some(notices) = self.notices_by_dep_id.remove(id) {
1679 for n in notices.into_iter() {
1680 if let Some(item_id) = n.item_id.as_ref() {
1685 if let Some(entry) = self.try_get_entry_by_global_id(item_id) {
1686 let catalog_item_id = entry.id();
1687 let entry = self.get_entry_mut(&catalog_item_id);
1688 let item = entry.item_mut();
1689 match item {
1690 CatalogItem::Index(idx) => {
1691 if let Some(ref mut m) = idx.dataflow_metainfo {
1692 m.optimizer_notices.retain(|x| &n != x);
1693 }
1694 }
1695 CatalogItem::MaterializedView(mv) => {
1696 if let Some(ref mut m) = mv.dataflow_metainfo {
1697 m.optimizer_notices.retain(|x| &n != x);
1698 }
1699 }
1700 _ => {}
1701 }
1702 }
1703 }
1704 dropped_notices.insert(n);
1705 }
1706 }
1707 }
1708
1709 let todo_dep_ids: BTreeSet<GlobalId> = dropped_notices
1712 .iter()
1713 .flat_map(|n| n.dependencies.iter())
1714 .filter(|dep_id| !drop_ids.contains(dep_id))
1715 .copied()
1716 .collect();
1717 for id in todo_dep_ids {
1718 if let Some(notices) = self.notices_by_dep_id.get_mut(&id) {
1719 notices.retain(|n| !dropped_notices.contains(n));
1720 if notices.is_empty() {
1721 self.notices_by_dep_id.remove(&id);
1722 }
1723 }
1724 }
1725
1726 dropped_notices
1727 }
1728
1729 fn get_schema_mut(
1730 &mut self,
1731 database_spec: &ResolvedDatabaseSpecifier,
1732 schema_spec: &SchemaSpecifier,
1733 conn_id: &ConnectionId,
1734 ) -> &mut Schema {
1735 match (database_spec, schema_spec) {
1737 (ResolvedDatabaseSpecifier::Ambient, SchemaSpecifier::Temporary) => self
1738 .temporary_schemas
1739 .get_mut(conn_id)
1740 .expect("catalog out of sync"),
1741 (ResolvedDatabaseSpecifier::Ambient, SchemaSpecifier::Id(id)) => self
1742 .ambient_schemas_by_id
1743 .get_mut(id)
1744 .expect("catalog out of sync"),
1745 (ResolvedDatabaseSpecifier::Id(database_id), SchemaSpecifier::Id(schema_id)) => self
1746 .database_by_id
1747 .get_mut(database_id)
1748 .expect("catalog out of sync")
1749 .schemas_by_id
1750 .get_mut(schema_id)
1751 .expect("catalog out of sync"),
1752 (ResolvedDatabaseSpecifier::Id(_), SchemaSpecifier::Temporary) => {
1753 unreachable!("temporary schemas are in the ambient database")
1754 }
1755 }
1756 }
1757
1758 #[instrument(name = "catalog::parse_views")]
1768 async fn parse_builtin_views(
1769 state: &mut CatalogState,
1770 builtin_views: Vec<(&'static BuiltinView, CatalogItemId, GlobalId)>,
1771 retractions: &mut InProgressRetractions,
1772 local_expression_cache: &mut LocalExpressionCache,
1773 ) -> Vec<BuiltinTableUpdate<&'static BuiltinTable>> {
1774 let mut builtin_table_updates = Vec::with_capacity(builtin_views.len());
1775 let (updates, additions): (Vec<_>, Vec<_>) =
1776 builtin_views
1777 .into_iter()
1778 .partition_map(|(view, item_id, gid)| {
1779 match retractions.system_object_mappings.remove(&item_id) {
1780 Some(entry) => Either::Left(entry),
1781 None => Either::Right((view, item_id, gid)),
1782 }
1783 });
1784
1785 for entry in updates {
1786 let item_id = entry.id();
1791 state.insert_entry(entry);
1792 builtin_table_updates.extend(state.pack_item_update(item_id, Diff::ONE));
1793 }
1794
1795 let mut handles = Vec::new();
1796 let mut awaiting_id_dependencies: BTreeMap<CatalogItemId, Vec<CatalogItemId>> =
1797 BTreeMap::new();
1798 let mut awaiting_name_dependencies: BTreeMap<String, Vec<CatalogItemId>> = BTreeMap::new();
1799 let mut awaiting_all = Vec::new();
1802 let mut completed_ids: BTreeSet<CatalogItemId> = BTreeSet::new();
1804 let mut completed_names: BTreeSet<String> = BTreeSet::new();
1805
1806 let mut views: BTreeMap<CatalogItemId, (&BuiltinView, GlobalId)> = additions
1808 .into_iter()
1809 .map(|(view, item_id, gid)| (item_id, (view, gid)))
1810 .collect();
1811 let item_ids: Vec<_> = views.keys().copied().collect();
1812
1813 let mut ready: VecDeque<CatalogItemId> = views.keys().cloned().collect();
1814 while !handles.is_empty() || !ready.is_empty() || !awaiting_all.is_empty() {
1815 if handles.is_empty() && ready.is_empty() {
1816 ready.extend(awaiting_all.drain(..));
1818 }
1819
1820 if !ready.is_empty() {
1822 let spawn_state = Arc::new(state.clone());
1823 while let Some(id) = ready.pop_front() {
1824 let (view, global_id) = views.get(&id).expect("must exist");
1825 let global_id = *global_id;
1826 let create_sql = view.create_sql();
1827 let versions = BTreeMap::new();
1829
1830 let span = info_span!(parent: None, "parse builtin view", name = view.name);
1831 OpenTelemetryContext::obtain().attach_as_parent_to(&span);
1832 let task_state = Arc::clone(&spawn_state);
1833 let cached_expr = local_expression_cache.remove_cached_expression(&global_id);
1834 let handle = mz_ore::task::spawn_blocking(
1835 || "parse view",
1836 move || {
1837 span.in_scope(|| {
1838 let res = task_state.parse_item_inner(
1839 global_id,
1840 &create_sql,
1841 &versions,
1842 None,
1843 false,
1844 None,
1845 cached_expr,
1846 None,
1847 );
1848 (id, global_id, res)
1849 })
1850 },
1851 );
1852 handles.push(handle);
1853 }
1854 }
1855
1856 let (selected, _idx, remaining) = future::select_all(handles).await;
1858 handles = remaining;
1859 let (id, global_id, res) = selected;
1860 let mut insert_cached_expr = |cached_expr| {
1861 if let Some(cached_expr) = cached_expr {
1862 local_expression_cache.insert_cached_expression(global_id, cached_expr);
1863 }
1864 };
1865 match res {
1866 Ok((item, uncached_expr)) => {
1867 if let Some((uncached_expr, optimizer_features)) = uncached_expr {
1868 local_expression_cache.insert_uncached_expression(
1869 global_id,
1870 uncached_expr,
1871 optimizer_features,
1872 );
1873 }
1874 let (view, _gid) = views.remove(&id).expect("must exist");
1876 let schema_id = state
1877 .ambient_schemas_by_name
1878 .get(view.schema)
1879 .unwrap_or_else(|| panic!("unknown ambient schema: {}", view.schema));
1880 let qname = QualifiedItemName {
1881 qualifiers: ItemQualifiers {
1882 database_spec: ResolvedDatabaseSpecifier::Ambient,
1883 schema_spec: SchemaSpecifier::Id(*schema_id),
1884 },
1885 item: view.name.into(),
1886 };
1887 let mut acl_items = vec![rbac::owner_privilege(
1888 mz_sql::catalog::ObjectType::View,
1889 MZ_SYSTEM_ROLE_ID,
1890 )];
1891 acl_items.extend_from_slice(&view.access);
1892
1893 state.insert_item(
1894 id,
1895 view.oid,
1896 qname,
1897 item,
1898 MZ_SYSTEM_ROLE_ID,
1899 PrivilegeMap::from_mz_acl_items(acl_items),
1900 );
1901
1902 let mut resolved_dependent_items = Vec::new();
1904 if let Some(dependent_items) = awaiting_id_dependencies.remove(&id) {
1905 resolved_dependent_items.extend(dependent_items);
1906 }
1907 let entry = state.get_entry(&id);
1908 let full_name = state.resolve_full_name(entry.name(), None).to_string();
1909 if let Some(dependent_items) = awaiting_name_dependencies.remove(&full_name) {
1910 resolved_dependent_items.extend(dependent_items);
1911 }
1912 ready.extend(resolved_dependent_items);
1913
1914 completed_ids.insert(id);
1915 completed_names.insert(full_name);
1916 }
1917 Err((
1919 AdapterError::PlanError(plan::PlanError::InvalidId(missing_dep)),
1920 cached_expr,
1921 )) => {
1922 insert_cached_expr(cached_expr);
1923 if completed_ids.contains(&missing_dep) {
1924 ready.push_back(id);
1925 } else {
1926 awaiting_id_dependencies
1927 .entry(missing_dep)
1928 .or_default()
1929 .push(id);
1930 }
1931 }
1932 Err((
1934 AdapterError::PlanError(plan::PlanError::Catalog(
1935 SqlCatalogError::UnknownItem(missing_dep),
1936 )),
1937 cached_expr,
1938 )) => {
1939 insert_cached_expr(cached_expr);
1940 match CatalogItemId::from_str(&missing_dep) {
1941 Ok(missing_dep) => {
1942 if completed_ids.contains(&missing_dep) {
1943 ready.push_back(id);
1944 } else {
1945 awaiting_id_dependencies
1946 .entry(missing_dep)
1947 .or_default()
1948 .push(id);
1949 }
1950 }
1951 Err(_) => {
1952 if completed_names.contains(&missing_dep) {
1953 ready.push_back(id);
1954 } else {
1955 awaiting_name_dependencies
1956 .entry(missing_dep)
1957 .or_default()
1958 .push(id);
1959 }
1960 }
1961 }
1962 }
1963 Err((
1964 AdapterError::PlanError(plan::PlanError::InvalidCast { .. }),
1965 cached_expr,
1966 )) => {
1967 insert_cached_expr(cached_expr);
1968 awaiting_all.push(id);
1969 }
1970 Err((e, _)) => {
1971 let (bad_view, _gid) = views.get(&id).expect("must exist");
1972 panic!(
1973 "internal error: failed to load bootstrap view:\n\
1974 {name}\n\
1975 error:\n\
1976 {e:?}\n\n\
1977 Make sure that the schema name is specified in the builtin view's create sql statement.
1978 ",
1979 name = bad_view.name,
1980 )
1981 }
1982 }
1983 }
1984
1985 assert!(awaiting_id_dependencies.is_empty());
1986 assert!(
1987 awaiting_name_dependencies.is_empty(),
1988 "awaiting_name_dependencies: {awaiting_name_dependencies:?}"
1989 );
1990 assert!(awaiting_all.is_empty());
1991 assert!(views.is_empty());
1992
1993 builtin_table_updates.extend(
1995 item_ids
1996 .into_iter()
1997 .flat_map(|id| state.pack_item_update(id, Diff::ONE)),
1998 );
1999
2000 builtin_table_updates
2001 }
2002
2003 fn insert_entry(&mut self, entry: CatalogEntry) {
2005 if !entry.id.is_system() {
2006 if let Some(cluster_id) = entry.item.cluster_id() {
2007 self.clusters_by_id
2008 .get_mut(&cluster_id)
2009 .expect("catalog out of sync")
2010 .bound_objects
2011 .insert(entry.id);
2012 };
2013 }
2014
2015 for u in entry.references().items() {
2016 match self.entry_by_id.get_mut(u) {
2017 Some(metadata) => metadata.referenced_by.push(entry.id()),
2018 None => panic!(
2019 "Catalog: missing dependent catalog item {} while installing {}",
2020 &u,
2021 self.resolve_full_name(entry.name(), entry.conn_id())
2022 ),
2023 }
2024 }
2025 for u in entry.uses() {
2026 if u == entry.id() {
2029 continue;
2030 }
2031 match self.entry_by_id.get_mut(&u) {
2032 Some(metadata) => metadata.used_by.push(entry.id()),
2033 None => panic!(
2034 "Catalog: missing dependent catalog item {} while installing {}",
2035 &u,
2036 self.resolve_full_name(entry.name(), entry.conn_id())
2037 ),
2038 }
2039 }
2040 for gid in entry.item.global_ids() {
2041 self.entry_by_global_id.insert(gid, entry.id());
2042 }
2043 let conn_id = entry.item().conn_id().unwrap_or(&SYSTEM_CONN_ID);
2044 if entry.name().qualifiers.schema_spec == SchemaSpecifier::Temporary
2047 && !self.temporary_schemas.contains_key(conn_id)
2048 {
2049 self.create_temporary_schema(conn_id, entry.owner_id)
2050 .expect("failed to create temporary schema");
2051 }
2052 let schema = self.get_schema_mut(
2053 &entry.name().qualifiers.database_spec,
2054 &entry.name().qualifiers.schema_spec,
2055 conn_id,
2056 );
2057
2058 let prev_id = match entry.item() {
2059 CatalogItem::Func(_) => schema
2060 .functions
2061 .insert(entry.name().item.clone(), entry.id()),
2062 CatalogItem::Type(_) => schema.types.insert(entry.name().item.clone(), entry.id()),
2063 _ => schema.items.insert(entry.name().item.clone(), entry.id()),
2064 };
2065
2066 assert!(
2067 prev_id.is_none(),
2068 "builtin name collision on {:?}",
2069 entry.name().item.clone()
2070 );
2071
2072 self.entry_by_id.insert(entry.id(), entry.clone());
2073 }
2074
2075 fn insert_item(
2077 &mut self,
2078 id: CatalogItemId,
2079 oid: u32,
2080 name: QualifiedItemName,
2081 item: CatalogItem,
2082 owner_id: RoleId,
2083 privileges: PrivilegeMap,
2084 ) {
2085 let entry = CatalogEntry {
2086 item,
2087 name,
2088 id,
2089 oid,
2090 used_by: Vec::new(),
2091 referenced_by: Vec::new(),
2092 owner_id,
2093 privileges,
2094 };
2095
2096 self.insert_entry(entry);
2097 }
2098
2099 #[mz_ore::instrument(level = "trace")]
2100 fn drop_item(&mut self, id: CatalogItemId) -> CatalogEntry {
2101 let metadata = self.entry_by_id.remove(&id).expect("catalog out of sync");
2102 for u in metadata.references().items() {
2103 if let Some(dep_metadata) = self.entry_by_id.get_mut(u) {
2104 dep_metadata.referenced_by.retain(|u| *u != metadata.id())
2105 }
2106 }
2107 for u in metadata.uses() {
2108 if let Some(dep_metadata) = self.entry_by_id.get_mut(&u) {
2109 dep_metadata.used_by.retain(|u| *u != metadata.id())
2110 }
2111 }
2112 for gid in metadata.global_ids() {
2113 self.entry_by_global_id.remove(&gid);
2114 }
2115
2116 let conn_id = metadata.item().conn_id().unwrap_or(&SYSTEM_CONN_ID);
2117 let schema = self.get_schema_mut(
2118 &metadata.name().qualifiers.database_spec,
2119 &metadata.name().qualifiers.schema_spec,
2120 conn_id,
2121 );
2122 if metadata.item_type() == CatalogItemType::Type {
2123 schema
2124 .types
2125 .remove(&metadata.name().item)
2126 .expect("catalog out of sync");
2127 } else {
2128 assert_ne!(metadata.item_type(), CatalogItemType::Func);
2131
2132 schema
2133 .items
2134 .remove(&metadata.name().item)
2135 .expect("catalog out of sync");
2136 };
2137
2138 if !id.is_system() {
2139 if let Some(cluster_id) = metadata.item().cluster_id() {
2140 assert!(
2141 self.clusters_by_id
2142 .get_mut(&cluster_id)
2143 .expect("catalog out of sync")
2144 .bound_objects
2145 .remove(&id),
2146 "catalog out of sync"
2147 );
2148 }
2149 }
2150
2151 metadata
2152 }
2153
2154 fn insert_introspection_source_index(
2155 &mut self,
2156 cluster_id: ClusterId,
2157 log: &'static BuiltinLog,
2158 item_id: CatalogItemId,
2159 global_id: GlobalId,
2160 oid: u32,
2161 ) {
2162 let (index_name, index) =
2163 self.create_introspection_source_index(cluster_id, log, global_id);
2164 self.insert_item(
2165 item_id,
2166 oid,
2167 index_name,
2168 index,
2169 MZ_SYSTEM_ROLE_ID,
2170 PrivilegeMap::default(),
2171 );
2172 }
2173
2174 fn create_introspection_source_index(
2175 &self,
2176 cluster_id: ClusterId,
2177 log: &'static BuiltinLog,
2178 global_id: GlobalId,
2179 ) -> (QualifiedItemName, CatalogItem) {
2180 let source_name = FullItemName {
2181 database: RawDatabaseSpecifier::Ambient,
2182 schema: log.schema.into(),
2183 item: log.name.into(),
2184 };
2185 let index_name = format!("{}_{}_primary_idx", log.name, cluster_id);
2186 let mut index_name = QualifiedItemName {
2187 qualifiers: ItemQualifiers {
2188 database_spec: ResolvedDatabaseSpecifier::Ambient,
2189 schema_spec: SchemaSpecifier::Id(self.get_mz_introspection_schema_id()),
2190 },
2191 item: index_name.clone(),
2192 };
2193 index_name = self.find_available_name(index_name, &SYSTEM_CONN_ID);
2194 let index_item_name = index_name.item.clone();
2195 let (log_item_id, log_global_id) = self.resolve_builtin_log(log);
2196 let index = CatalogItem::Index(Index {
2197 global_id,
2198 on: log_global_id,
2199 keys: log
2200 .variant
2201 .index_by()
2202 .into_iter()
2203 .map(MirScalarExpr::column)
2204 .collect(),
2205 create_sql: index_sql(
2206 index_item_name,
2207 cluster_id,
2208 source_name,
2209 &log.variant.desc(),
2210 &log.variant.index_by(),
2211 ),
2212 conn_id: None,
2213 resolved_ids: [(log_item_id, log_global_id)].into_iter().collect(),
2214 cluster_id,
2215 is_retained_metrics_object: false,
2216 custom_logical_compaction_window: None,
2217 optimized_plan: None,
2218 physical_plan: None,
2219 dataflow_metainfo: None,
2220 });
2221 (index_name, index)
2222 }
2223
2224 fn insert_system_configuration(&mut self, name: &str, value: VarInput) -> Result<bool, Error> {
2229 Ok(Arc::make_mut(&mut self.system_configuration).set(name, value)?)
2230 }
2231
2232 fn remove_system_configuration(&mut self, name: &str) -> Result<bool, Error> {
2237 Ok(Arc::make_mut(&mut self.system_configuration).reset(name)?)
2238 }
2239}
2240
2241fn sort_updates(updates: Vec<StateUpdate>) -> Vec<StateUpdate> {
2249 fn push_update<T>(
2250 update: T,
2251 diff: StateDiff,
2252 retractions: &mut Vec<T>,
2253 additions: &mut Vec<T>,
2254 ) {
2255 match diff {
2256 StateDiff::Retraction => retractions.push(update),
2257 StateDiff::Addition => additions.push(update),
2258 }
2259 }
2260
2261 soft_assert_no_log!(
2262 updates.iter().map(|update| update.ts).all_equal(),
2263 "all timestamps should be equal: {updates:?}"
2264 );
2265 soft_assert_no_log!(
2266 {
2267 let mut dedup = BTreeSet::new();
2268 updates.iter().all(|update| dedup.insert(&update.kind))
2269 },
2270 "updates should be consolidated: {updates:?}"
2271 );
2272
2273 let mut pre_cluster_retractions = Vec::new();
2275 let mut pre_cluster_additions = Vec::new();
2276 let mut cluster_retractions = Vec::new();
2277 let mut cluster_additions = Vec::new();
2278 let mut builtin_item_updates = Vec::new();
2279 let mut item_retractions = Vec::new();
2280 let mut item_additions = Vec::new();
2281 let mut temp_item_retractions = Vec::new();
2282 let mut temp_item_additions = Vec::new();
2283 let mut post_item_retractions = Vec::new();
2284 let mut post_item_additions = Vec::new();
2285 for update in updates {
2286 let diff = update.diff.clone();
2287 match update.kind {
2288 StateUpdateKind::Role(_)
2289 | StateUpdateKind::RoleAuth(_)
2290 | StateUpdateKind::Database(_)
2291 | StateUpdateKind::Schema(_)
2292 | StateUpdateKind::DefaultPrivilege(_)
2293 | StateUpdateKind::SystemPrivilege(_)
2294 | StateUpdateKind::SystemConfiguration(_)
2295 | StateUpdateKind::NetworkPolicy(_) => push_update(
2296 update,
2297 diff,
2298 &mut pre_cluster_retractions,
2299 &mut pre_cluster_additions,
2300 ),
2301 StateUpdateKind::Cluster(_)
2302 | StateUpdateKind::ClusterSystemConfiguration(_)
2303 | StateUpdateKind::IntrospectionSourceIndex(_)
2304 | StateUpdateKind::ClusterReplica(_)
2305 | StateUpdateKind::ReplicaSystemConfiguration(_) => push_update(
2306 update,
2307 diff,
2308 &mut cluster_retractions,
2309 &mut cluster_additions,
2310 ),
2311 StateUpdateKind::SystemObjectMapping(system_object_mapping) => {
2312 builtin_item_updates.push((system_object_mapping, update.ts, update.diff))
2313 }
2314 StateUpdateKind::TemporaryItem(item) => push_update(
2315 (item, update.ts, update.diff),
2316 diff,
2317 &mut temp_item_retractions,
2318 &mut temp_item_additions,
2319 ),
2320 StateUpdateKind::Item(item) => push_update(
2321 (item, update.ts, update.diff),
2322 diff,
2323 &mut item_retractions,
2324 &mut item_additions,
2325 ),
2326 StateUpdateKind::Comment(_)
2327 | StateUpdateKind::SourceReferences(_)
2328 | StateUpdateKind::AuditLog(_)
2329 | StateUpdateKind::StorageCollectionMetadata(_)
2330 | StateUpdateKind::UnfinalizedShard(_) => push_update(
2331 update,
2332 diff,
2333 &mut post_item_retractions,
2334 &mut post_item_additions,
2335 ),
2336 }
2337 }
2338
2339 let builtin_item_updates = builtin_item_updates
2342 .into_iter()
2343 .map(|(system_object_mapping, ts, diff)| {
2344 let idx = BUILTIN_LOOKUP
2345 .get(&system_object_mapping.description)
2346 .expect("missing builtin")
2347 .0;
2348 (idx, system_object_mapping, ts, diff)
2349 })
2350 .sorted_by_key(|(idx, _, _, _)| *idx)
2351 .map(|(_, system_object_mapping, ts, diff)| (system_object_mapping, ts, diff));
2352
2353 let mut builtin_source_retractions = Vec::new();
2357 let mut builtin_source_additions = Vec::new();
2358 let mut other_builtin_retractions = Vec::new();
2359 let mut other_builtin_additions = Vec::new();
2360 for (builtin_item_update, ts, diff) in builtin_item_updates {
2361 let object_type = builtin_item_update.description.object_type;
2362 let update = StateUpdate {
2363 kind: StateUpdateKind::SystemObjectMapping(builtin_item_update),
2364 ts,
2365 diff,
2366 };
2367 if object_type == CatalogItemType::Source {
2368 push_update(
2369 update,
2370 diff,
2371 &mut builtin_source_retractions,
2372 &mut builtin_source_additions,
2373 );
2374 } else {
2375 push_update(
2376 update,
2377 diff,
2378 &mut other_builtin_retractions,
2379 &mut other_builtin_additions,
2380 );
2381 }
2382 }
2383
2384 fn sort_items_topological(items: &mut Vec<(mz_catalog::durable::Item, Timestamp, StateDiff)>) {
2390 tracing::debug!(?items, "sorting items by dependencies");
2391
2392 let key_fn = |item: &(mz_catalog::durable::Item, _, _)| item.0.id;
2393 let dependencies_fn = |item: &(mz_catalog::durable::Item, _, _)| {
2394 let statement = mz_sql::parse::parse(&item.0.create_sql)
2395 .expect("valid create_sql")
2396 .into_element()
2397 .ast;
2398 mz_sql::names::dependencies(&statement).expect("failed to find dependencies of item")
2399 };
2400 sort_topological(items, key_fn, dependencies_fn);
2401 }
2402
2403 fn sort_item_updates(
2419 item_updates: Vec<(mz_catalog::durable::Item, Timestamp, StateDiff)>,
2420 ) -> VecDeque<(mz_catalog::durable::Item, Timestamp, StateDiff)> {
2421 let mut types = Vec::new();
2424 let mut funcs = Vec::new();
2427 let mut secrets = Vec::new();
2428 let mut connections = Vec::new();
2429 let mut sources = Vec::new();
2430 let mut tables = Vec::new();
2431 let mut derived_items = Vec::new();
2432 let mut sinks = Vec::new();
2433 for update in item_updates {
2434 match update.0.item_type() {
2435 CatalogItemType::Type => types.push(update),
2436 CatalogItemType::Func => funcs.push(update),
2437 CatalogItemType::Secret => secrets.push(update),
2438 CatalogItemType::Connection => connections.push(update),
2439 CatalogItemType::Source => sources.push(update),
2440 CatalogItemType::Table => tables.push(update),
2441 CatalogItemType::View
2442 | CatalogItemType::MaterializedView
2443 | CatalogItemType::Index => derived_items.push(update),
2444 CatalogItemType::Sink => sinks.push(update),
2445 }
2446 }
2447
2448 sort_items_topological(&mut connections);
2452 sort_items_topological(&mut derived_items);
2453
2454 for group in [
2456 &mut types,
2457 &mut funcs,
2458 &mut secrets,
2459 &mut sources,
2460 &mut tables,
2461 &mut sinks,
2462 ] {
2463 group.sort_by_key(|(item, _, _)| item.id);
2464 }
2465
2466 iter::empty()
2467 .chain(types)
2468 .chain(funcs)
2469 .chain(secrets)
2470 .chain(connections)
2471 .chain(sources)
2472 .chain(tables)
2473 .chain(derived_items)
2474 .chain(sinks)
2475 .collect()
2476 }
2477
2478 let item_retractions = sort_item_updates(item_retractions);
2479 let item_additions = sort_item_updates(item_additions);
2480
2481 fn sort_temp_item_updates(
2485 temp_item_updates: Vec<(TemporaryItem, Timestamp, StateDiff)>,
2486 ) -> VecDeque<(TemporaryItem, Timestamp, StateDiff)> {
2487 let mut types = Vec::new();
2490 let mut funcs = Vec::new();
2492 let mut secrets = Vec::new();
2493 let mut connections = Vec::new();
2494 let mut sources = Vec::new();
2495 let mut tables = Vec::new();
2496 let mut derived_items = Vec::new();
2497 let mut sinks = Vec::new();
2498 for update in temp_item_updates {
2499 match update.0.item_type() {
2500 CatalogItemType::Type => types.push(update),
2501 CatalogItemType::Func => funcs.push(update),
2502 CatalogItemType::Secret => secrets.push(update),
2503 CatalogItemType::Connection => connections.push(update),
2504 CatalogItemType::Source => sources.push(update),
2505 CatalogItemType::Table => tables.push(update),
2506 CatalogItemType::View
2507 | CatalogItemType::MaterializedView
2508 | CatalogItemType::Index => derived_items.push(update),
2509 CatalogItemType::Sink => sinks.push(update),
2510 }
2511 }
2512
2513 for group in [
2515 &mut types,
2516 &mut funcs,
2517 &mut secrets,
2518 &mut connections,
2519 &mut sources,
2520 &mut tables,
2521 &mut derived_items,
2522 &mut sinks,
2523 ] {
2524 group.sort_by_key(|(item, _, _)| item.id);
2525 }
2526
2527 iter::empty()
2528 .chain(types)
2529 .chain(funcs)
2530 .chain(secrets)
2531 .chain(connections)
2532 .chain(sources)
2533 .chain(tables)
2534 .chain(derived_items)
2535 .chain(sinks)
2536 .collect()
2537 }
2538 let temp_item_retractions = sort_temp_item_updates(temp_item_retractions);
2539 let temp_item_additions = sort_temp_item_updates(temp_item_additions);
2540
2541 fn merge_item_updates(
2557 item_updates: VecDeque<(mz_catalog::durable::Item, Timestamp, StateDiff)>,
2558 temp_item_updates: VecDeque<(TemporaryItem, Timestamp, StateDiff)>,
2559 ) -> Vec<StateUpdate> {
2560 let mut state_updates = Vec::with_capacity(item_updates.len() + temp_item_updates.len());
2561 for (item, ts, diff) in item_updates {
2562 state_updates.push(StateUpdate {
2563 kind: StateUpdateKind::Item(item),
2564 ts,
2565 diff,
2566 });
2567 }
2568 for (temp_item, ts, diff) in temp_item_updates {
2569 state_updates.push(StateUpdate {
2570 kind: StateUpdateKind::TemporaryItem(temp_item),
2571 ts,
2572 diff,
2573 });
2574 }
2575 state_updates
2576 }
2577 let item_retractions = merge_item_updates(item_retractions, temp_item_retractions);
2578 let item_additions = merge_item_updates(item_additions, temp_item_additions);
2579
2580 iter::empty()
2582 .chain(post_item_retractions.into_iter().rev())
2584 .chain(item_retractions.into_iter().rev())
2585 .chain(other_builtin_retractions.into_iter().rev())
2586 .chain(cluster_retractions.into_iter().rev())
2587 .chain(builtin_source_retractions.into_iter().rev())
2588 .chain(pre_cluster_retractions.into_iter().rev())
2589 .chain(pre_cluster_additions)
2590 .chain(builtin_source_additions)
2591 .chain(cluster_additions)
2592 .chain(other_builtin_additions)
2593 .chain(item_additions)
2594 .chain(post_item_additions)
2595 .collect()
2596}
2597
2598enum ApplyState {
2603 BuiltinViewAdditions(Vec<(&'static BuiltinView, CatalogItemId, GlobalId)>),
2605 Items(Vec<StateUpdate>),
2611 Updates(Vec<StateUpdate>),
2613}
2614
2615impl ApplyState {
2616 fn new(update: StateUpdate) -> Self {
2617 use StateUpdateKind::*;
2618 match &update.kind {
2619 SystemObjectMapping(som)
2620 if som.description.object_type == CatalogItemType::View
2621 && update.diff == StateDiff::Addition =>
2622 {
2623 let view_addition = lookup_builtin_view_addition(som.clone());
2624 Self::BuiltinViewAdditions(vec![view_addition])
2625 }
2626
2627 IntrospectionSourceIndex(_) | SystemObjectMapping(_) | TemporaryItem(_) | Item(_) => {
2628 Self::Items(vec![update])
2629 }
2630
2631 Role(_)
2632 | RoleAuth(_)
2633 | Database(_)
2634 | Schema(_)
2635 | DefaultPrivilege(_)
2636 | SystemPrivilege(_)
2637 | SystemConfiguration(_)
2638 | ClusterSystemConfiguration(_)
2639 | ReplicaSystemConfiguration(_)
2640 | Cluster(_)
2641 | NetworkPolicy(_)
2642 | ClusterReplica(_)
2643 | SourceReferences(_)
2644 | Comment(_)
2645 | AuditLog(_)
2646 | StorageCollectionMetadata(_)
2647 | UnfinalizedShard(_) => Self::Updates(vec![update]),
2648 }
2649 }
2650
2651 async fn apply(
2657 self,
2658 state: &mut CatalogState,
2659 retractions: &mut InProgressRetractions,
2660 local_expression_cache: &mut LocalExpressionCache,
2661 ) -> (
2662 Vec<BuiltinTableUpdate<&'static BuiltinTable>>,
2663 Vec<ParsedStateUpdate>,
2664 ) {
2665 match self {
2666 Self::BuiltinViewAdditions(builtin_view_additions) => {
2667 let restore = Arc::clone(&state.system_configuration);
2668 Arc::make_mut(&mut state.system_configuration).enable_for_item_parsing();
2669 let builtin_table_updates = CatalogState::parse_builtin_views(
2670 state,
2671 builtin_view_additions,
2672 retractions,
2673 local_expression_cache,
2674 )
2675 .await;
2676 state.system_configuration = restore;
2677 (builtin_table_updates, Vec::new())
2678 }
2679 Self::Items(updates) => state.with_enable_for_item_parsing(|state| {
2680 state
2681 .apply_updates_inner(updates, retractions, local_expression_cache)
2682 .expect("corrupt catalog")
2683 }),
2684 Self::Updates(updates) => state
2685 .apply_updates_inner(updates, retractions, local_expression_cache)
2686 .expect("corrupt catalog"),
2687 }
2688 }
2689
2690 async fn step(
2691 self,
2692 next: Self,
2693 state: &mut CatalogState,
2694 retractions: &mut InProgressRetractions,
2695 local_expression_cache: &mut LocalExpressionCache,
2696 ) -> (
2697 Self,
2698 (
2699 Vec<BuiltinTableUpdate<&'static BuiltinTable>>,
2700 Vec<ParsedStateUpdate>,
2701 ),
2702 ) {
2703 match (self, next) {
2704 (
2705 Self::BuiltinViewAdditions(mut builtin_view_additions),
2706 Self::BuiltinViewAdditions(next_builtin_view_additions),
2707 ) => {
2708 builtin_view_additions.extend(next_builtin_view_additions);
2710 (
2711 Self::BuiltinViewAdditions(builtin_view_additions),
2712 (Vec::new(), Vec::new()),
2713 )
2714 }
2715 (Self::Items(mut updates), Self::Items(next_updates)) => {
2716 updates.extend(next_updates);
2718 (Self::Items(updates), (Vec::new(), Vec::new()))
2719 }
2720 (Self::Updates(mut updates), Self::Updates(next_updates)) => {
2721 updates.extend(next_updates);
2723 (Self::Updates(updates), (Vec::new(), Vec::new()))
2724 }
2725 (apply_state, next_apply_state) => {
2726 let updates = apply_state
2728 .apply(state, retractions, local_expression_cache)
2729 .await;
2730 (next_apply_state, updates)
2731 }
2732 }
2733 }
2734}
2735
2736trait MutableMap<K, V> {
2739 fn insert(&mut self, key: K, value: V) -> Option<V>;
2740 fn remove(&mut self, key: &K) -> Option<V>;
2741}
2742
2743impl<K: Ord, V> MutableMap<K, V> for BTreeMap<K, V> {
2744 fn insert(&mut self, key: K, value: V) -> Option<V> {
2745 BTreeMap::insert(self, key, value)
2746 }
2747 fn remove(&mut self, key: &K) -> Option<V> {
2748 BTreeMap::remove(self, key)
2749 }
2750}
2751
2752impl<K: Ord + Clone, V: Clone> MutableMap<K, V> for imbl::OrdMap<K, V> {
2753 fn insert(&mut self, key: K, value: V) -> Option<V> {
2754 imbl::OrdMap::insert(self, key, value)
2755 }
2756 fn remove(&mut self, key: &K) -> Option<V> {
2757 imbl::OrdMap::remove(self, key)
2758 }
2759}
2760
2761fn apply_inverted_lookup<K, V>(map: &mut impl MutableMap<K, V>, key: &K, value: V, diff: StateDiff)
2766where
2767 K: Ord + Clone + Debug,
2768 V: PartialEq + Debug,
2769{
2770 match diff {
2771 StateDiff::Retraction => {
2772 let prev = map.remove(key);
2773 assert_eq!(
2774 prev,
2775 Some(value),
2776 "retraction does not match existing value: {key:?}"
2777 );
2778 }
2779 StateDiff::Addition => {
2780 let prev = map.insert(key.clone(), value);
2781 assert_eq!(
2782 prev, None,
2783 "values must be explicitly retracted before inserting a new value: {key:?}"
2784 );
2785 }
2786 }
2787}
2788
2789fn apply_with_update<K, V, D>(
2792 map: &mut impl MutableMap<K, V>,
2793 durable: D,
2794 key_fn: impl FnOnce(&D) -> K,
2795 diff: StateDiff,
2796 retractions: &mut BTreeMap<D::Key, V>,
2797) where
2798 K: Ord,
2799 V: UpdateFrom<D> + PartialEq + Debug,
2800 D: DurableType,
2801 D::Key: Ord,
2802{
2803 match diff {
2804 StateDiff::Retraction => {
2805 let mem_key = key_fn(&durable);
2806 let value = map
2807 .remove(&mem_key)
2808 .expect("retraction does not match existing value: {key:?}");
2809 let durable_key = durable.into_key_value().0;
2810 retractions.insert(durable_key, value);
2811 }
2812 StateDiff::Addition => {
2813 let mem_key = key_fn(&durable);
2814 let durable_key = durable.key();
2815 let value = match retractions.remove(&durable_key) {
2816 Some(mut retraction) => {
2817 retraction.update_from(durable);
2818 retraction
2819 }
2820 None => durable.into(),
2821 };
2822 let prev = map.insert(mem_key, value);
2823 assert_eq!(
2824 prev, None,
2825 "values must be explicitly retracted before inserting a new value"
2826 );
2827 }
2828 }
2829}
2830
2831fn lookup_builtin_view_addition(
2833 mapping: SystemObjectMapping,
2834) -> (&'static BuiltinView, CatalogItemId, GlobalId) {
2835 let (_, builtin) = BUILTIN_LOOKUP
2836 .get(&mapping.description)
2837 .expect("missing builtin view");
2838 let Builtin::View(view) = builtin else {
2839 unreachable!("programming error, expected BuiltinView found {builtin:?}");
2840 };
2841
2842 (
2843 view,
2844 mapping.unique_identifier.catalog_id,
2845 mapping.unique_identifier.global_id,
2846 )
2847}