Skip to main content

mz_catalog/builtin/
mz_catalog.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 for the `mz_catalog` schema.
11
12use std::collections::BTreeMap;
13use std::sync::LazyLock;
14
15use mz_pgrepr::oid;
16use mz_repr::namespaces::MZ_CATALOG_SCHEMA;
17use mz_repr::{RelationDesc, SemanticType, SqlScalarType};
18use mz_sql::catalog::{
19    CatalogType, CatalogTypeDetails, CatalogTypePgMetadata, NameReference, ObjectType,
20};
21use mz_sql::rbac;
22use mz_sql::session::user::{MZ_SYSTEM_ROLE_ID, SUPPORT_USER_NAME, SYSTEM_USER_NAME};
23use mz_storage_client::controller::IntrospectionType;
24
25use super::{
26    BuiltinIndex, BuiltinMaterializedView, BuiltinSource, BuiltinTable, BuiltinType, BuiltinView,
27    Cardinality, LinkProperties, Ontology, OntologyLink, PUBLIC_SELECT,
28};
29
30pub const TYPE_LIST: BuiltinType<NameReference> = BuiltinType {
31    name: "list",
32    schema: MZ_CATALOG_SCHEMA,
33    oid: mz_pgrepr::oid::TYPE_LIST_OID,
34    details: CatalogTypeDetails {
35        typ: CatalogType::Pseudo,
36        array_id: None,
37        pg_metadata: None,
38    },
39};
40
41pub const TYPE_MAP: BuiltinType<NameReference> = BuiltinType {
42    name: "map",
43    schema: MZ_CATALOG_SCHEMA,
44    oid: mz_pgrepr::oid::TYPE_MAP_OID,
45    details: CatalogTypeDetails {
46        typ: CatalogType::Pseudo,
47        array_id: None,
48        pg_metadata: None,
49    },
50};
51
52pub const TYPE_ANYCOMPATIBLELIST: BuiltinType<NameReference> = BuiltinType {
53    name: "anycompatiblelist",
54    schema: MZ_CATALOG_SCHEMA,
55    oid: mz_pgrepr::oid::TYPE_ANYCOMPATIBLELIST_OID,
56    details: CatalogTypeDetails {
57        typ: CatalogType::Pseudo,
58        array_id: None,
59        pg_metadata: None,
60    },
61};
62
63pub const TYPE_ANYCOMPATIBLEMAP: BuiltinType<NameReference> = BuiltinType {
64    name: "anycompatiblemap",
65    schema: MZ_CATALOG_SCHEMA,
66    oid: mz_pgrepr::oid::TYPE_ANYCOMPATIBLEMAP_OID,
67    details: CatalogTypeDetails {
68        typ: CatalogType::Pseudo,
69        array_id: None,
70        pg_metadata: None,
71    },
72};
73
74pub const TYPE_UINT2: BuiltinType<NameReference> = BuiltinType {
75    name: "uint2",
76    schema: MZ_CATALOG_SCHEMA,
77    oid: mz_pgrepr::oid::TYPE_UINT2_OID,
78    details: CatalogTypeDetails {
79        typ: CatalogType::UInt16,
80        array_id: None,
81        pg_metadata: None,
82    },
83};
84
85pub const TYPE_UINT2_ARRAY: BuiltinType<NameReference> = BuiltinType {
86    name: "_uint2",
87    schema: MZ_CATALOG_SCHEMA,
88    oid: mz_pgrepr::oid::TYPE_UINT2_ARRAY_OID,
89    details: CatalogTypeDetails {
90        typ: CatalogType::Array {
91            element_reference: TYPE_UINT2.name,
92        },
93        array_id: None,
94        pg_metadata: None,
95    },
96};
97
98pub const TYPE_UINT4: BuiltinType<NameReference> = BuiltinType {
99    name: "uint4",
100    schema: MZ_CATALOG_SCHEMA,
101    oid: mz_pgrepr::oid::TYPE_UINT4_OID,
102    details: CatalogTypeDetails {
103        typ: CatalogType::UInt32,
104        array_id: None,
105        pg_metadata: None,
106    },
107};
108
109pub const TYPE_UINT4_ARRAY: BuiltinType<NameReference> = BuiltinType {
110    name: "_uint4",
111    schema: MZ_CATALOG_SCHEMA,
112    oid: mz_pgrepr::oid::TYPE_UINT4_ARRAY_OID,
113    details: CatalogTypeDetails {
114        typ: CatalogType::Array {
115            element_reference: TYPE_UINT4.name,
116        },
117        array_id: None,
118        pg_metadata: None,
119    },
120};
121
122pub const TYPE_UINT8: BuiltinType<NameReference> = BuiltinType {
123    name: "uint8",
124    schema: MZ_CATALOG_SCHEMA,
125    oid: mz_pgrepr::oid::TYPE_UINT8_OID,
126    details: CatalogTypeDetails {
127        typ: CatalogType::UInt64,
128        array_id: None,
129        pg_metadata: None,
130    },
131};
132
133pub const TYPE_UINT8_ARRAY: BuiltinType<NameReference> = BuiltinType {
134    name: "_uint8",
135    schema: MZ_CATALOG_SCHEMA,
136    oid: mz_pgrepr::oid::TYPE_UINT8_ARRAY_OID,
137    details: CatalogTypeDetails {
138        typ: CatalogType::Array {
139            element_reference: TYPE_UINT8.name,
140        },
141        array_id: None,
142        pg_metadata: None,
143    },
144};
145
146pub const TYPE_MZ_TIMESTAMP: BuiltinType<NameReference> = BuiltinType {
147    name: "mz_timestamp",
148    schema: MZ_CATALOG_SCHEMA,
149    oid: mz_pgrepr::oid::TYPE_MZ_TIMESTAMP_OID,
150    details: CatalogTypeDetails {
151        typ: CatalogType::MzTimestamp,
152        array_id: None,
153        pg_metadata: None,
154    },
155};
156
157pub const TYPE_MZ_TIMESTAMP_ARRAY: BuiltinType<NameReference> = BuiltinType {
158    name: "_mz_timestamp",
159    schema: MZ_CATALOG_SCHEMA,
160    oid: mz_pgrepr::oid::TYPE_MZ_TIMESTAMP_ARRAY_OID,
161    details: CatalogTypeDetails {
162        typ: CatalogType::Array {
163            element_reference: TYPE_MZ_TIMESTAMP.name,
164        },
165        array_id: None,
166        pg_metadata: None,
167    },
168};
169
170pub const TYPE_MZ_ACL_ITEM: BuiltinType<NameReference> = BuiltinType {
171    name: "mz_aclitem",
172    schema: MZ_CATALOG_SCHEMA,
173    oid: mz_pgrepr::oid::TYPE_MZ_ACL_ITEM_OID,
174    details: CatalogTypeDetails {
175        typ: CatalogType::MzAclItem,
176        array_id: None,
177        pg_metadata: None,
178    },
179};
180
181pub const TYPE_MZ_ACL_ITEM_ARRAY: BuiltinType<NameReference> = BuiltinType {
182    name: "_mz_aclitem",
183    schema: MZ_CATALOG_SCHEMA,
184    oid: mz_pgrepr::oid::TYPE_MZ_ACL_ITEM_ARRAY_OID,
185    details: CatalogTypeDetails {
186        typ: CatalogType::Array {
187            element_reference: TYPE_MZ_ACL_ITEM.name,
188        },
189        array_id: None,
190        pg_metadata: Some(CatalogTypePgMetadata {
191            typinput_oid: 750,
192            typreceive_oid: 2400,
193            typsend_oid: 2401,
194        }),
195    },
196};
197
198pub static MZ_ICEBERG_SINKS: LazyLock<BuiltinMaterializedView> = LazyLock::new(|| {
199    BuiltinMaterializedView {
200        name: "mz_iceberg_sinks",
201        schema: MZ_CATALOG_SCHEMA,
202        oid: oid::MV_MZ_ICEBERG_SINKS_OID,
203        desc: RelationDesc::builder()
204            .with_column("id", SqlScalarType::String.nullable(false))
205            .with_column("namespace", SqlScalarType::String.nullable(false))
206            .with_column("table", SqlScalarType::String.nullable(false))
207            .finish(),
208        column_comments: BTreeMap::from_iter([
209            ("id", "The ID of the sink."),
210            (
211                "namespace",
212                "The namespace of the Iceberg table into which the sink is writing.",
213            ),
214            ("table", "The Iceberg table into which the sink is writing."),
215        ]),
216        // Planning requires `NAMESPACE` and `TABLE`, so both are always there.
217        sql: "
218IN CLUSTER mz_catalog_server
219WITH (
220    ASSERT NOT NULL id,
221    ASSERT NOT NULL namespace,
222    ASSERT NOT NULL \"table\"
223) AS
224SELECT
225    mz_internal.parse_catalog_id(data->'key'->'gid') AS id,
226    parsed->>'namespace' AS namespace,
227    parsed->>'table' AS \"table\"
228FROM
229    mz_internal.mz_catalog_raw
230    CROSS JOIN LATERAL (
231        SELECT mz_internal.parse_catalog_create_sql(data->'value'->'definition'->'V1'->>'create_sql')
232    ) AS l(parsed)
233WHERE
234    data->>'kind' = 'Item' AND
235    parsed->>'sink_type' = 'iceberg'",
236        is_retained_metrics_object: false,
237        access: vec![PUBLIC_SELECT],
238        ontology: Some(Ontology {
239            entity_name: "iceberg_sink",
240            description: "Iceberg-specific sink configuration (namespace, table)",
241            links: &const {
242                [OntologyLink {
243                    name: "details_of",
244                    target: "sink",
245                    properties: LinkProperties::fk("id", "id", Cardinality::OneToOne),
246                }]
247            },
248            column_semantic_types: &[("id", SemanticType::CatalogItemId)],
249        }),
250    }
251});
252
253pub static MZ_KAFKA_SINKS: LazyLock<BuiltinMaterializedView> = LazyLock::new(|| {
254    BuiltinMaterializedView {
255        name: "mz_kafka_sinks",
256        schema: MZ_CATALOG_SCHEMA,
257        oid: oid::MV_MZ_KAFKA_SINKS_OID,
258        desc: RelationDesc::builder()
259            .with_column("id", SqlScalarType::String.nullable(false))
260            .with_column("topic", SqlScalarType::String.nullable(false))
261            .with_key(vec![0])
262            .finish(),
263        column_comments: BTreeMap::from_iter([
264            ("id", "The ID of the sink."),
265            (
266                "topic",
267                "The name of the Kafka topic into which the sink is writing.",
268            ),
269        ]),
270        // Planning requires `TOPIC`, so it is always there.
271        sql: "
272IN CLUSTER mz_catalog_server
273WITH (
274    ASSERT NOT NULL id,
275    ASSERT NOT NULL topic
276) AS
277SELECT
278    mz_internal.parse_catalog_id(data->'key'->'gid') AS id,
279    parsed->>'topic' AS topic
280FROM
281    mz_internal.mz_catalog_raw
282    CROSS JOIN LATERAL (
283        SELECT mz_internal.parse_catalog_create_sql(data->'value'->'definition'->'V1'->>'create_sql')
284    ) AS l(parsed)
285WHERE
286    data->>'kind' = 'Item' AND
287    parsed->>'sink_type' = 'kafka'",
288        is_retained_metrics_object: false,
289        access: vec![PUBLIC_SELECT],
290        ontology: Some(Ontology {
291            entity_name: "kafka_sink",
292            description: "Kafka-specific sink configuration (topic)",
293            links: &const {
294                [OntologyLink {
295                    name: "details_of",
296                    target: "sink",
297                    properties: LinkProperties::fk("id", "id", Cardinality::OneToOne),
298                }]
299            },
300            column_semantic_types: &[("id", SemanticType::CatalogItemId)],
301        }),
302    }
303});
304// Reads Item rows from `mz_catalog_raw`, pulls the broker addresses and any
305// explicit progress topic out of the persisted `create_sql` via
306// `parse_connection_details`, and keeps only kafka connections (the connection
307// type is derived the same way `mz_connections` derives it). The default
308// progress topic is reconstructed here rather than in the helper because it
309// needs the environment id and the connection's own id.
310pub static MZ_KAFKA_CONNECTIONS: LazyLock<BuiltinMaterializedView> = LazyLock::new(|| {
311    BuiltinMaterializedView {
312        name: "mz_kafka_connections",
313        schema: MZ_CATALOG_SCHEMA,
314        oid: oid::MV_MZ_KAFKA_CONNECTIONS_OID,
315        desc: RelationDesc::builder()
316            .with_column("id", SqlScalarType::String.nullable(false))
317            .with_column(
318                "brokers",
319                SqlScalarType::Array(Box::new(SqlScalarType::String)).nullable(false),
320            )
321            .with_column("sink_progress_topic", SqlScalarType::String.nullable(false))
322            .with_key(vec![0])
323            .finish(),
324        column_comments: BTreeMap::from_iter([
325            ("id", "The ID of the connection."),
326            (
327                "brokers",
328                "The addresses of the Kafka brokers to connect to.",
329            ),
330            (
331                "sink_progress_topic",
332                "The name of the Kafka topic where any sinks associated with this connection will track their progress information and other metadata. The contents of this topic are unspecified.",
333            ),
334        ]),
335        // The `sink_progress_topic` default must match
336        // `KafkaConnection::progress_topic` in
337        // src/storage-types/src/connections.rs. Keep the two in sync.
338        sql: "
339IN CLUSTER mz_catalog_server
340WITH (
341    ASSERT NOT NULL id,
342    ASSERT NOT NULL brokers,
343    ASSERT NOT NULL sink_progress_topic
344) AS
345SELECT
346    mz_internal.parse_catalog_id(r.data->'key'->'gid') AS id,
347    ARRAY(
348        SELECT b.value
349        FROM jsonb_array_elements_text(details->'brokers')
350             WITH ORDINALITY AS b(value, ord)
351        ORDER BY b.ord
352    ) AS brokers,
353    COALESCE(
354        details->>'progress_topic',
355        '_materialize-progress-' || mz_environment_id() || '-'
356            || mz_internal.parse_catalog_id(r.data->'key'->'gid')
357    ) AS sink_progress_topic
358FROM
359    mz_internal.mz_catalog_raw r,
360    LATERAL (
361        SELECT mz_internal.parse_connection_details(
362            r.data->'value'->'definition'->'V1'->>'create_sql')
363    ) AS d(details)
364WHERE
365    r.data->>'kind' = 'Item' AND
366    -- The connection_type filter selects the kind. A non-matching row yields a
367    -- NULL connection_type and is dropped here, so no `details IS NOT NULL` is
368    -- needed (parse_connection_details returns jsonb null, which passes it).
369    mz_internal.parse_catalog_create_sql(
370        r.data->'value'->'definition'->'V1'->>'create_sql')->>'connection_type' = 'kafka'",
371        is_retained_metrics_object: false,
372        access: vec![PUBLIC_SELECT],
373        ontology: Some(Ontology {
374            entity_name: "kafka_connection",
375            description: "Kafka-specific connection configuration (brokers, progress topic)",
376            links: &const {
377                [OntologyLink {
378                    name: "details_of",
379                    target: "connection",
380                    properties: LinkProperties::fk("id", "id", Cardinality::OneToOne),
381                }]
382            },
383            column_semantic_types: &[("id", SemanticType::CatalogItemId)],
384        }),
385    }
386});
387pub static MZ_KAFKA_SOURCES: LazyLock<BuiltinMaterializedView> = LazyLock::new(|| {
388    BuiltinMaterializedView {
389        name: "mz_kafka_sources",
390        schema: MZ_CATALOG_SCHEMA,
391        oid: oid::MV_MZ_KAFKA_SOURCES_OID,
392        desc: RelationDesc::builder()
393            .with_column("id", SqlScalarType::String.nullable(false))
394            .with_column("group_id_prefix", SqlScalarType::String.nullable(false))
395            .with_column("topic", SqlScalarType::String.nullable(false))
396            .with_key(vec![0])
397            .finish(),
398        column_comments: BTreeMap::from_iter([
399            (
400                "id",
401                "The ID of the Kafka source. Corresponds to `mz_catalog.mz_sources.id`.",
402            ),
403            (
404                "group_id_prefix",
405                "The value of the `GROUP ID PREFIX` connection option.",
406            ),
407            (
408                "topic",
409                "The name of the Kafka topic the source is reading from.",
410            ),
411        ]),
412        // NOTE: the `group_id_prefix` column is misnamed. It holds the
413        // full computed `group.id` (see `KafkaSourceConnection::group_id`
414        // / `KafkaConnection::id_base`), not just the user-supplied
415        // prefix. The MV reproduces that behaviour verbatim.
416        sql: "
417IN CLUSTER mz_catalog_server
418WITH (
419    ASSERT NOT NULL id,
420    ASSERT NOT NULL group_id_prefix,
421    ASSERT NOT NULL topic
422) AS
423SELECT
424    mz_internal.parse_catalog_id(data->'key'->'gid') AS id,
425    COALESCE(details->>'group_id_prefix', '')
426        || 'materialize-' || mz_environment_id()
427        || '-' || (details->>'connection_id')
428        || '-' || mz_internal.parse_catalog_id(data->'value'->'global_id')
429        AS group_id_prefix,
430    details->>'topic' AS topic
431FROM
432    mz_internal.mz_catalog_raw,
433    LATERAL (
434        SELECT mz_internal.parse_catalog_create_sql(data->'value'->'definition'->'V1'->>'create_sql')
435    ) AS l(parsed),
436    LATERAL (
437        SELECT mz_internal.parse_kafka_source_details(data->'value'->'definition'->'V1'->>'create_sql')
438    ) AS d(details)
439WHERE
440    data->>'kind' = 'Item' AND
441    parsed->>'source_type' = 'kafka'",
442        is_retained_metrics_object: false,
443        access: vec![PUBLIC_SELECT],
444        ontology: Some(Ontology {
445            entity_name: "kafka_source",
446            description: "Kafka-specific source configuration (topic, group ID)",
447            links: &const {
448                [OntologyLink {
449                    name: "details_of",
450                    target: "source",
451                    properties: LinkProperties::fk("id", "id", Cardinality::OneToOne),
452                }]
453            },
454            column_semantic_types: &[("id", SemanticType::CatalogItemId)],
455        }),
456    }
457});
458
459pub static MZ_DATABASES: LazyLock<BuiltinMaterializedView> =
460    LazyLock::new(|| BuiltinMaterializedView {
461        name: "mz_databases",
462        schema: MZ_CATALOG_SCHEMA,
463        oid: oid::MV_MZ_DATABASES_OID,
464        desc: RelationDesc::builder()
465            .with_column("id", SqlScalarType::String.nullable(false))
466            .with_column("oid", SqlScalarType::Oid.nullable(false))
467            .with_column("name", SqlScalarType::String.nullable(false))
468            .with_column("owner_id", SqlScalarType::String.nullable(false))
469            .with_column(
470                "privileges",
471                SqlScalarType::Array(Box::new(SqlScalarType::MzAclItem)).nullable(false),
472            )
473            .with_key(vec![0])
474            .with_key(vec![1])
475            .finish(),
476        column_comments: BTreeMap::from_iter([
477            ("id", "Materialize's unique ID for the database."),
478            ("oid", "A PostgreSQL-compatible OID for the database."),
479            ("name", "The name of the database."),
480            (
481                "owner_id",
482                "The role ID of the owner of the database. Corresponds to `mz_roles.id`.",
483            ),
484            ("privileges", "The privileges belonging to the database."),
485        ]),
486        sql: "
487IN CLUSTER mz_catalog_server
488WITH (
489    ASSERT NOT NULL id,
490    ASSERT NOT NULL oid,
491    ASSERT NOT NULL name,
492    ASSERT NOT NULL owner_id,
493    ASSERT NOT NULL privileges
494) AS
495SELECT
496    mz_internal.parse_catalog_id(data->'key'->'id') AS id,
497    (data->'value'->>'oid')::oid AS oid,
498    data->'value'->>'name' AS name,
499    mz_internal.parse_catalog_id(data->'value'->'owner_id') AS owner_id,
500    mz_internal.parse_catalog_privileges(data->'value'->'privileges') AS privileges
501FROM mz_internal.mz_catalog_raw
502WHERE data->>'kind' = 'Database'",
503        is_retained_metrics_object: false,
504        access: vec![PUBLIC_SELECT],
505        ontology: Some(Ontology {
506            entity_name: "database",
507            description: "A top-level namespace that contains schemas",
508            links: &const {
509                [OntologyLink {
510                    name: "owned_by",
511                    target: "role",
512                    properties: LinkProperties::fk("owner_id", "id", Cardinality::ManyToOne),
513                }]
514            },
515            column_semantic_types: &const {
516                [
517                    ("id", SemanticType::DatabaseId),
518                    ("oid", SemanticType::OID),
519                    ("owner_id", SemanticType::RoleId),
520                ]
521            },
522        }),
523    });
524
525pub static MZ_SCHEMAS: LazyLock<BuiltinMaterializedView> =
526    LazyLock::new(|| BuiltinMaterializedView {
527        name: "mz_schemas",
528        schema: MZ_CATALOG_SCHEMA,
529        oid: oid::MV_MZ_SCHEMAS_OID,
530        desc: RelationDesc::builder()
531            .with_column("id", SqlScalarType::String.nullable(false))
532            .with_column("oid", SqlScalarType::Oid.nullable(false))
533            .with_column("database_id", SqlScalarType::String.nullable(true))
534            .with_column("name", SqlScalarType::String.nullable(false))
535            .with_column("owner_id", SqlScalarType::String.nullable(false))
536            .with_column(
537                "privileges",
538                SqlScalarType::Array(Box::new(SqlScalarType::MzAclItem)).nullable(false),
539            )
540            .with_key(vec![0])
541            .with_key(vec![1])
542            .finish(),
543        column_comments: BTreeMap::from_iter([
544            ("id", "Materialize's unique ID for the schema."),
545            ("oid", "A PostgreSQL-compatible oid for the schema."),
546            (
547                "database_id",
548                "The ID of the database containing the schema. Corresponds to `mz_databases.id`.",
549            ),
550            ("name", "The name of the schema."),
551            (
552                "owner_id",
553                "The role ID of the owner of the schema. Corresponds to `mz_roles.id`.",
554            ),
555            ("privileges", "The privileges belonging to the schema."),
556        ]),
557        sql: "
558IN CLUSTER mz_catalog_server
559WITH (
560    ASSERT NOT NULL id,
561    ASSERT NOT NULL oid,
562    ASSERT NOT NULL name,
563    ASSERT NOT NULL owner_id,
564    ASSERT NOT NULL privileges
565) AS
566SELECT
567    mz_internal.parse_catalog_id(data->'key'->'id') AS id,
568    (data->'value'->>'oid')::oid AS oid,
569    CASE WHEN data->'value'->'database_id' != 'null'
570         THEN mz_internal.parse_catalog_id(data->'value'->'database_id')
571    END AS database_id,
572    data->'value'->>'name' AS name,
573    mz_internal.parse_catalog_id(data->'value'->'owner_id') AS owner_id,
574    mz_internal.parse_catalog_privileges(data->'value'->'privileges') AS privileges
575FROM mz_internal.mz_catalog_raw
576WHERE data->>'kind' = 'Schema'",
577        is_retained_metrics_object: false,
578        access: vec![PUBLIC_SELECT],
579        ontology: Some(Ontology {
580            entity_name: "schema",
581            description: "A namespace within a database that contains objects",
582            links: &const {
583                [
584                    OntologyLink {
585                        name: "in_database",
586                        target: "database",
587                        properties: LinkProperties::fk_nullable(
588                            "database_id",
589                            "id",
590                            Cardinality::ManyToOne,
591                        ),
592                    },
593                    OntologyLink {
594                        name: "owned_by",
595                        target: "role",
596                        properties: LinkProperties::fk("owner_id", "id", Cardinality::ManyToOne),
597                    },
598                ]
599            },
600            column_semantic_types: &const {
601                [
602                    ("id", SemanticType::SchemaId),
603                    ("oid", SemanticType::OID),
604                    ("database_id", SemanticType::DatabaseId),
605                    ("owner_id", SemanticType::RoleId),
606                ]
607            },
608        }),
609    });
610
611pub static MZ_COLUMNS: LazyLock<BuiltinTable> = LazyLock::new(|| BuiltinTable {
612    name: "mz_columns",
613    schema: MZ_CATALOG_SCHEMA,
614    oid: oid::TABLE_MZ_COLUMNS_OID,
615    desc: RelationDesc::builder()
616        .with_column("id", SqlScalarType::String.nullable(false)) // not a key
617        .with_column("name", SqlScalarType::String.nullable(false))
618        .with_column("position", SqlScalarType::UInt64.nullable(false))
619        .with_column("nullable", SqlScalarType::Bool.nullable(false))
620        .with_column("type", SqlScalarType::String.nullable(false))
621        .with_column("default", SqlScalarType::String.nullable(true))
622        .with_column("type_oid", SqlScalarType::Oid.nullable(false))
623        .with_column("type_mod", SqlScalarType::Int32.nullable(false))
624        .finish(),
625    column_comments: BTreeMap::from_iter([
626        (
627            "id",
628            "The unique ID of the table, source, or view containing the column.",
629        ),
630        ("name", "The name of the column."),
631        (
632            "position",
633            "The 1-indexed position of the column in its containing table, source, or view.",
634        ),
635        ("nullable", "Can the column contain a `NULL` value?"),
636        ("type", "The data type of the column."),
637        ("default", "The default expression of the column."),
638        (
639            "type_oid",
640            "The OID of the type of the column (references `mz_types`).",
641        ),
642        ("type_mod", "The packed type identifier of the column."),
643    ]),
644    is_retained_metrics_object: false,
645    access: vec![PUBLIC_SELECT],
646    ontology: Some(Ontology {
647        entity_name: "column",
648        description: "A column of a relation, with its name, position, type, and nullability",
649        links: &const {
650            [OntologyLink {
651                name: "belongs_to_relation",
652                target: "object",
653                properties: LinkProperties::ForeignKey {
654                    source_column: "id",
655                    target_column: "id",
656                    cardinality: Cardinality::ManyToOne,
657                    source_id_type: None,
658                    requires_mapping: None,
659                    nullable: false,
660                    note: Some("id in mz_columns is the relation ID, not a unique column ID"),
661                    extra_key_columns: None,
662                },
663            }]
664        },
665        column_semantic_types: &const {
666            [
667                ("id", SemanticType::CatalogItemId),
668                ("type_oid", SemanticType::OID),
669            ]
670        },
671    }),
672});
673
674/// User-created indexes, sourced from `mz_catalog_raw` `Item` entries with
675/// `parse_catalog_create_sql(...)` yielding `type = 'index'`.
676const USER_INDEXES_CTE: &str = "\
677    user_indexes AS (
678        SELECT
679            mz_internal.parse_catalog_id(data->'key'->'gid') AS id,
680            (data->'value'->>'oid')::oid AS oid,
681            data->'value'->>'name' AS name,
682            parsed->>'on_id' AS on_id,
683            parsed->>'cluster_id' AS cluster_id,
684            mz_internal.parse_catalog_id(data->'value'->'owner_id') AS owner_id,
685            data->'value'->'definition'->'V1'->>'create_sql' AS create_sql,
686            mz_internal.redact_sql(data->'value'->'definition'->'V1'->>'create_sql') AS redacted_create_sql
687        FROM
688            mz_internal.mz_catalog_raw
689            CROSS JOIN LATERAL (
690                SELECT mz_internal.parse_catalog_create_sql(data->'value'->'definition'->'V1'->>'create_sql')
691            ) AS l(parsed)
692        WHERE
693            data->>'kind' = 'Item' AND
694            parsed->>'type' = 'index'
695    )";
696
697/// Resolves the catalog id of the `mz_catalog_server` cluster at query time so
698/// the MV doesn't hardcode a system id literal.
699const CATALOG_SERVER_CLUSTER_CTE: &str = "\
700    catalog_server_cluster AS (
701        SELECT mz_internal.parse_catalog_id(data->'key'->'id') AS id
702        FROM mz_internal.mz_catalog_raw
703        WHERE data->>'kind' = 'Cluster' AND data->'value'->>'name' = 'mz_catalog_server'
704    )";
705
706/// Helper CTEs over `GidMapping` rows used to look up the system id of a
707/// builtin index by name and of the relation it indexes by (schema, name).
708const GID_MAPPING_CTES: &str = "\
709    builtin_index_gid_mappings AS (
710        SELECT
711            's' || (data->'value'->>'catalog_id') AS id,
712            data->'key'->>'object_name' AS name
713        FROM mz_internal.mz_catalog_raw
714        WHERE
715            data->>'kind' = 'GidMapping' AND
716            data->'key'->>'object_type' = '6'
717    ),
718    on_gid_mappings AS (
719        SELECT
720            's' || (data->'value'->>'catalog_id') AS id,
721            data->'key'->>'schema_name' AS schema_name,
722            data->'key'->>'object_name' AS object_name
723        FROM mz_internal.mz_catalog_raw
724        WHERE data->>'kind' = 'GidMapping'
725    )";
726
727pub static MZ_INDEXES: LazyLock<BuiltinMaterializedView> = LazyLock::new(|| {
728    // Reconstructs `CREATE INDEX ... IN CLUSTER [<id>] ON [<id> AS "schema"."name"] (<keys>)`
729    // from `mz_builtin_indexes` joined to `GidMapping` lookups and the
730    // `mz_catalog_server` cluster id.
731    let builtin_indexes_cte = format!("\
732    builtin_indexes AS (
733        SELECT *, mz_internal.redact_sql(create_sql) AS redacted_create_sql
734        FROM (
735            SELECT
736                bigm.id AS id,
737                biv.oid AS oid,
738                biv.name AS name,
739                om.id AS on_id,
740                csc.id AS cluster_id,
741                '{MZ_SYSTEM_ROLE_ID}' AS owner_id,
742                'CREATE INDEX \"' || biv.name || '\" IN CLUSTER [' || csc.id || '] ON [' || om.id || ' AS \"' || biv.on_schema_name || '\".\"' || biv.on_name || '\"] (' || biv.key_exprs || ')' AS create_sql
743            FROM mz_internal.mz_builtin_indexes biv
744            JOIN builtin_index_gid_mappings bigm ON bigm.name = biv.name
745            JOIN on_gid_mappings om ON om.schema_name = biv.on_schema_name AND om.object_name = biv.on_name
746            CROSS JOIN catalog_server_cluster csc
747        ) AS t
748    )");
749
750    let introspection_source_indexes_cte = format!("\
751    introspection_source_indexes AS (
752        SELECT *, mz_internal.redact_sql(create_sql) AS redacted_create_sql
753        FROM (
754            SELECT
755                'si' || (isi.data->'value'->>'catalog_id') AS id,
756                (isi.data->'value'->>'oid')::oid AS oid,
757                idx_name || '_' || cluster_id || '_primary_idx' AS name,
758                's' || (gm.data->'value'->>'catalog_id') AS on_id,
759                cluster_id,
760                '{MZ_SYSTEM_ROLE_ID}' AS owner_id,
761                'CREATE INDEX \"' || idx_name || '_' || cluster_id || '_primary_idx\" IN CLUSTER [' || cluster_id || '] ON \"mz_introspection\".\"' || idx_name || '\" (' || bli.col_list || ')' AS create_sql
762            FROM mz_internal.mz_catalog_raw AS isi
763            CROSS JOIN LATERAL (
764                SELECT isi.data->'key'->>'name', mz_internal.parse_catalog_id(isi.data->'key'->'cluster_id')
765            ) AS l(idx_name, cluster_id)
766            JOIN mz_internal.mz_catalog_raw AS gm ON
767                gm.data->>'kind' = 'GidMapping' AND
768                gm.data->'key'->>'object_type' = '2' AND
769                gm.data->'key'->>'schema_name' = 'mz_introspection' AND
770                gm.data->'key'->>'object_name' = idx_name
771            JOIN mz_internal.mz_builtin_log_indexes AS bli ON bli.name = idx_name
772            WHERE isi.data->>'kind' = 'ClusterIntrospectionSourceIndex'
773        ) AS t
774    )");
775
776    let sql = format!(
777        "
778IN CLUSTER mz_catalog_server
779WITH (
780    ASSERT NOT NULL id,
781    ASSERT NOT NULL oid,
782    ASSERT NOT NULL name,
783    ASSERT NOT NULL on_id,
784    ASSERT NOT NULL cluster_id,
785    ASSERT NOT NULL owner_id,
786    ASSERT NOT NULL create_sql,
787    ASSERT NOT NULL redacted_create_sql
788) AS
789WITH
790{USER_INDEXES_CTE},
791{CATALOG_SERVER_CLUSTER_CTE},
792{GID_MAPPING_CTES},
793{builtin_indexes_cte},
794{introspection_source_indexes_cte}
795SELECT * FROM user_indexes
796UNION ALL
797SELECT * FROM builtin_indexes
798UNION ALL
799SELECT * FROM introspection_source_indexes
800"
801    );
802
803    BuiltinMaterializedView {
804        name: "mz_indexes",
805        schema: MZ_CATALOG_SCHEMA,
806        oid: oid::MV_MZ_INDEXES_OID,
807        desc: RelationDesc::builder()
808            .with_column("id", SqlScalarType::String.nullable(false))
809            .with_column("oid", SqlScalarType::Oid.nullable(false))
810            .with_column("name", SqlScalarType::String.nullable(false))
811            .with_column("on_id", SqlScalarType::String.nullable(false))
812            .with_column("cluster_id", SqlScalarType::String.nullable(false))
813            .with_column("owner_id", SqlScalarType::String.nullable(false))
814            .with_column("create_sql", SqlScalarType::String.nullable(false))
815            .with_column("redacted_create_sql", SqlScalarType::String.nullable(false))
816            .with_key(vec![0])
817            .with_key(vec![1])
818            .finish(),
819        column_comments: BTreeMap::from_iter([
820            ("id", "Materialize's unique ID for the index."),
821            ("oid", "A PostgreSQL-compatible OID for the index."),
822            ("name", "The name of the index."),
823            (
824                "on_id",
825                "The ID of the relation on which the index is built.",
826            ),
827            (
828                "cluster_id",
829                "The ID of the cluster in which the index is built.",
830            ),
831            (
832                "owner_id",
833                "The role ID of the owner of the index. Corresponds to `mz_roles.id`.",
834            ),
835            ("create_sql", "The `CREATE` SQL statement for the index."),
836            (
837                "redacted_create_sql",
838                "The redacted `CREATE` SQL statement for the index.",
839            ),
840        ]),
841        sql: Box::leak(sql.into_boxed_str()),
842        is_retained_metrics_object: false,
843        access: vec![PUBLIC_SELECT],
844        ontology: Some(Ontology {
845            entity_name: "index",
846            description: "An in-memory index on a relation for fast lookups",
847            links: &const {
848                [
849                    OntologyLink {
850                        name: "owned_by",
851                        target: "role",
852                        properties: LinkProperties::fk("owner_id", "id", Cardinality::ManyToOne),
853                    },
854                    OntologyLink {
855                        name: "runs_on_cluster",
856                        target: "cluster",
857                        properties: LinkProperties::fk("cluster_id", "id", Cardinality::ManyToOne),
858                    },
859                    OntologyLink {
860                        name: "indexes_relation",
861                        target: "relation",
862                        properties: LinkProperties::fk("on_id", "id", Cardinality::ManyToOne),
863                    },
864                ]
865            },
866            column_semantic_types: &const {
867                [
868                    ("id", SemanticType::CatalogItemId),
869                    ("oid", SemanticType::OID),
870                    ("on_id", SemanticType::CatalogItemId),
871                    ("cluster_id", SemanticType::ClusterId),
872                    ("owner_id", SemanticType::RoleId),
873                    ("create_sql", SemanticType::SqlDefinition),
874                    ("redacted_create_sql", SemanticType::RedactedSqlDefinition),
875                ]
876            },
877        }),
878    }
879});
880pub static MZ_INDEX_COLUMNS: LazyLock<BuiltinTable> = LazyLock::new(|| BuiltinTable {
881    name: "mz_index_columns",
882    schema: MZ_CATALOG_SCHEMA,
883    oid: oid::TABLE_MZ_INDEX_COLUMNS_OID,
884    desc: RelationDesc::builder()
885        .with_column("index_id", SqlScalarType::String.nullable(false))
886        .with_column("index_position", SqlScalarType::UInt64.nullable(false))
887        .with_column("on_position", SqlScalarType::UInt64.nullable(true))
888        .with_column("on_expression", SqlScalarType::String.nullable(true))
889        .with_column("nullable", SqlScalarType::Bool.nullable(false))
890        .finish(),
891    column_comments: BTreeMap::from_iter([
892        (
893            "index_id",
894            "The ID of the index which contains this column. Corresponds to `mz_indexes.id`.",
895        ),
896        (
897            "index_position",
898            "The 1-indexed position of this column within the index. (The order of columns in an index does not necessarily match the order of columns in the relation on which the index is built.)",
899        ),
900        (
901            "on_position",
902            "If not `NULL`, specifies the 1-indexed position of a column in the relation on which this index is built that determines the value of this index column.",
903        ),
904        (
905            "on_expression",
906            "If not `NULL`, specifies a SQL expression that is evaluated to compute the value of this index column. The expression may contain references to any of the columns of the relation.",
907        ),
908        (
909            "nullable",
910            "Can this column of the index evaluate to `NULL`?",
911        ),
912    ]),
913    is_retained_metrics_object: false,
914    access: vec![PUBLIC_SELECT],
915    ontology: Some(Ontology {
916        entity_name: "index_column",
917        description: "A column or expression in an index, with its position",
918        links: &const {
919            [OntologyLink {
920                name: "belongs_to_index",
921                target: "index",
922                properties: LinkProperties::fk("index_id", "id", Cardinality::ManyToOne),
923            }]
924        },
925        column_semantic_types: &[("index_id", SemanticType::CatalogItemId)],
926    }),
927});
928pub static MZ_TABLES: LazyLock<BuiltinMaterializedView> = LazyLock::new(|| {
929    BuiltinMaterializedView {
930    name: "mz_tables",
931    schema: MZ_CATALOG_SCHEMA,
932    oid: oid::MV_MZ_TABLES_OID,
933    desc: RelationDesc::builder()
934        .with_column("id", SqlScalarType::String.nullable(false))
935        .with_column("oid", SqlScalarType::Oid.nullable(false))
936        .with_column("schema_id", SqlScalarType::String.nullable(false))
937        .with_column("name", SqlScalarType::String.nullable(false))
938        .with_column("owner_id", SqlScalarType::String.nullable(false))
939        .with_column(
940            "privileges",
941            SqlScalarType::Array(Box::new(SqlScalarType::MzAclItem)).nullable(false),
942        )
943        .with_column("create_sql", SqlScalarType::String.nullable(true))
944        .with_column("redacted_create_sql", SqlScalarType::String.nullable(true))
945        .with_column("source_id", SqlScalarType::String.nullable(true))
946        .with_key(vec![0])
947        .with_key(vec![1])
948        .finish(),
949    column_comments: BTreeMap::from_iter([
950        ("id", "Materialize's unique ID for the table."),
951        ("oid", "A PostgreSQL-compatible OID for the table."),
952        (
953            "schema_id",
954            "The ID of the schema to which the table belongs. Corresponds to `mz_schemas.id`.",
955        ),
956        ("name", "The name of the table."),
957        (
958            "owner_id",
959            "The role ID of the owner of the table. Corresponds to `mz_roles.id`.",
960        ),
961        ("privileges", "The privileges belonging to the table."),
962        ("create_sql", "The `CREATE` SQL statement for the table."),
963        (
964            "redacted_create_sql",
965            "The redacted `CREATE` SQL statement for the table.",
966        ),
967        (
968            "source_id",
969            "The ID of the source associated with the table, if any. Corresponds to `mz_sources.id`.",
970        ),
971    ]),
972    // Temporary tables live in a per-session temporary schema that has no
973    // durable schema record. Their rows keep the temporary schema sentinel
974    // "0" that the previous builtin-table implementation exposed.
975    sql: Box::leak(format!("
976IN CLUSTER mz_catalog_server
977WITH (
978    ASSERT NOT NULL id,
979    ASSERT NOT NULL oid,
980    ASSERT NOT NULL schema_id,
981    ASSERT NOT NULL name,
982    ASSERT NOT NULL owner_id,
983    ASSERT NOT NULL privileges
984) AS
985WITH
986    user_tables AS (
987        SELECT
988            mz_internal.parse_catalog_id(data->'key'->'gid') AS id,
989            (data->'value'->>'oid')::oid AS oid,
990            CASE WHEN data->'value'->>'ephemeral_owner_session' IS NULL
991                THEN mz_internal.parse_catalog_id(data->'value'->'schema_id')
992                ELSE '0'
993            END AS schema_id,
994            data->'value'->>'name' AS name,
995            mz_internal.parse_catalog_id(data->'value'->'owner_id') AS owner_id,
996            mz_internal.parse_catalog_privileges(data->'value'->'privileges') AS privileges,
997            data->'value'->'definition'->'V1'->>'create_sql' AS create_sql,
998            mz_internal.redact_sql(data->'value'->'definition'->'V1'->>'create_sql') AS redacted_create_sql,
999            mz_internal.parse_catalog_create_sql(data->'value'->'definition'->'V1'->>'create_sql')->>'source_id' AS source_id
1000        FROM mz_internal.mz_catalog_raw
1001        WHERE
1002            data->>'kind' = 'Item' AND
1003            mz_internal.parse_catalog_create_sql(data->'value'->'definition'->'V1'->>'create_sql')->>'type' = 'table'
1004    ),
1005    builtin_mappings AS (
1006        SELECT
1007            data->'key'->>'schema_name' AS schema_name,
1008            data->'key'->>'object_name' AS name,
1009            's' || (data->'value'->>'catalog_id') AS id
1010        FROM mz_internal.mz_catalog_raw
1011        WHERE
1012            data->>'kind' = 'GidMapping' AND
1013            data->'key'->>'object_type' = '1'
1014    ),
1015    builtin_tables AS (
1016        SELECT
1017            m.id,
1018            t.oid,
1019            s.id AS schema_id,
1020            t.name,
1021            '{MZ_SYSTEM_ROLE_ID}' AS owner_id,
1022            t.privileges,
1023            NULL::text AS create_sql,
1024            NULL::text AS redacted_create_sql,
1025            NULL::text AS source_id
1026        FROM mz_internal.mz_builtin_tables t
1027        JOIN builtin_mappings m USING (schema_name, name)
1028        JOIN mz_schemas s ON s.name = t.schema_name
1029        WHERE s.database_id IS NULL
1030    )
1031SELECT * FROM user_tables
1032UNION ALL
1033SELECT * FROM builtin_tables").into_boxed_str()),
1034    is_retained_metrics_object: true,
1035    access: vec![PUBLIC_SELECT],
1036    ontology: Some(Ontology {
1037        entity_name: "table",
1038        description: "A user-writable table that can be inserted into and updated",
1039        links: &const {
1040            [
1041                OntologyLink {
1042                    name: "in_schema",
1043                    target: "schema",
1044                    properties: LinkProperties::fk("schema_id", "id", Cardinality::ManyToOne),
1045                },
1046                OntologyLink {
1047                    name: "owned_by",
1048                    target: "role",
1049                    properties: LinkProperties::fk("owner_id", "id", Cardinality::ManyToOne),
1050                },
1051                OntologyLink {
1052                    name: "created_by_source",
1053                    target: "source",
1054                    properties: LinkProperties::fk_nullable(
1055                        "source_id",
1056                        "id",
1057                        Cardinality::ManyToOne,
1058                    ),
1059                },
1060            ]
1061        },
1062        column_semantic_types: &const {
1063            [
1064                ("id", SemanticType::CatalogItemId),
1065                ("oid", SemanticType::OID),
1066                ("schema_id", SemanticType::SchemaId),
1067                ("owner_id", SemanticType::RoleId),
1068                ("create_sql", SemanticType::SqlDefinition),
1069                ("redacted_create_sql", SemanticType::RedactedSqlDefinition),
1070                ("source_id", SemanticType::CatalogItemId),
1071            ]
1072        },
1073    }),
1074}
1075});
1076
1077pub static MZ_CONNECTIONS: LazyLock<BuiltinMaterializedView> = LazyLock::new(|| {
1078    BuiltinMaterializedView {
1079        name: "mz_connections",
1080        schema: MZ_CATALOG_SCHEMA,
1081        oid: oid::MV_MZ_CONNECTIONS_OID,
1082        desc: RelationDesc::builder()
1083            .with_column("id", SqlScalarType::String.nullable(false))
1084            .with_column("oid", SqlScalarType::Oid.nullable(false))
1085            .with_column("schema_id", SqlScalarType::String.nullable(false))
1086            .with_column("name", SqlScalarType::String.nullable(false))
1087            .with_column("type", SqlScalarType::String.nullable(false))
1088            .with_column("owner_id", SqlScalarType::String.nullable(false))
1089            .with_column(
1090                "privileges",
1091                SqlScalarType::Array(Box::new(SqlScalarType::MzAclItem)).nullable(false),
1092            )
1093            .with_column("create_sql", SqlScalarType::String.nullable(false))
1094            .with_column("redacted_create_sql", SqlScalarType::String.nullable(false))
1095            .with_key(vec![0])
1096            .with_key(vec![1])
1097            .finish(),
1098        column_comments: BTreeMap::from_iter([
1099            ("id", "The unique ID of the connection."),
1100            ("oid", "A PostgreSQL-compatible OID for the connection."),
1101            (
1102                "schema_id",
1103                "The ID of the schema to which the connection belongs. Corresponds to `mz_schemas.id`.",
1104            ),
1105            ("name", "The name of the connection."),
1106            (
1107                "type",
1108                "The type of the connection: `confluent-schema-registry`, `kafka`, `postgres`, or `ssh-tunnel`.",
1109            ),
1110            (
1111                "owner_id",
1112                "The role ID of the owner of the connection. Corresponds to `mz_roles.id`.",
1113            ),
1114            ("privileges", "The privileges belonging to the connection."),
1115            (
1116                "create_sql",
1117                "The `CREATE` SQL statement for the connection.",
1118            ),
1119            (
1120                "redacted_create_sql",
1121                "The redacted `CREATE` SQL statement for the connection.",
1122            ),
1123        ]),
1124        sql: "
1125IN CLUSTER mz_catalog_server
1126WITH (
1127    ASSERT NOT NULL id,
1128    ASSERT NOT NULL oid,
1129    ASSERT NOT NULL schema_id,
1130    ASSERT NOT NULL name,
1131    ASSERT NOT NULL type,
1132    ASSERT NOT NULL owner_id,
1133    ASSERT NOT NULL privileges,
1134    ASSERT NOT NULL create_sql,
1135    ASSERT NOT NULL redacted_create_sql
1136) AS
1137SELECT
1138    mz_internal.parse_catalog_id(data->'key'->'gid') AS id,
1139    (data->'value'->>'oid')::oid AS oid,
1140    mz_internal.parse_catalog_id(data->'value'->'schema_id') AS schema_id,
1141    data->'value'->>'name' AS name,
1142    mz_internal.parse_catalog_create_sql(data->'value'->'definition'->'V1'->>'create_sql')->>'connection_type' AS type,
1143    mz_internal.parse_catalog_id(data->'value'->'owner_id') AS owner_id,
1144    mz_internal.parse_catalog_privileges(data->'value'->'privileges') AS privileges,
1145    data->'value'->'definition'->'V1'->>'create_sql' AS create_sql,
1146    mz_internal.redact_sql(data->'value'->'definition'->'V1'->>'create_sql') AS redacted_create_sql
1147FROM mz_internal.mz_catalog_raw
1148WHERE
1149    data->>'kind' = 'Item' AND
1150    mz_internal.parse_catalog_create_sql(data->'value'->'definition'->'V1'->>'create_sql')->>'type' = 'connection'",
1151        is_retained_metrics_object: false,
1152        access: vec![PUBLIC_SELECT],
1153        ontology: Some(Ontology {
1154            entity_name: "connection",
1155            description: "A reusable connection configuration to an external system",
1156            links: &const { [
1157                OntologyLink {
1158                    name: "in_schema",
1159                    target: "schema",
1160                    properties: LinkProperties::fk("schema_id", "id", Cardinality::ManyToOne),
1161                },
1162                OntologyLink {
1163                    name: "owned_by",
1164                    target: "role",
1165                    properties: LinkProperties::fk("owner_id", "id", Cardinality::ManyToOne),
1166                },
1167            ] },
1168            column_semantic_types: &const {[("id", SemanticType::CatalogItemId), ("oid", SemanticType::OID), ("schema_id", SemanticType::SchemaId), ("type", SemanticType::ConnectionType), ("owner_id", SemanticType::RoleId), ("create_sql", SemanticType::SqlDefinition), ("redacted_create_sql", SemanticType::RedactedSqlDefinition)]},
1169        }),
1170    }
1171});
1172
1173// The two SSH public keys are stored verbatim in the persisted `create_sql`
1174// (they are generated, not user-supplied, and explicitly not redacted), so the
1175// view reads them straight out via `parse_connection_details` and keeps only
1176// ssh-tunnel connections.
1177pub static MZ_SSH_TUNNEL_CONNECTIONS: LazyLock<BuiltinMaterializedView> =
1178    LazyLock::new(|| BuiltinMaterializedView {
1179        name: "mz_ssh_tunnel_connections",
1180        schema: MZ_CATALOG_SCHEMA,
1181        oid: oid::MV_MZ_SSH_TUNNEL_CONNECTIONS_OID,
1182        desc: RelationDesc::builder()
1183            .with_column("id", SqlScalarType::String.nullable(false))
1184            .with_column("public_key_1", SqlScalarType::String.nullable(false))
1185            .with_column("public_key_2", SqlScalarType::String.nullable(false))
1186            .with_key(vec![0])
1187            .finish(),
1188        column_comments: BTreeMap::from_iter([
1189            ("id", "The ID of the connection."),
1190            (
1191                "public_key_1",
1192                "The first public key associated with the SSH tunnel.",
1193            ),
1194            (
1195                "public_key_2",
1196                "The second public key associated with the SSH tunnel.",
1197            ),
1198        ]),
1199        sql: "
1200IN CLUSTER mz_catalog_server
1201WITH (
1202    ASSERT NOT NULL id,
1203    ASSERT NOT NULL public_key_1,
1204    ASSERT NOT NULL public_key_2
1205) AS
1206SELECT
1207    mz_internal.parse_catalog_id(r.data->'key'->'gid') AS id,
1208    details->>'public_key_1' AS public_key_1,
1209    details->>'public_key_2' AS public_key_2
1210FROM
1211    mz_internal.mz_catalog_raw r,
1212    LATERAL (
1213        SELECT mz_internal.parse_connection_details(
1214            r.data->'value'->'definition'->'V1'->>'create_sql')
1215    ) AS d(details)
1216WHERE
1217    r.data->>'kind' = 'Item' AND
1218    -- The connection_type filter selects the kind. A non-matching row yields a
1219    -- NULL connection_type and is dropped here, so no `details IS NOT NULL` is
1220    -- needed (parse_connection_details returns jsonb null, which passes it).
1221    mz_internal.parse_catalog_create_sql(
1222        r.data->'value'->'definition'->'V1'->>'create_sql')->>'connection_type' = 'ssh-tunnel'",
1223        is_retained_metrics_object: false,
1224        access: vec![PUBLIC_SELECT],
1225        ontology: Some(Ontology {
1226            entity_name: "ssh_tunnel_connection",
1227            description: "SSH tunnel connection with public keys",
1228            links: &const {
1229                [OntologyLink {
1230                    name: "details_of",
1231                    target: "connection",
1232                    properties: LinkProperties::fk("id", "id", Cardinality::OneToOne),
1233                }]
1234            },
1235            column_semantic_types: &[("id", SemanticType::CatalogItemId)],
1236        }),
1237    });
1238pub static MZ_SOURCES: LazyLock<BuiltinMaterializedView> = LazyLock::new(|| {
1239    let sql = format!("
1240IN CLUSTER mz_catalog_server
1241WITH (
1242    ASSERT NOT NULL id,
1243    ASSERT NOT NULL oid,
1244    ASSERT NOT NULL schema_id,
1245    ASSERT NOT NULL name,
1246    ASSERT NOT NULL type,
1247    ASSERT NOT NULL owner_id,
1248    ASSERT NOT NULL privileges
1249) AS
1250WITH
1251    user_sources AS (
1252        SELECT
1253            mz_internal.parse_catalog_id(data->'key'->'gid') AS id,
1254            (data->'value'->>'oid')::oid AS oid,
1255            mz_internal.parse_catalog_id(data->'value'->'schema_id') AS schema_id,
1256            data->'value'->>'name' AS name,
1257            parsed->>'source_type' AS type,
1258            parsed->>'connection_id' AS connection_id,
1259            NULL AS size,
1260            parsed->>'envelope_type' AS envelope_type,
1261            parsed->>'key_format' AS key_format,
1262            parsed->>'value_format' AS value_format,
1263            COALESCE(
1264                parsed->>'cluster_id',
1265                (
1266                    SELECT mz_internal.parse_catalog_create_sql(p.data->'value'->'definition'->'V1'->>'create_sql')->>'cluster_id'
1267                    FROM mz_internal.mz_catalog_raw p
1268                    WHERE
1269                        p.data->>'kind' = 'Item' AND
1270                        mz_internal.parse_catalog_id(p.data->'key'->'gid') = parsed->>'of_source_id'
1271                )
1272            ) AS cluster_id,
1273            mz_internal.parse_catalog_id(data->'value'->'owner_id') AS owner_id,
1274            mz_internal.parse_catalog_privileges(data->'value'->'privileges') AS privileges,
1275            data->'value'->'definition'->'V1'->>'create_sql' AS create_sql,
1276            mz_internal.redact_sql(data->'value'->'definition'->'V1'->>'create_sql') AS redacted_create_sql
1277        FROM
1278            mz_internal.mz_catalog_raw
1279            CROSS JOIN LATERAL (
1280                SELECT mz_internal.parse_catalog_create_sql(data->'value'->'definition'->'V1'->>'create_sql')
1281            ) AS l(parsed)
1282        WHERE
1283            data->>'kind' = 'Item' AND
1284            parsed->>'type' IN ('source', 'subsource')
1285    ),
1286    builtin_mappings AS (
1287        SELECT
1288            data->'key'->>'schema_name' AS schema_name,
1289            data->'key'->>'object_name' AS name,
1290            's' || (data->'value'->>'catalog_id') AS id
1291        FROM mz_internal.mz_catalog_raw
1292        WHERE
1293            data->>'kind' = 'GidMapping' AND
1294            data->'key'->>'object_type' = '2'
1295    ),
1296    builtin_sources AS (
1297        SELECT
1298            m.id,
1299            src.oid,
1300            s.id AS schema_id,
1301            src.name,
1302            src.type,
1303            NULL AS connection_id,
1304            NULL AS size,
1305            NULL AS envelope_type,
1306            NULL AS key_format,
1307            NULL AS value_format,
1308            NULL AS cluster_id,
1309            '{MZ_SYSTEM_ROLE_ID}' AS owner_id,
1310            src.privileges,
1311            NULL AS create_sql,
1312            NULL AS redacted_create_sql
1313        FROM mz_internal.mz_builtin_sources AS src
1314        JOIN builtin_mappings m USING (schema_name, name)
1315        JOIN mz_schemas s ON s.name = src.schema_name
1316        WHERE s.database_id IS NULL
1317    )
1318SELECT * FROM user_sources
1319UNION ALL
1320SELECT * FROM builtin_sources");
1321
1322    BuiltinMaterializedView {
1323        name: "mz_sources",
1324        schema: MZ_CATALOG_SCHEMA,
1325        oid: oid::MV_MZ_SOURCES_OID,
1326        desc: RelationDesc::builder()
1327            .with_column("id", SqlScalarType::String.nullable(false))
1328            .with_column("oid", SqlScalarType::Oid.nullable(false))
1329            .with_column("schema_id", SqlScalarType::String.nullable(false))
1330            .with_column("name", SqlScalarType::String.nullable(false))
1331            .with_column("type", SqlScalarType::String.nullable(false))
1332            .with_column("connection_id", SqlScalarType::String.nullable(true))
1333            .with_column("size", SqlScalarType::String.nullable(true))
1334            .with_column("envelope_type", SqlScalarType::String.nullable(true))
1335            .with_column("key_format", SqlScalarType::String.nullable(true))
1336            .with_column("value_format", SqlScalarType::String.nullable(true))
1337            .with_column("cluster_id", SqlScalarType::String.nullable(true))
1338            .with_column("owner_id", SqlScalarType::String.nullable(false))
1339            .with_column(
1340                "privileges",
1341                SqlScalarType::Array(Box::new(SqlScalarType::MzAclItem)).nullable(false),
1342            )
1343            .with_column("create_sql", SqlScalarType::String.nullable(true))
1344            .with_column("redacted_create_sql", SqlScalarType::String.nullable(true))
1345            .with_key(vec![0])
1346            .with_key(vec![1])
1347            .finish(),
1348        column_comments: BTreeMap::from_iter([
1349            ("id", "Materialize's unique ID for the source."),
1350            ("oid", "A PostgreSQL-compatible OID for the source."),
1351            (
1352                "schema_id",
1353                "The ID of the schema to which the source belongs. Corresponds to `mz_schemas.id`.",
1354            ),
1355            ("name", "The name of the source."),
1356            (
1357                "type",
1358                "The type of the source: `kafka`, `mysql`, `postgres`, `load-generator`, `progress`, or `subsource`.",
1359            ),
1360            (
1361                "connection_id",
1362                "The ID of the connection associated with the source, if any. Corresponds to `mz_connections.id`.",
1363            ),
1364            ("size", "*Deprecated* The size of the source."),
1365            (
1366                "envelope_type",
1367                "For old-syntax Kafka sources, the envelope type: `none`, `upsert`, or `debezium`. `NULL` for new-syntax Kafka sources, whose envelopes are defined per source table (see `mz_kafka_source_tables`), and for other source types.",
1368            ),
1369            (
1370                "key_format",
1371                "For Kafka sources, the format of the Kafka message key: `avro`, `csv`, `regex`, `bytes`, `json`, `text`, or `NULL`.",
1372            ),
1373            (
1374                "value_format",
1375                "For Kafka sources, the format of the Kafka message value: `avro`, `csv`, `regex`, `bytes`, `json`, `text`. `NULL` for other source types.",
1376            ),
1377            (
1378                "cluster_id",
1379                "The ID of the cluster maintaining the source. Corresponds to `mz_clusters.id`.",
1380            ),
1381            (
1382                "owner_id",
1383                "The role ID of the owner of the source. Corresponds to `mz_roles.id`.",
1384            ),
1385            ("privileges", "The privileges granted on the source."),
1386            ("create_sql", "The `CREATE` SQL statement for the source."),
1387            (
1388                "redacted_create_sql",
1389                "The redacted `CREATE` SQL statement for the source.",
1390            ),
1391        ]),
1392        sql: Box::leak(sql.into_boxed_str()),
1393        is_retained_metrics_object: true,
1394        access: vec![PUBLIC_SELECT],
1395        ontology: Some(Ontology {
1396            entity_name: "source",
1397            description: "An external data source ingested into Materialize (e.g., Kafka, Postgres)",
1398            links: &const {
1399                [
1400                    OntologyLink {
1401                        name: "in_schema",
1402                        target: "schema",
1403                        properties: LinkProperties::fk("schema_id", "id", Cardinality::ManyToOne),
1404                    },
1405                    OntologyLink {
1406                        name: "owned_by",
1407                        target: "role",
1408                        properties: LinkProperties::fk("owner_id", "id", Cardinality::ManyToOne),
1409                    },
1410                    OntologyLink {
1411                        name: "runs_on_cluster",
1412                        target: "cluster",
1413                        properties: LinkProperties::fk_nullable(
1414                            "cluster_id",
1415                            "id",
1416                            Cardinality::ManyToOne,
1417                        ),
1418                    },
1419                    OntologyLink {
1420                        name: "uses_connection",
1421                        target: "connection",
1422                        properties: LinkProperties::fk_nullable(
1423                            "connection_id",
1424                            "id",
1425                            Cardinality::ManyToOne,
1426                        ),
1427                    },
1428                ]
1429            },
1430            column_semantic_types: &const {
1431                [
1432                    ("id", SemanticType::CatalogItemId),
1433                    ("oid", SemanticType::OID),
1434                    ("schema_id", SemanticType::SchemaId),
1435                    ("type", SemanticType::SourceType),
1436                    ("connection_id", SemanticType::CatalogItemId),
1437                    ("cluster_id", SemanticType::ClusterId),
1438                    ("owner_id", SemanticType::RoleId),
1439                    ("create_sql", SemanticType::SqlDefinition),
1440                    ("redacted_create_sql", SemanticType::RedactedSqlDefinition),
1441                ]
1442            },
1443        }),
1444    }
1445});
1446/// Sink metadata, all of it derived from the persisted `create_sql`. The
1447/// `CreateSink` arm of `parse_catalog_create_sql` does the parsing, including
1448/// the deprecated `format` column and its avro/json-only collapse. `size` is
1449/// deprecated and always NULL.
1450pub static MZ_SINKS: LazyLock<BuiltinMaterializedView> = LazyLock::new(|| {
1451    BuiltinMaterializedView {
1452        name: "mz_sinks",
1453        schema: MZ_CATALOG_SCHEMA,
1454        oid: oid::MV_MZ_SINKS_OID,
1455        desc: RelationDesc::builder()
1456            .with_column("id", SqlScalarType::String.nullable(false))
1457            .with_column("oid", SqlScalarType::Oid.nullable(false))
1458            .with_column("schema_id", SqlScalarType::String.nullable(false))
1459            .with_column("name", SqlScalarType::String.nullable(false))
1460            .with_column("type", SqlScalarType::String.nullable(false))
1461            .with_column("connection_id", SqlScalarType::String.nullable(true))
1462            .with_column("size", SqlScalarType::String.nullable(true))
1463            .with_column("envelope_type", SqlScalarType::String.nullable(true))
1464            // This `format` column is deprecated and replaced by the `key_format` and `value_format` columns
1465            // below. This should be removed in the future.
1466            .with_column("format", SqlScalarType::String.nullable(true))
1467            .with_column("key_format", SqlScalarType::String.nullable(true))
1468            .with_column("value_format", SqlScalarType::String.nullable(true))
1469            .with_column("cluster_id", SqlScalarType::String.nullable(false))
1470            .with_column("owner_id", SqlScalarType::String.nullable(false))
1471            .with_column("create_sql", SqlScalarType::String.nullable(false))
1472            .with_column("redacted_create_sql", SqlScalarType::String.nullable(false))
1473            .with_key(vec![0])
1474            .with_key(vec![1])
1475            .finish(),
1476        column_comments: BTreeMap::from_iter([
1477            ("id", "Materialize's unique ID for the sink."),
1478            ("oid", "A PostgreSQL-compatible OID for the sink."),
1479            (
1480                "schema_id",
1481                "The ID of the schema to which the sink belongs. Corresponds to `mz_schemas.id`.",
1482            ),
1483            ("name", "The name of the sink."),
1484            ("type", "The type of the sink: `kafka`."),
1485            (
1486                "connection_id",
1487                "The ID of the connection associated with the sink, if any. Corresponds to `mz_connections.id`.",
1488            ),
1489            ("size", "The size of the sink."),
1490            (
1491                "envelope_type",
1492                "The envelope of the sink: `upsert`, or `debezium`.",
1493            ),
1494            (
1495                "format",
1496                "*Deprecated* The format of the Kafka messages produced by the sink: `avro`, `json`, `text`, or `bytes`.",
1497            ),
1498            (
1499                "key_format",
1500                "The format of the Kafka message key for messages produced by the sink: `avro`, `json`, `bytes`, `text`, or `NULL`.",
1501            ),
1502            (
1503                "value_format",
1504                "The format of the Kafka message value for messages produced by the sink: `avro`, `json`, `text`, or `bytes`.",
1505            ),
1506            (
1507                "cluster_id",
1508                "The ID of the cluster maintaining the sink. Corresponds to `mz_clusters.id`.",
1509            ),
1510            (
1511                "owner_id",
1512                "The role ID of the owner of the sink. Corresponds to `mz_roles.id`.",
1513            ),
1514            ("create_sql", "The `CREATE` SQL statement for the sink."),
1515            (
1516                "redacted_create_sql",
1517                "The redacted `CREATE` SQL statement for the sink.",
1518            ),
1519        ]),
1520        sql: "
1521IN CLUSTER mz_catalog_server
1522WITH (
1523    ASSERT NOT NULL id,
1524    ASSERT NOT NULL oid,
1525    ASSERT NOT NULL schema_id,
1526    ASSERT NOT NULL name,
1527    ASSERT NOT NULL type,
1528    ASSERT NOT NULL cluster_id,
1529    ASSERT NOT NULL owner_id,
1530    ASSERT NOT NULL create_sql,
1531    ASSERT NOT NULL redacted_create_sql
1532) AS
1533SELECT
1534    mz_internal.parse_catalog_id(data->'key'->'gid') AS id,
1535    (data->'value'->>'oid')::oid AS oid,
1536    mz_internal.parse_catalog_id(data->'value'->'schema_id') AS schema_id,
1537    data->'value'->>'name' AS name,
1538    parsed->>'sink_type' AS type,
1539    parsed->>'connection_id' AS connection_id,
1540    NULL::text AS size,
1541    parsed->>'envelope_type' AS envelope_type,
1542    parsed->>'format' AS format,
1543    parsed->>'key_format' AS key_format,
1544    parsed->>'value_format' AS value_format,
1545    parsed->>'cluster_id' AS cluster_id,
1546    mz_internal.parse_catalog_id(data->'value'->'owner_id') AS owner_id,
1547    data->'value'->'definition'->'V1'->>'create_sql' AS create_sql,
1548    mz_internal.redact_sql(data->'value'->'definition'->'V1'->>'create_sql') AS redacted_create_sql
1549FROM
1550    mz_internal.mz_catalog_raw
1551    CROSS JOIN LATERAL (
1552        SELECT mz_internal.parse_catalog_create_sql(data->'value'->'definition'->'V1'->>'create_sql')
1553    ) AS l(parsed)
1554WHERE
1555    data->>'kind' = 'Item' AND
1556    parsed->>'type' = 'sink'",
1557        is_retained_metrics_object: true,
1558        access: vec![PUBLIC_SELECT],
1559        ontology: Some(Ontology {
1560            entity_name: "sink",
1561            description: "An export of data from Materialize to an external system",
1562            links: &const {
1563                [
1564                    OntologyLink {
1565                        name: "in_schema",
1566                        target: "schema",
1567                        properties: LinkProperties::fk("schema_id", "id", Cardinality::ManyToOne),
1568                    },
1569                    OntologyLink {
1570                        name: "owned_by",
1571                        target: "role",
1572                        properties: LinkProperties::fk("owner_id", "id", Cardinality::ManyToOne),
1573                    },
1574                    OntologyLink {
1575                        name: "runs_on_cluster",
1576                        target: "cluster",
1577                        properties: LinkProperties::fk("cluster_id", "id", Cardinality::ManyToOne),
1578                    },
1579                    OntologyLink {
1580                        name: "uses_connection",
1581                        target: "connection",
1582                        properties: LinkProperties::fk_nullable(
1583                            "connection_id",
1584                            "id",
1585                            Cardinality::ManyToOne,
1586                        ),
1587                    },
1588                ]
1589            },
1590            column_semantic_types: &const {
1591                [
1592                    ("id", SemanticType::CatalogItemId),
1593                    ("oid", SemanticType::OID),
1594                    ("schema_id", SemanticType::SchemaId),
1595                    ("connection_id", SemanticType::CatalogItemId),
1596                    ("cluster_id", SemanticType::ClusterId),
1597                    ("owner_id", SemanticType::RoleId),
1598                    ("create_sql", SemanticType::SqlDefinition),
1599                    ("redacted_create_sql", SemanticType::RedactedSqlDefinition),
1600                ]
1601            },
1602        }),
1603    }
1604});
1605pub static MZ_VIEWS: LazyLock<BuiltinMaterializedView> = LazyLock::new(|| {
1606    BuiltinMaterializedView {
1607    name: "mz_views",
1608    schema: MZ_CATALOG_SCHEMA,
1609    oid: oid::MV_MZ_VIEWS_OID,
1610    desc: RelationDesc::builder()
1611        .with_column("id", SqlScalarType::String.nullable(false))
1612        .with_column("oid", SqlScalarType::Oid.nullable(false))
1613        .with_column("schema_id", SqlScalarType::String.nullable(false))
1614        .with_column("name", SqlScalarType::String.nullable(false))
1615        .with_column("definition", SqlScalarType::String.nullable(false))
1616        .with_column("owner_id", SqlScalarType::String.nullable(false))
1617        .with_column(
1618            "privileges",
1619            SqlScalarType::Array(Box::new(SqlScalarType::MzAclItem)).nullable(false),
1620        )
1621        .with_column("create_sql", SqlScalarType::String.nullable(false))
1622        .with_column("redacted_create_sql", SqlScalarType::String.nullable(false))
1623        .with_key(vec![0])
1624        .with_key(vec![1])
1625        .finish(),
1626    column_comments: BTreeMap::from_iter([
1627        ("id", "Materialize's unique ID for the view."),
1628        ("oid", "A PostgreSQL-compatible OID for the view."),
1629        (
1630            "schema_id",
1631            "The ID of the schema to which the view belongs. Corresponds to `mz_schemas.id`.",
1632        ),
1633        ("name", "The name of the view."),
1634        ("definition", "The view definition (a `SELECT` query)."),
1635        (
1636            "owner_id",
1637            "The role ID of the owner of the view. Corresponds to `mz_roles.id`.",
1638        ),
1639        ("privileges", "The privileges belonging to the view."),
1640        ("create_sql", "The `CREATE` SQL statement for the view."),
1641        (
1642            "redacted_create_sql",
1643            "The redacted `CREATE` SQL statement for the view.",
1644        ),
1645    ]),
1646    // Temporary views live in a per-session temporary schema that has no
1647    // durable schema record. Their rows keep the temporary schema sentinel
1648    // "0" that the previous builtin-table implementation exposed.
1649    //
1650    // The generated `mz_builtin_*` views appear here with placeholder
1651    // definition and create SQL. See `make_builtin_views`.
1652    sql: Box::leak(format!("
1653IN CLUSTER mz_catalog_server
1654WITH (
1655    ASSERT NOT NULL id,
1656    ASSERT NOT NULL oid,
1657    ASSERT NOT NULL schema_id,
1658    ASSERT NOT NULL name,
1659    ASSERT NOT NULL definition,
1660    ASSERT NOT NULL owner_id,
1661    ASSERT NOT NULL privileges,
1662    ASSERT NOT NULL create_sql,
1663    ASSERT NOT NULL redacted_create_sql
1664) AS
1665WITH
1666    user_views AS (
1667        SELECT
1668            mz_internal.parse_catalog_id(data->'key'->'gid') AS id,
1669            (data->'value'->>'oid')::oid AS oid,
1670            CASE WHEN data->'value'->>'ephemeral_owner_session' IS NULL
1671                THEN mz_internal.parse_catalog_id(data->'value'->'schema_id')
1672                ELSE '0'
1673            END AS schema_id,
1674            data->'value'->>'name' AS name,
1675            mz_internal.parse_catalog_create_sql(data->'value'->'definition'->'V1'->>'create_sql')->>'definition' AS definition,
1676            mz_internal.parse_catalog_id(data->'value'->'owner_id') AS owner_id,
1677            mz_internal.parse_catalog_privileges(data->'value'->'privileges') AS privileges,
1678            data->'value'->'definition'->'V1'->>'create_sql' AS create_sql,
1679            mz_internal.redact_sql(data->'value'->'definition'->'V1'->>'create_sql') AS redacted_create_sql
1680        FROM mz_internal.mz_catalog_raw
1681        WHERE
1682            data->>'kind' = 'Item' AND
1683            mz_internal.parse_catalog_create_sql(data->'value'->'definition'->'V1'->>'create_sql')->>'type' = 'view'
1684    ),
1685    builtin_mappings AS (
1686        SELECT
1687            data->'key'->>'schema_name' AS schema_name,
1688            data->'key'->>'object_name' AS name,
1689            's' || (data->'value'->>'catalog_id') AS id
1690        FROM mz_internal.mz_catalog_raw
1691        WHERE
1692            data->>'kind' = 'GidMapping' AND
1693            data->'key'->>'object_type' = '4'
1694    ),
1695    builtin_views AS (
1696        SELECT
1697            m.id,
1698            v.oid,
1699            s.id AS schema_id,
1700            v.name,
1701            v.definition,
1702            '{MZ_SYSTEM_ROLE_ID}' AS owner_id,
1703            v.privileges,
1704            v.create_sql,
1705            mz_internal.redact_sql(v.create_sql) AS redacted_create_sql
1706        FROM mz_internal.mz_builtin_views v
1707        JOIN builtin_mappings m USING (schema_name, name)
1708        JOIN mz_schemas s ON s.name = v.schema_name
1709        WHERE s.database_id IS NULL
1710    )
1711SELECT * FROM user_views
1712UNION ALL
1713SELECT * FROM builtin_views").into_boxed_str()),
1714    is_retained_metrics_object: false,
1715    access: vec![PUBLIC_SELECT],
1716    ontology: Some(Ontology {
1717        entity_name: "view",
1718        description: "A non-materialized view defined by a SQL query",
1719        links: &const {
1720            [
1721                OntologyLink {
1722                    name: "in_schema",
1723                    target: "schema",
1724                    properties: LinkProperties::fk("schema_id", "id", Cardinality::ManyToOne),
1725                },
1726                OntologyLink {
1727                    name: "owned_by",
1728                    target: "role",
1729                    properties: LinkProperties::fk("owner_id", "id", Cardinality::ManyToOne),
1730                },
1731            ]
1732        },
1733        column_semantic_types: &const {
1734            [
1735                ("id", SemanticType::CatalogItemId),
1736                ("oid", SemanticType::OID),
1737                ("schema_id", SemanticType::SchemaId),
1738                ("definition", SemanticType::SqlDefinition),
1739                ("owner_id", SemanticType::RoleId),
1740                ("create_sql", SemanticType::SqlDefinition),
1741                ("redacted_create_sql", SemanticType::RedactedSqlDefinition),
1742            ]
1743        },
1744    }),
1745}
1746});
1747
1748pub static MZ_MATERIALIZED_VIEWS: LazyLock<BuiltinMaterializedView> = LazyLock::new(|| {
1749    BuiltinMaterializedView {
1750        name: "mz_materialized_views",
1751        schema: MZ_CATALOG_SCHEMA,
1752        oid: oid::MV_MZ_MATERIALIZED_VIEWS_OID,
1753        desc: RelationDesc::builder()
1754            .with_column("id", SqlScalarType::String.nullable(false))
1755            .with_column("oid", SqlScalarType::Oid.nullable(false))
1756            .with_column("schema_id", SqlScalarType::String.nullable(false))
1757            .with_column("name", SqlScalarType::String.nullable(false))
1758            .with_column("cluster_id", SqlScalarType::String.nullable(false))
1759            .with_column("definition", SqlScalarType::String.nullable(false))
1760            .with_column("owner_id", SqlScalarType::String.nullable(false))
1761            .with_column(
1762                "privileges",
1763                SqlScalarType::Array(Box::new(SqlScalarType::MzAclItem)).nullable(false),
1764            )
1765            .with_column("create_sql", SqlScalarType::String.nullable(false))
1766            .with_column("redacted_create_sql", SqlScalarType::String.nullable(false))
1767            .with_key(vec![0])
1768            .with_key(vec![1])
1769            .finish(),
1770        column_comments: BTreeMap::from_iter([
1771            ("id", "Materialize's unique ID for the materialized view."),
1772            (
1773                "oid",
1774                "A PostgreSQL-compatible OID for the materialized view.",
1775            ),
1776            (
1777                "schema_id",
1778                "The ID of the schema to which the materialized view belongs. Corresponds to `mz_schemas.id`.",
1779            ),
1780            ("name", "The name of the materialized view."),
1781            (
1782                "cluster_id",
1783                "The ID of the cluster maintaining the materialized view. Corresponds to `mz_clusters.id`.",
1784            ),
1785            (
1786                "definition",
1787                "The materialized view definition (a `SELECT` query).",
1788            ),
1789            (
1790                "owner_id",
1791                "The role ID of the owner of the materialized view. Corresponds to `mz_roles.id`.",
1792            ),
1793            (
1794                "privileges",
1795                "The privileges belonging to the materialized view.",
1796            ),
1797            (
1798                "create_sql",
1799                "The `CREATE` SQL statement for the materialized view.",
1800            ),
1801            (
1802                "redacted_create_sql",
1803                "The redacted `CREATE` SQL statement for the materialized view.",
1804            ),
1805        ]),
1806        sql: Box::leak(format!("
1807IN CLUSTER mz_catalog_server
1808WITH (
1809    ASSERT NOT NULL id,
1810    ASSERT NOT NULL oid,
1811    ASSERT NOT NULL schema_id,
1812    ASSERT NOT NULL name,
1813    ASSERT NOT NULL cluster_id,
1814    ASSERT NOT NULL definition,
1815    ASSERT NOT NULL owner_id,
1816    ASSERT NOT NULL privileges,
1817    ASSERT NOT NULL create_sql,
1818    ASSERT NOT NULL redacted_create_sql
1819) AS
1820WITH
1821    user_mvs AS (
1822        SELECT
1823            mz_internal.parse_catalog_id(data->'key'->'gid') AS id,
1824            (data->'value'->>'oid')::oid AS oid,
1825            mz_internal.parse_catalog_id(data->'value'->'schema_id') AS schema_id,
1826            data->'value'->>'name' AS name,
1827            mz_internal.parse_catalog_create_sql(data->'value'->'definition'->'V1'->>'create_sql')->>'cluster_id' AS cluster_id,
1828            mz_internal.parse_catalog_create_sql(data->'value'->'definition'->'V1'->>'create_sql')->>'definition' AS definition,
1829            mz_internal.parse_catalog_id(data->'value'->'owner_id') AS owner_id,
1830            mz_internal.parse_catalog_privileges(data->'value'->'privileges') AS privileges,
1831            data->'value'->'definition'->'V1'->>'create_sql' AS create_sql,
1832            mz_internal.redact_sql(data->'value'->'definition'->'V1'->>'create_sql') AS redacted_create_sql
1833        FROM mz_internal.mz_catalog_raw
1834        WHERE
1835            data->>'kind' = 'Item' AND
1836            mz_internal.parse_catalog_create_sql(data->'value'->'definition'->'V1'->>'create_sql')->>'type' = 'materialized-view'
1837    ),
1838    builtin_mappings AS (
1839        SELECT
1840            data->'key'->>'schema_name' AS schema_name,
1841            data->'key'->>'object_name' AS name,
1842            's' || (data->'value'->>'catalog_id') AS id
1843        FROM mz_internal.mz_catalog_raw
1844        WHERE
1845            data->>'kind' = 'GidMapping' AND
1846            data->'key'->>'object_type' = '5'
1847    ),
1848    builtin_mvs AS (
1849        SELECT
1850            m.id,
1851            mv.oid,
1852            s.id AS schema_id,
1853            mv.name,
1854            c.id AS cluster_id,
1855            mv.definition,
1856            '{MZ_SYSTEM_ROLE_ID}' AS owner_id,
1857            mv.privileges,
1858            mv.create_sql,
1859            mz_internal.redact_sql(mv.create_sql) AS redacted_create_sql
1860        FROM mz_internal.mz_builtin_materialized_views mv
1861        JOIN builtin_mappings m USING (schema_name, name)
1862        JOIN mz_schemas s ON s.name = mv.schema_name
1863        JOIN mz_clusters c ON c.name = mv.cluster_name
1864        WHERE s.database_id IS NULL
1865    )
1866SELECT * FROM user_mvs
1867UNION ALL
1868SELECT * FROM builtin_mvs").into_boxed_str()),
1869        is_retained_metrics_object: false,
1870        access: vec![PUBLIC_SELECT],
1871        ontology: Some(Ontology {
1872            entity_name: "mv",
1873            description: "A materialized view maintained incrementally on a cluster",
1874            links: &const { [
1875                OntologyLink { name: "in_schema", target: "schema", properties: LinkProperties::fk("schema_id", "id", Cardinality::ManyToOne) },
1876                OntologyLink { name: "owned_by", target: "role", properties: LinkProperties::fk("owner_id", "id", Cardinality::ManyToOne) },
1877                OntologyLink { name: "runs_on_cluster", target: "cluster", properties: LinkProperties::fk("cluster_id", "id", Cardinality::ManyToOne) },
1878            ] },
1879            column_semantic_types: &const {[("id", SemanticType::CatalogItemId), ("oid", SemanticType::OID), ("schema_id", SemanticType::SchemaId), ("cluster_id", SemanticType::ClusterId), ("definition", SemanticType::SqlDefinition), ("owner_id", SemanticType::RoleId), ("create_sql", SemanticType::SqlDefinition), ("redacted_create_sql", SemanticType::RedactedSqlDefinition)]},
1880        }),
1881    }
1882});
1883pub static MZ_TYPES: LazyLock<BuiltinTable> = LazyLock::new(|| BuiltinTable {
1884    name: "mz_types",
1885    schema: MZ_CATALOG_SCHEMA,
1886    oid: oid::TABLE_MZ_TYPES_OID,
1887    desc: RelationDesc::builder()
1888        .with_column("id", SqlScalarType::String.nullable(false))
1889        .with_column("oid", SqlScalarType::Oid.nullable(false))
1890        .with_column("schema_id", SqlScalarType::String.nullable(false))
1891        .with_column("name", SqlScalarType::String.nullable(false))
1892        .with_column("category", SqlScalarType::String.nullable(false))
1893        .with_column("owner_id", SqlScalarType::String.nullable(false))
1894        .with_column(
1895            "privileges",
1896            SqlScalarType::Array(Box::new(SqlScalarType::MzAclItem)).nullable(false),
1897        )
1898        .with_column("create_sql", SqlScalarType::String.nullable(true))
1899        .with_column("redacted_create_sql", SqlScalarType::String.nullable(true))
1900        .with_key(vec![0])
1901        .with_key(vec![1])
1902        .finish(),
1903    column_comments: BTreeMap::from_iter([
1904        ("id", "Materialize's unique ID for the type."),
1905        ("oid", "A PostgreSQL-compatible OID for the type."),
1906        (
1907            "schema_id",
1908            "The ID of the schema to which the type belongs. Corresponds to `mz_schemas.id`.",
1909        ),
1910        ("name", "The name of the type."),
1911        ("category", "The category of the type."),
1912        (
1913            "owner_id",
1914            "The role ID of the owner of the type. Corresponds to `mz_roles.id`.",
1915        ),
1916        ("privileges", "The privileges belonging to the type."),
1917        ("create_sql", "The `CREATE` SQL statement for the type."),
1918        (
1919            "redacted_create_sql",
1920            "The redacted `CREATE` SQL statement for the type.",
1921        ),
1922    ]),
1923    is_retained_metrics_object: false,
1924    access: vec![PUBLIC_SELECT],
1925    ontology: Some(Ontology {
1926        entity_name: "type",
1927        description: "A named data type (base, array, list, map, or pseudo)",
1928        links: &const {
1929            [
1930                OntologyLink {
1931                    name: "in_schema",
1932                    target: "schema",
1933                    properties: LinkProperties::fk("schema_id", "id", Cardinality::ManyToOne),
1934                },
1935                OntologyLink {
1936                    name: "owned_by",
1937                    target: "role",
1938                    properties: LinkProperties::fk("owner_id", "id", Cardinality::ManyToOne),
1939                },
1940            ]
1941        },
1942        column_semantic_types: &const {
1943            [
1944                ("id", SemanticType::CatalogItemId),
1945                ("oid", SemanticType::OID),
1946                ("schema_id", SemanticType::SchemaId),
1947                ("owner_id", SemanticType::RoleId),
1948                ("create_sql", SemanticType::SqlDefinition),
1949                ("redacted_create_sql", SemanticType::RedactedSqlDefinition),
1950            ]
1951        },
1952    }),
1953});
1954pub static MZ_ARRAY_TYPES: LazyLock<BuiltinTable> = LazyLock::new(|| BuiltinTable {
1955    name: "mz_array_types",
1956    schema: MZ_CATALOG_SCHEMA,
1957    oid: oid::TABLE_MZ_ARRAY_TYPES_OID,
1958    desc: RelationDesc::builder()
1959        .with_column("id", SqlScalarType::String.nullable(false))
1960        .with_column("element_id", SqlScalarType::String.nullable(false))
1961        .finish(),
1962    column_comments: BTreeMap::from_iter([
1963        ("id", "The ID of the array type."),
1964        ("element_id", "The ID of the array's element type."),
1965    ]),
1966    is_retained_metrics_object: false,
1967    access: vec![PUBLIC_SELECT],
1968    ontology: Some(Ontology {
1969        entity_name: "array_type",
1970        description: "An array type with its element type",
1971        links: &const {
1972            [
1973                OntologyLink {
1974                    name: "detail_of",
1975                    target: "type",
1976                    properties: LinkProperties::fk("id", "id", Cardinality::OneToOne),
1977                },
1978                OntologyLink {
1979                    name: "has_element_type",
1980                    target: "type",
1981                    properties: LinkProperties::fk("element_id", "id", Cardinality::ManyToOne),
1982                },
1983            ]
1984        },
1985        column_semantic_types: &const {
1986            [
1987                ("id", SemanticType::CatalogItemId),
1988                ("element_id", SemanticType::CatalogItemId),
1989            ]
1990        },
1991    }),
1992});
1993pub static MZ_BASE_TYPES: LazyLock<BuiltinTable> = LazyLock::new(|| BuiltinTable {
1994    name: "mz_base_types",
1995    schema: MZ_CATALOG_SCHEMA,
1996    oid: oid::TABLE_MZ_BASE_TYPES_OID,
1997    desc: RelationDesc::builder()
1998        .with_column("id", SqlScalarType::String.nullable(false))
1999        .finish(),
2000    column_comments: BTreeMap::from_iter([("id", "The ID of the type.")]),
2001    is_retained_metrics_object: false,
2002    access: vec![PUBLIC_SELECT],
2003    ontology: Some(Ontology {
2004        entity_name: "base_type",
2005        description: "A primitive/base data type",
2006        links: &const { [] },
2007        column_semantic_types: &[("id", SemanticType::CatalogItemId)],
2008    }),
2009});
2010pub static MZ_LIST_TYPES: LazyLock<BuiltinTable> = LazyLock::new(|| BuiltinTable {
2011    name: "mz_list_types",
2012    schema: MZ_CATALOG_SCHEMA,
2013    oid: oid::TABLE_MZ_LIST_TYPES_OID,
2014    desc: RelationDesc::builder()
2015        .with_column("id", SqlScalarType::String.nullable(false))
2016        .with_column("element_id", SqlScalarType::String.nullable(false))
2017        .with_column(
2018            "element_modifiers",
2019            SqlScalarType::List {
2020                element_type: Box::new(SqlScalarType::Int64),
2021                custom_id: None,
2022            }
2023            .nullable(true),
2024        )
2025        .finish(),
2026    column_comments: BTreeMap::from_iter([
2027        ("id", "The ID of the list type."),
2028        ("element_id", "The IID of the list's element type."),
2029        (
2030            "element_modifiers",
2031            "The element type modifiers, or `NULL` if none.",
2032        ),
2033    ]),
2034    is_retained_metrics_object: false,
2035    access: vec![PUBLIC_SELECT],
2036    ontology: Some(Ontology {
2037        entity_name: "list_type",
2038        description: "A list type with its element type",
2039        links: &const {
2040            [
2041                OntologyLink {
2042                    name: "detail_of",
2043                    target: "type",
2044                    properties: LinkProperties::fk("id", "id", Cardinality::OneToOne),
2045                },
2046                OntologyLink {
2047                    name: "has_element_type",
2048                    target: "type",
2049                    properties: LinkProperties::fk("element_id", "id", Cardinality::ManyToOne),
2050                },
2051            ]
2052        },
2053        column_semantic_types: &const {
2054            [
2055                ("id", SemanticType::CatalogItemId),
2056                ("element_id", SemanticType::CatalogItemId),
2057            ]
2058        },
2059    }),
2060});
2061pub static MZ_MAP_TYPES: LazyLock<BuiltinTable> = LazyLock::new(|| BuiltinTable {
2062    name: "mz_map_types",
2063    schema: MZ_CATALOG_SCHEMA,
2064    oid: oid::TABLE_MZ_MAP_TYPES_OID,
2065    desc: RelationDesc::builder()
2066        .with_column("id", SqlScalarType::String.nullable(false))
2067        .with_column("key_id", SqlScalarType::String.nullable(false))
2068        .with_column("value_id", SqlScalarType::String.nullable(false))
2069        .with_column(
2070            "key_modifiers",
2071            SqlScalarType::List {
2072                element_type: Box::new(SqlScalarType::Int64),
2073                custom_id: None,
2074            }
2075            .nullable(true),
2076        )
2077        .with_column(
2078            "value_modifiers",
2079            SqlScalarType::List {
2080                element_type: Box::new(SqlScalarType::Int64),
2081                custom_id: None,
2082            }
2083            .nullable(true),
2084        )
2085        .finish(),
2086    column_comments: BTreeMap::from_iter([
2087        ("id", "The ID of the map type."),
2088        ("key_id", "The ID of the map's key type."),
2089        ("value_id", "The ID of the map's value type."),
2090        (
2091            "key_modifiers",
2092            "The key type modifiers, or `NULL` if none.",
2093        ),
2094        (
2095            "value_modifiers",
2096            "The value type modifiers, or `NULL` if none.",
2097        ),
2098    ]),
2099    is_retained_metrics_object: false,
2100    access: vec![PUBLIC_SELECT],
2101    ontology: Some(Ontology {
2102        entity_name: "map_type",
2103        description: "A map type with its key and value types",
2104        links: &const {
2105            [
2106                OntologyLink {
2107                    name: "detail_of",
2108                    target: "type",
2109                    properties: LinkProperties::fk("id", "id", Cardinality::OneToOne),
2110                },
2111                OntologyLink {
2112                    name: "has_key_type",
2113                    target: "type",
2114                    properties: LinkProperties::fk("key_id", "id", Cardinality::ManyToOne),
2115                },
2116                OntologyLink {
2117                    name: "has_value_type",
2118                    target: "type",
2119                    properties: LinkProperties::fk("value_id", "id", Cardinality::ManyToOne),
2120                },
2121            ]
2122        },
2123        column_semantic_types: &const {
2124            [
2125                ("id", SemanticType::CatalogItemId),
2126                ("key_id", SemanticType::CatalogItemId),
2127                ("value_id", SemanticType::CatalogItemId),
2128            ]
2129        },
2130    }),
2131});
2132pub static MZ_ROLES: LazyLock<BuiltinMaterializedView> = LazyLock::new(|| {
2133    // The two built-in super-roles are identified by name; their names live as
2134    // compile-time constants in `mz_sql::session::user`, so we interpolate to
2135    // keep the SQL in sync with the Rust definition.
2136    let sql = format!(
2137        "
2138IN CLUSTER mz_catalog_server
2139WITH (
2140    ASSERT NOT NULL id,
2141    ASSERT NOT NULL oid,
2142    ASSERT NOT NULL name,
2143    ASSERT NOT NULL inherit
2144) AS
2145SELECT
2146    mz_internal.parse_catalog_id(data->'key'->'id') AS id,
2147    (data->'value'->>'oid')::oid AS oid,
2148    data->'value'->>'name' AS name,
2149    (data->'value'->'attributes'->>'inherit')::bool AS inherit,
2150    COALESCE(
2151        (data->'value'->'attributes'->>'login')::bool,
2152        data->'value'->>'name' IN ('{system}', '{support}')
2153    ) AS rolcanlogin,
2154    COALESCE(
2155        (data->'value'->'attributes'->>'superuser')::bool,
2156        CASE WHEN data->'value'->>'name' IN ('{system}', '{support}') THEN true END
2157    ) AS rolsuper
2158FROM mz_internal.mz_catalog_raw
2159WHERE data->>'kind' = 'Role' AND data->'key'->'id' != '\"Public\"'::jsonb",
2160        system = SYSTEM_USER_NAME,
2161        support = SUPPORT_USER_NAME,
2162    );
2163
2164    BuiltinMaterializedView {
2165        name: "mz_roles",
2166        schema: MZ_CATALOG_SCHEMA,
2167        oid: oid::MV_MZ_ROLES_OID,
2168        desc: RelationDesc::builder()
2169            .with_column("id", SqlScalarType::String.nullable(false))
2170            .with_column("oid", SqlScalarType::Oid.nullable(false))
2171            .with_column("name", SqlScalarType::String.nullable(false))
2172            .with_column("inherit", SqlScalarType::Bool.nullable(false))
2173            .with_column("rolcanlogin", SqlScalarType::Bool.nullable(true))
2174            .with_column("rolsuper", SqlScalarType::Bool.nullable(true))
2175            .with_key(vec![0])
2176            .with_key(vec![1])
2177            .finish(),
2178        column_comments: BTreeMap::from_iter([
2179            ("id", "Materialize's unique ID for the role."),
2180            ("oid", "A PostgreSQL-compatible OID for the role."),
2181            ("name", "The name of the role."),
2182            (
2183                "inherit",
2184                "Indicates whether the role has inheritance of privileges.",
2185            ),
2186            ("rolcanlogin", "Indicates whether the role can log in."),
2187            ("rolsuper", "Indicates whether the role is a superuser."),
2188        ]),
2189        sql: Box::leak(sql.into_boxed_str()),
2190        is_retained_metrics_object: false,
2191        access: vec![PUBLIC_SELECT],
2192        ontology: Some(Ontology {
2193            entity_name: "role",
2194            description: "A user or role for authentication and access control",
2195            links: &const { [] },
2196            column_semantic_types: &const { [("id", SemanticType::RoleId), ("oid", SemanticType::OID)] },
2197        }),
2198    }
2199});
2200
2201pub static MZ_ROLE_MEMBERS: LazyLock<BuiltinMaterializedView> = LazyLock::new(|| {
2202    BuiltinMaterializedView {
2203        name: "mz_role_members",
2204        schema: MZ_CATALOG_SCHEMA,
2205        oid: oid::MV_MZ_ROLE_MEMBERS_OID,
2206        desc: RelationDesc::builder()
2207            .with_column("role_id", SqlScalarType::String.nullable(false))
2208            .with_column("member", SqlScalarType::String.nullable(false))
2209            .with_column("grantor", SqlScalarType::String.nullable(false))
2210            .finish(),
2211        column_comments: BTreeMap::from_iter([
2212            (
2213                "role_id",
2214                "The ID of the role the `member` is a member of. Corresponds to `mz_roles.id`.",
2215            ),
2216            (
2217                "member",
2218                "The ID of the role that is a member of `role_id`. Corresponds to `mz_roles.id`.",
2219            ),
2220            (
2221                "grantor",
2222                "The ID of the role that granted membership of `member` to `role_id`. Corresponds to `mz_roles.id`.",
2223            ),
2224        ]),
2225        sql: "
2226IN CLUSTER mz_catalog_server
2227WITH (
2228    ASSERT NOT NULL role_id,
2229    ASSERT NOT NULL member,
2230    ASSERT NOT NULL grantor
2231) AS
2232SELECT
2233    mz_internal.parse_catalog_id(entry->'key') AS role_id,
2234    mz_internal.parse_catalog_id(data->'key'->'id') AS member,
2235    mz_internal.parse_catalog_id(entry->'value') AS grantor
2236FROM
2237    mz_internal.mz_catalog_raw,
2238    jsonb_array_elements(data->'value'->'membership'->'map') AS entry
2239WHERE data->>'kind' = 'Role'",
2240        is_retained_metrics_object: false,
2241        access: vec![PUBLIC_SELECT],
2242        ontology: Some(Ontology {
2243            entity_name: "role_membership",
2244            description: "A membership grant: one role is a member of another role",
2245            links: &const {
2246                [
2247                    OntologyLink {
2248                        name: "group_role",
2249                        target: "role",
2250                        properties: LinkProperties::fk("role_id", "id", Cardinality::ManyToOne),
2251                    },
2252                    OntologyLink {
2253                        name: "member_role",
2254                        target: "role",
2255                        properties: LinkProperties::fk("member", "id", Cardinality::ManyToOne),
2256                    },
2257                    OntologyLink {
2258                        name: "granted_by",
2259                        target: "role",
2260                        properties: LinkProperties::fk("grantor", "id", Cardinality::ManyToOne),
2261                    },
2262                ]
2263            },
2264            column_semantic_types: &const {
2265                [
2266                    ("role_id", SemanticType::RoleId),
2267                    ("member", SemanticType::RoleId),
2268                    ("grantor", SemanticType::RoleId),
2269                ]
2270            },
2271        }),
2272    }
2273});
2274
2275pub static MZ_ROLE_PARAMETERS: LazyLock<BuiltinMaterializedView> = LazyLock::new(|| {
2276    BuiltinMaterializedView {
2277        name: "mz_role_parameters",
2278        schema: MZ_CATALOG_SCHEMA,
2279        oid: oid::MV_MZ_ROLE_PARAMETERS_OID,
2280        desc: RelationDesc::builder()
2281            .with_column("role_id", SqlScalarType::String.nullable(false))
2282            .with_column("parameter_name", SqlScalarType::String.nullable(false))
2283            .with_column("parameter_value", SqlScalarType::String.nullable(false))
2284            .finish(),
2285        column_comments: BTreeMap::from_iter([
2286            (
2287                "role_id",
2288                "The ID of the role whose configuration parameter default is set. Corresponds to `mz_roles.id`.",
2289            ),
2290            (
2291                "parameter_name",
2292                "The configuration parameter name. One of the supported configuration parameters.",
2293            ),
2294            (
2295                "parameter_value",
2296                "The default value of the parameter for the given role. Can be either a single value, or a comma-separated list of values for configuration parameters that accept a list.",
2297            ),
2298        ]),
2299        sql: "
2300IN CLUSTER mz_catalog_server
2301WITH (
2302    ASSERT NOT NULL role_id,
2303    ASSERT NOT NULL parameter_name,
2304    ASSERT NOT NULL parameter_value
2305) AS
2306SELECT
2307    mz_internal.parse_catalog_id(data->'key'->'id') AS role_id,
2308    entry->>'key' AS parameter_name,
2309    CASE
2310        WHEN entry->'val' ? 'Flat' THEN entry->'val'->>'Flat'
2311        ELSE (
2312            SELECT pg_catalog.string_agg(t.elem, ', ' ORDER BY t.ord)
2313            FROM jsonb_array_elements_text(entry->'val'->'SqlSet')
2314                WITH ORDINALITY AS t(elem, ord)
2315        )
2316    END AS parameter_value
2317FROM
2318    mz_internal.mz_catalog_raw,
2319    jsonb_array_elements(data->'value'->'vars'->'entries') AS entry
2320WHERE data->>'kind' = 'Role'",
2321        is_retained_metrics_object: false,
2322        access: vec![PUBLIC_SELECT],
2323        ontology: Some(Ontology {
2324            entity_name: "role_parameter",
2325            description: "A session parameter default set for a role",
2326            links: &const {
2327                [OntologyLink {
2328                    name: "default_parameter_setting_of",
2329                    target: "role",
2330                    properties: LinkProperties::fk("role_id", "id", Cardinality::ManyToOne),
2331                }]
2332            },
2333            column_semantic_types: &[("role_id", SemanticType::RoleId)],
2334        }),
2335    }
2336});
2337pub static MZ_ROLE_AUTH: LazyLock<BuiltinTable> = LazyLock::new(|| BuiltinTable {
2338    name: "mz_role_auth",
2339    schema: MZ_CATALOG_SCHEMA,
2340    oid: oid::TABLE_MZ_ROLE_AUTH_OID,
2341    desc: RelationDesc::builder()
2342        .with_column("role_id", SqlScalarType::String.nullable(false))
2343        .with_column("role_oid", SqlScalarType::Oid.nullable(false))
2344        .with_column("password_hash", SqlScalarType::String.nullable(true))
2345        .with_column(
2346            "updated_at",
2347            SqlScalarType::TimestampTz { precision: None }.nullable(false),
2348        )
2349        .finish(),
2350    column_comments: BTreeMap::from_iter([
2351        (
2352            "role_id",
2353            "The ID of the role. Corresponds to `mz_roles.id`.",
2354        ),
2355        ("role_oid", "A PostgreSQL-compatible OID for the role."),
2356        (
2357            "password_hash",
2358            "The hashed password for the role, if any. Uses the `SCRAM-SHA-256` algorithm.",
2359        ),
2360        (
2361            "updated_at",
2362            "The time at which the password was last updated.",
2363        ),
2364    ]),
2365    is_retained_metrics_object: false,
2366    access: vec![rbac::owner_privilege(ObjectType::Table, MZ_SYSTEM_ROLE_ID)],
2367    ontology: None,
2368});
2369pub static MZ_PSEUDO_TYPES: LazyLock<BuiltinTable> = LazyLock::new(|| BuiltinTable {
2370    name: "mz_pseudo_types",
2371    schema: MZ_CATALOG_SCHEMA,
2372    oid: oid::TABLE_MZ_PSEUDO_TYPES_OID,
2373    desc: RelationDesc::builder()
2374        .with_column("id", SqlScalarType::String.nullable(false))
2375        .finish(),
2376    column_comments: BTreeMap::from_iter([("id", "The ID of the type.")]),
2377    is_retained_metrics_object: false,
2378    access: vec![PUBLIC_SELECT],
2379    ontology: Some(Ontology {
2380        entity_name: "pseudo_type",
2381        description: "A pseudo-type used in function signatures",
2382        links: &const { [] },
2383        column_semantic_types: &[("id", SemanticType::CatalogItemId)],
2384    }),
2385});
2386pub static MZ_FUNCTIONS: LazyLock<BuiltinTable> = LazyLock::new(|| {
2387    BuiltinTable {
2388        name: "mz_functions",
2389        schema: MZ_CATALOG_SCHEMA,
2390        oid: oid::TABLE_MZ_FUNCTIONS_OID,
2391        desc: RelationDesc::builder()
2392            .with_column("id", SqlScalarType::String.nullable(false)) // not a key!
2393            .with_column("oid", SqlScalarType::Oid.nullable(false))
2394            .with_column("schema_id", SqlScalarType::String.nullable(false))
2395            .with_column("name", SqlScalarType::String.nullable(false))
2396            .with_column(
2397                "argument_type_ids",
2398                SqlScalarType::Array(Box::new(SqlScalarType::String)).nullable(false),
2399            )
2400            .with_column(
2401                "variadic_argument_type_id",
2402                SqlScalarType::String.nullable(true),
2403            )
2404            .with_column("return_type_id", SqlScalarType::String.nullable(true))
2405            .with_column("returns_set", SqlScalarType::Bool.nullable(false))
2406            .with_column("owner_id", SqlScalarType::String.nullable(false))
2407            .finish(),
2408        column_comments: BTreeMap::from_iter([
2409            ("id", "Materialize's unique ID for the function."),
2410            ("oid", "A PostgreSQL-compatible OID for the function."),
2411            (
2412                "schema_id",
2413                "The ID of the schema to which the function belongs. Corresponds to `mz_schemas.id`.",
2414            ),
2415            ("name", "The name of the function."),
2416            (
2417                "argument_type_ids",
2418                "The ID of each argument's type. Each entry refers to `mz_types.id`.",
2419            ),
2420            (
2421                "variadic_argument_type_id",
2422                "The ID of the variadic argument's type, or `NULL` if the function does not have a variadic argument. Refers to `mz_types.id`.",
2423            ),
2424            (
2425                "return_type_id",
2426                "The returned value's type, or `NULL` if the function does not return a value. Refers to `mz_types.id`. Note that for table functions with > 1 column, this type corresponds to [`record`].",
2427            ),
2428            (
2429                "returns_set",
2430                "Whether the function returns a set, i.e. the function is a table function.",
2431            ),
2432            (
2433                "owner_id",
2434                "The role ID of the owner of the function. Corresponds to `mz_roles.id`.",
2435            ),
2436        ]),
2437        is_retained_metrics_object: false,
2438        access: vec![PUBLIC_SELECT],
2439        ontology: Some(Ontology {
2440            entity_name: "function",
2441            description: "A built-in or user-defined function",
2442            links: &const {
2443                [
2444                    OntologyLink {
2445                        name: "in_schema",
2446                        target: "schema",
2447                        properties: LinkProperties::fk("schema_id", "id", Cardinality::ManyToOne),
2448                    },
2449                    OntologyLink {
2450                        name: "owned_by",
2451                        target: "role",
2452                        properties: LinkProperties::fk("owner_id", "id", Cardinality::ManyToOne),
2453                    },
2454                    OntologyLink {
2455                        name: "returns_type",
2456                        target: "type",
2457                        properties: LinkProperties::fk_nullable(
2458                            "return_type_id",
2459                            "id",
2460                            Cardinality::ManyToOne,
2461                        ),
2462                    },
2463                    OntologyLink {
2464                        name: "has_variadic_arg_type",
2465                        target: "type",
2466                        properties: LinkProperties::fk_nullable(
2467                            "variadic_argument_type_id",
2468                            "id",
2469                            Cardinality::ManyToOne,
2470                        ),
2471                    },
2472                ]
2473            },
2474            column_semantic_types: &const {
2475                [
2476                    ("id", SemanticType::CatalogItemId),
2477                    ("oid", SemanticType::OID),
2478                    ("schema_id", SemanticType::SchemaId),
2479                    ("variadic_argument_type_id", SemanticType::CatalogItemId),
2480                    ("return_type_id", SemanticType::CatalogItemId),
2481                    ("owner_id", SemanticType::RoleId),
2482                ]
2483            },
2484        }),
2485    }
2486});
2487pub static MZ_OPERATORS: LazyLock<BuiltinTable> = LazyLock::new(|| BuiltinTable {
2488    name: "mz_operators",
2489    schema: MZ_CATALOG_SCHEMA,
2490    oid: oid::TABLE_MZ_OPERATORS_OID,
2491    desc: RelationDesc::builder()
2492        .with_column("oid", SqlScalarType::Oid.nullable(false))
2493        .with_column("name", SqlScalarType::String.nullable(false))
2494        .with_column(
2495            "argument_type_ids",
2496            SqlScalarType::Array(Box::new(SqlScalarType::String)).nullable(false),
2497        )
2498        .with_column("return_type_id", SqlScalarType::String.nullable(true))
2499        .finish(),
2500    column_comments: BTreeMap::new(),
2501    is_retained_metrics_object: false,
2502    access: vec![PUBLIC_SELECT],
2503    ontology: Some(Ontology {
2504        entity_name: "operator",
2505        description: "A built-in SQL operator",
2506        links: &const {
2507            [OntologyLink {
2508                name: "returns_type",
2509                target: "type",
2510                properties: LinkProperties::fk_nullable(
2511                    "return_type_id",
2512                    "id",
2513                    Cardinality::ManyToOne,
2514                ),
2515            }]
2516        },
2517        column_semantic_types: &const {
2518            [
2519                ("oid", SemanticType::OID),
2520                ("return_type_id", SemanticType::CatalogItemId),
2521            ]
2522        },
2523    }),
2524});
2525
2526pub static MZ_CLUSTERS: LazyLock<BuiltinMaterializedView> = LazyLock::new(|| {
2527    BuiltinMaterializedView {
2528        name: "mz_clusters",
2529        schema: MZ_CATALOG_SCHEMA,
2530        oid: oid::MV_MZ_CLUSTERS_OID,
2531        desc: RelationDesc::builder()
2532            .with_column("id", SqlScalarType::String.nullable(false))
2533            .with_column("name", SqlScalarType::String.nullable(false))
2534            .with_column("owner_id", SqlScalarType::String.nullable(false))
2535            .with_column(
2536                "privileges",
2537                SqlScalarType::Array(Box::new(SqlScalarType::MzAclItem)).nullable(false),
2538            )
2539            .with_column("managed", SqlScalarType::Bool.nullable(false))
2540            .with_column("size", SqlScalarType::String.nullable(true))
2541            .with_column("replication_factor", SqlScalarType::UInt32.nullable(true))
2542            .with_column("disk", SqlScalarType::Bool.nullable(true))
2543            .with_column(
2544                "availability_zones",
2545                SqlScalarType::List {
2546                    element_type: Box::new(SqlScalarType::String),
2547                    custom_id: None,
2548                }
2549                .nullable(true),
2550            )
2551            .with_column(
2552                "introspection_debugging",
2553                SqlScalarType::Bool.nullable(true),
2554            )
2555            .with_column(
2556                "introspection_interval",
2557                SqlScalarType::Interval.nullable(true),
2558            )
2559            .with_key(vec![0])
2560            .finish(),
2561        column_comments: BTreeMap::from_iter([
2562            ("id", "Materialize's unique ID for the cluster."),
2563            ("name", "The name of the cluster."),
2564            (
2565                "owner_id",
2566                "The role ID of the owner of the cluster. Corresponds to `mz_roles.id`.",
2567            ),
2568            ("privileges", "The privileges belonging to the cluster."),
2569            (
2570                "managed",
2571                "Whether the cluster is a managed cluster with automatically managed replicas.",
2572            ),
2573            (
2574                "size",
2575                "If the cluster is managed, the desired size of the cluster's replicas. `NULL` for unmanaged clusters.",
2576            ),
2577            (
2578                "replication_factor",
2579                "If the cluster is managed, the desired number of replicas of the cluster. `NULL` for unmanaged clusters.",
2580            ),
2581            (
2582                "disk",
2583                "**Unstable** If the cluster is managed, `true` if the replicas have the `DISK` option . `NULL` for unmanaged clusters.",
2584            ),
2585            (
2586                "availability_zones",
2587                "**Unstable** If the cluster is managed, the list of availability zones specified in `AVAILABILITY ZONES`. `NULL` for unmanaged clusters.",
2588            ),
2589            (
2590                "introspection_debugging",
2591                "Whether introspection of the gathering of the introspection data is enabled.",
2592            ),
2593            (
2594                "introspection_interval",
2595                "The interval at which to collect introspection data.",
2596            ),
2597        ]),
2598        // `config.variant` is a serde-tagged enum: `"Unmanaged"` (bare string)
2599        // or `{"Managed": {...}}`. Managed-only fields (size, replication_factor,
2600        // availability_zones, logging, schedule) live under `Managed`, and
2601        // resolve to NULL for unmanaged clusters.
2602        //
2603        // `disk` is computed as in
2604        // `CatalogState::cluster_replica_size_has_disk`:
2605        // `NOT swap_enabled AND disk_bytes != 0`. Both flags are sourced from
2606        // `mz_internal.mz_cluster_replica_size_internal`, which the catalog
2607        // populates for every size — including ones flagged `disabled`, which
2608        // the public `mz_cluster_replica_sizes` table omits. Using the internal
2609        // table directly preserves the prior behavior of indexing the in-memory
2610        // size map regardless of `disabled`.
2611        //
2612        // `availability_zones` is normalised to NULL when empty, matching
2613        // `pack_cluster_update`'s `None` for an empty `Vec`. `list_agg` over
2614        // `jsonb_array_elements_text WITH ORDINALITY` preserves the configured
2615        // order, matching the prior `push_list` of the `Vec`.
2616        //
2617        // `introspection_interval` is a Duration `{secs, nanos}` in the JSON;
2618        // we compose a string and cast to interval because Materialize has no
2619        // `make_interval`.
2620        //
2621        // The `kind = 'Cluster'` filter is pushed into a subquery on
2622        // `mz_catalog_raw` by hand. database-issues/8495 keeps the optimizer
2623        // from pushing a top-level `WHERE` below the LEFT JOIN, so without the
2624        // subquery the join scans the entire raw catalog.
2625        sql: "
2626IN CLUSTER mz_catalog_server
2627WITH (
2628    ASSERT NOT NULL id,
2629    ASSERT NOT NULL name,
2630    ASSERT NOT NULL owner_id,
2631    ASSERT NOT NULL privileges,
2632    ASSERT NOT NULL managed
2633) AS
2634SELECT
2635    mz_internal.parse_catalog_id(data->'key'->'id') AS id,
2636    data->'value'->>'name' AS name,
2637    mz_internal.parse_catalog_id(data->'value'->'owner_id') AS owner_id,
2638    mz_internal.parse_catalog_privileges(data->'value'->'privileges') AS privileges,
2639    jsonb_typeof(data->'value'->'config'->'variant') = 'object' AS managed,
2640    data->'value'->'config'->'variant'->'Managed'->>'size' AS size,
2641    (data->'value'->'config'->'variant'->'Managed'->>'replication_factor')::uint4 AS replication_factor,
2642    CASE
2643        WHEN jsonb_typeof(data->'value'->'config'->'variant') = 'object' THEN
2644            NOT COALESCE(internal.swap_enabled, false)
2645            AND COALESCE(internal.disk_bytes, 0) != 0
2646    END AS disk,
2647    CASE
2648        WHEN jsonb_array_length(data->'value'->'config'->'variant'->'Managed'->'availability_zones') > 0 THEN
2649            (
2650                SELECT mz_catalog.list_agg(az.value ORDER BY az.ord)
2651                FROM jsonb_array_elements_text(data->'value'->'config'->'variant'->'Managed'->'availability_zones')
2652                     WITH ORDINALITY AS az(value, ord)
2653            )
2654    END AS availability_zones,
2655    (data->'value'->'config'->'variant'->'Managed'->'logging'->>'log_logging')::bool AS introspection_debugging,
2656    CASE
2657        WHEN data->'value'->'config'->'variant'->'Managed'->'logging'->'interval' != 'null'::jsonb THEN
2658            (
2659                (data->'value'->'config'->'variant'->'Managed'->'logging'->'interval'->>'secs')
2660                || ' seconds '
2661                || ((data->'value'->'config'->'variant'->'Managed'->'logging'->'interval'->>'nanos')::bigint / 1000)::text
2662                || ' microseconds'
2663            )::interval
2664    END AS introspection_interval
2665FROM (
2666    SELECT data FROM mz_internal.mz_catalog_raw WHERE data->>'kind' = 'Cluster'
2667) raw
2668LEFT JOIN mz_internal.mz_cluster_replica_size_internal internal
2669    ON internal.size = data->'value'->'config'->'variant'->'Managed'->>'size'",
2670        is_retained_metrics_object: false,
2671        access: vec![PUBLIC_SELECT],
2672        ontology: Some(Ontology {
2673            entity_name: "cluster",
2674            description: "A compute cluster that runs dataflows for sources, sinks, MVs, and indexes",
2675            links: &const {
2676                [
2677                    OntologyLink {
2678                        name: "owned_by",
2679                        target: "role",
2680                        properties: LinkProperties::fk("owner_id", "id", Cardinality::ManyToOne),
2681                    },
2682                    OntologyLink {
2683                        name: "has_size",
2684                        target: "replica_size",
2685                        properties: LinkProperties::fk_nullable("size", "size", Cardinality::ManyToOne),
2686                    },
2687                ]
2688            },
2689            column_semantic_types: &const {
2690                [
2691                    ("id", SemanticType::ClusterId),
2692                    ("owner_id", SemanticType::RoleId),
2693                ]
2694            },
2695        }),
2696    }
2697});
2698
2699pub static MZ_SECRETS: LazyLock<BuiltinMaterializedView> = LazyLock::new(|| {
2700    BuiltinMaterializedView {
2701        name: "mz_secrets",
2702        schema: MZ_CATALOG_SCHEMA,
2703        oid: oid::MV_MZ_SECRETS_OID,
2704        desc: RelationDesc::builder()
2705            .with_column("id", SqlScalarType::String.nullable(false))
2706            .with_column("oid", SqlScalarType::Oid.nullable(false))
2707            .with_column("schema_id", SqlScalarType::String.nullable(false))
2708            .with_column("name", SqlScalarType::String.nullable(false))
2709            .with_column("owner_id", SqlScalarType::String.nullable(false))
2710            .with_column(
2711                "privileges",
2712                SqlScalarType::Array(Box::new(SqlScalarType::MzAclItem)).nullable(false),
2713            )
2714            .finish(),
2715        column_comments: BTreeMap::from_iter([
2716            ("id", "The unique ID of the secret."),
2717            ("oid", "A PostgreSQL-compatible oid for the secret."),
2718            (
2719                "schema_id",
2720                "The ID of the schema to which the secret belongs. Corresponds to `mz_schemas.id`.",
2721            ),
2722            ("name", "The name of the secret."),
2723            (
2724                "owner_id",
2725                "The role ID of the owner of the secret. Corresponds to `mz_roles.id`.",
2726            ),
2727            ("privileges", "The privileges belonging to the secret."),
2728        ]),
2729        sql: "
2730IN CLUSTER mz_catalog_server
2731WITH (
2732    ASSERT NOT NULL id,
2733    ASSERT NOT NULL oid,
2734    ASSERT NOT NULL schema_id,
2735    ASSERT NOT NULL name,
2736    ASSERT NOT NULL owner_id,
2737    ASSERT NOT NULL privileges
2738) AS
2739SELECT
2740    mz_internal.parse_catalog_id(data->'key'->'gid') AS id,
2741    (data->'value'->>'oid')::oid AS oid,
2742    mz_internal.parse_catalog_id(data->'value'->'schema_id') AS schema_id,
2743    data->'value'->>'name' AS name,
2744    mz_internal.parse_catalog_id(data->'value'->'owner_id') AS owner_id,
2745    mz_internal.parse_catalog_privileges(data->'value'->'privileges') AS privileges
2746FROM mz_internal.mz_catalog_raw
2747WHERE
2748    data->>'kind' = 'Item' AND
2749    mz_internal.parse_catalog_create_sql(data->'value'->'definition'->'V1'->>'create_sql')->>'type' = 'secret'",
2750        is_retained_metrics_object: false,
2751        access: vec![PUBLIC_SELECT],
2752        ontology: Some(Ontology {
2753            entity_name: "secret",
2754            description: "A user-defined secret containing sensitive configuration (e.g., credentials)",
2755            links: &const { [
2756                OntologyLink {
2757                    name: "in_schema",
2758                    target: "schema",
2759                    properties: LinkProperties::fk("schema_id", "id", Cardinality::ManyToOne),
2760                },
2761                OntologyLink {
2762                    name: "owned_by",
2763                    target: "role",
2764                    properties: LinkProperties::fk("owner_id", "id", Cardinality::ManyToOne),
2765                },
2766            ] },
2767            column_semantic_types: &const {[("id", SemanticType::CatalogItemId), ("oid", SemanticType::OID), ("schema_id", SemanticType::SchemaId), ("owner_id", SemanticType::RoleId)]},
2768        }),
2769    }
2770});
2771
2772pub static MZ_CLUSTER_REPLICAS: LazyLock<BuiltinMaterializedView> = LazyLock::new(|| {
2773    BuiltinMaterializedView {
2774        name: "mz_cluster_replicas",
2775        schema: MZ_CATALOG_SCHEMA,
2776        oid: oid::MV_MZ_CLUSTER_REPLICAS_OID,
2777        desc: RelationDesc::builder()
2778            .with_column("id", SqlScalarType::String.nullable(false))
2779            .with_column("name", SqlScalarType::String.nullable(false))
2780            .with_column("cluster_id", SqlScalarType::String.nullable(false))
2781            .with_column("size", SqlScalarType::String.nullable(true))
2782            // `NULL` for un-orchestrated clusters and for replicas where the user
2783            // hasn't specified them.
2784            .with_column("availability_zone", SqlScalarType::String.nullable(true))
2785            .with_column("owner_id", SqlScalarType::String.nullable(false))
2786            .with_column("disk", SqlScalarType::Bool.nullable(true))
2787            .with_key(vec![0])
2788            .finish(),
2789        column_comments: BTreeMap::from_iter([
2790            ("id", "Materialize's unique ID for the cluster replica."),
2791            ("name", "The name of the cluster replica."),
2792            (
2793                "cluster_id",
2794                "The ID of the cluster to which the replica belongs. Corresponds to `mz_clusters.id`.",
2795            ),
2796            (
2797                "size",
2798                "The cluster replica's size, selected during creation.",
2799            ),
2800            (
2801                "availability_zone",
2802                "The availability zones the replica is provisioned in, comma-separated. `NULL` if nothing constrains the replica's placement.",
2803            ),
2804            (
2805                "owner_id",
2806                "The role ID of the owner of the cluster replica. Corresponds to `mz_roles.id`.",
2807            ),
2808            ("disk", "If the replica has a local disk."),
2809        ]),
2810        // `config.location` is a serde-tagged enum: `{"Unmanaged": {...}}` or
2811        // `{"Managed": {...}}`. For replicas with an unmanaged location all
2812        // orchestrator-facing fields (size, availability_zone, disk) are NULL.
2813        //
2814        // `availability_zone` surfaces the durable `Managed` location's
2815        // `availability_zones` list as a comma-separated string in stored
2816        // order. For a managed cluster that is the provisioned AVAILABILITY
2817        // ZONES pool. For an unmanaged cluster it is the single AVAILABILITY
2818        // ZONE pin. An empty list (nothing constrains placement) maps to NULL,
2819        // matching the list-to-NULL normalization the `mz_clusters`
2820        // `availability_zones` column uses.
2821        //
2822        // `disk` mirrors `cluster_replica_size_has_disk`, joining
2823        // `mz_cluster_replica_size_internal` for both `swap_enabled` and
2824        // `disk_bytes`. The catalog populates that table for every size
2825        // (including ones flagged `disabled`), so a managed replica pinned to
2826        // a disabled size still resolves correctly. If a row is somehow
2827        // missing, the COALESCEs resolve `disk` to `false` (treating an
2828        // unknown size as having no disk), not NULL.
2829        //
2830        // The `kind = 'ClusterReplica'` filter is pushed into a subquery on
2831        // `mz_catalog_raw` by hand. database-issues/8495 keeps the optimizer
2832        // from pushing a top-level `WHERE` below the LEFT JOIN.
2833        sql: "
2834IN CLUSTER mz_catalog_server
2835WITH (
2836    ASSERT NOT NULL id,
2837    ASSERT NOT NULL name,
2838    ASSERT NOT NULL cluster_id,
2839    ASSERT NOT NULL owner_id
2840) AS
2841SELECT
2842    mz_internal.parse_catalog_id(data->'key'->'id') AS id,
2843    data->'value'->>'name' AS name,
2844    mz_internal.parse_catalog_id(data->'value'->'cluster_id') AS cluster_id,
2845    data->'value'->'config'->'location'->'Managed'->>'size' AS size,
2846    CASE
2847        WHEN jsonb_array_length(data->'value'->'config'->'location'->'Managed'->'availability_zones') > 0 THEN
2848            (
2849                SELECT pg_catalog.string_agg(az.value, ',' ORDER BY az.ord)
2850                FROM jsonb_array_elements_text(data->'value'->'config'->'location'->'Managed'->'availability_zones')
2851                     WITH ORDINALITY AS az(value, ord)
2852            )
2853    END AS availability_zone,
2854    mz_internal.parse_catalog_id(data->'value'->'owner_id') AS owner_id,
2855    CASE
2856        WHEN data->'value'->'config'->'location' ? 'Managed' THEN
2857            NOT COALESCE(internal.swap_enabled, false)
2858            AND COALESCE(internal.disk_bytes, 0) != 0
2859    END AS disk
2860FROM (
2861    SELECT data FROM mz_internal.mz_catalog_raw WHERE data->>'kind' = 'ClusterReplica'
2862) raw
2863LEFT JOIN mz_internal.mz_cluster_replica_size_internal internal
2864    ON internal.size = data->'value'->'config'->'location'->'Managed'->>'size'",
2865        is_retained_metrics_object: true,
2866        access: vec![PUBLIC_SELECT],
2867        ontology: Some(Ontology {
2868            entity_name: "replica",
2869            description: "A physical replica of a cluster providing fault tolerance",
2870            links: &const {
2871                [
2872                    OntologyLink {
2873                        name: "owned_by",
2874                        target: "role",
2875                        properties: LinkProperties::fk("owner_id", "id", Cardinality::ManyToOne),
2876                    },
2877                    OntologyLink {
2878                        name: "belongs_to_cluster",
2879                        target: "cluster",
2880                        properties: LinkProperties::fk("cluster_id", "id", Cardinality::ManyToOne),
2881                    },
2882                    OntologyLink {
2883                        name: "has_size",
2884                        target: "replica_size",
2885                        properties: LinkProperties::fk_nullable(
2886                            "size",
2887                            "size",
2888                            Cardinality::ManyToOne,
2889                        ),
2890                    },
2891                ]
2892            },
2893            column_semantic_types: &const {
2894                [
2895                    ("id", SemanticType::ReplicaId),
2896                    ("cluster_id", SemanticType::ClusterId),
2897                    ("owner_id", SemanticType::RoleId),
2898                ]
2899            },
2900        }),
2901    }
2902});
2903
2904pub static MZ_CLUSTER_REPLICA_SIZES: LazyLock<BuiltinTable> = LazyLock::new(|| BuiltinTable {
2905    name: "mz_cluster_replica_sizes",
2906    schema: MZ_CATALOG_SCHEMA,
2907    oid: oid::TABLE_MZ_CLUSTER_REPLICA_SIZES_OID,
2908    desc: RelationDesc::builder()
2909        .with_column("size", SqlScalarType::String.nullable(false))
2910        .with_column("processes", SqlScalarType::UInt64.nullable(false))
2911        .with_column("workers", SqlScalarType::UInt64.nullable(false))
2912        .with_column("cpu_nano_cores", SqlScalarType::UInt64.nullable(false))
2913        .with_column("memory_bytes", SqlScalarType::UInt64.nullable(false))
2914        .with_column("disk_bytes", SqlScalarType::UInt64.nullable(true))
2915        .with_column(
2916            "credits_per_hour",
2917            SqlScalarType::Numeric { max_scale: None }.nullable(false),
2918        )
2919        .finish(),
2920    column_comments: BTreeMap::from_iter([
2921        ("size", "The human-readable replica size."),
2922        ("processes", "The number of processes in the replica."),
2923        (
2924            "workers",
2925            "The number of Timely Dataflow workers per process.",
2926        ),
2927        (
2928            "cpu_nano_cores",
2929            "The CPU allocation per process, in billionths of a vCPU core.",
2930        ),
2931        ("memory_bytes", "The RAM allocation per process, in bytes."),
2932        ("disk_bytes", "The disk allocation per process."),
2933        (
2934            "credits_per_hour",
2935            "The number of compute credits consumed per hour.",
2936        ),
2937    ]),
2938    is_retained_metrics_object: true,
2939    access: vec![PUBLIC_SELECT],
2940    ontology: Some(Ontology {
2941        entity_name: "replica_size",
2942        description: "Available cluster replica sizes with CPU, memory, and credit cost",
2943        links: &const { [] },
2944        column_semantic_types: &const {
2945            [
2946                ("memory_bytes", SemanticType::ByteCount),
2947                ("disk_bytes", SemanticType::ByteCount),
2948                ("credits_per_hour", SemanticType::CreditRate),
2949            ]
2950        },
2951    }),
2952});
2953
2954pub static MZ_AUDIT_EVENTS: LazyLock<BuiltinMaterializedView> = LazyLock::new(|| {
2955    BuiltinMaterializedView {
2956        name: "mz_audit_events",
2957        schema: MZ_CATALOG_SCHEMA,
2958        oid: oid::MV_MZ_AUDIT_EVENTS_OID,
2959        desc: RelationDesc::builder()
2960            .with_column("id", SqlScalarType::UInt64.nullable(false))
2961            .with_column("event_type", SqlScalarType::String.nullable(false))
2962            .with_column("object_type", SqlScalarType::String.nullable(false))
2963            .with_column("details", SqlScalarType::Jsonb.nullable(false))
2964            .with_column("user", SqlScalarType::String.nullable(true))
2965            .with_column(
2966                "occurred_at",
2967                SqlScalarType::TimestampTz { precision: None }.nullable(false),
2968            )
2969            .with_key(vec![0])
2970            .finish(),
2971        column_comments: BTreeMap::from_iter([
2972            (
2973                "id",
2974                "Materialize's unique, monotonically increasing ID for the event.",
2975            ),
2976            (
2977                "event_type",
2978                "The type of the event: `create`, `drop`, `alter`, `grant`, `revoke`, or `comment`.",
2979            ),
2980            (
2981                "object_type",
2982                "The type of the affected object: `cluster`, `cluster-replica`, `connection`, `continual-task`, `database`, `func`, `index`, `materialized-view`, `metric-sink`, `network-policy`, `role`, `schema`, `secret`, `sink`, `source`, `system`, `table`, `type`, or `view`.",
2983            ),
2984            (
2985                "details",
2986                "Additional details about the event. The shape of the details varies based on `event_type` and `object_type`.",
2987            ),
2988            (
2989                "user",
2990                "The user who triggered the event, or `NULL` if triggered by the system.",
2991            ),
2992            (
2993                "occurred_at",
2994                "The time at which the event occurred. Guaranteed to be in order of event creation. Events created in the same transaction will have identical values.",
2995            ),
2996        ]),
2997        // `event_type` and `object_type` are stored in `mz_catalog_raw` as the
2998        // numeric `Serialize_repr` of `proto::audit_log_event_v1::{EventType,
2999        // ObjectType}`. The CASE expressions map them to the kebab strings
3000        // that `audit_log::{EventType, ObjectType}`'s Display impls produce.
3001        //
3002        // `event` is `AuditLogEvent::V1(AuditLogEventV1)`, externally tagged,
3003        // so we reach through `key.event.V1` for the inner struct.
3004        //
3005        // `user` is `Option<StringWrapper>`: JSON null when absent, otherwise
3006        // `{"inner": "<name>"}`. `->'user'->>'inner'` collapses both to a
3007        // PostgreSQL NULL or the text.
3008        //
3009        // `details` in `mz_catalog_raw` is the externally-tagged proto
3010        // `Details` enum. `parse_catalog_audit_log_details` reshapes it into
3011        // `audit_log::EventDetails::as_json`'s output, the format the prior
3012        // BuiltinTable populator wrote. See that function's docstring and
3013        // the round-trip test in `src/catalog/tests/audit_log_details.rs`.
3014        //
3015        // `occurred_at` is `EpochMillis` (u64). Dividing by 1000.0 and feeding
3016        // to `to_timestamp` matches `mz_ore::now::to_datetime`'s round-trip
3017        // through `chrono::DateTime::from_timestamp_millis`.
3018        sql: "
3019IN CLUSTER mz_catalog_server
3020WITH (
3021    ASSERT NOT NULL id,
3022    ASSERT NOT NULL event_type,
3023    ASSERT NOT NULL object_type,
3024    ASSERT NOT NULL details,
3025    ASSERT NOT NULL occurred_at
3026) AS
3027WITH ev AS (
3028    SELECT data->'key'->'event'->'V1' AS e
3029    FROM mz_internal.mz_catalog_raw
3030    WHERE data->>'kind' = 'AuditLog'
3031)
3032SELECT
3033    (e->>'id')::uint8                                                       AS id,
3034    CASE (e->>'event_type')
3035        WHEN '1' THEN 'create'
3036        WHEN '2' THEN 'drop'
3037        WHEN '3' THEN 'alter'
3038        WHEN '4' THEN 'grant'
3039        WHEN '5' THEN 'revoke'
3040        WHEN '6' THEN 'comment'
3041    END                                                                     AS event_type,
3042    CASE (e->>'object_type')
3043        WHEN '1'  THEN 'cluster'
3044        WHEN '2'  THEN 'cluster-replica'
3045        WHEN '3'  THEN 'connection'
3046        WHEN '4'  THEN 'database'
3047        WHEN '5'  THEN 'func'
3048        WHEN '6'  THEN 'index'
3049        WHEN '7'  THEN 'materialized-view'
3050        WHEN '8'  THEN 'role'
3051        WHEN '9'  THEN 'secret'
3052        WHEN '10' THEN 'schema'
3053        WHEN '11' THEN 'sink'
3054        WHEN '12' THEN 'source'
3055        WHEN '13' THEN 'table'
3056        WHEN '14' THEN 'type'
3057        WHEN '15' THEN 'view'
3058        WHEN '16' THEN 'system'
3059        WHEN '17' THEN 'continual-task'
3060        WHEN '18' THEN 'network-policy'
3061        WHEN '19' THEN 'metric-sink'
3062    END                                                                     AS object_type,
3063    mz_internal.parse_catalog_audit_log_details(e->'details')               AS details,
3064    e->'user'->>'inner'                                                     AS \"user\",
3065    -- `occurred_at` is serialized by `proto::EpochMillis` as
3066    -- `{\"millis\": <u64>}`; reach through `'millis'` to get the integer.
3067    to_timestamp(((e->'occurred_at'->>'millis')::float8) / 1000.0)          AS occurred_at
3068FROM ev",
3069        is_retained_metrics_object: false,
3070        access: vec![PUBLIC_SELECT],
3071        ontology: Some(Ontology {
3072            entity_name: "audit_event",
3073            description: "An audit log entry recording a DDL operation",
3074            links: &const { [] },
3075            column_semantic_types: &const {
3076                [
3077                    ("object_type", SemanticType::ObjectType),
3078                    ("occurred_at", SemanticType::WallclockTimestamp),
3079                ]
3080            },
3081        }),
3082    }
3083});
3084
3085pub static MZ_EGRESS_IPS: LazyLock<BuiltinTable> = LazyLock::new(|| BuiltinTable {
3086    name: "mz_egress_ips",
3087    schema: MZ_CATALOG_SCHEMA,
3088    oid: oid::TABLE_MZ_EGRESS_IPS_OID,
3089    desc: RelationDesc::builder()
3090        .with_column("egress_ip", SqlScalarType::String.nullable(false))
3091        .with_column("prefix_length", SqlScalarType::Int32.nullable(false))
3092        .with_column("cidr", SqlScalarType::String.nullable(false))
3093        .finish(),
3094    column_comments: BTreeMap::from_iter([
3095        ("egress_ip", "The start of the range of IP addresses."),
3096        (
3097            "prefix_length",
3098            "The number of leading bits in the CIDR netmask.",
3099        ),
3100        ("cidr", "The CIDR representation."),
3101    ]),
3102    is_retained_metrics_object: false,
3103    access: vec![PUBLIC_SELECT],
3104    ontology: Some(Ontology {
3105        entity_name: "egress_ip",
3106        description: "IP addresses used for outbound connections from Materialize",
3107        links: &const { [] },
3108        column_semantic_types: &[],
3109    }),
3110});
3111
3112// The privatelink principal is entirely context-derived (there is nothing to
3113// parse out of create_sql), so this view selects the aws-privatelink
3114// connections and reconstructs the principal ARN from the plan-time AWS context
3115// functions. `principal` is NOT NULL and the removed packer emitted no row when
3116// the AWS principal context was absent. A view cannot skip a row, but the
3117// context functions fold to NULL without the context, so `WHERE principal IS
3118// NOT NULL` reproduces that skip (zero rows on envs without the context).
3119pub static MZ_AWS_PRIVATELINK_CONNECTIONS: LazyLock<BuiltinMaterializedView> =
3120    LazyLock::new(|| {
3121        BuiltinMaterializedView {
3122            name: "mz_aws_privatelink_connections",
3123            schema: MZ_CATALOG_SCHEMA,
3124            oid: oid::MV_MZ_AWS_PRIVATELINK_CONNECTIONS_OID,
3125            desc: RelationDesc::builder()
3126                .with_column("id", SqlScalarType::String.nullable(false))
3127                .with_column("principal", SqlScalarType::String.nullable(false))
3128                .with_key(vec![0])
3129                .finish(),
3130            column_comments: BTreeMap::from_iter([
3131                ("id", "The ID of the connection."),
3132                (
3133                    "principal",
3134                    "The AWS Principal that Materialize will use to connect to the VPC endpoint.",
3135                ),
3136            ]),
3137            // `principal` reproduces `AwsPrincipalContext::to_principal_string` in
3138            // src/catalog/src/config.rs. Keep the two in sync.
3139            sql: "
3140IN CLUSTER mz_catalog_server
3141WITH (
3142    ASSERT NOT NULL id,
3143    ASSERT NOT NULL principal
3144) AS
3145SELECT id, principal FROM (
3146    SELECT
3147        mz_internal.parse_catalog_id(r.data->'key'->'gid') AS id,
3148        'arn:aws:iam::' || mz_aws_account_id() || ':role/mz_'
3149            || mz_aws_external_id_prefix() || '_'
3150            || mz_internal.parse_catalog_id(r.data->'key'->'gid') AS principal
3151    FROM mz_internal.mz_catalog_raw r
3152    WHERE
3153        r.data->>'kind' = 'Item' AND
3154        mz_internal.parse_catalog_create_sql(
3155            r.data->'value'->'definition'->'V1'->>'create_sql')->>'connection_type'
3156                = 'aws-privatelink'
3157)
3158WHERE principal IS NOT NULL",
3159            is_retained_metrics_object: false,
3160            access: vec![PUBLIC_SELECT],
3161            ontology: Some(Ontology {
3162                entity_name: "aws_privatelink_connection",
3163                description: "AWS PrivateLink connection configuration",
3164                links: &const {
3165                    [OntologyLink {
3166                        name: "details_of",
3167                        target: "connection",
3168                        properties: LinkProperties::fk("id", "id", Cardinality::OneToOne),
3169                    }]
3170                },
3171                column_semantic_types: &[("id", SemanticType::CatalogItemId)],
3172            }),
3173        }
3174    });
3175
3176pub static MZ_CLUSTER_REPLICA_FRONTIERS: LazyLock<BuiltinSource> =
3177    LazyLock::new(|| BuiltinSource {
3178        name: "mz_cluster_replica_frontiers",
3179        schema: MZ_CATALOG_SCHEMA,
3180        oid: oid::SOURCE_MZ_CLUSTER_REPLICA_FRONTIERS_OID,
3181        data_source: IntrospectionType::ReplicaFrontiers.into(),
3182        desc: RelationDesc::builder()
3183            .with_column("object_id", SqlScalarType::String.nullable(false))
3184            .with_column("replica_id", SqlScalarType::String.nullable(false))
3185            .with_column("write_frontier", SqlScalarType::MzTimestamp.nullable(true))
3186            .finish(),
3187        column_comments: BTreeMap::from_iter([
3188            (
3189                "object_id",
3190                "The ID of the source, sink, index, materialized view, or subscription.",
3191            ),
3192            ("replica_id", "The ID of a cluster replica."),
3193            (
3194                "write_frontier",
3195                "The next timestamp at which the output may change.",
3196            ),
3197        ]),
3198        is_retained_metrics_object: false,
3199        access: vec![PUBLIC_SELECT],
3200        ontology: None,
3201    });
3202
3203pub static MZ_CLUSTER_REPLICA_FRONTIERS_IND: LazyLock<BuiltinIndex> =
3204    LazyLock::new(|| BuiltinIndex {
3205        name: "mz_cluster_replica_frontiers_ind",
3206        schema: MZ_CATALOG_SCHEMA,
3207        oid: oid::INDEX_MZ_CLUSTER_REPLICA_FRONTIERS_IND_OID,
3208        sql: "IN CLUSTER mz_catalog_server ON mz_catalog.mz_cluster_replica_frontiers (object_id)",
3209        is_retained_metrics_object: false,
3210    });
3211
3212pub static MZ_DEFAULT_PRIVILEGES: LazyLock<BuiltinMaterializedView> = LazyLock::new(|| {
3213    BuiltinMaterializedView {
3214        name: "mz_default_privileges",
3215        schema: MZ_CATALOG_SCHEMA,
3216        oid: oid::MV_MZ_DEFAULT_PRIVILEGES_OID,
3217        desc: RelationDesc::builder()
3218            .with_column("role_id", SqlScalarType::String.nullable(false))
3219            .with_column("database_id", SqlScalarType::String.nullable(true))
3220            .with_column("schema_id", SqlScalarType::String.nullable(true))
3221            .with_column("object_type", SqlScalarType::String.nullable(false))
3222            .with_column("grantee", SqlScalarType::String.nullable(false))
3223            .with_column("privileges", SqlScalarType::String.nullable(false))
3224            .finish(),
3225        column_comments: BTreeMap::from_iter([
3226            (
3227                "role_id",
3228                "Privileges described in this row will be granted on objects created by `role_id`. The role ID `p` stands for the `PUBLIC` pseudo-role and applies to all roles.",
3229            ),
3230            (
3231                "database_id",
3232                "Privileges described in this row will be granted only on objects in the database identified by `database_id` if non-null.",
3233            ),
3234            (
3235                "schema_id",
3236                "Privileges described in this row will be granted only on objects in the schema identified by `schema_id` if non-null.",
3237            ),
3238            (
3239                "object_type",
3240                "Privileges described in this row will be granted only on objects of type `object_type`.",
3241            ),
3242            (
3243                "grantee",
3244                "Privileges described in this row will be granted to `grantee`. The role ID `p` stands for the `PUBLIC` pseudo-role and applies to all roles.",
3245            ),
3246            ("privileges", "The set of privileges that will be granted."),
3247        ]),
3248        // `object_type` in `mz_catalog_raw` is the numeric `Serialize_repr` form
3249        // of `mz_catalog_protos::ObjectType`. The CASE mirrors
3250        // `mz_sql::catalog::ObjectType`'s `Display` impl, lowercased, matching
3251        // the prior `pack_default_privileges_update` populator. Variant `16` is
3252        // reserved/unused; any new proto variant must add a branch here. The
3253        // `object_type_case_matches_proto_display` test in this crate checks
3254        // the mapping.
3255        sql: "
3256IN CLUSTER mz_catalog_server
3257WITH (
3258    ASSERT NOT NULL role_id,
3259    ASSERT NOT NULL object_type,
3260    ASSERT NOT NULL grantee,
3261    ASSERT NOT NULL privileges
3262) AS
3263SELECT
3264    mz_internal.parse_catalog_id(data->'key'->'role_id') AS role_id,
3265    CASE WHEN data->'key'->'database_id' != 'null'::jsonb
3266         THEN mz_internal.parse_catalog_id(data->'key'->'database_id') END AS database_id,
3267    CASE WHEN data->'key'->'schema_id' != 'null'::jsonb
3268         THEN mz_internal.parse_catalog_id(data->'key'->'schema_id') END AS schema_id,
3269    CASE data->'key'->>'object_type'
3270        WHEN '1'  THEN 'table'
3271        WHEN '2'  THEN 'view'
3272        WHEN '3'  THEN 'materialized view'
3273        WHEN '4'  THEN 'source'
3274        WHEN '5'  THEN 'sink'
3275        WHEN '6'  THEN 'index'
3276        WHEN '7'  THEN 'type'
3277        WHEN '8'  THEN 'role'
3278        WHEN '9'  THEN 'cluster'
3279        WHEN '10' THEN 'cluster replica'
3280        WHEN '11' THEN 'secret'
3281        WHEN '12' THEN 'connection'
3282        WHEN '13' THEN 'database'
3283        WHEN '14' THEN 'schema'
3284        WHEN '15' THEN 'function'
3285        -- variant 16 reserved/unused in mz_catalog_protos::ObjectType.
3286        WHEN '17' THEN 'network policy'
3287    END AS object_type,
3288    mz_internal.parse_catalog_id(data->'key'->'grantee') AS grantee,
3289    mz_internal.parse_catalog_acl_mode(data->'value'->'privileges') AS privileges
3290FROM mz_internal.mz_catalog_raw
3291WHERE data->>'kind' = 'DefaultPrivileges'",
3292        is_retained_metrics_object: false,
3293        access: vec![PUBLIC_SELECT],
3294        ontology: Some(Ontology {
3295            entity_name: "default_privilege",
3296            description: "A default privilege rule applied to newly created objects",
3297            links: &const {
3298                [
3299                    OntologyLink {
3300                        name: "default_priv_for_role",
3301                        target: "role",
3302                        properties: LinkProperties::fk("role_id", "id", Cardinality::ManyToOne),
3303                    },
3304                    OntologyLink {
3305                        name: "default_priv_in_database",
3306                        target: "database",
3307                        properties: LinkProperties::fk_nullable(
3308                            "database_id",
3309                            "id",
3310                            Cardinality::ManyToOne,
3311                        ),
3312                    },
3313                    OntologyLink {
3314                        name: "default_priv_in_schema",
3315                        target: "schema",
3316                        properties: LinkProperties::fk_nullable(
3317                            "schema_id",
3318                            "id",
3319                            Cardinality::ManyToOne,
3320                        ),
3321                    },
3322                    OntologyLink {
3323                        name: "default_priv_granted_to",
3324                        target: "role",
3325                        properties: LinkProperties::fk("grantee", "id", Cardinality::ManyToOne),
3326                    },
3327                ]
3328            },
3329            column_semantic_types: &const {
3330                [
3331                    ("role_id", SemanticType::RoleId),
3332                    ("database_id", SemanticType::DatabaseId),
3333                    ("schema_id", SemanticType::SchemaId),
3334                    ("object_type", SemanticType::ObjectType),
3335                    ("grantee", SemanticType::RoleId),
3336                ]
3337            },
3338        }),
3339    }
3340});
3341
3342pub static MZ_SYSTEM_PRIVILEGES: LazyLock<BuiltinMaterializedView> = LazyLock::new(|| {
3343    BuiltinMaterializedView {
3344        name: "mz_system_privileges",
3345        schema: MZ_CATALOG_SCHEMA,
3346        oid: oid::MV_MZ_SYSTEM_PRIVILEGES_OID,
3347        desc: RelationDesc::builder()
3348            .with_column("privileges", SqlScalarType::MzAclItem.nullable(false))
3349            .finish(),
3350        column_comments: BTreeMap::from_iter([(
3351            "privileges",
3352            "The privileges belonging to the system.",
3353        )]),
3354        // The durable row holds `(grantee, grantor, acl_mode)`; we rebuild the
3355        // single-element JSON shape that `parse_catalog_privileges` expects and
3356        // unnest it to recover the `mz_aclitem`.
3357        sql: "
3358IN CLUSTER mz_catalog_server
3359WITH (
3360    ASSERT NOT NULL privileges
3361) AS
3362SELECT
3363    unnest(mz_internal.parse_catalog_privileges(
3364        jsonb_build_array(
3365            jsonb_build_object(
3366                'grantee',  data->'key'->'grantee',
3367                'grantor',  data->'key'->'grantor',
3368                'acl_mode', data->'value'->'acl_mode'
3369            )
3370        )
3371    )) AS privileges
3372FROM mz_internal.mz_catalog_raw
3373WHERE data->>'kind' = 'SystemPrivileges'",
3374        is_retained_metrics_object: false,
3375        access: vec![PUBLIC_SELECT],
3376        ontology: Some(Ontology {
3377            entity_name: "system_privilege",
3378            description: "A system-level privilege grant",
3379            links: &const { [] },
3380            column_semantic_types: &[],
3381        }),
3382    }
3383});
3384
3385pub static MZ_STORAGE_USAGE: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
3386    name: "mz_storage_usage",
3387    schema: MZ_CATALOG_SCHEMA,
3388    oid: oid::VIEW_MZ_STORAGE_USAGE_OID,
3389    desc: RelationDesc::builder()
3390        .with_column("object_id", SqlScalarType::String.nullable(false))
3391        .with_column("size_bytes", SqlScalarType::UInt64.nullable(false))
3392        .with_column(
3393            "collection_timestamp",
3394            SqlScalarType::TimestampTz { precision: None }.nullable(false),
3395        )
3396        .with_key(vec![0, 2])
3397        .finish(),
3398    column_comments: BTreeMap::from_iter([
3399        (
3400            "object_id",
3401            "The ID of the table, source, or materialized view.",
3402        ),
3403        (
3404            "size_bytes",
3405            "The number of storage bytes used by the object.",
3406        ),
3407        (
3408            "collection_timestamp",
3409            "The time at which storage usage of the object was assessed.",
3410        ),
3411    ]),
3412    sql: "
3413SELECT
3414    object_id,
3415    sum(size_bytes)::uint8 AS size_bytes,
3416    collection_timestamp
3417FROM
3418    mz_internal.mz_storage_shards
3419    JOIN mz_internal.mz_storage_usage_by_shard USING (shard_id)
3420GROUP BY object_id, collection_timestamp",
3421    access: vec![PUBLIC_SELECT],
3422    ontology: Some(Ontology {
3423        entity_name: "storage_usage",
3424        description: "Historical storage usage per object over time",
3425        links: &const {
3426            [OntologyLink {
3427                name: "storage_usage_of",
3428                target: "object",
3429                properties: LinkProperties::fk("object_id", "id", Cardinality::ManyToOne),
3430            }]
3431        },
3432        column_semantic_types: &const {
3433            [
3434                ("object_id", SemanticType::CatalogItemId),
3435                ("size_bytes", SemanticType::ByteCount),
3436                ("collection_timestamp", SemanticType::WallclockTimestamp),
3437            ]
3438        },
3439    }),
3440});
3441
3442pub static MZ_RECENT_STORAGE_USAGE: LazyLock<BuiltinView> = LazyLock::new(|| {
3443    BuiltinView {
3444    name: "mz_recent_storage_usage",
3445    schema: MZ_CATALOG_SCHEMA,
3446    oid: oid::VIEW_MZ_RECENT_STORAGE_USAGE_OID,
3447    desc: RelationDesc::builder()
3448        .with_column("object_id", SqlScalarType::String.nullable(false))
3449        .with_column("size_bytes", SqlScalarType::UInt64.nullable(true))
3450        .with_key(vec![0])
3451        .finish(),
3452    column_comments: BTreeMap::from_iter([
3453        ("object_id", "The ID of the table, source, or materialized view."),
3454        ("size_bytes", "The number of storage bytes used by the object in the most recent assessment."),
3455    ]),
3456    sql: "
3457WITH
3458
3459recent_storage_usage_by_shard AS (
3460    SELECT shard_id, size_bytes, collection_timestamp
3461    FROM mz_internal.mz_storage_usage_by_shard
3462    -- Restricting to the last 6 hours makes it feasible to index the view.
3463    WHERE collection_timestamp + '6 hours' >= mz_now()
3464),
3465
3466most_recent_collection_timestamp_by_shard AS (
3467    SELECT shard_id, max(collection_timestamp) AS collection_timestamp
3468    FROM recent_storage_usage_by_shard
3469    GROUP BY shard_id
3470)
3471
3472SELECT
3473    object_id,
3474    sum(size_bytes)::uint8 AS size_bytes
3475FROM
3476    mz_internal.mz_storage_shards
3477    LEFT JOIN most_recent_collection_timestamp_by_shard
3478        ON mz_storage_shards.shard_id = most_recent_collection_timestamp_by_shard.shard_id
3479    LEFT JOIN recent_storage_usage_by_shard
3480        ON mz_storage_shards.shard_id = recent_storage_usage_by_shard.shard_id
3481        AND most_recent_collection_timestamp_by_shard.collection_timestamp = recent_storage_usage_by_shard.collection_timestamp
3482GROUP BY object_id",
3483    access: vec![PUBLIC_SELECT],
3484    ontology: Some(Ontology {
3485        entity_name: "recent_storage",
3486        description: "Most recent storage usage snapshot per object",
3487        links: &const { [
3488            OntologyLink { name: "recent_storage_of", target: "object", properties: LinkProperties::fk("object_id", "id", Cardinality::OneToOne) },
3489        ] },
3490        column_semantic_types: &const {[("object_id", SemanticType::CatalogItemId), ("size_bytes", SemanticType::ByteCount)]},
3491    }),
3492}
3493});
3494
3495pub static MZ_RECENT_STORAGE_USAGE_IND: LazyLock<BuiltinIndex> = LazyLock::new(|| BuiltinIndex {
3496    name: "mz_recent_storage_usage_ind",
3497    schema: MZ_CATALOG_SCHEMA,
3498    oid: oid::INDEX_MZ_RECENT_STORAGE_USAGE_IND_OID,
3499    sql: "IN CLUSTER mz_catalog_server ON mz_catalog.mz_recent_storage_usage (object_id)",
3500    is_retained_metrics_object: false,
3501});
3502
3503pub static MZ_RELATIONS: LazyLock<BuiltinView> = LazyLock::new(|| {
3504    BuiltinView {
3505        name: "mz_relations",
3506        schema: MZ_CATALOG_SCHEMA,
3507        oid: oid::VIEW_MZ_RELATIONS_OID,
3508        desc: RelationDesc::builder()
3509            .with_column("id", SqlScalarType::String.nullable(false))
3510            .with_column("oid", SqlScalarType::Oid.nullable(false))
3511            .with_column("schema_id", SqlScalarType::String.nullable(false))
3512            .with_column("name", SqlScalarType::String.nullable(false))
3513            .with_column("type", SqlScalarType::String.nullable(false))
3514            .with_column("owner_id", SqlScalarType::String.nullable(false))
3515            .with_column("cluster_id", SqlScalarType::String.nullable(true))
3516            .with_column("privileges", SqlScalarType::Array(Box::new(SqlScalarType::MzAclItem)).nullable(false))
3517            .finish(),
3518        column_comments: BTreeMap::from_iter([
3519            ("id", "Materialize's unique ID for the relation."),
3520            ("oid", "A PostgreSQL-compatible OID for the relation."),
3521            ("schema_id", "The ID of the schema to which the relation belongs. Corresponds to `mz_schemas.id`."),
3522            ("name", "The name of the relation."),
3523            ("type", "The type of the relation: either `table`, `source`, `view`, or `materialized-view`."),
3524            ("owner_id", "The role ID of the owner of the relation. Corresponds to `mz_roles.id`."),
3525            ("cluster_id", "The ID of the cluster maintaining the source, materialized view, index, or sink. Corresponds to `mz_clusters.id`. `NULL` for other object types."),
3526            ("privileges", "The privileges belonging to the relation."),
3527        ]),
3528        sql: "
3529      SELECT id, oid, schema_id, name, 'table' AS type, owner_id, NULL::text AS cluster_id, privileges FROM mz_catalog.mz_tables
3530UNION ALL SELECT id, oid, schema_id, name, 'source', owner_id, cluster_id, privileges FROM mz_catalog.mz_sources
3531UNION ALL SELECT id, oid, schema_id, name, 'view', owner_id, NULL::text, privileges FROM mz_catalog.mz_views
3532UNION ALL SELECT id, oid, schema_id, name, 'materialized-view', owner_id, cluster_id, privileges FROM mz_catalog.mz_materialized_views",
3533        access: vec![PUBLIC_SELECT],
3534        ontology: Some(Ontology {
3535            entity_name: "relation",
3536            description: "Union of all relation types: tables, sources, views, MVs (convenience view)",
3537            links: &const { [
3538                OntologyLink { name: "union_includes", target: "table", properties: LinkProperties::union_disc("type", "table") },
3539                OntologyLink { name: "union_includes", target: "source", properties: LinkProperties::union_disc("type", "source") },
3540                OntologyLink { name: "union_includes", target: "view", properties: LinkProperties::union_disc("type", "view") },
3541                OntologyLink { name: "union_includes", target: "mv", properties: LinkProperties::union_disc("type", "materialized-view") },
3542            ] },
3543            column_semantic_types: &const {[("id", SemanticType::CatalogItemId), ("oid", SemanticType::OID), ("schema_id", SemanticType::SchemaId), ("type", SemanticType::ObjectType), ("owner_id", SemanticType::RoleId), ("cluster_id", SemanticType::ClusterId)]},
3544        }),
3545    }
3546});
3547
3548pub static MZ_OBJECTS: LazyLock<BuiltinView> = LazyLock::new(|| {
3549    BuiltinView {
3550        name: "mz_objects",
3551        schema: MZ_CATALOG_SCHEMA,
3552        oid: oid::VIEW_MZ_OBJECTS_OID,
3553        desc: RelationDesc::builder()
3554            .with_column("id", SqlScalarType::String.nullable(false))
3555            .with_column("oid", SqlScalarType::Oid.nullable(false))
3556            .with_column("schema_id", SqlScalarType::String.nullable(false))
3557            .with_column("name", SqlScalarType::String.nullable(false))
3558            .with_column("type", SqlScalarType::String.nullable(false))
3559            .with_column("owner_id", SqlScalarType::String.nullable(false))
3560            .with_column("cluster_id", SqlScalarType::String.nullable(true))
3561            .with_column("privileges", SqlScalarType::Array(Box::new(SqlScalarType::MzAclItem)).nullable(true))
3562            .finish(),
3563        column_comments: BTreeMap::from_iter([
3564            ("id", "Materialize's unique ID for the object."),
3565            ("oid", "A PostgreSQL-compatible OID for the object."),
3566            ("schema_id", "The ID of the schema to which the object belongs. Corresponds to `mz_schemas.id`."),
3567            ("name", "The name of the object."),
3568            ("type", "The type of the object: one of `table`, `source`, `view`, `materialized-view`, `sink`, `metric-sink`, `index`, `connection`, `secret`, `type`, or `function`."),
3569            ("owner_id", "The role ID of the owner of the object. Corresponds to `mz_roles.id`."),
3570            ("cluster_id", "The ID of the cluster maintaining the source, materialized view, index, or sink. Corresponds to `mz_clusters.id`. `NULL` for other object types."),
3571            ("privileges", "The privileges belonging to the object."),
3572        ]),
3573        sql:
3574        "SELECT id, oid, schema_id, name, type, owner_id, cluster_id, privileges FROM mz_catalog.mz_relations
3575UNION ALL
3576    SELECT id, oid, schema_id, name, 'sink', owner_id, cluster_id, NULL::mz_catalog.mz_aclitem[] FROM mz_catalog.mz_sinks
3577UNION ALL
3578    SELECT id, oid, schema_id, name, 'metric-sink', owner_id, cluster_id, NULL::mz_catalog.mz_aclitem[] FROM mz_internal.mz_metric_sinks
3579UNION ALL
3580    SELECT mz_indexes.id, mz_indexes.oid, mz_relations.schema_id, mz_indexes.name, 'index', mz_indexes.owner_id, mz_indexes.cluster_id, NULL::mz_catalog.mz_aclitem[]
3581    FROM mz_catalog.mz_indexes
3582    JOIN mz_catalog.mz_relations ON mz_indexes.on_id = mz_relations.id
3583UNION ALL
3584    SELECT id, oid, schema_id, name, 'connection', owner_id, NULL::text, privileges FROM mz_catalog.mz_connections
3585UNION ALL
3586    SELECT id, oid, schema_id, name, 'type', owner_id, NULL::text, privileges FROM mz_catalog.mz_types
3587UNION ALL
3588    SELECT id, oid, schema_id, name, 'function', owner_id, NULL::text, NULL::mz_catalog.mz_aclitem[] FROM mz_catalog.mz_functions
3589UNION ALL
3590    SELECT id, oid, schema_id, name, 'secret', owner_id, NULL::text, privileges FROM mz_catalog.mz_secrets",
3591        access: vec![PUBLIC_SELECT],
3592        ontology: Some(Ontology {
3593            entity_name: "object",
3594            description: "Union of all object types: relations, indexes, connections, etc. (convenience view)",
3595            links: &const {
3596                [
3597                    OntologyLink {
3598                        name: "union_includes",
3599                        target: "relation",
3600                        properties: LinkProperties::Union {
3601                            discriminator_column: None,
3602                            discriminator_value: None,
3603                            note: Some("covers all mz_relations rows (table, source, view, mv)"),
3604                        },
3605                    },
3606                    OntologyLink {
3607                        name: "union_includes",
3608                        target: "table",
3609                        properties: LinkProperties::union_disc("type", "table"),
3610                    },
3611                    OntologyLink {
3612                        name: "union_includes",
3613                        target: "source",
3614                        properties: LinkProperties::union_disc("type", "source"),
3615                    },
3616                    OntologyLink {
3617                        name: "union_includes",
3618                        target: "view",
3619                        properties: LinkProperties::union_disc("type", "view"),
3620                    },
3621                    OntologyLink {
3622                        name: "union_includes",
3623                        target: "mv",
3624                        properties: LinkProperties::union_disc("type", "materialized-view"),
3625                    },
3626                    OntologyLink {
3627                        name: "union_includes",
3628                        target: "sink",
3629                        properties: LinkProperties::union_disc("type", "sink"),
3630                    },
3631                    OntologyLink {
3632                        name: "union_includes",
3633                        target: "index",
3634                        properties: LinkProperties::union_disc("type", "index"),
3635                    },
3636                    OntologyLink {
3637                        name: "union_includes",
3638                        target: "connection",
3639                        properties: LinkProperties::union_disc("type", "connection"),
3640                    },
3641                    OntologyLink {
3642                        name: "union_includes",
3643                        target: "type",
3644                        properties: LinkProperties::union_disc("type", "type"),
3645                    },
3646                    OntologyLink {
3647                        name: "union_includes",
3648                        target: "function",
3649                        properties: LinkProperties::union_disc("type", "function"),
3650                    },
3651                    OntologyLink {
3652                        name: "union_includes",
3653                        target: "secret",
3654                        properties: LinkProperties::union_disc("type", "secret"),
3655                    },
3656                    OntologyLink {
3657                        name: "in_schema",
3658                        target: "schema",
3659                        properties: LinkProperties::fk("schema_id", "id", Cardinality::ManyToOne),
3660                    },
3661                    OntologyLink {
3662                        name: "owned_by",
3663                        target: "role",
3664                        properties: LinkProperties::fk("owner_id", "id", Cardinality::ManyToOne),
3665                    },
3666                    OntologyLink {
3667                        name: "on_cluster",
3668                        target: "cluster",
3669                        properties: LinkProperties::fk_nullable(
3670                            "cluster_id",
3671                            "id",
3672                            Cardinality::ManyToOne,
3673                        ),
3674                    },
3675                ]
3676            },
3677            column_semantic_types: &const {
3678                [
3679                    ("id", SemanticType::CatalogItemId),
3680                    ("oid", SemanticType::OID),
3681                    ("schema_id", SemanticType::SchemaId),
3682                    ("type", SemanticType::ObjectType),
3683                    ("owner_id", SemanticType::RoleId),
3684                    ("cluster_id", SemanticType::ClusterId),
3685                ]
3686            },
3687        }),
3688    }
3689});
3690
3691pub static MZ_TIMEZONE_ABBREVIATIONS: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
3692    name: "mz_timezone_abbreviations",
3693    schema: MZ_CATALOG_SCHEMA,
3694    oid: oid::VIEW_MZ_TIMEZONE_ABBREVIATIONS_OID,
3695    desc: RelationDesc::builder()
3696        .with_column("abbreviation", SqlScalarType::String.nullable(false))
3697        .with_column("utc_offset", SqlScalarType::Interval.nullable(true))
3698        .with_column("dst", SqlScalarType::Bool.nullable(true))
3699        .with_column("timezone_name", SqlScalarType::String.nullable(true))
3700        .with_key(vec![0])
3701        .finish(),
3702    column_comments: BTreeMap::from_iter([
3703        ("abbreviation", "The timezone abbreviation."),
3704        (
3705            "utc_offset",
3706            "The UTC offset of the timezone or `NULL` if fixed.",
3707        ),
3708        (
3709            "dst",
3710            "Whether the timezone is in daylight savings or `NULL` if fixed.",
3711        ),
3712        (
3713            "timezone_name",
3714            "The full name of the non-fixed timezone or `NULL` if not fixed.",
3715        ),
3716    ]),
3717    sql: format!(
3718        "SELECT * FROM ({}) _ (abbreviation, utc_offset, dst, timezone_name)",
3719        mz_pgtz::abbrev::MZ_CATALOG_TIMEZONE_ABBREVIATIONS_SQL,
3720    )
3721    .leak(),
3722    access: vec![PUBLIC_SELECT],
3723    ontology: None,
3724});
3725
3726pub static MZ_TIMEZONE_NAMES: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
3727    name: "mz_timezone_names",
3728    schema: MZ_CATALOG_SCHEMA,
3729    oid: oid::VIEW_MZ_TIMEZONE_NAMES_OID,
3730    desc: RelationDesc::builder()
3731        .with_column("name", SqlScalarType::String.nullable(false))
3732        .with_key(vec![0])
3733        .finish(),
3734    column_comments: BTreeMap::from_iter([("name", "The timezone name.")]),
3735    sql: format!(
3736        "SELECT * FROM ({}) _ (name)",
3737        mz_pgtz::timezone::MZ_CATALOG_TIMEZONE_NAMES_SQL,
3738    )
3739    .leak(),
3740    access: vec![PUBLIC_SELECT],
3741    ontology: None,
3742});
3743
3744pub const MZ_DATABASES_IND: BuiltinIndex = BuiltinIndex {
3745    name: "mz_databases_ind",
3746    schema: MZ_CATALOG_SCHEMA,
3747    oid: oid::INDEX_MZ_DATABASES_IND_OID,
3748    sql: "IN CLUSTER mz_catalog_server
3749ON mz_catalog.mz_databases (name)",
3750    is_retained_metrics_object: false,
3751};
3752
3753pub const MZ_SCHEMAS_IND: BuiltinIndex = BuiltinIndex {
3754    name: "mz_schemas_ind",
3755    schema: MZ_CATALOG_SCHEMA,
3756    oid: oid::INDEX_MZ_SCHEMAS_IND_OID,
3757    sql: "IN CLUSTER mz_catalog_server
3758ON mz_catalog.mz_schemas (database_id)",
3759    is_retained_metrics_object: false,
3760};
3761
3762pub const MZ_CONNECTIONS_IND: BuiltinIndex = BuiltinIndex {
3763    name: "mz_connections_ind",
3764    schema: MZ_CATALOG_SCHEMA,
3765    oid: oid::INDEX_MZ_CONNECTIONS_IND_OID,
3766    sql: "IN CLUSTER mz_catalog_server
3767ON mz_catalog.mz_connections (schema_id)",
3768    is_retained_metrics_object: false,
3769};
3770
3771pub const MZ_TABLES_IND: BuiltinIndex = BuiltinIndex {
3772    name: "mz_tables_ind",
3773    schema: MZ_CATALOG_SCHEMA,
3774    oid: oid::INDEX_MZ_TABLES_IND_OID,
3775    sql: "IN CLUSTER mz_catalog_server
3776ON mz_catalog.mz_tables (schema_id)",
3777    is_retained_metrics_object: false,
3778};
3779
3780pub const MZ_TYPES_IND: BuiltinIndex = BuiltinIndex {
3781    name: "mz_types_ind",
3782    schema: MZ_CATALOG_SCHEMA,
3783    oid: oid::INDEX_MZ_TYPES_IND_OID,
3784    sql: "IN CLUSTER mz_catalog_server
3785ON mz_catalog.mz_types (schema_id)",
3786    is_retained_metrics_object: false,
3787};
3788
3789pub const MZ_OBJECTS_IND: BuiltinIndex = BuiltinIndex {
3790    name: "mz_objects_ind",
3791    schema: MZ_CATALOG_SCHEMA,
3792    oid: oid::INDEX_MZ_OBJECTS_IND_OID,
3793    sql: "IN CLUSTER mz_catalog_server
3794ON mz_catalog.mz_objects (schema_id)",
3795    is_retained_metrics_object: false,
3796};
3797
3798pub const MZ_COLUMNS_IND: BuiltinIndex = BuiltinIndex {
3799    name: "mz_columns_ind",
3800    schema: MZ_CATALOG_SCHEMA,
3801    oid: oid::INDEX_MZ_COLUMNS_IND_OID,
3802    sql: "IN CLUSTER mz_catalog_server
3803ON mz_catalog.mz_columns (name)",
3804    is_retained_metrics_object: false,
3805};
3806
3807pub const MZ_SECRETS_IND: BuiltinIndex = BuiltinIndex {
3808    name: "mz_secrets_ind",
3809    schema: MZ_CATALOG_SCHEMA,
3810    oid: oid::INDEX_MZ_SECRETS_IND_OID,
3811    sql: "IN CLUSTER mz_catalog_server
3812ON mz_catalog.mz_secrets (name)",
3813    is_retained_metrics_object: false,
3814};
3815
3816pub const MZ_VIEWS_IND: BuiltinIndex = BuiltinIndex {
3817    name: "mz_views_ind",
3818    schema: MZ_CATALOG_SCHEMA,
3819    oid: oid::INDEX_MZ_VIEWS_IND_OID,
3820    sql: "IN CLUSTER mz_catalog_server
3821ON mz_catalog.mz_views (schema_id)",
3822    is_retained_metrics_object: false,
3823};
3824
3825pub const MZ_CLUSTERS_IND: BuiltinIndex = BuiltinIndex {
3826    name: "mz_clusters_ind",
3827    schema: MZ_CATALOG_SCHEMA,
3828    oid: oid::INDEX_MZ_CLUSTERS_IND_OID,
3829    sql: "IN CLUSTER mz_catalog_server
3830ON mz_catalog.mz_clusters (id)",
3831    is_retained_metrics_object: false,
3832};
3833
3834pub const MZ_INDEXES_IND: BuiltinIndex = BuiltinIndex {
3835    name: "mz_indexes_ind",
3836    schema: MZ_CATALOG_SCHEMA,
3837    oid: oid::INDEX_MZ_INDEXES_IND_OID,
3838    sql: "IN CLUSTER mz_catalog_server
3839ON mz_catalog.mz_indexes (id)",
3840    is_retained_metrics_object: false,
3841};
3842
3843pub const MZ_ROLES_IND: BuiltinIndex = BuiltinIndex {
3844    name: "mz_roles_ind",
3845    schema: MZ_CATALOG_SCHEMA,
3846    oid: oid::INDEX_MZ_ROLES_IND_OID,
3847    sql: "IN CLUSTER mz_catalog_server
3848ON mz_catalog.mz_roles (id)",
3849    is_retained_metrics_object: false,
3850};
3851
3852pub const MZ_SOURCES_IND: BuiltinIndex = BuiltinIndex {
3853    name: "mz_sources_ind",
3854    schema: MZ_CATALOG_SCHEMA,
3855    oid: oid::INDEX_MZ_SOURCES_IND_OID,
3856    sql: "IN CLUSTER mz_catalog_server
3857ON mz_catalog.mz_sources (id)",
3858    is_retained_metrics_object: true,
3859};
3860
3861pub const MZ_SINKS_IND: BuiltinIndex = BuiltinIndex {
3862    name: "mz_sinks_ind",
3863    schema: MZ_CATALOG_SCHEMA,
3864    oid: oid::INDEX_MZ_SINKS_IND_OID,
3865    sql: "IN CLUSTER mz_catalog_server
3866ON mz_catalog.mz_sinks (id)",
3867    is_retained_metrics_object: true,
3868};
3869
3870pub const MZ_MATERIALIZED_VIEWS_IND: BuiltinIndex = BuiltinIndex {
3871    name: "mz_materialized_views_ind",
3872    schema: MZ_CATALOG_SCHEMA,
3873    oid: oid::INDEX_MZ_MATERIALIZED_VIEWS_IND_OID,
3874    sql: "IN CLUSTER mz_catalog_server
3875ON mz_catalog.mz_materialized_views (id)",
3876    is_retained_metrics_object: false,
3877};
3878
3879pub const MZ_CLUSTER_REPLICAS_IND: BuiltinIndex = BuiltinIndex {
3880    name: "mz_cluster_replicas_ind",
3881    schema: MZ_CATALOG_SCHEMA,
3882    oid: oid::INDEX_MZ_CLUSTER_REPLICAS_IND_OID,
3883    sql: "IN CLUSTER mz_catalog_server
3884ON mz_catalog.mz_cluster_replicas (id)",
3885    is_retained_metrics_object: true,
3886};
3887
3888pub const MZ_CLUSTER_REPLICA_SIZES_IND: BuiltinIndex = BuiltinIndex {
3889    name: "mz_cluster_replica_sizes_ind",
3890    schema: MZ_CATALOG_SCHEMA,
3891    oid: oid::INDEX_MZ_CLUSTER_REPLICA_SIZES_IND_OID,
3892    sql: "IN CLUSTER mz_catalog_server
3893ON mz_catalog.mz_cluster_replica_sizes (size)",
3894    is_retained_metrics_object: true,
3895};
3896
3897pub const MZ_KAFKA_SOURCES_IND: BuiltinIndex = BuiltinIndex {
3898    name: "mz_kafka_sources_ind",
3899    schema: MZ_CATALOG_SCHEMA,
3900    oid: oid::INDEX_MZ_KAFKA_SOURCES_IND_OID,
3901    sql: "IN CLUSTER mz_catalog_server
3902ON mz_catalog.mz_kafka_sources (id)",
3903    is_retained_metrics_object: true,
3904};
3905
3906#[cfg(test)]
3907mod tests {
3908    use mz_catalog_protos::objects::ObjectType as ProtoObjectType;
3909    use mz_sql::catalog::ObjectType as SqlObjectType;
3910
3911    use crate::builtin::mz_catalog::MZ_DEFAULT_PRIVILEGES;
3912
3913    /// Checks the `object_type` CASE in `MZ_DEFAULT_PRIVILEGES` against the
3914    /// proto enum and the SQL Display impl it's meant to mirror.
3915    ///
3916    /// The CASE maps `mz_catalog_protos::ObjectType`'s numeric `Serialize_repr`
3917    /// to `mz_sql::catalog::ObjectType`'s `Display`, lowercased. The match in
3918    /// `expected_for` is exhaustive, so a new proto variant won't compile until
3919    /// it's handled. A wrong string in the CASE fails the substring assertion.
3920    #[mz_ore::test]
3921    fn object_type_case_matches_proto_display() {
3922        // `None` means the variant never shows up in a stored `DefaultPrivilege`
3923        // key, so the CASE deliberately has no arm for it: `Unknown` is the
3924        // zero-value sentinel, and `ON METRIC SINKS` is rejected by
3925        // `plan_alter_default_privileges` before a key ever gets built. Match is
3926        // exhaustive: a new variant forces an update.
3927        fn expected_for(proto: ProtoObjectType) -> Option<SqlObjectType> {
3928            match proto {
3929                ProtoObjectType::Unknown => None,
3930                ProtoObjectType::MetricSink => None,
3931                ProtoObjectType::Table => Some(SqlObjectType::Table),
3932                ProtoObjectType::View => Some(SqlObjectType::View),
3933                ProtoObjectType::MaterializedView => Some(SqlObjectType::MaterializedView),
3934                ProtoObjectType::Source => Some(SqlObjectType::Source),
3935                ProtoObjectType::Sink => Some(SqlObjectType::Sink),
3936                ProtoObjectType::Index => Some(SqlObjectType::Index),
3937                ProtoObjectType::Type => Some(SqlObjectType::Type),
3938                ProtoObjectType::Role => Some(SqlObjectType::Role),
3939                ProtoObjectType::Cluster => Some(SqlObjectType::Cluster),
3940                ProtoObjectType::ClusterReplica => Some(SqlObjectType::ClusterReplica),
3941                ProtoObjectType::Secret => Some(SqlObjectType::Secret),
3942                ProtoObjectType::Connection => Some(SqlObjectType::Connection),
3943                ProtoObjectType::Database => Some(SqlObjectType::Database),
3944                ProtoObjectType::Schema => Some(SqlObjectType::Schema),
3945                ProtoObjectType::Func => Some(SqlObjectType::Func),
3946                ProtoObjectType::NetworkPolicy => Some(SqlObjectType::NetworkPolicy),
3947            }
3948        }
3949
3950        // The proto enum has no `IntoEnumIterator`, so list every variant by
3951        // hand. A missed entry here just goes unchecked, but the exhaustive
3952        // match in `expected_for` won't compile when a new proto variant lands,
3953        // which is the actual drift defense.
3954        let variants: &[ProtoObjectType] = &[
3955            ProtoObjectType::Unknown,
3956            ProtoObjectType::Table,
3957            ProtoObjectType::View,
3958            ProtoObjectType::MaterializedView,
3959            ProtoObjectType::Source,
3960            ProtoObjectType::Sink,
3961            ProtoObjectType::Index,
3962            ProtoObjectType::Type,
3963            ProtoObjectType::Role,
3964            ProtoObjectType::Cluster,
3965            ProtoObjectType::ClusterReplica,
3966            ProtoObjectType::Secret,
3967            ProtoObjectType::Connection,
3968            ProtoObjectType::Database,
3969            ProtoObjectType::Schema,
3970            ProtoObjectType::Func,
3971            ProtoObjectType::NetworkPolicy,
3972            ProtoObjectType::MetricSink,
3973        ];
3974
3975        let sql = MZ_DEFAULT_PRIVILEGES.sql;
3976        for &proto in variants {
3977            // `ObjectType` is `#[repr(u8)]`; the discriminant matches the
3978            // `Serialize_repr` JSON value the SQL CASE arms compare against.
3979            #[allow(clippy::as_conversions)]
3980            let repr = proto as u8;
3981            match expected_for(proto) {
3982                Some(sql_ty) => {
3983                    let display = sql_ty.to_string().to_lowercase();
3984                    // The arms use variable whitespace between `WHEN '..'` and
3985                    // `THEN` to align columns; verify the WHEN and THEN strings
3986                    // appear together with at most one or two spaces between.
3987                    let one_space = format!("WHEN '{repr}' THEN '{display}'");
3988                    let two_spaces = format!("WHEN '{repr}'  THEN '{display}'");
3989                    assert!(
3990                        sql.contains(&one_space) || sql.contains(&two_spaces),
3991                        "missing CASE arm for `{proto:?}`: expected \
3992                         `WHEN '{repr}' THEN '{display}'` (or with double space) \
3993                         in MZ_DEFAULT_PRIVILEGES.sql",
3994                    );
3995                }
3996                None => {
3997                    let pattern = format!("WHEN '{repr}'");
3998                    assert!(
3999                        !sql.contains(&pattern),
4000                        "unexpected CASE arm for sentinel `{proto:?}`: \
4001                         found `{pattern}` in MZ_DEFAULT_PRIVILEGES.sql",
4002                    );
4003                }
4004            }
4005        }
4006    }
4007}