Skip to main content

mz_catalog/
builtin.rs

1// Copyright Materialize, Inc. and contributors. All rights reserved.
2//
3// Use of this software is governed by the Business Source License
4// included in the LICENSE file.
5//
6// As of the Change Date specified in that file, in accordance with
7// the Business Source License, use of this software will be governed
8// by the Apache License, Version 2.0.
9
10//! Built-in catalog items.
11//!
12//! Builtins exist in the `mz_catalog` ambient schema. They are automatically
13//! installed into the catalog when it is opened. Their definitions are not
14//! persisted in the catalog, but hardcoded in this module. This makes it easy
15//! to add new builtins, or change the definition of existing builtins, in new
16//! versions of Materialize.
17//!
18//! Builtin's names, columns, and types are part of the stable API of
19//! Materialize. Be careful to maintain backwards compatibility when changing
20//! definitions of existing builtins!
21//!
22//! More information about builtin system tables and types can be found in
23//! <https://materialize.com/docs/sql/system-catalog/>.
24
25mod builtin;
26pub mod notice;
27mod ontology;
28mod pg_catalog;
29pub use pg_catalog::*;
30mod mz_catalog;
31pub use mz_catalog::*;
32mod mz_internal;
33pub use mz_internal::*;
34mod mz_object_dependencies;
35pub use mz_object_dependencies::*;
36mod mz_introspection;
37pub use mz_introspection::*;
38mod information_schema;
39pub use information_schema::*;
40
41use std::collections::BTreeMap;
42use std::hash::Hash;
43use std::string::ToString;
44use std::sync::LazyLock;
45
46use mz_compute_client::logging::LogVariant;
47use mz_ore::collections::HashMap;
48use mz_pgrepr::oid;
49use mz_repr::adt::mz_acl_item::{AclMode, MzAclItem};
50use mz_repr::namespaces::{
51    INFORMATION_SCHEMA, MZ_CATALOG_SCHEMA, MZ_INTERNAL_SCHEMA, MZ_UNSAFE_SCHEMA, PG_CATALOG_SCHEMA,
52};
53use mz_repr::role_id::RoleId;
54use mz_repr::{RelationDesc, SemanticType, SqlRelationType};
55use mz_sql::catalog::RoleAttributesRaw;
56use mz_sql::catalog::{
57    CatalogItemType, CatalogTypeDetails, NameReference, ObjectType, SystemObjectType, TypeReference,
58};
59use mz_sql::rbac;
60use mz_sql::session::user::{
61    ANALYTICS_USER_NAME, JWT_SYNC_ROLE_NAME, MZ_ANALYTICS_ROLE_ID, MZ_JWT_SYNC_ROLE_ID,
62    MZ_MONITOR_REDACTED_ROLE_ID, MZ_MONITOR_ROLE_ID, MZ_SUPPORT_ROLE_ID, MZ_SYSTEM_ROLE_ID,
63    SUPPORT_USER_NAME, SYSTEM_USER_NAME,
64};
65use serde::Serialize;
66
67use crate::durable::objects::SystemObjectDescription;
68use crate::memory::objects::DataSourceDesc;
69
70pub const BUILTIN_PREFIXES: &[&str] = &["mz_", "pg_", "external_"];
71
72/// A sentinel used in place of a fingerprint that indicates that a builtin
73/// object is runtime alterable. Runtime alterable objects don't have meaningful
74/// fingerprints because they may have been intentionally changed by the user
75/// after creation.
76// NOTE(benesch): ideally we'd use a fingerprint type that used a sum type
77// rather than a loosely typed string to represent the runtime alterable
78// state like so:
79//
80//     enum Fingerprint {
81//         SqlText(String),
82//         RuntimeAlterable,
83//     }
84//
85// However, that would entail a complicated migration for the existing system object
86// mapping collection stored on disk.
87pub const RUNTIME_ALTERABLE_FINGERPRINT_SENTINEL: &str = "<RUNTIME-ALTERABLE>";
88
89#[derive(Clone, Debug)]
90pub enum Builtin<T: 'static + TypeReference> {
91    Log(&'static BuiltinLog),
92    Table(&'static BuiltinTable),
93    View(&'static BuiltinView),
94    MaterializedView(&'static BuiltinMaterializedView),
95    Type(&'static BuiltinType<T>),
96    Func(BuiltinFunc),
97    Source(&'static BuiltinSource),
98    Index(&'static BuiltinIndex),
99    Connection(&'static BuiltinConnection),
100}
101
102impl<T: TypeReference> Builtin<T> {
103    pub fn name(&self) -> &'static str {
104        match self {
105            Builtin::Log(log) => log.name,
106            Builtin::Table(table) => table.name,
107            Builtin::View(view) => view.name,
108            Builtin::MaterializedView(mv) => mv.name,
109            Builtin::Type(typ) => typ.name,
110            Builtin::Func(func) => func.name,
111            Builtin::Source(coll) => coll.name,
112            Builtin::Index(index) => index.name,
113            Builtin::Connection(connection) => connection.name,
114        }
115    }
116
117    pub fn schema(&self) -> &'static str {
118        match self {
119            Builtin::Log(log) => log.schema,
120            Builtin::Table(table) => table.schema,
121            Builtin::View(view) => view.schema,
122            Builtin::MaterializedView(mv) => mv.schema,
123            Builtin::Type(typ) => typ.schema,
124            Builtin::Func(func) => func.schema,
125            Builtin::Source(coll) => coll.schema,
126            Builtin::Index(index) => index.schema,
127            Builtin::Connection(connection) => connection.schema,
128        }
129    }
130
131    pub fn catalog_item_type(&self) -> CatalogItemType {
132        match self {
133            Builtin::Log(_) => CatalogItemType::Source,
134            Builtin::Source(_) => CatalogItemType::Source,
135            Builtin::Table(_) => CatalogItemType::Table,
136            Builtin::View(_) => CatalogItemType::View,
137            Builtin::MaterializedView(_) => CatalogItemType::MaterializedView,
138            Builtin::Type(_) => CatalogItemType::Type,
139            Builtin::Func(_) => CatalogItemType::Func,
140            Builtin::Index(_) => CatalogItemType::Index,
141            Builtin::Connection(_) => CatalogItemType::Connection,
142        }
143    }
144
145    /// Whether the object can be altered at runtime by its owner.
146    pub fn runtime_alterable(&self) -> bool {
147        match self {
148            Builtin::Connection(c) => c.runtime_alterable,
149            _ => false,
150        }
151    }
152}
153
154#[derive(Clone, Debug, Hash, Serialize)]
155pub struct BuiltinLog {
156    pub variant: LogVariant,
157    pub name: &'static str,
158    pub schema: &'static str,
159    pub oid: u32,
160    /// ACL items to apply to the object
161    pub access: Vec<MzAclItem>,
162    #[serde(default)]
163    pub ontology: Option<Ontology>,
164}
165
166/// Ontology metadata for a builtin catalog object.
167///
168/// When present on a builtin, it marks it as an ontology entity with an explicit
169/// `entity_name`, `description`, and optional per-column semantic type annotations.
170///
171/// ## Why `column_semantic_types` lives here and not in `RelationDesc`
172///
173/// Semantic types are pure catalog-level metadata: they annotate what an ID
174/// column *means* (e.g. "this is a ClusterId") without affecting the Arrow
175/// data type used for encoding. Keeping them in `RelationDesc` would cause
176/// persist schema mismatches during zero-downtime upgrades: the old binary
177/// registers a schema without semantic types, the new binary tries to register
178/// a schema with them, and `register_schema` returns `None` because the schemas
179/// are not `PartialEq`. Since the only consumers of semantic types are the
180/// ontology views (which already have access to `Ontology`), storing them here
181/// is both correct and avoids the schema-evolution problem entirely.
182#[derive(Clone, Hash, Debug, PartialEq, Eq, Serialize)]
183pub struct Ontology {
184    /// The ontology entity name (e.g., "database", "table", "mv"). Names a
185    /// single row of this relation, so prefer singular event/object nouns
186    /// (e.g., "replica_status_event" not "replica_status_history").
187    pub entity_name: &'static str,
188    /// One-line description of this entity.
189    pub description: &'static str,
190    /// Relationships originating from this entity (foreign keys, unions,
191    /// mappings, dependencies, metrics).
192    pub links: &'static [OntologyLink],
193    /// Per-column semantic type annotations: `(column_name, SemanticType)`.
194    /// Only columns that carry a meaningful semantic type need to appear here.
195    pub column_semantic_types: &'static [(&'static str, SemanticType)],
196}
197
198/// Cardinality of an ontology link.
199#[derive(
200    Clone,
201    Copy,
202    Debug,
203    Hash,
204    PartialEq,
205    Eq,
206    serde::Serialize,
207    serde::Deserialize
208)]
209#[serde(rename_all = "snake_case")]
210pub enum Cardinality {
211    OneToOne,
212    ManyToOne,
213}
214
215/// Helper used by serde to skip serializing `false` boolean fields.
216fn is_false(v: &bool) -> bool {
217    !v
218}
219
220/// Typed properties for an ontology link. Serialized to the `properties` JSONB
221/// column in `mz_ontology_link_types`. The `kind` field is inlined from the
222/// enum variant name via `#[serde(tag = "kind")]`.
223///
224/// Choosing the right variant matters:
225///
226/// - [`LinkProperties::ForeignKey`]: the source entity has a column whose value is an ID that
227///   directly references a row in the target entity. Use this when there is an explicit FK column
228///   (e.g. `schema_id` -> `schema`).
229/// - [`LinkProperties::DependsOn`]: this entity logically depends on the target entity via a
230///   graph-edge table (e.g. `mz_compute_dependencies` records that a compute object depends on
231///   another object). The `source_column` is the column **in this entity** that holds the
232///   dependent's ID; `target_column` is the column in the target entity being depended upon. Use
233///   this for dependency-graph tables, **not** `ForeignKey`.
234/// - [`LinkProperties::Union`]: the source entity is a superset view that contains the target
235///   entity as a subset, optionally filtered by a discriminator column.
236/// - [`LinkProperties::MapsTo`]: the source entity provides an ID translation to the target entity,
237///   possibly via an intermediate table or across ID namespaces.
238/// - [`LinkProperties::Measures`]: the source entity records metric measurements about the target
239///   entity.
240#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, serde::Serialize)]
241#[serde(tag = "kind", rename_all = "snake_case")]
242pub enum LinkProperties {
243    /// A foreign-key relationship: `source_column` in the source entity
244    /// references `target_column` in the target entity.
245    ForeignKey {
246        /// Column in the source entity that holds the reference.
247        source_column: &'static str,
248        /// Column in the target entity being referenced (usually `id`).
249        target_column: &'static str,
250        /// How many source rows may reference a single target row.
251        cardinality: Cardinality,
252        /// Semantic type of the source column, if it carries an ID that
253        /// requires type-aware resolution (e.g. `CatalogItemId`, `GlobalId`).
254        #[serde(skip_serializing_if = "Option::is_none")]
255        source_id_type: Option<mz_repr::SemanticType>,
256        /// Intermediate mapping relation needed when `source_id_type` does not
257        /// directly match the target entity's ID type (e.g.
258        /// `mz_internal.mz_object_global_ids` to go from `GlobalId` to catalog
259        /// object).
260        #[serde(skip_serializing_if = "Option::is_none")]
261        requires_mapping: Option<&'static str>,
262        /// True when the source column may be NULL (the reference is optional).
263        #[serde(default, skip_serializing_if = "is_false")]
264        nullable: bool,
265        /// Free-form annotation for cases that need extra context.
266        #[serde(skip_serializing_if = "Option::is_none")]
267        note: Option<&'static str>,
268        /// Additional `(source_column, target_column)` pairs that together with
269        /// `source_column`/`target_column` form a composite join key. Used for
270        /// `_per_worker` entities whose primary key is `(id, worker_id)`, and
271        /// for message-count raw relations whose join key includes worker IDs.
272        /// Serialized as an array; omitted when `None`.
273        #[serde(skip_serializing_if = "Option::is_none")]
274        extra_key_columns: Option<&'static [(&'static str, &'static str)]>,
275    },
276    /// A union relationship: the source entity is a superset view that includes
277    /// the target entity, optionally filtered by a discriminator column/value.
278    Union {
279        /// Column used to discriminate between subtypes (e.g. `type`).
280        #[serde(skip_serializing_if = "Option::is_none")]
281        discriminator_column: Option<&'static str>,
282        /// Value of `discriminator_column` that selects the target entity.
283        #[serde(skip_serializing_if = "Option::is_none")]
284        discriminator_value: Option<&'static str>,
285        /// Free-form annotation for cases that need extra context.
286        #[serde(skip_serializing_if = "Option::is_none")]
287        note: Option<&'static str>,
288    },
289    /// A mapping relationship: the source entity maps to the target entity,
290    /// optionally via an intermediate table and/or with an ID-type conversion.
291    MapsTo {
292        /// Column in the source entity that holds the ID to map from.
293        source_column: &'static str,
294        /// Column in the target entity being mapped to.
295        target_column: &'static str,
296        /// Intermediate relation used to perform the mapping.
297        #[serde(skip_serializing_if = "Option::is_none")]
298        via: Option<&'static str>,
299        /// Semantic type of the source ID before mapping.
300        #[serde(skip_serializing_if = "Option::is_none")]
301        from_type: Option<mz_repr::SemanticType>,
302        /// Semantic type of the target ID after mapping.
303        #[serde(skip_serializing_if = "Option::is_none")]
304        to_type: Option<mz_repr::SemanticType>,
305        /// Free-form annotation for cases that need extra context.
306        #[serde(skip_serializing_if = "Option::is_none")]
307        note: Option<&'static str>,
308    },
309    /// A dependency relationship: this entity directly depends on the
310    /// target entity (e.g. a materialization that references an object).
311    DependsOn {
312        /// Column in this entity that holds the dependency ID.
313        source_column: &'static str,
314        /// Column in the target entity being depended upon (usually `id`).
315        target_column: &'static str,
316        /// Semantic type of the source column.
317        #[serde(skip_serializing_if = "Option::is_none")]
318        source_id_type: Option<mz_repr::SemanticType>,
319        /// Intermediate mapping relation needed when `source_id_type` does not
320        /// directly match the target entity's ID type (e.g. GlobalId →
321        /// `mz_internal.mz_object_global_ids` to reach a catalog object).
322        #[serde(skip_serializing_if = "Option::is_none")]
323        requires_mapping: Option<&'static str>,
324    },
325    /// A metric relationship: the source entity records measurements of a named
326    /// metric on the target entity.
327    Measures {
328        /// Column in the source entity that references the target entity.
329        source_column: &'static str,
330        /// Column in the target entity being measured (usually `id`).
331        target_column: &'static str,
332        /// Name of the metric being measured (e.g. `cpu_time_ns`).
333        metric: &'static str,
334        /// Semantic type of the source column, if ID-type resolution is needed.
335        #[serde(skip_serializing_if = "Option::is_none")]
336        source_id_type: Option<mz_repr::SemanticType>,
337        /// Intermediate mapping relation needed when the source ID type differs
338        /// from the target entity's ID type.
339        #[serde(skip_serializing_if = "Option::is_none")]
340        requires_mapping: Option<&'static str>,
341        /// Free-form annotation for cases that need extra context.
342        #[serde(skip_serializing_if = "Option::is_none")]
343        note: Option<&'static str>,
344        /// Additional `(source_column, target_column)` pairs that together with
345        /// `source_column`/`target_column` form a composite join key.
346        #[serde(skip_serializing_if = "Option::is_none")]
347        extra_key_columns: Option<&'static [(&'static str, &'static str)]>,
348    },
349}
350
351impl LinkProperties {
352    /// Basic foreign-key link with no optional fields set.
353    pub const fn fk(
354        source_column: &'static str,
355        target_column: &'static str,
356        cardinality: Cardinality,
357    ) -> Self {
358        Self::ForeignKey {
359            source_column,
360            target_column,
361            cardinality,
362            source_id_type: None,
363            requires_mapping: None,
364            nullable: false,
365            note: None,
366            extra_key_columns: None,
367        }
368    }
369
370    /// Foreign-key link where the source column may be NULL.
371    pub const fn fk_nullable(
372        source_column: &'static str,
373        target_column: &'static str,
374        cardinality: Cardinality,
375    ) -> Self {
376        Self::ForeignKey {
377            source_column,
378            target_column,
379            cardinality,
380            source_id_type: None,
381            requires_mapping: None,
382            nullable: true,
383            note: None,
384            extra_key_columns: None,
385        }
386    }
387
388    /// Foreign-key link whose source column carries a typed ID (e.g.
389    /// `CatalogItemId`) but does not require an intermediate mapping table.
390    pub const fn fk_typed(
391        source_column: &'static str,
392        target_column: &'static str,
393        cardinality: Cardinality,
394        source_id_type: mz_repr::SemanticType,
395    ) -> Self {
396        Self::ForeignKey {
397            source_column,
398            target_column,
399            cardinality,
400            source_id_type: Some(source_id_type),
401            requires_mapping: None,
402            nullable: false,
403            note: None,
404            extra_key_columns: None,
405        }
406    }
407
408    /// Foreign-key link whose source column carries a typed ID that requires
409    /// an intermediate mapping table to resolve (e.g. `GlobalId` →
410    /// `mz_internal.mz_object_global_ids`).
411    pub const fn fk_mapped(
412        source_column: &'static str,
413        target_column: &'static str,
414        cardinality: Cardinality,
415        source_id_type: mz_repr::SemanticType,
416        requires_mapping: &'static str,
417    ) -> Self {
418        Self::ForeignKey {
419            source_column,
420            target_column,
421            cardinality,
422            source_id_type: Some(source_id_type),
423            requires_mapping: Some(requires_mapping),
424            nullable: false,
425            note: None,
426            extra_key_columns: None,
427        }
428    }
429
430    /// Foreign-key link with a composite join key. `extra_key_columns` lists
431    /// additional `(source_column, target_column)` pairs beyond the primary
432    /// `source_column`/`target_column` pair. Examples:
433    /// - `&[("worker_id", "worker_id")]` for `_per_worker` entities
434    /// - `&[("from_worker_id", "worker_id")]` for message-count raw relations
435    pub const fn fk_composite(
436        source_column: &'static str,
437        target_column: &'static str,
438        cardinality: Cardinality,
439        extra_key_columns: &'static [(&'static str, &'static str)],
440    ) -> Self {
441        Self::ForeignKey {
442            source_column,
443            target_column,
444            cardinality,
445            source_id_type: None,
446            requires_mapping: None,
447            nullable: false,
448            note: None,
449            extra_key_columns: Some(extra_key_columns),
450        }
451    }
452
453    /// Union link filtered by a discriminator column/value pair.
454    pub const fn union_disc(
455        discriminator_column: &'static str,
456        discriminator_value: &'static str,
457    ) -> Self {
458        Self::Union {
459            discriminator_column: Some(discriminator_column),
460            discriminator_value: Some(discriminator_value),
461            note: None,
462        }
463    }
464
465    /// Basic measures link with no optional fields set.
466    pub const fn measures(
467        source_column: &'static str,
468        target_column: &'static str,
469        metric: &'static str,
470    ) -> Self {
471        Self::Measures {
472            source_column,
473            target_column,
474            metric,
475            source_id_type: None,
476            requires_mapping: None,
477            note: None,
478            extra_key_columns: None,
479        }
480    }
481
482    /// Measures link with a composite join key.
483    pub const fn measures_composite(
484        source_column: &'static str,
485        target_column: &'static str,
486        metric: &'static str,
487        extra_key_columns: &'static [(&'static str, &'static str)],
488    ) -> Self {
489        Self::Measures {
490            source_column,
491            target_column,
492            metric,
493            source_id_type: None,
494            requires_mapping: None,
495            note: None,
496            extra_key_columns: Some(extra_key_columns),
497        }
498    }
499
500    /// Measures link whose source ID requires an intermediate mapping table.
501    pub const fn measures_mapped(
502        source_column: &'static str,
503        target_column: &'static str,
504        metric: &'static str,
505        source_id_type: mz_repr::SemanticType,
506        requires_mapping: &'static str,
507    ) -> Self {
508        Self::Measures {
509            source_column,
510            target_column,
511            metric,
512            source_id_type: Some(source_id_type),
513            requires_mapping: Some(requires_mapping),
514            note: None,
515            extra_key_columns: None,
516        }
517    }
518}
519
520/// A directed relationship from one ontology entity to another.
521///
522/// Each link has a `name` (the relationship label, e.g. `"owned_by"`), a
523/// `target` entity name, and a [`LinkProperties`] variant that captures the
524/// kind of relationship.
525#[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize)]
526pub struct OntologyLink {
527    /// Relationship name describing the relationship FROM this entity TO the
528    /// target (e.g., `"owned_by"` means "this entity is owned by the target",
529    /// `"depends_on"` means "this entity depends on the target"). When the
530    /// same name appears on multiple links of the same entity, all links
531    /// share that relationship role (e.g., several `"union_includes"` links).
532    pub name: &'static str,
533    /// Target entity name (e.g., "role", "schema").
534    pub target: &'static str,
535    /// Typed properties for the `properties` JSONB column.
536    pub properties: LinkProperties,
537}
538
539#[derive(Clone, Hash, Debug, PartialEq, Eq)]
540pub struct BuiltinTable {
541    pub name: &'static str,
542    pub schema: &'static str,
543    pub oid: u32,
544    pub desc: RelationDesc,
545    pub column_comments: BTreeMap<&'static str, &'static str>,
546    /// Whether the table's retention policy is controlled by
547    /// the system variable `METRICS_RETENTION`
548    pub is_retained_metrics_object: bool,
549    /// ACL items to apply to the object
550    pub access: Vec<MzAclItem>,
551    /// Ontology metadata. None means this builtin is not an ontology entity.
552    pub ontology: Option<Ontology>,
553}
554
555#[derive(Clone, Debug, PartialEq, Eq)]
556pub struct BuiltinSource {
557    pub name: &'static str,
558    pub schema: &'static str,
559    pub oid: u32,
560    pub desc: RelationDesc,
561    pub column_comments: BTreeMap<&'static str, &'static str>,
562    pub data_source: DataSourceDesc,
563    /// Whether the source's retention policy is controlled by
564    /// the system variable `METRICS_RETENTION`
565    pub is_retained_metrics_object: bool,
566    /// ACL items to apply to the object
567    pub access: Vec<MzAclItem>,
568    /// Ontology metadata. None means this builtin is not an ontology entity.
569    pub ontology: Option<Ontology>,
570}
571
572#[derive(Hash, Debug)]
573pub struct BuiltinView {
574    pub name: &'static str,
575    pub schema: &'static str,
576    pub oid: u32,
577    pub desc: RelationDesc,
578    pub column_comments: BTreeMap<&'static str, &'static str>,
579    pub sql: &'static str,
580    /// ACL items to apply to the object
581    pub access: Vec<MzAclItem>,
582    /// Ontology metadata. None means this builtin is not an ontology entity.
583    pub ontology: Option<Ontology>,
584}
585
586impl BuiltinView {
587    pub fn create_sql(&self) -> String {
588        format!("CREATE VIEW {}.{} AS {}", self.schema, self.name, self.sql)
589    }
590}
591
592#[derive(Hash, Debug)]
593pub struct BuiltinMaterializedView {
594    pub name: &'static str,
595    pub schema: &'static str,
596    pub oid: u32,
597    pub desc: RelationDesc,
598    pub column_comments: BTreeMap<&'static str, &'static str>,
599    /// SQL fragment for the MV, following `CREATE MATERIALIZED VIEW [name]`
600    ///
601    /// Format: `IN CLUSTER [cluster_name] AS [query]`
602    pub sql: &'static str,
603    /// Whether the MV's retention policy is controlled by
604    /// the system variable `METRICS_RETENTION`
605    pub is_retained_metrics_object: bool,
606    /// ACL items to apply to the object
607    pub access: Vec<MzAclItem>,
608    /// Ontology metadata. None means this builtin is not an ontology entity.
609    pub ontology: Option<Ontology>,
610}
611
612impl BuiltinMaterializedView {
613    pub fn create_sql(&self) -> String {
614        format!(
615            "CREATE MATERIALIZED VIEW {}.{} {}",
616            self.schema, self.name, self.sql
617        )
618    }
619}
620
621#[derive(Debug)]
622pub struct BuiltinType<T: TypeReference> {
623    pub name: &'static str,
624    pub schema: &'static str,
625    pub oid: u32,
626    pub details: CatalogTypeDetails<T>,
627}
628
629#[derive(Clone, Debug)]
630pub struct BuiltinFunc {
631    pub schema: &'static str,
632    pub name: &'static str,
633    pub inner: &'static mz_sql::func::Func,
634}
635
636/// Note: When creating a built-in index, it's usually best to choose a key that has only one
637/// component. For example, if you created an index
638/// `ON mz_internal.mz_object_lifetimes (id, object_type)`, then this index couldn't be used for a
639/// lookup for `WHERE object_type = ...`, and neither for joins keyed on just `id`.
640/// See <https://materialize.com/docs/transform-data/optimization/#matching-multi-column-indexes-to-multi-column-where-clauses>
641#[derive(Debug)]
642pub struct BuiltinIndex {
643    pub name: &'static str,
644    pub schema: &'static str,
645    pub oid: u32,
646    /// SQL fragment for the index, following `CREATE INDEX [name]`
647    ///
648    /// Format: `IN CLUSTER [cluster_name] ON [table_name] ([column_exprs])`
649    pub sql: &'static str,
650    pub is_retained_metrics_object: bool,
651}
652
653impl BuiltinIndex {
654    pub fn create_sql(&self) -> String {
655        format!("CREATE INDEX {}\n{}", self.name, self.sql)
656    }
657}
658
659#[derive(Hash, Debug)]
660pub struct BuiltinConnection {
661    pub name: &'static str,
662    pub schema: &'static str,
663    pub oid: u32,
664    pub sql: &'static str,
665    pub access: &'static [MzAclItem],
666    pub owner_id: &'static RoleId,
667    /// Whether the object can be altered at runtime by its owner.
668    ///
669    /// Note that when `runtime_alterable` is true, changing the `sql` in future
670    /// versions does not trigger a migration.
671    pub runtime_alterable: bool,
672}
673
674#[derive(Clone, Debug)]
675pub struct BuiltinRole {
676    pub id: RoleId,
677    /// Name of the builtin role.
678    ///
679    /// IMPORTANT: Must start with a prefix from [`BUILTIN_PREFIXES`].
680    pub name: &'static str,
681    pub oid: u32,
682    pub attributes: RoleAttributesRaw,
683}
684
685#[derive(Clone, Debug)]
686pub struct BuiltinCluster {
687    /// Name of the cluster.
688    ///
689    /// IMPORTANT: Must start with a prefix from [`BUILTIN_PREFIXES`].
690    pub name: &'static str,
691    pub privileges: &'static [MzAclItem],
692    pub owner_id: &'static RoleId,
693}
694
695/// Uniquely identifies the definition of a builtin object.
696pub trait Fingerprint {
697    fn fingerprint(&self) -> String;
698}
699
700impl<T: TypeReference> Fingerprint for &Builtin<T> {
701    fn fingerprint(&self) -> String {
702        match self {
703            Builtin::Log(log) => log.fingerprint(),
704            Builtin::Table(table) => table.fingerprint(),
705            Builtin::View(view) => view.fingerprint(),
706            Builtin::MaterializedView(mv) => mv.fingerprint(),
707            Builtin::Type(typ) => typ.fingerprint(),
708            Builtin::Func(func) => func.fingerprint(),
709            Builtin::Source(coll) => coll.fingerprint(),
710            Builtin::Index(index) => index.fingerprint(),
711            Builtin::Connection(connection) => connection.fingerprint(),
712        }
713    }
714}
715
716// Types and Funcs never change fingerprints so we just return constant 0
717impl<T: TypeReference> Fingerprint for &BuiltinType<T> {
718    fn fingerprint(&self) -> String {
719        "".to_string()
720    }
721}
722
723impl Fingerprint for &BuiltinFunc {
724    fn fingerprint(&self) -> String {
725        "".to_string()
726    }
727}
728
729impl Fingerprint for &BuiltinLog {
730    fn fingerprint(&self) -> String {
731        self.variant.desc().fingerprint()
732    }
733}
734
735impl Fingerprint for &BuiltinTable {
736    fn fingerprint(&self) -> String {
737        self.desc.fingerprint()
738    }
739}
740
741impl Fingerprint for &BuiltinView {
742    fn fingerprint(&self) -> String {
743        self.sql.to_string()
744    }
745}
746
747impl Fingerprint for &BuiltinSource {
748    fn fingerprint(&self) -> String {
749        self.desc.fingerprint()
750    }
751}
752
753impl Fingerprint for &BuiltinMaterializedView {
754    fn fingerprint(&self) -> String {
755        self.create_sql()
756    }
757}
758
759impl Fingerprint for &BuiltinIndex {
760    fn fingerprint(&self) -> String {
761        self.create_sql()
762    }
763}
764
765impl Fingerprint for &BuiltinConnection {
766    fn fingerprint(&self) -> String {
767        self.sql.to_string()
768    }
769}
770
771impl Fingerprint for RelationDesc {
772    fn fingerprint(&self) -> String {
773        self.typ().fingerprint()
774    }
775}
776
777impl Fingerprint for SqlRelationType {
778    fn fingerprint(&self) -> String {
779        serde_json::to_string(self).expect("serialization cannot fail")
780    }
781}
782
783/// Asserts that `name` is safe to embed unquoted inside a `'...'`-quoted SQL literal
784/// or inside a `"..."`-quoted SQL identifier. Generated builtin relations
785/// (`make_mz_indexes`, `make_mz_object_dependencies_raw`, ...) concatenate builtin names
786/// into SQL fragments, so a quote or backslash would produce malformed SQL. Builtin
787/// names should always be plain ASCII identifiers.
788pub(super) fn assert_safe_builtin_name(name: &str, kind: &str) {
789    assert!(
790        !name.contains('\'') && !name.contains('"') && !name.contains('\\'),
791        "builtin {kind} name {name:?} contains an unsupported character; \
792         generated builtin relations reconstruct SQL via string \
793         concatenation and assume names contain no quotes or backslashes"
794    );
795}
796
797pub(super) const PUBLIC_SELECT: MzAclItem = MzAclItem {
798    grantee: RoleId::Public,
799    grantor: MZ_SYSTEM_ROLE_ID,
800    acl_mode: AclMode::SELECT,
801};
802
803pub(super) const SUPPORT_SELECT: MzAclItem = MzAclItem {
804    grantee: MZ_SUPPORT_ROLE_ID,
805    grantor: MZ_SYSTEM_ROLE_ID,
806    acl_mode: AclMode::SELECT,
807};
808
809pub(super) const ANALYTICS_SELECT: MzAclItem = MzAclItem {
810    grantee: MZ_ANALYTICS_ROLE_ID,
811    grantor: MZ_SYSTEM_ROLE_ID,
812    acl_mode: AclMode::SELECT,
813};
814
815pub(super) const MONITOR_SELECT: MzAclItem = MzAclItem {
816    grantee: MZ_MONITOR_ROLE_ID,
817    grantor: MZ_SYSTEM_ROLE_ID,
818    acl_mode: AclMode::SELECT,
819};
820
821pub(super) const MONITOR_REDACTED_SELECT: MzAclItem = MzAclItem {
822    grantee: MZ_MONITOR_REDACTED_ROLE_ID,
823    grantor: MZ_SYSTEM_ROLE_ID,
824    acl_mode: AclMode::SELECT,
825};
826
827pub static MZ_CATALOG_RAW_DESCRIPTION: LazyLock<SystemObjectDescription> =
828    LazyLock::new(|| SystemObjectDescription {
829        schema_name: MZ_CATALOG_RAW.schema.to_string(),
830        object_type: CatalogItemType::Source,
831        object_name: MZ_CATALOG_RAW.name.to_string(),
832    });
833
834pub static MZ_STORAGE_USAGE_BY_SHARD_DESCRIPTION: LazyLock<SystemObjectDescription> =
835    LazyLock::new(|| SystemObjectDescription {
836        schema_name: MZ_STORAGE_USAGE_BY_SHARD.schema.to_string(),
837        object_type: CatalogItemType::Table,
838        object_name: MZ_STORAGE_USAGE_BY_SHARD.name.to_string(),
839    });
840
841/// Identifies [`MZ_OBJECT_ARRANGEMENT_SIZE_HISTORY`] for the schema-migration
842/// guard in `builtin_schema_migration.rs`, which forbids migrating this table
843/// because its startup pruner assumes it is the only source of retractions.
844pub static MZ_OBJECT_ARRANGEMENT_SIZE_HISTORY_DESCRIPTION: LazyLock<SystemObjectDescription> =
845    LazyLock::new(|| SystemObjectDescription {
846        schema_name: MZ_OBJECT_ARRANGEMENT_SIZE_HISTORY.schema.to_string(),
847        object_type: CatalogItemType::Table,
848        object_name: MZ_OBJECT_ARRANGEMENT_SIZE_HISTORY.name.to_string(),
849    });
850
851/// Identifies [`MZ_OBJECT_HYDRATION_HISTORY`] for the schema-migration guard.
852pub static MZ_OBJECT_HYDRATION_HISTORY_DESCRIPTION: LazyLock<SystemObjectDescription> =
853    LazyLock::new(|| SystemObjectDescription {
854        schema_name: MZ_OBJECT_HYDRATION_HISTORY.schema.to_string(),
855        object_type: CatalogItemType::Table,
856        object_name: MZ_OBJECT_HYDRATION_HISTORY.name.to_string(),
857    });
858
859/// Identifies [`MZ_REPLICA_HYDRATION_HISTORY`] for the schema-migration guard.
860pub static MZ_REPLICA_HYDRATION_HISTORY_DESCRIPTION: LazyLock<SystemObjectDescription> =
861    LazyLock::new(|| SystemObjectDescription {
862        schema_name: MZ_REPLICA_HYDRATION_HISTORY.schema.to_string(),
863        object_type: CatalogItemType::Table,
864        object_name: MZ_REPLICA_HYDRATION_HISTORY.name.to_string(),
865    });
866
867/// Identifies [`MZ_CLUSTER_REPLICA_FRONTIERS`] for the schema-migration guard in
868/// `builtin_schema_migration.rs`, which forbids migrating this source because the 0dt
869/// caught-up gate reads the leader's shard for it to learn the live frontiers.
870pub static MZ_CLUSTER_REPLICA_FRONTIERS_DESCRIPTION: LazyLock<SystemObjectDescription> =
871    LazyLock::new(|| SystemObjectDescription {
872        schema_name: MZ_CLUSTER_REPLICA_FRONTIERS.schema.to_string(),
873        object_type: CatalogItemType::Source,
874        object_name: MZ_CLUSTER_REPLICA_FRONTIERS.name.to_string(),
875    });
876pub const MZ_SYSTEM_ROLE: BuiltinRole = BuiltinRole {
877    id: MZ_SYSTEM_ROLE_ID,
878    name: SYSTEM_USER_NAME,
879    oid: oid::ROLE_MZ_SYSTEM_OID,
880    attributes: RoleAttributesRaw::new().with_all(),
881};
882
883pub const MZ_SUPPORT_ROLE: BuiltinRole = BuiltinRole {
884    id: MZ_SUPPORT_ROLE_ID,
885    name: SUPPORT_USER_NAME,
886    oid: oid::ROLE_MZ_SUPPORT_OID,
887    attributes: RoleAttributesRaw::new(),
888};
889
890pub const MZ_ANALYTICS_ROLE: BuiltinRole = BuiltinRole {
891    id: MZ_ANALYTICS_ROLE_ID,
892    name: ANALYTICS_USER_NAME,
893    oid: oid::ROLE_MZ_ANALYTICS_OID,
894    attributes: RoleAttributesRaw::new(),
895};
896
897/// This role can `SELECT` from various query history objects,
898/// e.g. `mz_prepared_statement_history`.
899pub const MZ_MONITOR_ROLE: BuiltinRole = BuiltinRole {
900    id: MZ_MONITOR_ROLE_ID,
901    name: "mz_monitor",
902    oid: oid::ROLE_MZ_MONITOR_OID,
903    attributes: RoleAttributesRaw::new(),
904};
905
906/// This role is like [`MZ_MONITOR_ROLE`], but can only query
907/// the redacted versions of the objects.
908pub const MZ_MONITOR_REDACTED: BuiltinRole = BuiltinRole {
909    id: MZ_MONITOR_REDACTED_ROLE_ID,
910    name: "mz_monitor_redacted",
911    oid: oid::ROLE_MZ_MONITOR_REDACTED_OID,
912    attributes: RoleAttributesRaw::new(),
913};
914
915/// Sentinel role used as the grantor for JWT group-sync-managed
916/// role memberships. Never logged into directly.
917pub const MZ_JWT_SYNC_ROLE: BuiltinRole = BuiltinRole {
918    id: MZ_JWT_SYNC_ROLE_ID,
919    name: JWT_SYNC_ROLE_NAME,
920    oid: oid::ROLE_MZ_JWT_SYNC_OID,
921    attributes: RoleAttributesRaw::new(),
922};
923
924pub const MZ_SYSTEM_CLUSTER: BuiltinCluster = BuiltinCluster {
925    name: SYSTEM_USER_NAME,
926    owner_id: &MZ_SYSTEM_ROLE_ID,
927    privileges: &[
928        MzAclItem {
929            grantee: MZ_SUPPORT_ROLE_ID,
930            grantor: MZ_SYSTEM_ROLE_ID,
931            acl_mode: AclMode::USAGE,
932        },
933        rbac::owner_privilege(ObjectType::Cluster, MZ_SYSTEM_ROLE_ID),
934    ],
935};
936
937pub const MZ_CATALOG_SERVER_CLUSTER: BuiltinCluster = BuiltinCluster {
938    name: "mz_catalog_server",
939    owner_id: &MZ_SYSTEM_ROLE_ID,
940    privileges: &[
941        MzAclItem {
942            grantee: RoleId::Public,
943            grantor: MZ_SYSTEM_ROLE_ID,
944            acl_mode: AclMode::USAGE,
945        },
946        MzAclItem {
947            grantee: MZ_SUPPORT_ROLE_ID,
948            grantor: MZ_SYSTEM_ROLE_ID,
949            acl_mode: AclMode::USAGE.union(AclMode::CREATE),
950        },
951        rbac::owner_privilege(ObjectType::Cluster, MZ_SYSTEM_ROLE_ID),
952    ],
953};
954
955pub const MZ_PROBE_CLUSTER: BuiltinCluster = BuiltinCluster {
956    name: "mz_probe",
957    owner_id: &MZ_SYSTEM_ROLE_ID,
958    privileges: &[
959        MzAclItem {
960            grantee: MZ_SUPPORT_ROLE_ID,
961            grantor: MZ_SYSTEM_ROLE_ID,
962            acl_mode: AclMode::USAGE,
963        },
964        MzAclItem {
965            grantee: MZ_MONITOR_ROLE_ID,
966            grantor: MZ_SYSTEM_ROLE_ID,
967            acl_mode: AclMode::USAGE,
968        },
969        rbac::owner_privilege(ObjectType::Cluster, MZ_SYSTEM_ROLE_ID),
970    ],
971};
972
973pub const MZ_SUPPORT_CLUSTER: BuiltinCluster = BuiltinCluster {
974    name: "mz_support",
975    owner_id: &MZ_SUPPORT_ROLE_ID,
976    privileges: &[
977        MzAclItem {
978            grantee: MZ_SYSTEM_ROLE_ID,
979            grantor: MZ_SUPPORT_ROLE_ID,
980            acl_mode: rbac::all_object_privileges(SystemObjectType::Object(ObjectType::Cluster)),
981        },
982        rbac::owner_privilege(ObjectType::Cluster, MZ_SUPPORT_ROLE_ID),
983    ],
984};
985
986pub const MZ_ANALYTICS_CLUSTER: BuiltinCluster = BuiltinCluster {
987    name: "mz_analytics",
988    owner_id: &MZ_ANALYTICS_ROLE_ID,
989    privileges: &[
990        MzAclItem {
991            grantee: MZ_SYSTEM_ROLE_ID,
992            grantor: MZ_ANALYTICS_ROLE_ID,
993            acl_mode: rbac::all_object_privileges(SystemObjectType::Object(ObjectType::Cluster)),
994        },
995        rbac::owner_privilege(ObjectType::Cluster, MZ_ANALYTICS_ROLE_ID),
996    ],
997};
998
999/// List of all builtin objects sorted topologically by dependency.
1000pub static BUILTINS_STATIC: LazyLock<Vec<Builtin<NameReference>>> = LazyLock::new(|| {
1001    let mut builtin_types = vec![
1002        Builtin::Type(&TYPE_ANY),
1003        Builtin::Type(&TYPE_ANYARRAY),
1004        Builtin::Type(&TYPE_ANYELEMENT),
1005        Builtin::Type(&TYPE_ANYNONARRAY),
1006        Builtin::Type(&TYPE_ANYRANGE),
1007        Builtin::Type(&TYPE_BOOL),
1008        Builtin::Type(&TYPE_BOOL_ARRAY),
1009        Builtin::Type(&TYPE_BYTEA),
1010        Builtin::Type(&TYPE_BYTEA_ARRAY),
1011        Builtin::Type(&TYPE_BPCHAR),
1012        Builtin::Type(&TYPE_BPCHAR_ARRAY),
1013        Builtin::Type(&TYPE_CHAR),
1014        Builtin::Type(&TYPE_CHAR_ARRAY),
1015        Builtin::Type(&TYPE_DATE),
1016        Builtin::Type(&TYPE_DATE_ARRAY),
1017        Builtin::Type(&TYPE_FLOAT4),
1018        Builtin::Type(&TYPE_FLOAT4_ARRAY),
1019        Builtin::Type(&TYPE_FLOAT8),
1020        Builtin::Type(&TYPE_FLOAT8_ARRAY),
1021        Builtin::Type(&TYPE_INT4),
1022        Builtin::Type(&TYPE_INT4_ARRAY),
1023        Builtin::Type(&TYPE_INT8),
1024        Builtin::Type(&TYPE_INT8_ARRAY),
1025        Builtin::Type(&TYPE_INTERVAL),
1026        Builtin::Type(&TYPE_INTERVAL_ARRAY),
1027        Builtin::Type(&TYPE_JSONB),
1028        Builtin::Type(&TYPE_JSONB_ARRAY),
1029        Builtin::Type(&TYPE_LIST),
1030        Builtin::Type(&TYPE_MAP),
1031        Builtin::Type(&TYPE_NAME),
1032        Builtin::Type(&TYPE_NAME_ARRAY),
1033        Builtin::Type(&TYPE_NUMERIC),
1034        Builtin::Type(&TYPE_NUMERIC_ARRAY),
1035        Builtin::Type(&TYPE_OID),
1036        Builtin::Type(&TYPE_OID_ARRAY),
1037        Builtin::Type(&TYPE_RECORD),
1038        Builtin::Type(&TYPE_RECORD_ARRAY),
1039        Builtin::Type(&TYPE_REGCLASS),
1040        Builtin::Type(&TYPE_REGCLASS_ARRAY),
1041        Builtin::Type(&TYPE_REGPROC),
1042        Builtin::Type(&TYPE_REGPROC_ARRAY),
1043        Builtin::Type(&TYPE_REGTYPE),
1044        Builtin::Type(&TYPE_REGTYPE_ARRAY),
1045        Builtin::Type(&TYPE_INT2),
1046        Builtin::Type(&TYPE_INT2_ARRAY),
1047        Builtin::Type(&TYPE_TEXT),
1048        Builtin::Type(&TYPE_TEXT_ARRAY),
1049        Builtin::Type(&TYPE_TIME),
1050        Builtin::Type(&TYPE_TIME_ARRAY),
1051        Builtin::Type(&TYPE_TIMESTAMP),
1052        Builtin::Type(&TYPE_TIMESTAMP_ARRAY),
1053        Builtin::Type(&TYPE_TIMESTAMPTZ),
1054        Builtin::Type(&TYPE_TIMESTAMPTZ_ARRAY),
1055        Builtin::Type(&TYPE_UUID),
1056        Builtin::Type(&TYPE_UUID_ARRAY),
1057        Builtin::Type(&TYPE_VARCHAR),
1058        Builtin::Type(&TYPE_VARCHAR_ARRAY),
1059        Builtin::Type(&TYPE_INT2_VECTOR),
1060        Builtin::Type(&TYPE_INT2_VECTOR_ARRAY),
1061        Builtin::Type(&TYPE_ANYCOMPATIBLE),
1062        Builtin::Type(&TYPE_ANYCOMPATIBLEARRAY),
1063        Builtin::Type(&TYPE_ANYCOMPATIBLENONARRAY),
1064        Builtin::Type(&TYPE_ANYCOMPATIBLELIST),
1065        Builtin::Type(&TYPE_ANYCOMPATIBLEMAP),
1066        Builtin::Type(&TYPE_ANYCOMPATIBLERANGE),
1067        Builtin::Type(&TYPE_UINT2),
1068        Builtin::Type(&TYPE_UINT2_ARRAY),
1069        Builtin::Type(&TYPE_UINT4),
1070        Builtin::Type(&TYPE_UINT4_ARRAY),
1071        Builtin::Type(&TYPE_UINT8),
1072        Builtin::Type(&TYPE_UINT8_ARRAY),
1073        Builtin::Type(&TYPE_MZ_TIMESTAMP),
1074        Builtin::Type(&TYPE_MZ_TIMESTAMP_ARRAY),
1075        Builtin::Type(&TYPE_INT4_RANGE),
1076        Builtin::Type(&TYPE_INT4_RANGE_ARRAY),
1077        Builtin::Type(&TYPE_INT8_RANGE),
1078        Builtin::Type(&TYPE_INT8_RANGE_ARRAY),
1079        Builtin::Type(&TYPE_DATE_RANGE),
1080        Builtin::Type(&TYPE_DATE_RANGE_ARRAY),
1081        Builtin::Type(&TYPE_NUM_RANGE),
1082        Builtin::Type(&TYPE_NUM_RANGE_ARRAY),
1083        Builtin::Type(&TYPE_TS_RANGE),
1084        Builtin::Type(&TYPE_TS_RANGE_ARRAY),
1085        Builtin::Type(&TYPE_TSTZ_RANGE),
1086        Builtin::Type(&TYPE_TSTZ_RANGE_ARRAY),
1087        Builtin::Type(&TYPE_MZ_ACL_ITEM),
1088        Builtin::Type(&TYPE_MZ_ACL_ITEM_ARRAY),
1089        Builtin::Type(&TYPE_ACL_ITEM),
1090        Builtin::Type(&TYPE_ACL_ITEM_ARRAY),
1091        Builtin::Type(&TYPE_INTERNAL),
1092    ];
1093
1094    let mut builtin_funcs = Vec::new();
1095    for (schema, funcs) in &[
1096        (PG_CATALOG_SCHEMA, &*mz_sql::func::PG_CATALOG_BUILTINS),
1097        (
1098            INFORMATION_SCHEMA,
1099            &*mz_sql::func::INFORMATION_SCHEMA_BUILTINS,
1100        ),
1101        (MZ_CATALOG_SCHEMA, &*mz_sql::func::MZ_CATALOG_BUILTINS),
1102        (MZ_INTERNAL_SCHEMA, &*mz_sql::func::MZ_INTERNAL_BUILTINS),
1103        (MZ_UNSAFE_SCHEMA, &*mz_sql::func::MZ_UNSAFE_BUILTINS),
1104    ] {
1105        for (name, func) in funcs.iter() {
1106            builtin_funcs.push(Builtin::Func(BuiltinFunc {
1107                name,
1108                schema,
1109                inner: func,
1110            }));
1111        }
1112    }
1113
1114    let mut builtin_items = vec![
1115        Builtin::Source(&MZ_CATALOG_RAW),
1116        Builtin::Log(&MZ_ARRANGEMENT_SHARING_RAW),
1117        Builtin::Log(&MZ_ARRANGEMENT_BATCHES_RAW),
1118        Builtin::Log(&MZ_ARRANGEMENT_RECORDS_RAW),
1119        Builtin::Log(&MZ_ARRANGEMENT_BATCHER_RECORDS_RAW),
1120        Builtin::Log(&MZ_ARRANGEMENT_BATCHER_SIZE_RAW),
1121        Builtin::Log(&MZ_ARRANGEMENT_BATCHER_CAPACITY_RAW),
1122        Builtin::Log(&MZ_ARRANGEMENT_BATCHER_ALLOCATIONS_RAW),
1123        Builtin::Log(&MZ_DATAFLOW_CHANNELS_PER_WORKER),
1124        Builtin::Log(&MZ_DATAFLOW_OPERATORS_PER_WORKER),
1125        Builtin::Log(&MZ_DATAFLOW_ADDRESSES_PER_WORKER),
1126        Builtin::Log(&MZ_DATAFLOW_OPERATOR_REACHABILITY_RAW),
1127        Builtin::Log(&MZ_COMPUTE_EXPORTS_PER_WORKER),
1128        Builtin::Log(&MZ_COMPUTE_DATAFLOW_GLOBAL_IDS_PER_WORKER),
1129        Builtin::Log(&MZ_CLUSTER_PROMETHEUS_METRICS),
1130        Builtin::Log(&MZ_CLUSTER_REPLICA_RESOURCE_USAGE),
1131        Builtin::Log(&MZ_MESSAGE_COUNTS_RECEIVED_RAW),
1132        Builtin::Log(&MZ_MESSAGE_COUNTS_SENT_RAW),
1133        Builtin::Log(&MZ_MESSAGE_BATCH_COUNTS_RECEIVED_RAW),
1134        Builtin::Log(&MZ_MESSAGE_BATCH_COUNTS_SENT_RAW),
1135        Builtin::Log(&MZ_ACTIVE_PEEKS_PER_WORKER),
1136        Builtin::Log(&MZ_PEEK_DURATIONS_HISTOGRAM_RAW),
1137        Builtin::Log(&MZ_ARRANGEMENT_HEAP_CAPACITY_RAW),
1138        Builtin::Log(&MZ_ARRANGEMENT_HEAP_ALLOCATIONS_RAW),
1139        Builtin::Log(&MZ_ARRANGEMENT_HEAP_SIZE_RAW),
1140        Builtin::Log(&MZ_SCHEDULING_ELAPSED_RAW),
1141        Builtin::Log(&MZ_COMPUTE_OPERATOR_DURATIONS_HISTOGRAM_RAW),
1142        Builtin::Log(&MZ_SCHEDULING_PARKS_HISTOGRAM_RAW),
1143        Builtin::Log(&MZ_COMPUTE_FRONTIERS_PER_WORKER),
1144        Builtin::Log(&MZ_COMPUTE_IMPORT_FRONTIERS_PER_WORKER),
1145        Builtin::Log(&MZ_COMPUTE_ERROR_COUNTS_RAW),
1146        Builtin::Log(&MZ_COMPUTE_HYDRATION_TIMES_PER_WORKER),
1147        Builtin::Log(&MZ_COMPUTE_OPERATOR_HYDRATION_STATUSES_PER_WORKER),
1148        Builtin::MaterializedView(&MZ_KAFKA_SINKS),
1149        Builtin::MaterializedView(&MZ_KAFKA_CONNECTIONS),
1150        Builtin::MaterializedView(&MZ_KAFKA_SOURCES),
1151        // mz_object_dependencies_raw is generated dynamically below with inlined
1152        // builtin VALUES and inserted directly before this entry.
1153        Builtin::MaterializedView(&MZ_OBJECT_DEPENDENCIES),
1154        Builtin::MaterializedView(&MZ_ICEBERG_SINKS),
1155        Builtin::MaterializedView(&MZ_DATABASES),
1156        Builtin::MaterializedView(&MZ_SCHEMAS),
1157        Builtin::Table(&MZ_COLUMNS),
1158        // mz_indexes is generated dynamically below with inlined builtin VALUES.
1159        Builtin::Table(&MZ_INDEX_COLUMNS),
1160        Builtin::MaterializedView(&MZ_TABLES),
1161        // mz_sources is generated dynamically below with inlined builtin VALUES.
1162        Builtin::Table(&MZ_SOURCE_REFERENCES),
1163        Builtin::MaterializedView(&MZ_POSTGRES_SOURCES),
1164        Builtin::MaterializedView(&MZ_POSTGRES_SOURCE_TABLES),
1165        Builtin::MaterializedView(&MZ_MYSQL_SOURCE_TABLES),
1166        Builtin::MaterializedView(&MZ_SQL_SERVER_SOURCE_TABLES),
1167        Builtin::MaterializedView(&MZ_KAFKA_SOURCE_TABLES),
1168        Builtin::MaterializedView(&MZ_SINKS),
1169        Builtin::MaterializedView(&MZ_VIEWS),
1170        Builtin::Table(&MZ_TYPES),
1171        Builtin::Table(&MZ_TYPE_PG_METADATA),
1172        Builtin::Table(&MZ_ARRAY_TYPES),
1173        Builtin::Table(&MZ_BASE_TYPES),
1174        Builtin::Table(&MZ_LIST_TYPES),
1175        Builtin::Table(&MZ_MAP_TYPES),
1176        Builtin::MaterializedView(&MZ_ROLES),
1177        Builtin::Table(&MZ_ROLE_AUTH),
1178        Builtin::MaterializedView(&MZ_ROLE_MEMBERS),
1179        Builtin::MaterializedView(&MZ_ROLE_PARAMETERS),
1180        Builtin::Table(&MZ_PSEUDO_TYPES),
1181        Builtin::Table(&MZ_FUNCTIONS),
1182        Builtin::Table(&MZ_OPERATORS),
1183        Builtin::Table(&MZ_AGGREGATES),
1184        Builtin::Table(&MZ_CLUSTER_REPLICA_SIZES),
1185        Builtin::Table(&MZ_CLUSTER_REPLICA_SIZE_INTERNAL),
1186        Builtin::MaterializedView(&MZ_CLUSTERS),
1187        Builtin::MaterializedView(&MZ_CLUSTER_WORKLOAD_CLASSES),
1188        Builtin::MaterializedView(&MZ_CLUSTER_SCHEDULES),
1189        Builtin::MaterializedView(&MZ_CLUSTER_RECONFIGURATIONS),
1190        Builtin::MaterializedView(&MZ_CLUSTER_AUTO_SCALING_STRATEGIES),
1191        Builtin::MaterializedView(&MZ_SECRETS),
1192        Builtin::MaterializedView(&MZ_CONNECTIONS),
1193        Builtin::MaterializedView(&MZ_SSH_TUNNEL_CONNECTIONS),
1194        Builtin::MaterializedView(&MZ_CLUSTER_REPLICAS),
1195        Builtin::Source(&MZ_CLUSTER_REPLICA_METRICS_HISTORY),
1196        Builtin::View(&MZ_CLUSTER_REPLICA_METRICS),
1197        Builtin::Source(&MZ_CLUSTER_REPLICA_STATUS_HISTORY),
1198        Builtin::View(&MZ_CLUSTER_REPLICA_STATUSES),
1199        Builtin::MaterializedView(&MZ_INTERNAL_CLUSTER_REPLICAS),
1200        Builtin::MaterializedView(&MZ_PENDING_CLUSTER_REPLICAS),
1201        Builtin::MaterializedView(&MZ_AUDIT_EVENTS),
1202        Builtin::Table(&MZ_STORAGE_USAGE_BY_SHARD),
1203        Builtin::Table(&MZ_EGRESS_IPS),
1204        Builtin::MaterializedView(&MZ_AWS_PRIVATELINK_CONNECTIONS),
1205        Builtin::MaterializedView(&MZ_AWS_CONNECTIONS),
1206        Builtin::Table(&MZ_SUBSCRIPTIONS),
1207        Builtin::Table(&MZ_SESSIONS),
1208        Builtin::MaterializedView(&MZ_OVERRIDDEN_SYSTEM_PARAMETERS),
1209        Builtin::MaterializedView(&MZ_CLUSTER_SYSTEM_PARAMETERS),
1210        Builtin::MaterializedView(&MZ_REPLICA_SYSTEM_PARAMETERS),
1211        Builtin::MaterializedView(&MZ_DEFAULT_PRIVILEGES),
1212        Builtin::MaterializedView(&MZ_SYSTEM_PRIVILEGES),
1213        Builtin::MaterializedView(&MZ_COMMENTS),
1214        Builtin::Table(&MZ_WEBHOOKS_SOURCES),
1215        Builtin::MaterializedView(&MZ_METRIC_SINKS),
1216        Builtin::Table(&MZ_HISTORY_RETENTION_STRATEGIES),
1217        Builtin::MaterializedView(&MZ_MATERIALIZED_VIEWS),
1218        Builtin::Table(&MZ_MATERIALIZED_VIEW_REFRESH_STRATEGIES),
1219        Builtin::MaterializedView(&MZ_NETWORK_POLICIES),
1220        Builtin::MaterializedView(&MZ_NETWORK_POLICY_RULES),
1221        Builtin::Table(&MZ_LICENSE_KEYS),
1222        Builtin::Table(&MZ_REPLACEMENTS),
1223        Builtin::View(&MZ_RELATIONS),
1224        Builtin::View(&MZ_OBJECT_OID_ALIAS),
1225        Builtin::View(&MZ_OBJECTS),
1226        Builtin::View(&MZ_OBJECT_FULLY_QUALIFIED_NAMES),
1227        Builtin::View(&MZ_OBJECTS_ID_NAMESPACE_TYPES),
1228        Builtin::View(&MZ_OBJECT_HISTORY),
1229        Builtin::View(&MZ_OBJECT_LIFETIMES),
1230        Builtin::Table(&MZ_OBJECT_GLOBAL_IDS),
1231        Builtin::View(&MZ_ARRANGEMENT_SHARING_PER_WORKER),
1232        Builtin::View(&MZ_ARRANGEMENT_SHARING),
1233        Builtin::View(&MZ_ARRANGEMENT_SIZES_PER_WORKER),
1234        Builtin::View(&MZ_ARRANGEMENT_SIZES),
1235        Builtin::View(&MZ_DATAFLOWS_PER_WORKER),
1236        Builtin::View(&MZ_DATAFLOWS),
1237        Builtin::View(&MZ_DATAFLOW_ADDRESSES),
1238        Builtin::View(&MZ_DATAFLOW_CHANNELS),
1239        Builtin::View(&MZ_DATAFLOW_OPERATORS),
1240        Builtin::View(&MZ_DATAFLOW_GLOBAL_IDS),
1241        Builtin::View(&MZ_COMPUTE_EXPORTS),
1242        Builtin::View(&MZ_MAPPABLE_OBJECTS),
1243        Builtin::View(&MZ_DATAFLOW_OPERATOR_DATAFLOWS_PER_WORKER),
1244        Builtin::View(&MZ_DATAFLOW_OPERATOR_DATAFLOWS),
1245        Builtin::View(&MZ_OBJECT_TRANSITIVE_DEPENDENCIES),
1246        Builtin::View(&MZ_DATAFLOW_OPERATOR_REACHABILITY_PER_WORKER),
1247        Builtin::View(&MZ_DATAFLOW_OPERATOR_REACHABILITY),
1248        Builtin::View(&MZ_CLUSTER_REPLICA_UTILIZATION),
1249        Builtin::View(&MZ_CLUSTER_REPLICA_UTILIZATION_HISTORY),
1250        Builtin::View(&MZ_DATAFLOW_OPERATOR_PARENTS_PER_WORKER),
1251        Builtin::View(&MZ_DATAFLOW_OPERATOR_PARENTS),
1252        Builtin::View(&MZ_DATAFLOW_ARRANGEMENT_SIZES),
1253        Builtin::View(&MZ_EXPECTED_GROUP_SIZE_ADVICE),
1254        Builtin::View(&MZ_COMPUTE_FRONTIERS),
1255        Builtin::View(&MZ_DATAFLOW_CHANNEL_OPERATORS_PER_WORKER),
1256        Builtin::View(&MZ_DATAFLOW_CHANNEL_OPERATORS),
1257        Builtin::View(&MZ_COMPUTE_IMPORT_FRONTIERS),
1258        Builtin::View(&MZ_MESSAGE_COUNTS_PER_WORKER),
1259        Builtin::View(&MZ_MESSAGE_COUNTS),
1260        Builtin::View(&MZ_ACTIVE_PEEKS),
1261        Builtin::View(&MZ_COMPUTE_OPERATOR_DURATIONS_HISTOGRAM_PER_WORKER),
1262        Builtin::View(&MZ_COMPUTE_OPERATOR_DURATIONS_HISTOGRAM),
1263        Builtin::View(&MZ_RECORDS_PER_DATAFLOW_OPERATOR_PER_WORKER),
1264        Builtin::View(&MZ_RECORDS_PER_DATAFLOW_OPERATOR),
1265        Builtin::View(&MZ_RECORDS_PER_DATAFLOW_PER_WORKER),
1266        Builtin::View(&MZ_RECORDS_PER_DATAFLOW),
1267        Builtin::View(&MZ_PEEK_DURATIONS_HISTOGRAM_PER_WORKER),
1268        Builtin::View(&MZ_PEEK_DURATIONS_HISTOGRAM),
1269        Builtin::View(&MZ_SCHEDULING_ELAPSED_PER_WORKER),
1270        Builtin::View(&MZ_SCHEDULING_ELAPSED),
1271        Builtin::View(&MZ_SCHEDULING_PARKS_HISTOGRAM_PER_WORKER),
1272        Builtin::View(&MZ_SCHEDULING_PARKS_HISTOGRAM),
1273        Builtin::View(&MZ_SHOW_ALL_OBJECTS),
1274        Builtin::View(&MZ_SHOW_COLUMNS),
1275        Builtin::View(&MZ_SHOW_CLUSTERS),
1276        Builtin::View(&MZ_SHOW_SECRETS),
1277        Builtin::View(&MZ_SHOW_DATABASES),
1278        Builtin::View(&MZ_SHOW_SCHEMAS),
1279        Builtin::View(&MZ_SHOW_TABLES),
1280        Builtin::View(&MZ_SHOW_VIEWS),
1281        Builtin::View(&MZ_SHOW_TYPES),
1282        Builtin::View(&MZ_SHOW_ROLES),
1283        Builtin::View(&MZ_SHOW_CONNECTIONS),
1284        Builtin::View(&MZ_SHOW_SOURCES),
1285        Builtin::View(&MZ_SHOW_SINKS),
1286        Builtin::View(&MZ_SHOW_MATERIALIZED_VIEWS),
1287        Builtin::View(&MZ_SHOW_INDEXES),
1288        Builtin::View(&MZ_CLUSTER_REPLICA_HISTORY),
1289        Builtin::View(&MZ_CLUSTER_REPLICA_NAME_HISTORY),
1290        Builtin::View(&MZ_TIMEZONE_NAMES),
1291        Builtin::View(&MZ_TIMEZONE_ABBREVIATIONS),
1292        Builtin::View(&PG_NAMESPACE_ALL_DATABASES),
1293        Builtin::Index(&PG_NAMESPACE_ALL_DATABASES_IND),
1294        Builtin::View(&PG_NAMESPACE),
1295        Builtin::View(&PG_CLASS_ALL_DATABASES),
1296        Builtin::Index(&PG_CLASS_ALL_DATABASES_IND),
1297        Builtin::View(&PG_CLASS),
1298        Builtin::View(&PG_DEPEND),
1299        Builtin::View(&PG_DATABASE),
1300        Builtin::View(&PG_INDEX),
1301        Builtin::View(&PG_TYPE_ALL_DATABASES),
1302        Builtin::Index(&PG_TYPE_ALL_DATABASES_IND),
1303        Builtin::View(&PG_TYPE),
1304        Builtin::View(&PG_DESCRIPTION_ALL_DATABASES),
1305        Builtin::Index(&PG_DESCRIPTION_ALL_DATABASES_IND),
1306        Builtin::View(&PG_DESCRIPTION),
1307        Builtin::View(&PG_ATTRIBUTE_ALL_DATABASES),
1308        Builtin::Index(&PG_ATTRIBUTE_ALL_DATABASES_IND),
1309        Builtin::View(&PG_ATTRIBUTE),
1310        Builtin::View(&PG_PROC),
1311        Builtin::View(&PG_OPERATOR),
1312        Builtin::View(&PG_RANGE),
1313        Builtin::View(&PG_ENUM),
1314        Builtin::View(&PG_ATTRDEF_ALL_DATABASES),
1315        Builtin::Index(&PG_ATTRDEF_ALL_DATABASES_IND),
1316        Builtin::View(&PG_ATTRDEF),
1317        Builtin::View(&PG_SETTINGS),
1318        Builtin::View(&PG_AUTH_MEMBERS),
1319        Builtin::View(&PG_CONSTRAINT),
1320        Builtin::View(&PG_TABLES),
1321        Builtin::View(&PG_TABLESPACE),
1322        Builtin::View(&PG_ACCESS_METHODS),
1323        Builtin::View(&PG_LOCKS),
1324        Builtin::View(&PG_AUTHID_CORE),
1325        Builtin::Index(&PG_AUTHID_CORE_IND),
1326        Builtin::View(&PG_AUTHID),
1327        Builtin::View(&PG_ROLES),
1328        Builtin::View(&PG_USER),
1329        Builtin::View(&PG_VIEWS),
1330        Builtin::View(&PG_MATVIEWS),
1331        Builtin::View(&PG_COLLATION),
1332        Builtin::View(&PG_POLICY),
1333        Builtin::View(&PG_INHERITS),
1334        Builtin::View(&PG_AGGREGATE),
1335        Builtin::View(&PG_TRIGGER),
1336        Builtin::View(&PG_REWRITE),
1337        Builtin::View(&PG_EXTENSION),
1338        Builtin::View(&PG_EVENT_TRIGGER),
1339        Builtin::View(&PG_LANGUAGE),
1340        Builtin::View(&PG_SHDESCRIPTION),
1341        Builtin::View(&PG_INDEXES),
1342        Builtin::View(&PG_TIMEZONE_ABBREVS),
1343        Builtin::View(&PG_TIMEZONE_NAMES),
1344        Builtin::View(&INFORMATION_SCHEMA_APPLICABLE_ROLES),
1345        Builtin::View(&INFORMATION_SCHEMA_COLUMNS),
1346        Builtin::View(&INFORMATION_SCHEMA_ENABLED_ROLES),
1347        Builtin::View(&INFORMATION_SCHEMA_KEY_COLUMN_USAGE),
1348        Builtin::View(&INFORMATION_SCHEMA_REFERENTIAL_CONSTRAINTS),
1349        Builtin::View(&INFORMATION_SCHEMA_ROUTINES),
1350        Builtin::View(&INFORMATION_SCHEMA_SCHEMATA),
1351        Builtin::View(&INFORMATION_SCHEMA_TABLES),
1352        Builtin::View(&INFORMATION_SCHEMA_TABLE_CONSTRAINTS),
1353        Builtin::View(&INFORMATION_SCHEMA_TABLE_PRIVILEGES),
1354        Builtin::View(&INFORMATION_SCHEMA_ROLE_TABLE_GRANTS),
1355        Builtin::View(&INFORMATION_SCHEMA_TRIGGERS),
1356        Builtin::View(&INFORMATION_SCHEMA_VIEWS),
1357        Builtin::View(&INFORMATION_SCHEMA_CHARACTER_SETS),
1358        Builtin::View(&MZ_SHOW_ROLE_MEMBERS),
1359        Builtin::View(&MZ_SHOW_MY_ROLE_MEMBERS),
1360        Builtin::View(&MZ_SHOW_SYSTEM_PRIVILEGES),
1361        Builtin::View(&MZ_SHOW_MY_SYSTEM_PRIVILEGES),
1362        Builtin::View(&MZ_SHOW_CLUSTER_PRIVILEGES),
1363        Builtin::View(&MZ_SHOW_MY_CLUSTER_PRIVILEGES),
1364        Builtin::View(&MZ_SHOW_DATABASE_PRIVILEGES),
1365        Builtin::View(&MZ_SHOW_MY_DATABASE_PRIVILEGES),
1366        Builtin::View(&MZ_SHOW_SCHEMA_PRIVILEGES),
1367        Builtin::View(&MZ_SHOW_MY_SCHEMA_PRIVILEGES),
1368        Builtin::View(&MZ_SHOW_OBJECT_PRIVILEGES),
1369        Builtin::View(&MZ_SHOW_MY_OBJECT_PRIVILEGES),
1370        Builtin::View(&MZ_SHOW_ALL_PRIVILEGES),
1371        Builtin::View(&MZ_SHOW_ALL_MY_PRIVILEGES),
1372        Builtin::View(&MZ_SHOW_DEFAULT_PRIVILEGES),
1373        Builtin::View(&MZ_SHOW_MY_DEFAULT_PRIVILEGES),
1374        Builtin::Source(&MZ_SINK_STATUS_HISTORY),
1375        Builtin::View(&MZ_SINK_STATUSES),
1376        Builtin::Source(&MZ_SOURCE_STATUS_HISTORY),
1377        Builtin::Source(&MZ_AWS_PRIVATELINK_CONNECTION_STATUS_HISTORY),
1378        Builtin::View(&MZ_AWS_PRIVATELINK_CONNECTION_STATUSES),
1379        Builtin::Source(&MZ_STATEMENT_EXECUTION_HISTORY),
1380        Builtin::View(&MZ_STATEMENT_EXECUTION_HISTORY_REDACTED),
1381        Builtin::Source(&MZ_PREPARED_STATEMENT_HISTORY),
1382        Builtin::Source(&MZ_SESSION_HISTORY),
1383        Builtin::Source(&MZ_SQL_TEXT),
1384        Builtin::View(&MZ_SQL_TEXT_REDACTED),
1385        Builtin::View(&MZ_RECENT_SQL_TEXT),
1386        Builtin::View(&MZ_RECENT_SQL_TEXT_REDACTED),
1387        Builtin::Index(&MZ_RECENT_SQL_TEXT_IND),
1388        Builtin::View(&MZ_ACTIVITY_LOG_THINNED),
1389        Builtin::View(&MZ_RECENT_ACTIVITY_LOG_THINNED),
1390        Builtin::View(&MZ_RECENT_ACTIVITY_LOG),
1391        Builtin::View(&MZ_RECENT_ACTIVITY_LOG_REDACTED),
1392        Builtin::Index(&MZ_RECENT_ACTIVITY_LOG_THINNED_IND),
1393        Builtin::View(&MZ_SOURCE_STATUSES),
1394        Builtin::Source(&MZ_STATEMENT_LIFECYCLE_HISTORY),
1395        Builtin::Source(&MZ_STORAGE_SHARDS),
1396        Builtin::Source(&MZ_SOURCE_STATISTICS_RAW),
1397        Builtin::Source(&MZ_SINK_STATISTICS_RAW),
1398        Builtin::View(&MZ_SOURCE_STATISTICS_WITH_HISTORY),
1399        Builtin::Index(&MZ_SOURCE_STATISTICS_WITH_HISTORY_IND),
1400        Builtin::View(&MZ_SOURCE_STATISTICS),
1401        Builtin::Index(&MZ_SOURCE_STATISTICS_IND),
1402        Builtin::View(&MZ_SINK_STATISTICS),
1403        Builtin::Index(&MZ_SINK_STATISTICS_IND),
1404        Builtin::View(&MZ_STORAGE_USAGE),
1405        Builtin::Source(&MZ_FRONTIERS),
1406        Builtin::View(&MZ_GLOBAL_FRONTIERS),
1407        Builtin::Source(&MZ_WALLCLOCK_LAG_HISTORY),
1408        Builtin::View(&MZ_WALLCLOCK_GLOBAL_LAG_HISTORY),
1409        Builtin::View(&MZ_WALLCLOCK_GLOBAL_LAG_RECENT_HISTORY),
1410        Builtin::View(&MZ_WALLCLOCK_GLOBAL_LAG),
1411        Builtin::Source(&MZ_WALLCLOCK_GLOBAL_LAG_HISTOGRAM_RAW),
1412        Builtin::View(&MZ_WALLCLOCK_GLOBAL_LAG_HISTOGRAM),
1413        Builtin::Source(&MZ_MATERIALIZED_VIEW_REFRESHES),
1414        Builtin::Source(&MZ_COMPUTE_DEPENDENCIES),
1415        Builtin::View(&MZ_MATERIALIZATION_DEPENDENCIES),
1416        Builtin::View(&MZ_OBJECT_GRAPH_EDGES),
1417        Builtin::View(&MZ_MATERIALIZATION_LAG),
1418        Builtin::View(&MZ_CONSOLE_CLUSTER_UTILIZATION_OVERVIEW),
1419        Builtin::View(&MZ_CONSOLE_CLUSTER_UTILIZATION_OVERVIEW_3H),
1420        Builtin::View(&MZ_CONSOLE_CLUSTER_UTILIZATION_OVERVIEW_24H),
1421        Builtin::View(&MZ_COMPUTE_ERROR_COUNTS_PER_WORKER),
1422        Builtin::View(&MZ_COMPUTE_ERROR_COUNTS),
1423        Builtin::Source(&MZ_COMPUTE_ERROR_COUNTS_RAW_UNIFIED),
1424        Builtin::Source(&MZ_COMPUTE_HYDRATION_TIMES),
1425        Builtin::Source(&MZ_OBJECT_ARRANGEMENT_SIZES_UNIFIED),
1426        Builtin::Index(&MZ_OBJECT_ARRANGEMENT_SIZES_IND),
1427        Builtin::Table(&MZ_OBJECT_ARRANGEMENT_SIZE_HISTORY),
1428        Builtin::Index(&MZ_OBJECT_ARRANGEMENT_SIZE_HISTORY_OBJECT_IND),
1429        Builtin::Index(&MZ_OBJECT_ARRANGEMENT_SIZE_HISTORY_TS_IND),
1430        Builtin::Log(&MZ_COMPUTE_LIR_MAPPING_PER_WORKER),
1431        Builtin::View(&MZ_LIR_MAPPING),
1432        Builtin::Source(&MZ_COMPUTE_OPERATOR_HYDRATION_STATUSES),
1433        Builtin::Source(&MZ_CLUSTER_REPLICA_FRONTIERS),
1434        Builtin::View(&MZ_COMPUTE_HYDRATION_STATUSES),
1435        Builtin::View(&MZ_HYDRATION_STATUSES),
1436        Builtin::Index(&MZ_HYDRATION_STATUSES_IND),
1437        Builtin::View(&MZ_SHOW_CLUSTER_REPLICAS),
1438        Builtin::View(&MZ_SHOW_NETWORK_POLICIES),
1439        Builtin::View(&MZ_CLUSTER_DEPLOYMENT_LINEAGE),
1440        Builtin::Index(&MZ_SHOW_DATABASES_IND),
1441        Builtin::Index(&MZ_SHOW_SCHEMAS_IND),
1442        Builtin::Index(&MZ_SHOW_CONNECTIONS_IND),
1443        Builtin::Index(&MZ_SHOW_TABLES_IND),
1444        Builtin::Index(&MZ_SHOW_SOURCES_IND),
1445        Builtin::Index(&MZ_SHOW_VIEWS_IND),
1446        Builtin::Index(&MZ_SHOW_MATERIALIZED_VIEWS_IND),
1447        Builtin::Index(&MZ_SHOW_SINKS_IND),
1448        Builtin::Index(&MZ_SHOW_TYPES_IND),
1449        Builtin::Index(&MZ_SHOW_ALL_OBJECTS_IND),
1450        Builtin::Index(&MZ_SHOW_INDEXES_IND),
1451        Builtin::Index(&MZ_SHOW_COLUMNS_IND),
1452        Builtin::Index(&MZ_SHOW_CLUSTERS_IND),
1453        Builtin::Index(&MZ_SHOW_CLUSTER_REPLICAS_IND),
1454        Builtin::Index(&MZ_SHOW_SECRETS_IND),
1455        Builtin::Index(&MZ_SHOW_ROLES_IND),
1456        Builtin::Index(&MZ_CLUSTERS_IND),
1457        Builtin::Index(&MZ_CLUSTER_RECONFIGURATIONS_IND),
1458        Builtin::Index(&MZ_CLUSTER_AUTO_SCALING_STRATEGIES_IND),
1459        Builtin::Index(&MZ_INDEXES_IND),
1460        Builtin::Index(&MZ_ROLES_IND),
1461        Builtin::Index(&MZ_SOURCES_IND),
1462        Builtin::Index(&MZ_SINKS_IND),
1463        Builtin::Index(&MZ_METRIC_SINKS_IND),
1464        Builtin::Index(&MZ_MATERIALIZED_VIEWS_IND),
1465        Builtin::Index(&MZ_SOURCE_STATUSES_IND),
1466        Builtin::Index(&MZ_SOURCE_STATUS_HISTORY_IND),
1467        Builtin::Index(&MZ_SINK_STATUSES_IND),
1468        Builtin::Index(&MZ_SINK_STATUS_HISTORY_IND),
1469        Builtin::Index(&MZ_CLUSTER_REPLICAS_IND),
1470        Builtin::Index(&MZ_CLUSTER_REPLICA_SIZES_IND),
1471        Builtin::Index(&MZ_CLUSTER_REPLICA_SIZE_INTERNAL_IND),
1472        Builtin::Index(&MZ_CLUSTER_REPLICA_STATUSES_IND),
1473        Builtin::Index(&MZ_CLUSTER_REPLICA_STATUS_HISTORY_IND),
1474        Builtin::Index(&MZ_CLUSTER_REPLICA_METRICS_IND),
1475        Builtin::Index(&MZ_CLUSTER_REPLICA_METRICS_HISTORY_IND),
1476        Builtin::Index(&MZ_CLUSTER_REPLICA_HISTORY_IND),
1477        Builtin::Index(&MZ_CLUSTER_REPLICA_NAME_HISTORY_IND),
1478        Builtin::Index(&MZ_OBJECT_LIFETIMES_IND),
1479        Builtin::Index(&MZ_OBJECT_HISTORY_IND),
1480        Builtin::Index(&MZ_OBJECT_DEPENDENCIES_IND),
1481        Builtin::Index(&MZ_COMPUTE_DEPENDENCIES_IND),
1482        Builtin::Index(&MZ_OBJECT_TRANSITIVE_DEPENDENCIES_IND),
1483        Builtin::Index(&MZ_OBJECT_GRAPH_EDGES_IND),
1484        Builtin::Index(&MZ_FRONTIERS_IND),
1485        Builtin::Index(&MZ_WALLCLOCK_GLOBAL_LAG_RECENT_HISTORY_IND),
1486        Builtin::Index(&MZ_KAFKA_SOURCES_IND),
1487        Builtin::Index(&MZ_WEBHOOK_SOURCES_IND),
1488        Builtin::Index(&MZ_COMMENTS_IND),
1489        Builtin::Index(&MZ_DATABASES_IND),
1490        Builtin::Index(&MZ_SCHEMAS_IND),
1491        Builtin::Index(&MZ_CONNECTIONS_IND),
1492        Builtin::Index(&MZ_TABLES_IND),
1493        Builtin::Index(&MZ_TYPES_IND),
1494        Builtin::Index(&MZ_OBJECTS_IND),
1495        Builtin::Index(&MZ_COLUMNS_IND),
1496        Builtin::Index(&MZ_SECRETS_IND),
1497        Builtin::Index(&MZ_VIEWS_IND),
1498        Builtin::Index(&MZ_CONSOLE_CLUSTER_UTILIZATION_OVERVIEW_IND),
1499        Builtin::Index(&MZ_CONSOLE_CLUSTER_UTILIZATION_OVERVIEW_3H_IND),
1500        Builtin::Index(&MZ_CONSOLE_CLUSTER_UTILIZATION_OVERVIEW_24H_IND),
1501        Builtin::Index(&MZ_CLUSTER_DEPLOYMENT_LINEAGE_IND),
1502        Builtin::Index(&MZ_CLUSTER_REPLICA_FRONTIERS_IND),
1503        Builtin::Index(&MZ_COMPUTE_HYDRATION_TIMES_IND),
1504        Builtin::View(&MZ_RECENT_STORAGE_USAGE),
1505        Builtin::Index(&MZ_RECENT_STORAGE_USAGE_IND),
1506        Builtin::Connection(&MZ_ANALYTICS),
1507        Builtin::View(&MZ_INDEX_ADVICE),
1508        Builtin::View(&MZ_MCP_DATA_PRODUCTS),
1509        Builtin::View(&MZ_MCP_DATA_PRODUCT_DETAILS),
1510        Builtin::Table(&MZ_OBJECT_HYDRATION_HISTORY),
1511        Builtin::Table(&MZ_REPLICA_HYDRATION_HISTORY),
1512    ];
1513
1514    builtin_items.extend(notice::builtins());
1515
1516    // Generate mz_sources with builtin source/log entries inlined as VALUES so
1517    // that its SQL fingerprint changes whenever a builtin source is added or
1518    // removed, forcing an explicit MigrationStep::replacement.
1519    //
1520    // Must happen BEFORE ontology::generate_views so that mz_sources's ontology
1521    // annotation (entity_name = "source") is visible to the ontology index views.
1522    // All sources/logs are already present in builtin_items at this point.
1523    {
1524        let source_iter = builtin_items.iter().filter_map(|b| match b {
1525            Builtin::Source(x) => Some(*x),
1526            _ => None,
1527        });
1528        let log_iter = builtin_items.iter().filter_map(|b| match b {
1529            Builtin::Log(x) => Some(*x),
1530            _ => None,
1531        });
1532        let mz_sources = builtin::make_mz_sources(source_iter, log_iter);
1533        let mz_sources_ref: &'static BuiltinMaterializedView = Box::leak(Box::new(mz_sources));
1534        // Insert at the original position of the old static MZ_SOURCES —
1535        // right before mz_source_references — to preserve stable IDs for
1536        // all items that follow it in the list.
1537        let insert_pos = builtin_items
1538            .iter()
1539            .position(|b| matches!(b, Builtin::Table(t) if t.name == "mz_source_references"))
1540            .expect("mz_source_references must be present in builtin_items");
1541        builtin_items.insert(insert_pos, Builtin::MaterializedView(mz_sources_ref));
1542    }
1543
1544    // Generate mz_indexes with builtin index/log entries inlined as VALUES so
1545    // that its SQL fingerprint changes whenever a builtin index or log is added or
1546    // removed, forcing an explicit MigrationStep::replacement.
1547    //
1548    // Must happen AFTER all builtin indexes and logs have been pushed into
1549    // builtin_items, so that make_mz_indexes sees the complete set. Must happen
1550    // BEFORE ontology::generate_views so the ontology generator sees mz_indexes
1551    // as a materialized view participating in catalog ontology, rather than
1552    // being absent from builtin_items.
1553    {
1554        let index_iter = builtin_items.iter().filter_map(|b| match b {
1555            Builtin::Index(x) => Some(*x),
1556            _ => None,
1557        });
1558        let log_iter = builtin_items.iter().filter_map(|b| match b {
1559            Builtin::Log(x) => Some(*x),
1560            _ => None,
1561        });
1562        let mz_indexes = mz_catalog::make_mz_indexes(index_iter, log_iter);
1563        let mz_indexes_ref: &'static BuiltinMaterializedView = Box::leak(Box::new(mz_indexes));
1564        let insert_pos = builtin_items
1565            .iter()
1566            .position(|b| matches!(b, Builtin::Table(t) if t.name == "mz_index_columns"))
1567            .expect("mz_index_columns must be present in builtin_items");
1568        builtin_items.insert(insert_pos, Builtin::MaterializedView(mz_indexes_ref));
1569    }
1570
1571    // Generate mz_object_dependencies_raw, which inlines every builtin's
1572    // dependency edges as VALUES.
1573    //
1574    // It has to run before ontology::generate_views and builtin::builtins, because those consume
1575    // mz_object_dependencies. However, because the views those two generators produce
1576    // have dependency edges of their own, it must use them as inputs. So this block runs both
1577    // generators early, keeps the edges of the views they hand back, and discards the views
1578    // themselves. The real ones are built below.
1579    {
1580        let ontology_preview = ontology::generate_views(&builtin_items);
1581        let builtin_reporter_preview: Vec<_> = builtin::builtins(&builtin_items).collect();
1582        let generator_input: Vec<_> = builtin_types
1583            .iter()
1584            .chain(builtin_funcs.iter())
1585            .chain(builtin_reporter_preview.iter())
1586            .chain(builtin_items.iter())
1587            .chain(ontology_preview.iter())
1588            .cloned()
1589            .collect();
1590        let mz_object_dependencies_raw =
1591            mz_object_dependencies::make_mz_object_dependencies_raw(&generator_input);
1592        let mz_object_dependencies_raw_ref: &'static BuiltinView =
1593            Box::leak(Box::new(mz_object_dependencies_raw));
1594        // The view goes directly before mz_object_dependencies, which reads it,
1595        // because BUILTINS_STATIC must list dependencies before their dependents.
1596        let insert_pos = builtin_items
1597            .iter()
1598            .position(|b| b.name() == "mz_object_dependencies")
1599            .expect("mz_object_dependencies must be present in builtin_items");
1600        builtin_items.insert(insert_pos, Builtin::View(mz_object_dependencies_raw_ref));
1601    }
1602
1603    // Generate ontology views by enumerating existing builtins.
1604    builtin_items.extend(ontology::generate_views(&builtin_items));
1605
1606    // Generate builtin relations reporting builtin objects last, since they need a complete view
1607    // of all other builtins.
1608    let mut builtin_builtins = builtin::builtins(&builtin_items).collect();
1609
1610    // Construct the full list of builtins, retaining dependency order.
1611    let mut builtins = Vec::new();
1612    builtins.append(&mut builtin_types);
1613    builtins.append(&mut builtin_funcs);
1614    builtins.append(&mut builtin_builtins);
1615    builtins.append(&mut builtin_items);
1616
1617    builtins
1618});
1619pub const BUILTIN_ROLES: &[&BuiltinRole] = &[
1620    &MZ_SYSTEM_ROLE,
1621    &MZ_SUPPORT_ROLE,
1622    &MZ_ANALYTICS_ROLE,
1623    &MZ_MONITOR_ROLE,
1624    &MZ_MONITOR_REDACTED,
1625    &MZ_JWT_SYNC_ROLE,
1626];
1627pub const BUILTIN_CLUSTERS: &[&BuiltinCluster] = &[
1628    &MZ_SYSTEM_CLUSTER,
1629    &MZ_CATALOG_SERVER_CLUSTER,
1630    &MZ_PROBE_CLUSTER,
1631    &MZ_SUPPORT_CLUSTER,
1632    &MZ_ANALYTICS_CLUSTER,
1633];
1634
1635#[allow(non_snake_case)]
1636pub mod BUILTINS {
1637    use super::*;
1638
1639    pub fn logs() -> impl Iterator<Item = &'static BuiltinLog> {
1640        BUILTINS_STATIC.iter().filter_map(|b| match b {
1641            Builtin::Log(log) => Some(*log),
1642            _ => None,
1643        })
1644    }
1645
1646    pub fn types() -> impl Iterator<Item = &'static BuiltinType<NameReference>> {
1647        BUILTINS_STATIC.iter().filter_map(|b| match b {
1648            Builtin::Type(typ) => Some(*typ),
1649            _ => None,
1650        })
1651    }
1652
1653    pub fn views() -> impl Iterator<Item = &'static BuiltinView> {
1654        BUILTINS_STATIC.iter().filter_map(|b| match b {
1655            Builtin::View(view) => Some(*view),
1656            _ => None,
1657        })
1658    }
1659
1660    pub fn materialized_views() -> impl Iterator<Item = &'static BuiltinMaterializedView> {
1661        BUILTINS_STATIC.iter().filter_map(|b| match b {
1662            Builtin::MaterializedView(mv) => Some(*mv),
1663            _ => None,
1664        })
1665    }
1666
1667    pub fn funcs() -> impl Iterator<Item = &'static BuiltinFunc> {
1668        BUILTINS_STATIC.iter().filter_map(|b| match b {
1669            Builtin::Func(func) => Some(func),
1670            _ => None,
1671        })
1672    }
1673
1674    pub fn iter() -> impl Iterator<Item = &'static Builtin<NameReference>> {
1675        BUILTINS_STATIC.iter()
1676    }
1677}
1678
1679pub static BUILTIN_LOG_LOOKUP: LazyLock<HashMap<&'static str, &'static BuiltinLog>> =
1680    LazyLock::new(|| BUILTINS::logs().map(|log| (log.name, log)).collect());
1681/// Keys are builtin object description, values are the builtin index when sorted by dependency and
1682/// the builtin itself.
1683pub static BUILTIN_LOOKUP: LazyLock<
1684    HashMap<SystemObjectDescription, (usize, &'static Builtin<NameReference>)>,
1685> = LazyLock::new(|| {
1686    BUILTINS_STATIC
1687        .iter()
1688        .enumerate()
1689        .map(|(idx, builtin)| {
1690            (
1691                SystemObjectDescription {
1692                    schema_name: builtin.schema().to_string(),
1693                    object_type: builtin.catalog_item_type(),
1694                    object_name: builtin.name().to_string(),
1695                },
1696                (idx, builtin),
1697            )
1698        })
1699        .collect()
1700});
1701
1702#[cfg(test)]
1703mod tests {
1704    use std::collections::{BTreeMap, BTreeSet};
1705
1706    use mz_pgrepr::oid::FIRST_MATERIALIZE_OID;
1707    use mz_sql_parser::ast::visit::{self, Visit};
1708    use mz_sql_parser::ast::{Raw, RawItemName, UnresolvedItemName};
1709
1710    use super::*;
1711
1712    /// Recomputes `mz_pgrepr::regproc::NAMES` from the builtin function registry
1713    /// and fails when the checked-in copy has drifted. It is checked in as data
1714    /// because `mz-pgrepr` sits below this crate in the dependency graph and so
1715    /// cannot read the registry itself.
1716    ///
1717    /// Run with `REWRITE=1` to splice the recomputed table back into
1718    /// `src/pgrepr-consts/src/regproc.rs`.
1719    #[mz_ore::test]
1720    #[cfg_attr(miri, ignore)] // unsupported operation: can't call foreign function `rust_psm_stack_pointer` on OS `linux`
1721    fn test_regproc_names_match_builtin_functions() {
1722        // `effective_search_path` unconditionally prepends these two, so a
1723        // uniquely named function in either resolves from its bare name.
1724        const IMPLICITLY_SEARCHED: &[&str] = &[MZ_CATALOG_SCHEMA, PG_CATALOG_SCHEMA];
1725
1726        // A bare name only identifies one OID when exactly one impl anywhere in
1727        // the registry carries it, so count impls across schemas.
1728        let mut impls_per_name: BTreeMap<&str, usize> = BTreeMap::new();
1729        for func in BUILTINS::funcs() {
1730            *impls_per_name.entry(func.name).or_default() += func.inner.func_impls().len();
1731        }
1732
1733        let mut expected: BTreeMap<u32, String> = BTreeMap::new();
1734        for func in BUILTINS::funcs() {
1735            // Mirrors PostgreSQL's `regprocout`, which qualifies a name that
1736            // would not resolve back to this OID on its own.
1737            let rendered =
1738                if impls_per_name[func.name] == 1 && IMPLICITLY_SEARCHED.contains(&func.schema) {
1739                    func.name.to_string()
1740                } else {
1741                    format!("{}.{}", func.schema, func.name)
1742                };
1743            for details in func.inner.func_impls() {
1744                let previous = expected.insert(details.oid, rendered.clone());
1745                assert_eq!(
1746                    previous, None,
1747                    "two builtin functions share OID {}",
1748                    details.oid
1749                );
1750            }
1751        }
1752
1753        let table: String = expected
1754            .iter()
1755            .map(|(oid, name)| format!("    ({}, \"{}\"),\n", oid, name))
1756            .collect();
1757
1758        if std::env::var_os("REWRITE").is_some() {
1759            rewrite_regproc_names(&table);
1760            return;
1761        }
1762
1763        let actual: BTreeMap<u32, String> = mz_pgrepr::regproc::NAMES
1764            .iter()
1765            .map(|(oid, name)| (*oid, name.to_string()))
1766            .collect();
1767
1768        if actual != expected {
1769            panic!(
1770                "mz_pgrepr::regproc::NAMES has drifted from the builtin function \
1771                 registry. Regenerate it with:\n\n    \
1772                 REWRITE=1 cargo test -p mz-catalog \
1773                 test_regproc_names_match_builtin_functions\n"
1774            );
1775        }
1776    }
1777
1778    /// Replaces the generated region of `mz_pgrepr::regproc::NAMES` with
1779    /// `table`, leaving every other byte of the file alone.
1780    ///
1781    /// The path is relative to this crate's directory, which is the working
1782    /// directory `cargo test` runs in.
1783    ///
1784    /// A splice anchored anywhere but the table would clobber the lookup
1785    /// functions below it, so both markers have to appear exactly once.
1786    fn rewrite_regproc_names(table: &str) {
1787        const PATH: &str = "../pgrepr-consts/src/regproc.rs";
1788        const BEGIN: &str = "    // BEGIN GENERATED\n";
1789        const END: &str = "    // END GENERATED\n";
1790
1791        let contents =
1792            std::fs::read_to_string(PATH).unwrap_or_else(|e| panic!("reading '{PATH}': {e}"));
1793        for marker in [BEGIN, END] {
1794            let count = contents.matches(marker).count();
1795            assert_eq!(
1796                count,
1797                1,
1798                "'{}' appears {} times in '{}', expected exactly once",
1799                marker.trim(),
1800                count,
1801                PATH
1802            );
1803        }
1804        let begin = contents.find(BEGIN).expect("checked above") + BEGIN.len();
1805        let end = contents.find(END).expect("checked above");
1806        assert!(
1807            begin <= end,
1808            "'{}' precedes '{}' in '{}'",
1809            END.trim(),
1810            BEGIN.trim(),
1811            PATH
1812        );
1813
1814        let rewritten = format!("{}{}{}", &contents[..begin], table, &contents[end..]);
1815        std::fs::write(PATH, rewritten).unwrap_or_else(|e| panic!("writing '{PATH}': {e}"));
1816    }
1817
1818    #[mz_ore::test]
1819    #[cfg_attr(miri, ignore)] // unsupported operation: can't call foreign function `rust_psm_stack_pointer` on OS `linux`
1820    fn test_builtin_type_schema() {
1821        for typ in BUILTINS::types() {
1822            if typ.oid < FIRST_MATERIALIZE_OID {
1823                assert_eq!(
1824                    typ.schema, PG_CATALOG_SCHEMA,
1825                    "{typ:?} should be in {PG_CATALOG_SCHEMA} schema"
1826                );
1827            } else {
1828                // `mz_pgrepr::Type` resolution relies on all non-PG types existing in the
1829                // mz_catalog schema.
1830                assert_eq!(
1831                    typ.schema, MZ_CATALOG_SCHEMA,
1832                    "{typ:?} should be in {MZ_CATALOG_SCHEMA} schema"
1833                );
1834            }
1835        }
1836    }
1837
1838    /// Visitor that collects the last component of all referenced
1839    /// item names from a SQL AST.
1840    struct ItemNameCollector {
1841        names: BTreeSet<String>,
1842    }
1843
1844    impl<'ast> Visit<'ast, Raw> for ItemNameCollector {
1845        fn visit_item_name(&mut self, name: &'ast <Raw as mz_sql_parser::ast::AstInfo>::ItemName) {
1846            let unresolved: &UnresolvedItemName = match name {
1847                RawItemName::Name(n) | RawItemName::Id(_, n, _) => n,
1848            };
1849            let parts = &unresolved.0;
1850            if !parts.is_empty() {
1851                let obj_name = parts[parts.len() - 1].as_str().to_string();
1852                self.names.insert(obj_name);
1853            }
1854            visit::visit_item_name(self, name);
1855        }
1856    }
1857
1858    /// Tests that `BUILTINS_STATIC` is ordered respecting dependencies:
1859    /// if builtin A references builtin B in its SQL, then B must appear
1860    /// before A in the list. (This ordering is assumed by, e.g.,
1861    /// `sort_updates` during catalog migrations.)
1862    #[mz_ore::test]
1863    #[cfg_attr(miri, ignore)] // unsupported operation: can't call foreign function `rust_psm_stack_pointer` on OS `linux`
1864    fn test_builtins_static_dependency_order() {
1865        // Build a map from name -> (schema, index) for all builtins.
1866        // We look up by just the name (last component) to catch
1867        // unqualified references in SQL.
1868        let mut builtin_by_name: BTreeMap<&str, (&str, usize)> = BTreeMap::new();
1869        let mut duplicate_names = Vec::new();
1870        for (idx, builtin) in BUILTINS_STATIC.iter().enumerate() {
1871            if let Some((prev_schema, prev_idx)) =
1872                builtin_by_name.insert(builtin.name(), (builtin.schema(), idx))
1873            {
1874                // Only flag duplicates across different schemas.
1875                // Same-schema duplicates (e.g., range types that
1876                // appear as both Type and Func) are fine because
1877                // they resolve to the same schema.
1878                if prev_schema != builtin.schema() {
1879                    duplicate_names.push(format!(
1880                        "name {:?} appears in both {}.{} (index \
1881                         {}) and {}.{} (index {})",
1882                        builtin.name(),
1883                        prev_schema,
1884                        builtin.name(),
1885                        prev_idx,
1886                        builtin.schema(),
1887                        builtin.name(),
1888                        idx,
1889                    ));
1890                }
1891            }
1892        }
1893        assert!(
1894            duplicate_names.is_empty(),
1895            "BUILTINS_STATIC has duplicate names across different \
1896             schemas (this test needs adjustment if such duplicates \
1897             are intentional):\n{}",
1898            duplicate_names.join("\n"),
1899        );
1900
1901        // Get the `CREATE ...` SQL for builtins that have it.
1902        let get_create_sql = |builtin: &Builtin<NameReference>| -> Option<String> {
1903            match builtin {
1904                Builtin::View(v) => Some(v.create_sql()),
1905                Builtin::MaterializedView(mv) => Some(mv.create_sql()),
1906                Builtin::Index(idx) => Some(idx.create_sql()),
1907                _ => None,
1908            }
1909        };
1910
1911        // For each SQL-bearing builtin, parse its SQL, walk the AST to
1912        // find referenced item names, and check that all referenced
1913        // builtins appear earlier in BUILTINS_STATIC.
1914        let mut violations = Vec::new();
1915        for (idx, builtin) in BUILTINS_STATIC.iter().enumerate() {
1916            let create_sql = match get_create_sql(builtin) {
1917                Some(sql) => sql,
1918                None => continue,
1919            };
1920
1921            let stmts = mz_sql_parser::parser::parse_statements(&create_sql).unwrap_or_else(|e| {
1922                panic!(
1923                    "failed to parse SQL for {}.{}: \
1924                         {e}\nSQL: {create_sql}",
1925                    builtin.schema(),
1926                    builtin.name(),
1927                )
1928            });
1929
1930            let mut collector = ItemNameCollector {
1931                names: BTreeSet::new(),
1932            };
1933            for stmt in &stmts {
1934                collector.visit_statement(&stmt.ast);
1935            }
1936
1937            for ref_name in &collector.names {
1938                if let Some(&(ref_schema, dep_idx)) = builtin_by_name.get(ref_name.as_str()) {
1939                    if dep_idx > idx {
1940                        violations.push(format!(
1941                            "{}.{} (index {}) references \
1942                             {}.{} (index {}), but the \
1943                             dependency appears later in \
1944                             BUILTINS_STATIC",
1945                            builtin.schema(),
1946                            builtin.name(),
1947                            idx,
1948                            ref_schema,
1949                            ref_name,
1950                            dep_idx,
1951                        ));
1952                    }
1953                }
1954            }
1955        }
1956
1957        assert!(
1958            violations.is_empty(),
1959            "BUILTINS_STATIC has dependency ordering violations:\n{}",
1960            violations.join("\n"),
1961        );
1962    }
1963
1964    /// Validates ontology metadata consistency:
1965    /// - Every link target references an entity that exists.
1966    /// - No duplicate entity names.
1967    /// - Every annotated builtin has a non-empty entity_name and description.
1968    #[mz_ore::test]
1969    #[cfg_attr(miri, ignore)]
1970    fn test_ontology_consistency() {
1971        // Collect all entity names from builtins with ontology annotations.
1972        let mut entity_names: BTreeSet<String> = BTreeSet::new();
1973        let mut duplicate_entities = Vec::new();
1974
1975        for builtin in BUILTINS_STATIC.iter() {
1976            let ontology = match builtin {
1977                Builtin::Table(t) => t.ontology.as_ref(),
1978                Builtin::View(v) => v.ontology.as_ref(),
1979                Builtin::MaterializedView(mv) => mv.ontology.as_ref(),
1980                Builtin::Source(s) => s.ontology.as_ref(),
1981                Builtin::Log(l) => l.ontology.as_ref(),
1982                _ => None,
1983            };
1984            if let Some(ont) = ontology {
1985                assert!(
1986                    !ont.entity_name.is_empty(),
1987                    "builtin {} has empty ontology entity_name",
1988                    builtin.name()
1989                );
1990                assert!(
1991                    !ont.description.is_empty(),
1992                    "builtin {} ({}) has empty ontology description",
1993                    builtin.name(),
1994                    ont.entity_name
1995                );
1996                if !entity_names.insert(ont.entity_name.to_string()) {
1997                    duplicate_entities.push(format!(
1998                        "duplicate entity_name {:?} on builtin {}",
1999                        ont.entity_name,
2000                        builtin.name()
2001                    ));
2002                }
2003            }
2004        }
2005        assert!(
2006            duplicate_entities.is_empty(),
2007            "ontology has duplicate entity names:\n{}",
2008            duplicate_entities.join("\n"),
2009        );
2010
2011        // Validate link targets reference existing entities.
2012        let mut bad_targets = Vec::new();
2013        for builtin in BUILTINS_STATIC.iter() {
2014            let ontology = match builtin {
2015                Builtin::Table(t) => t.ontology.as_ref(),
2016                Builtin::View(v) => v.ontology.as_ref(),
2017                Builtin::MaterializedView(mv) => mv.ontology.as_ref(),
2018                Builtin::Source(s) => s.ontology.as_ref(),
2019                Builtin::Log(l) => l.ontology.as_ref(),
2020                _ => None,
2021            };
2022            if let Some(ont) = ontology {
2023                for link in ont.links {
2024                    if !entity_names.contains(link.target) {
2025                        bad_targets.push(format!(
2026                            "entity {:?} link {:?} targets {:?} which is not a known entity",
2027                            ont.entity_name, link.name, link.target
2028                        ));
2029                    }
2030                }
2031            }
2032        }
2033        assert!(
2034            bad_targets.is_empty(),
2035            "ontology has links targeting unknown entities:\n{}",
2036            bad_targets.join("\n"),
2037        );
2038
2039        // Semantic type annotations are typed (SemanticType enum), so validity
2040        // is guaranteed at compile time — no runtime check needed.
2041
2042        // Validate that every "reference" column (one whose semantic type implies
2043        // a FK relationship) is covered by an OntologyLink on entities that
2044        // already have at least one FK-style link.
2045        //
2046        // Scope: only entities that have started FK annotation (at least one
2047        // link with a source_column). Entities with only union/maps_to links,
2048        // or no links at all, are not yet fully annotated and are skipped to
2049        // avoid noise.
2050        //
2051        // Exemptions:
2052        // - Column at index 0 named "id": almost always the entity's own PK, not a FK (e.g.
2053        //   mz_objects.id, mz_functions.id).
2054        // - Columns in the relation's declared key set.
2055        //
2056        // "Reference" types are ID types that imply a FK. Discriminators
2057        // (ObjectType, ConnectionType, SourceType), OID, and metric types
2058        // (ByteCount, etc.) are excluded.
2059        let reference_sem_types: BTreeSet<SemanticType> = BTreeSet::from([
2060            SemanticType::CatalogItemId,
2061            SemanticType::GlobalId,
2062            SemanticType::ClusterId,
2063            SemanticType::ReplicaId,
2064            SemanticType::SchemaId,
2065            SemanticType::DatabaseId,
2066            SemanticType::RoleId,
2067            SemanticType::NetworkPolicyId,
2068        ]);
2069
2070        let mut uncovered_fk_cols = Vec::new();
2071        for builtin in BUILTINS_STATIC.iter() {
2072            let desc_storage;
2073            let (name, desc, ontology): (&str, &RelationDesc, Option<&Ontology>) = match builtin {
2074                Builtin::Table(t) => (t.name, &t.desc, t.ontology.as_ref()),
2075                Builtin::View(v) => (v.name, &v.desc, v.ontology.as_ref()),
2076                Builtin::MaterializedView(mv) => (mv.name, &mv.desc, mv.ontology.as_ref()),
2077                Builtin::Source(s) => (s.name, &s.desc, s.ontology.as_ref()),
2078                Builtin::Log(l) => {
2079                    desc_storage = l.variant.desc();
2080                    (l.name, &desc_storage, l.ontology.as_ref())
2081                }
2082                _ => continue,
2083            };
2084            let Some(ont) = ontology else { continue };
2085
2086            // Collect all source_column values declared by existing links.
2087            let linked_cols: BTreeSet<&str> = ont
2088                .links
2089                .iter()
2090                .filter_map(|link| match &link.properties {
2091                    LinkProperties::ForeignKey { source_column, .. } => Some(*source_column),
2092                    LinkProperties::Measures { source_column, .. } => Some(*source_column),
2093                    LinkProperties::DependsOn { source_column, .. } => Some(*source_column),
2094                    LinkProperties::MapsTo { source_column, .. } => Some(*source_column),
2095                    LinkProperties::Union { .. } => None,
2096                })
2097                .collect();
2098
2099            // Skip entities that have no FK-style links yet — they are either
2100            // unannotated or use only union/maps_to links. Only enforce
2101            // coverage on entities that have started FK annotation.
2102            if linked_cols.is_empty() {
2103                continue;
2104            }
2105
2106            // Column indices that are part of the declared key set.
2107            let pk_indices: BTreeSet<usize> = desc.typ().keys.iter().flatten().copied().collect();
2108
2109            for (col_name, sem) in ont.column_semantic_types {
2110                if !reference_sem_types.contains(sem) {
2111                    continue;
2112                }
2113                let Some(idx) = desc.iter_names().position(|n| n.as_str() == *col_name) else {
2114                    continue;
2115                };
2116                // Exempt the entity's own primary identifier: column 0 named
2117                // "id" is by convention the entity's own PK (not a FK), even
2118                // when no explicit with_key() is declared on the relation.
2119                if idx == 0 && *col_name == "id" {
2120                    continue;
2121                }
2122                if pk_indices.contains(&idx) {
2123                    continue;
2124                }
2125                if linked_cols.contains(*col_name) {
2126                    continue;
2127                }
2128                uncovered_fk_cols.push(format!(
2129                    "entity {:?} (builtin {}) column {:?} has semantic type {:?} but no OntologyLink covers it (add a link with source_column: {:?})",
2130                    ont.entity_name, name, col_name, sem, col_name
2131                ));
2132            }
2133        }
2134        assert!(
2135            uncovered_fk_cols.is_empty(),
2136            "ontology entities have FK-typed columns with no OntologyLink:\n{}",
2137            uncovered_fk_cols.join("\n"),
2138        );
2139
2140        // Validate that every source_column in a link actually names a column
2141        // in the entity's RelationDesc. This catches stale annotations after
2142        // column renames or removals. With typed LinkProperties this is mostly
2143        // belt-and-suspenders since the type system enforces field presence, but
2144        // we still need to verify the string value matches a real column.
2145        let mut bad_source_cols = Vec::new();
2146        for builtin in BUILTINS_STATIC.iter() {
2147            let desc_storage;
2148            let (name, desc, ontology): (&str, &RelationDesc, Option<&Ontology>) = match builtin {
2149                Builtin::Table(t) => (t.name, &t.desc, t.ontology.as_ref()),
2150                Builtin::View(v) => (v.name, &v.desc, v.ontology.as_ref()),
2151                Builtin::MaterializedView(mv) => (mv.name, &mv.desc, mv.ontology.as_ref()),
2152                Builtin::Source(s) => (s.name, &s.desc, s.ontology.as_ref()),
2153                Builtin::Log(l) => {
2154                    desc_storage = l.variant.desc();
2155                    (l.name, &desc_storage, l.ontology.as_ref())
2156                }
2157                _ => continue,
2158            };
2159            let Some(ont) = ontology else { continue };
2160
2161            let col_names: BTreeSet<&str> = desc.iter_names().map(|c| c.as_str()).collect();
2162
2163            for link in ont.links {
2164                let source_col = match &link.properties {
2165                    LinkProperties::ForeignKey { source_column, .. } => Some(*source_column),
2166                    LinkProperties::Measures { source_column, .. } => Some(*source_column),
2167                    LinkProperties::DependsOn { source_column, .. } => Some(*source_column),
2168                    LinkProperties::MapsTo { source_column, .. } => Some(*source_column),
2169                    LinkProperties::Union { .. } => None,
2170                };
2171                let Some(col) = source_col else { continue };
2172                if !col_names.contains(col) {
2173                    bad_source_cols.push(format!(
2174                        "entity {:?} (builtin {}) link {:?} references source_column {:?} which does not exist in the relation",
2175                        ont.entity_name, name, link.name, col
2176                    ));
2177                }
2178                let extra_key_columns = match &link.properties {
2179                    LinkProperties::ForeignKey {
2180                        extra_key_columns: Some(extras),
2181                        ..
2182                    } => Some(*extras),
2183                    LinkProperties::Measures {
2184                        extra_key_columns: Some(extras),
2185                        ..
2186                    } => Some(*extras),
2187                    _ => None,
2188                };
2189                if let Some(extras) = extra_key_columns {
2190                    for (src_col, _) in extras {
2191                        if !col_names.contains(*src_col) {
2192                            bad_source_cols.push(format!(
2193                                "entity {:?} (builtin {}) link {:?} extra_key_columns references {:?} which does not exist in the relation",
2194                                ont.entity_name, name, link.name, src_col
2195                            ));
2196                        }
2197                    }
2198                }
2199            }
2200        }
2201        assert!(
2202            bad_source_cols.is_empty(),
2203            "ontology links reference non-existent source_columns:\n{}",
2204            bad_source_cols.join("\n"),
2205        );
2206
2207        // Sanity check: we have a reasonable number of annotated entities.
2208        assert!(
2209            entity_names.len() > 120,
2210            "expected > 120 ontology entities, found {}",
2211            entity_names.len()
2212        );
2213    }
2214
2215    /// Verify that `LinkProperties` serializes to the same JSON that the old
2216    /// hand-written `properties_json` strings contained. One representative
2217    /// case per constructor/variant is enough — the important thing is that
2218    /// field names, enum tag values, and skip-if-None/false behaviour are all
2219    /// correct.
2220    #[mz_ore::test]
2221    fn test_link_properties_serialization() {
2222        let check = |props: LinkProperties, expected: &str| {
2223            let got = serde_json::to_string(&props).expect("serialize");
2224            let got_val: serde_json::Value = serde_json::from_str(&got).expect("parse got");
2225            let exp_val: serde_json::Value =
2226                serde_json::from_str(expected).expect("parse expected");
2227            assert_eq!(got_val, exp_val, "mismatch for {expected}");
2228        };
2229
2230        // fk — basic, no optional fields
2231        check(
2232            LinkProperties::fk("owner_id", "id", Cardinality::ManyToOne),
2233            r#"{"kind":"foreign_key","source_column":"owner_id","target_column":"id","cardinality":"many_to_one"}"#,
2234        );
2235        // fk_composite — extra_key_columns present
2236        check(
2237            LinkProperties::fk_composite(
2238                "operator_id",
2239                "id",
2240                Cardinality::ManyToOne,
2241                &[("worker_id", "worker_id")],
2242            ),
2243            r#"{"kind":"foreign_key","source_column":"operator_id","target_column":"id","cardinality":"many_to_one","extra_key_columns":[["worker_id","worker_id"]]}"#,
2244        );
2245        // fk — one_to_one cardinality
2246        check(
2247            LinkProperties::fk("id", "id", Cardinality::OneToOne),
2248            r#"{"kind":"foreign_key","source_column":"id","target_column":"id","cardinality":"one_to_one"}"#,
2249        );
2250        // fk_nullable — nullable field present and true
2251        check(
2252            LinkProperties::fk_nullable("database_id", "id", Cardinality::ManyToOne),
2253            r#"{"kind":"foreign_key","source_column":"database_id","target_column":"id","cardinality":"many_to_one","nullable":true}"#,
2254        );
2255        // fk_typed — source_id_type present, requires_mapping absent
2256        check(
2257            LinkProperties::fk_typed(
2258                "replica_id",
2259                "id",
2260                Cardinality::ManyToOne,
2261                mz_repr::SemanticType::CatalogItemId,
2262            ),
2263            r#"{"kind":"foreign_key","source_column":"replica_id","target_column":"id","cardinality":"many_to_one","source_id_type":"CatalogItemId"}"#,
2264        );
2265        // fk_mapped — source_id_type + requires_mapping both present
2266        check(
2267            LinkProperties::fk_mapped(
2268                "object_id",
2269                "id",
2270                Cardinality::ManyToOne,
2271                mz_repr::SemanticType::GlobalId,
2272                "mz_internal.mz_object_global_ids",
2273            ),
2274            r#"{"kind":"foreign_key","source_column":"object_id","target_column":"id","cardinality":"many_to_one","source_id_type":"GlobalId","requires_mapping":"mz_internal.mz_object_global_ids"}"#,
2275        );
2276        // union_disc — discriminator fields present, note absent
2277        check(
2278            LinkProperties::union_disc("type", "table"),
2279            r#"{"kind":"union","discriminator_column":"type","discriminator_value":"table"}"#,
2280        );
2281        // Union — note only, discriminator absent
2282        check(
2283            LinkProperties::Union {
2284                discriminator_column: None,
2285                discriminator_value: None,
2286                note: Some("example note"),
2287            },
2288            r#"{"kind":"union","note":"example note"}"#,
2289        );
2290        // measures — basic
2291        check(
2292            LinkProperties::measures("id", "id", "cpu_time_ns"),
2293            r#"{"kind":"measures","source_column":"id","target_column":"id","metric":"cpu_time_ns"}"#,
2294        );
2295        // measures_composite — extra_key_columns present
2296        check(
2297            LinkProperties::measures_composite(
2298                "export_id",
2299                "export_id",
2300                "time_ns",
2301                &[("worker_id", "worker_id")],
2302            ),
2303            r#"{"kind":"measures","source_column":"export_id","target_column":"export_id","metric":"time_ns","extra_key_columns":[["worker_id","worker_id"]]}"#,
2304        );
2305        // measures_mapped — source_id_type + requires_mapping present
2306        check(
2307            LinkProperties::measures_mapped(
2308                "object_id",
2309                "id",
2310                "wallclock_lag",
2311                mz_repr::SemanticType::GlobalId,
2312                "mz_internal.mz_object_global_ids",
2313            ),
2314            r#"{"kind":"measures","source_column":"object_id","target_column":"id","metric":"wallclock_lag","source_id_type":"GlobalId","requires_mapping":"mz_internal.mz_object_global_ids"}"#,
2315        );
2316        // DependsOn — with mapping
2317        check(
2318            LinkProperties::DependsOn {
2319                source_column: "object_id",
2320                target_column: "id",
2321                source_id_type: Some(mz_repr::SemanticType::GlobalId),
2322                requires_mapping: Some("mz_internal.mz_object_global_ids"),
2323            },
2324            r#"{"kind":"depends_on","source_column":"object_id","target_column":"id","source_id_type":"GlobalId","requires_mapping":"mz_internal.mz_object_global_ids"}"#,
2325        );
2326        // DependsOn — direct (CatalogItemId, no mapping)
2327        check(
2328            LinkProperties::DependsOn {
2329                source_column: "object_id",
2330                target_column: "id",
2331                source_id_type: Some(mz_repr::SemanticType::CatalogItemId),
2332                requires_mapping: None,
2333            },
2334            r#"{"kind":"depends_on","source_column":"object_id","target_column":"id","source_id_type":"CatalogItemId"}"#,
2335        );
2336        // MapsTo — via + from_type + to_type
2337        check(
2338            LinkProperties::MapsTo {
2339                source_column: "id",
2340                target_column: "global_id",
2341                via: Some("mz_internal.mz_object_global_ids"),
2342                from_type: Some(mz_repr::SemanticType::CatalogItemId),
2343                to_type: Some(mz_repr::SemanticType::GlobalId),
2344                note: None,
2345            },
2346            r#"{"kind":"maps_to","source_column":"id","target_column":"global_id","via":"mz_internal.mz_object_global_ids","from_type":"CatalogItemId","to_type":"GlobalId"}"#,
2347        );
2348    }
2349
2350    /// Verifies that the `mz_sources` materialized view fingerprint changes
2351    /// whenever a new builtin source or log is added.
2352    ///
2353    /// This is the correctness property that `make_mz_sources` provides: by
2354    /// inlining the full set of builtin sources/logs as VALUES in its SQL, any
2355    /// change to those sets is reflected in `fingerprint()`. A stale fingerprint
2356    /// would prevent the catalog migration from replacing `mz_sources`, leaving
2357    /// it with out-of-date data, silently serving stale builtin source rows.
2358    #[mz_ore::test]
2359    #[cfg_attr(miri, ignore)]
2360    fn test_mz_sources_fingerprint_changes_with_new_builtin_source() {
2361        let sources: Vec<&'static BuiltinSource> = BUILTINS_STATIC
2362            .iter()
2363            .filter_map(|b| match b {
2364                Builtin::Source(x) => Some(*x),
2365                _ => None,
2366            })
2367            .collect();
2368        let logs: Vec<&'static BuiltinLog> = BUILTINS_STATIC
2369            .iter()
2370            .filter_map(|b| match b {
2371                Builtin::Log(x) => Some(*x),
2372                _ => None,
2373            })
2374            .collect();
2375
2376        // The fingerprint from make_mz_sources must match the live BUILTINS_STATIC entry.
2377        let mv_base = builtin::make_mz_sources(sources.iter().copied(), logs.iter().copied());
2378        let fp_base = Fingerprint::fingerprint(&&mv_base);
2379
2380        let mz_sources_static = BUILTINS_STATIC
2381            .iter()
2382            .find_map(|b| match b {
2383                Builtin::MaterializedView(mv) if mv.name == "mz_sources" => Some(*mv),
2384                _ => None,
2385            })
2386            .expect("mz_sources must be present in BUILTINS_STATIC");
2387        assert_eq!(
2388            fp_base,
2389            Fingerprint::fingerprint(&mz_sources_static),
2390            "make_mz_sources fingerprint must match the BUILTINS_STATIC mz_sources fingerprint"
2391        );
2392
2393        // Adding an extra source must change the fingerprint, proving that
2394        // make_mz_sources inlines the source list into its SQL.
2395        let extra_source = sources[0];
2396        let mv_extra = builtin::make_mz_sources(
2397            sources.iter().copied().chain(std::iter::once(extra_source)),
2398            logs.iter().copied(),
2399        );
2400        assert_ne!(
2401            fp_base,
2402            Fingerprint::fingerprint(&&mv_extra),
2403            "mz_sources fingerprint must change when a builtin source is added"
2404        );
2405    }
2406
2407    /// Verifies that the `mz_indexes` materialized view fingerprint changes
2408    /// whenever a new builtin index or log is added.
2409    ///
2410    /// This is the correctness property that `make_mz_indexes` provides: by
2411    /// inlining the full set of builtin indexes/logs as VALUES in its SQL,
2412    /// any change to those sets is reflected in `fingerprint()`. A stale
2413    /// fingerprint would prevent the catalog migration from replacing
2414    /// `mz_indexes`, leaving it with out-of-date data, silently serving
2415    /// stale builtin index rows.
2416    #[mz_ore::test]
2417    #[cfg_attr(miri, ignore)]
2418    fn test_mz_indexes_fingerprint_changes_with_new_builtin_index() {
2419        let indexes: Vec<&'static BuiltinIndex> = BUILTINS_STATIC
2420            .iter()
2421            .filter_map(|b| match b {
2422                Builtin::Index(x) => Some(*x),
2423                _ => None,
2424            })
2425            .collect();
2426        let logs: Vec<&'static BuiltinLog> = BUILTINS_STATIC
2427            .iter()
2428            .filter_map(|b| match b {
2429                Builtin::Log(x) => Some(*x),
2430                _ => None,
2431            })
2432            .collect();
2433
2434        // The fingerprint from make_mz_indexes must match the live BUILTINS_STATIC entry.
2435        let mv_base = mz_catalog::make_mz_indexes(indexes.iter().copied(), logs.iter().copied());
2436        let fp_base = Fingerprint::fingerprint(&&mv_base);
2437
2438        let mz_indexes_static = BUILTINS_STATIC
2439            .iter()
2440            .find_map(|b| match b {
2441                Builtin::MaterializedView(mv) if mv.name == "mz_indexes" => Some(*mv),
2442                _ => None,
2443            })
2444            .expect("mz_indexes must be present in BUILTINS_STATIC");
2445        assert_eq!(
2446            fp_base,
2447            Fingerprint::fingerprint(&mz_indexes_static),
2448            "make_mz_indexes fingerprint must match the BUILTINS_STATIC mz_indexes fingerprint"
2449        );
2450
2451        // Adding an extra index must change the fingerprint, proving that
2452        // make_mz_indexes inlines the index list into its SQL.
2453        let extra_index = indexes[0];
2454        let mv_extra_index = mz_catalog::make_mz_indexes(
2455            indexes.iter().copied().chain(std::iter::once(extra_index)),
2456            logs.iter().copied(),
2457        );
2458        assert_ne!(
2459            fp_base,
2460            Fingerprint::fingerprint(&&mv_extra_index),
2461            "mz_indexes fingerprint must change when a builtin index is added"
2462        );
2463
2464        // Adding an extra log must also change the fingerprint, because the
2465        // log set feeds the introspection-source-indexes CTE.
2466        let extra_log = logs[0];
2467        let mv_extra_log = mz_catalog::make_mz_indexes(
2468            indexes.iter().copied(),
2469            logs.iter().copied().chain(std::iter::once(extra_log)),
2470        );
2471        assert_ne!(
2472            fp_base,
2473            Fingerprint::fingerprint(&&mv_extra_log),
2474            "mz_indexes fingerprint must change when a builtin log is added"
2475        );
2476    }
2477
2478    /// Because `mz_object_dependencies_raw`` is built from prior copies of the ontology and builtin
2479    /// reporter views to get their edges since they must be built afterwards. Thus we test
2480    /// that regenerating the view using all builtins (excluding itself) equals the SQL of the real
2481    /// view.
2482    #[mz_ore::test]
2483    #[cfg_attr(miri, ignore)] // slow: parses every builtin's SQL twice
2484    fn test_mz_object_dependencies_raw_sql_is_stable() {
2485        let without_self: Vec<Builtin<NameReference>> = BUILTINS_STATIC
2486            .iter()
2487            .filter(|b| {
2488                !matches!(b, Builtin::View(v) if v.name == mz_object_dependencies::MZ_OBJECT_DEPENDENCIES_RAW)
2489            })
2490            .cloned()
2491            .collect();
2492
2493        let regenerated = mz_object_dependencies::make_mz_object_dependencies_raw(&without_self);
2494
2495        let from_static = BUILTINS_STATIC
2496            .iter()
2497            .find_map(|b| match b {
2498                Builtin::View(v)
2499                    if v.name == mz_object_dependencies::MZ_OBJECT_DEPENDENCIES_RAW =>
2500                {
2501                    Some(*v)
2502                }
2503                _ => None,
2504            })
2505            .expect("mz_object_dependencies_raw must be present in BUILTINS_STATIC");
2506
2507        assert_eq!(
2508            regenerated.sql, from_static.sql,
2509            "regenerating mz_object_dependencies_raw from the final builtin \
2510             list must reproduce the SQL generated during static init"
2511        );
2512    }
2513}