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