Skip to main content

mz_catalog/builtin/
mz_internal.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_internal` schema.
11
12use std::collections::BTreeMap;
13use std::sync::LazyLock;
14
15use mz_pgrepr::oid;
16use mz_repr::adt::mz_acl_item::MzAclItem;
17use mz_repr::namespaces::MZ_INTERNAL_SCHEMA;
18use mz_repr::{RelationDesc, SemanticType, SqlScalarType};
19use mz_sql::catalog::{ObjectType, SystemObjectType};
20use mz_sql::rbac;
21use mz_sql::session::user::{MZ_ANALYTICS_ROLE_ID, MZ_SYSTEM_ROLE_ID};
22use mz_storage_client::controller::IntrospectionType;
23use mz_storage_client::healthcheck::{
24    MZ_AWS_PRIVATELINK_CONNECTION_STATUS_HISTORY_DESC, MZ_PREPARED_STATEMENT_HISTORY_DESC,
25    MZ_SESSION_HISTORY_DESC, MZ_SINK_STATUS_HISTORY_DESC, MZ_SOURCE_STATUS_HISTORY_DESC,
26    MZ_SQL_TEXT_DESC, MZ_STATEMENT_EXECUTION_HISTORY_DESC, REPLICA_METRICS_HISTORY_DESC,
27    REPLICA_STATUS_HISTORY_DESC, WALLCLOCK_GLOBAL_LAG_HISTOGRAM_RAW_DESC,
28    WALLCLOCK_LAG_HISTORY_DESC,
29};
30use mz_storage_client::statistics::{MZ_SINK_STATISTICS_RAW_DESC, MZ_SOURCE_STATISTICS_RAW_DESC};
31
32use crate::memory::objects::DataSourceDesc;
33
34use super::{
35    ANALYTICS_SELECT, BuiltinConnection, BuiltinIndex, BuiltinMaterializedView, BuiltinSource,
36    BuiltinTable, BuiltinView, Cardinality, LinkProperties, MONITOR_REDACTED_SELECT,
37    MONITOR_SELECT, Ontology, OntologyLink, PUBLIC_SELECT, SUPPORT_SELECT,
38};
39
40pub static MZ_CATALOG_RAW: LazyLock<BuiltinSource> = LazyLock::new(|| BuiltinSource {
41    name: "mz_catalog_raw",
42    schema: MZ_INTERNAL_SCHEMA,
43    oid: oid::SOURCE_MZ_CATALOG_RAW_OID,
44    data_source: DataSourceDesc::Catalog,
45    desc: crate::durable::persist_desc(),
46    column_comments: BTreeMap::new(),
47    is_retained_metrics_object: false,
48    // The raw catalog contains unredacted SQL statements, so we limit access to the system user.
49    access: vec![],
50    ontology: None,
51});
52pub static MZ_POSTGRES_SOURCES: LazyLock<BuiltinTable> = LazyLock::new(|| BuiltinTable {
53    name: "mz_postgres_sources",
54    schema: MZ_INTERNAL_SCHEMA,
55    oid: oid::TABLE_MZ_POSTGRES_SOURCES_OID,
56    desc: RelationDesc::builder()
57        .with_column("id", SqlScalarType::String.nullable(false))
58        .with_column("replication_slot", SqlScalarType::String.nullable(false))
59        .with_column("timeline_id", SqlScalarType::UInt64.nullable(true))
60        .finish(),
61    column_comments: BTreeMap::from_iter([
62        (
63            "id",
64            "The ID of the source. Corresponds to `mz_catalog.mz_sources.id`.",
65        ),
66        (
67            "replication_slot",
68            "The name of the replication slot in the PostgreSQL database that Materialize will create and stream data from.",
69        ),
70        (
71            "timeline_id",
72            "The PostgreSQL timeline ID determined on source creation.",
73        ),
74    ]),
75    is_retained_metrics_object: false,
76    access: vec![PUBLIC_SELECT],
77    ontology: Some(Ontology {
78        entity_name: "postgres_source",
79        description: "Postgres source-level details",
80        links: &const {
81            [OntologyLink {
82                name: "details_of",
83                target: "source",
84                properties: LinkProperties::fk("id", "id", Cardinality::OneToOne),
85            }]
86        },
87        column_semantic_types: &[("id", SemanticType::CatalogItemId)],
88    }),
89});
90pub static MZ_POSTGRES_SOURCE_TABLES: LazyLock<BuiltinTable> = LazyLock::new(|| BuiltinTable {
91    name: "mz_postgres_source_tables",
92    schema: MZ_INTERNAL_SCHEMA,
93    oid: oid::TABLE_MZ_POSTGRES_SOURCE_TABLES_OID,
94    desc: RelationDesc::builder()
95        .with_column("id", SqlScalarType::String.nullable(false))
96        .with_column("schema_name", SqlScalarType::String.nullable(false))
97        .with_column("table_name", SqlScalarType::String.nullable(false))
98        .finish(),
99    column_comments: BTreeMap::from_iter([
100        (
101            "id",
102            "The ID of the subsource or table. Corresponds to `mz_catalog.mz_sources.id` or `mz_catalog.mz_tables.id`.",
103        ),
104        (
105            "schema_name",
106            "The schema of the upstream table being ingested.",
107        ),
108        (
109            "table_name",
110            "The name of the upstream table being ingested.",
111        ),
112    ]),
113    is_retained_metrics_object: true,
114    access: vec![PUBLIC_SELECT],
115    ontology: Some(Ontology {
116        entity_name: "postgres_source_table",
117        description: "Postgres source table-level details",
118        links: &const {
119            [OntologyLink {
120                name: "describes_source_table",
121                target: "table",
122                properties: LinkProperties::fk("id", "id", Cardinality::OneToOne),
123            }]
124        },
125        column_semantic_types: &[("id", SemanticType::CatalogItemId)],
126    }),
127});
128pub static MZ_MYSQL_SOURCE_TABLES: LazyLock<BuiltinTable> = LazyLock::new(|| BuiltinTable {
129    name: "mz_mysql_source_tables",
130    schema: MZ_INTERNAL_SCHEMA,
131    oid: oid::TABLE_MZ_MYSQL_SOURCE_TABLES_OID,
132    desc: RelationDesc::builder()
133        .with_column("id", SqlScalarType::String.nullable(false))
134        .with_column("schema_name", SqlScalarType::String.nullable(false))
135        .with_column("table_name", SqlScalarType::String.nullable(false))
136        .finish(),
137    column_comments: BTreeMap::from_iter([
138        (
139            "id",
140            "The ID of the subsource or table. Corresponds to `mz_catalog.mz_sources.id` or `mz_catalog.mz_tables.id`.",
141        ),
142        (
143            "schema_name",
144            "The schema (or, database) of the upstream table being ingested.",
145        ),
146        (
147            "table_name",
148            "The name of the upstream table being ingested.",
149        ),
150    ]),
151    is_retained_metrics_object: true,
152    access: vec![PUBLIC_SELECT],
153    ontology: Some(Ontology {
154        entity_name: "mysql_source_table",
155        description: "MySQL source table-level details",
156        links: &const {
157            [OntologyLink {
158                name: "describes_source_table",
159                target: "table",
160                properties: LinkProperties::fk("id", "id", Cardinality::OneToOne),
161            }]
162        },
163        column_semantic_types: &[("id", SemanticType::CatalogItemId)],
164    }),
165});
166pub static MZ_SQL_SERVER_SOURCE_TABLES: LazyLock<BuiltinTable> = LazyLock::new(|| BuiltinTable {
167    name: "mz_sql_server_source_tables",
168    schema: MZ_INTERNAL_SCHEMA,
169    oid: oid::TABLE_MZ_SQL_SERVER_SOURCE_TABLES_OID,
170    desc: RelationDesc::builder()
171        .with_column("id", SqlScalarType::String.nullable(false))
172        .with_column("schema_name", SqlScalarType::String.nullable(false))
173        .with_column("table_name", SqlScalarType::String.nullable(false))
174        .finish(),
175    column_comments: BTreeMap::from_iter([
176        (
177            "id",
178            "The ID of the subsource or table. Corresponds to `mz_catalog.mz_sources.id` or `mz_catalog.mz_tables.id`.",
179        ),
180        (
181            "schema_name",
182            "The schema of the upstream table being ingested.",
183        ),
184        (
185            "table_name",
186            "The name of the upstream table being ingested.",
187        ),
188    ]),
189    is_retained_metrics_object: true,
190    access: vec![PUBLIC_SELECT],
191    ontology: Some(Ontology {
192        entity_name: "sql_server_source_table",
193        description: "SQL Server source table-level details",
194        links: &const {
195            [OntologyLink {
196                name: "describes_source_table",
197                target: "table",
198                properties: LinkProperties::fk("id", "id", Cardinality::OneToOne),
199            }]
200        },
201        column_semantic_types: &[("id", SemanticType::CatalogItemId)],
202    }),
203});
204pub static MZ_KAFKA_SOURCE_TABLES: LazyLock<BuiltinTable> = LazyLock::new(|| BuiltinTable {
205    name: "mz_kafka_source_tables",
206    schema: MZ_INTERNAL_SCHEMA,
207    oid: oid::TABLE_MZ_KAFKA_SOURCE_TABLES_OID,
208    desc: RelationDesc::builder()
209        .with_column("id", SqlScalarType::String.nullable(false))
210        .with_column("topic", SqlScalarType::String.nullable(false))
211        .with_column("envelope_type", SqlScalarType::String.nullable(true))
212        .with_column("key_format", SqlScalarType::String.nullable(true))
213        .with_column("value_format", SqlScalarType::String.nullable(true))
214        .finish(),
215    column_comments: BTreeMap::from_iter([
216        (
217            "id",
218            "The ID of the table. Corresponds to `mz_catalog.mz_tables.id`.",
219        ),
220        ("topic", "The topic being ingested."),
221        (
222            "envelope_type",
223            "The envelope type: `none`, `upsert`, or `debezium`. `NULL` for other source types.",
224        ),
225        (
226            "key_format",
227            "The format of the Kafka message key: `avro`, `csv`, `regex`, `bytes`, `json`, `text`, or `NULL`.",
228        ),
229        (
230            "value_format",
231            "The format of the Kafka message value: `avro`, `csv`, `regex`, `bytes`, `json`, `text`. `NULL` for other source types.",
232        ),
233    ]),
234    is_retained_metrics_object: true,
235    access: vec![PUBLIC_SELECT],
236    ontology: Some(Ontology {
237        entity_name: "kafka_source_table",
238        description: "Kafka source table-level details",
239        links: &const {
240            [OntologyLink {
241                name: "describes_source_table",
242                target: "table",
243                properties: LinkProperties::fk("id", "id", Cardinality::OneToOne),
244            }]
245        },
246        column_semantic_types: &[("id", SemanticType::CatalogItemId)],
247    }),
248});
249pub static MZ_OBJECT_DEPENDENCIES: LazyLock<BuiltinTable> = LazyLock::new(|| BuiltinTable {
250    name: "mz_object_dependencies",
251    schema: MZ_INTERNAL_SCHEMA,
252    oid: oid::TABLE_MZ_OBJECT_DEPENDENCIES_OID,
253    desc: RelationDesc::builder()
254        .with_column("object_id", SqlScalarType::String.nullable(false))
255        .with_column(
256            "referenced_object_id",
257            SqlScalarType::String.nullable(false),
258        )
259        .finish(),
260    column_comments: BTreeMap::from_iter([
261        (
262            "object_id",
263            "The ID of the dependent object. Corresponds to `mz_objects.id`.",
264        ),
265        (
266            "referenced_object_id",
267            "The ID of the referenced object. Corresponds to `mz_objects.id`.",
268        ),
269    ]),
270    is_retained_metrics_object: true,
271    access: vec![PUBLIC_SELECT],
272    ontology: Some(Ontology {
273        entity_name: "object_dependency",
274        description: "A dependency edge: one object depends on another",
275        links: &const {
276            [
277                OntologyLink {
278                    name: "depends_on",
279                    target: "object",
280                    properties: LinkProperties::DependsOn {
281                        source_column: "object_id",
282                        target_column: "id",
283                        source_id_type: Some(mz_repr::SemanticType::CatalogItemId),
284                        requires_mapping: None,
285                    },
286                },
287                OntologyLink {
288                    name: "dependency_is",
289                    target: "object",
290                    properties: LinkProperties::DependsOn {
291                        source_column: "referenced_object_id",
292                        target_column: "id",
293                        source_id_type: Some(mz_repr::SemanticType::CatalogItemId),
294                        requires_mapping: None,
295                    },
296                },
297            ]
298        },
299        column_semantic_types: &const {
300            [
301                ("object_id", SemanticType::CatalogItemId),
302                ("referenced_object_id", SemanticType::CatalogItemId),
303            ]
304        },
305    }),
306});
307pub static MZ_COMPUTE_DEPENDENCIES: LazyLock<BuiltinSource> = LazyLock::new(|| BuiltinSource {
308    name: "mz_compute_dependencies",
309    schema: MZ_INTERNAL_SCHEMA,
310    oid: oid::SOURCE_MZ_COMPUTE_DEPENDENCIES_OID,
311    data_source: IntrospectionType::ComputeDependencies.into(),
312    desc: RelationDesc::builder()
313        .with_column("object_id", SqlScalarType::String.nullable(false))
314        .with_column("dependency_id", SqlScalarType::String.nullable(false))
315        .finish(),
316    column_comments: BTreeMap::from_iter([
317        (
318            "object_id",
319            "The ID of a compute object. Corresponds to `mz_catalog.mz_indexes.id`, `mz_catalog.mz_materialized_views.id`, or `mz_internal.mz_subscriptions.id`.",
320        ),
321        (
322            "dependency_id",
323            "The ID of a compute dependency. Corresponds to `mz_catalog.mz_indexes.id`, `mz_catalog.mz_materialized_views.id`, `mz_catalog.mz_sources.id`, or `mz_catalog.mz_tables.id`.",
324        ),
325    ]),
326    is_retained_metrics_object: false,
327    access: vec![PUBLIC_SELECT],
328    ontology: Some(Ontology {
329        entity_name: "compute_dependency",
330        description: "Dependency edge from a compute object (index, materialized view, or subscription) to one of the sources of its data",
331        links: &const {
332            [
333                OntologyLink {
334                    name: "depends_on",
335                    target: "object",
336                    properties: LinkProperties::DependsOn {
337                        source_column: "object_id",
338                        target_column: "id",
339                        source_id_type: Some(mz_repr::SemanticType::GlobalId),
340                        requires_mapping: Some("mz_internal.mz_object_global_ids"),
341                    },
342                },
343                OntologyLink {
344                    name: "dependency_is",
345                    target: "object",
346                    properties: LinkProperties::DependsOn {
347                        source_column: "dependency_id",
348                        target_column: "id",
349                        source_id_type: Some(mz_repr::SemanticType::GlobalId),
350                        requires_mapping: Some("mz_internal.mz_object_global_ids"),
351                    },
352                },
353            ]
354        },
355        column_semantic_types: &const {
356            [
357                ("object_id", SemanticType::GlobalId),
358                ("dependency_id", SemanticType::GlobalId),
359            ]
360        },
361    }),
362});
363
364pub static MZ_MATERIALIZED_VIEW_REFRESH_STRATEGIES: LazyLock<BuiltinTable> = LazyLock::new(|| {
365    BuiltinTable {
366        name: "mz_materialized_view_refresh_strategies",
367        schema: MZ_INTERNAL_SCHEMA,
368        oid: oid::TABLE_MZ_MATERIALIZED_VIEW_REFRESH_STRATEGIES_OID,
369        desc: RelationDesc::builder()
370            .with_column(
371                "materialized_view_id",
372                SqlScalarType::String.nullable(false),
373            )
374            .with_column("type", SqlScalarType::String.nullable(false))
375            .with_column("interval", SqlScalarType::Interval.nullable(true))
376            .with_column(
377                "aligned_to",
378                SqlScalarType::TimestampTz { precision: None }.nullable(true),
379            )
380            .with_column(
381                "at",
382                SqlScalarType::TimestampTz { precision: None }.nullable(true),
383            )
384            .finish(),
385        column_comments: BTreeMap::from_iter([
386            (
387                "materialized_view_id",
388                "The ID of the materialized view. Corresponds to `mz_catalog.mz_materialized_views.id`",
389            ),
390            (
391                "type",
392                "`at`, `every`, or `on-commit`. Default: `on-commit`",
393            ),
394            (
395                "interval",
396                "The refresh interval of a `REFRESH EVERY` option, or `NULL` if the `type` is not `every`.",
397            ),
398            (
399                "aligned_to",
400                "The `ALIGNED TO` option of a `REFRESH EVERY` option, or `NULL` if the `type` is not `every`.",
401            ),
402            (
403                "at",
404                "The time of a `REFRESH AT`, or `NULL` if the `type` is not `at`.",
405            ),
406        ]),
407        is_retained_metrics_object: false,
408        access: vec![PUBLIC_SELECT],
409        ontology: None,
410    }
411});
412
413pub static MZ_NETWORK_POLICIES: LazyLock<BuiltinMaterializedView> = LazyLock::new(|| {
414    BuiltinMaterializedView {
415        name: "mz_network_policies",
416        schema: MZ_INTERNAL_SCHEMA,
417        oid: oid::MV_MZ_NETWORK_POLICIES_OID,
418        desc: RelationDesc::builder()
419            .with_column("id", SqlScalarType::String.nullable(false))
420            .with_column("name", SqlScalarType::String.nullable(false))
421            .with_column("owner_id", SqlScalarType::String.nullable(false))
422            .with_column(
423                "privileges",
424                SqlScalarType::Array(Box::new(SqlScalarType::MzAclItem)).nullable(false),
425            )
426            .with_column("oid", SqlScalarType::Oid.nullable(false))
427            .with_key(vec![0])
428            .with_key(vec![4])
429            .finish(),
430        column_comments: BTreeMap::from_iter([
431            ("id", "The ID of the network policy."),
432            ("name", "The name of the network policy."),
433            (
434                "owner_id",
435                "The role ID of the owner of the network policy. Corresponds to `mz_catalog.mz_roles.id`.",
436            ),
437            (
438                "privileges",
439                "The privileges belonging to the network policy.",
440            ),
441            ("oid", "A PostgreSQL-compatible OID for the network policy."),
442        ]),
443        sql: "
444IN CLUSTER mz_catalog_server
445WITH (
446    ASSERT NOT NULL id,
447    ASSERT NOT NULL name,
448    ASSERT NOT NULL owner_id,
449    ASSERT NOT NULL privileges,
450    ASSERT NOT NULL oid
451) AS
452SELECT
453    mz_internal.parse_catalog_id(data->'key'->'id') AS id,
454    data->'value'->>'name' AS name,
455    mz_internal.parse_catalog_id(data->'value'->'owner_id') AS owner_id,
456    mz_internal.parse_catalog_privileges(data->'value'->'privileges') AS privileges,
457    (data->'value'->>'oid')::oid AS oid
458FROM mz_internal.mz_catalog_raw
459WHERE data->>'kind' = 'NetworkPolicy'",
460        is_retained_metrics_object: false,
461        access: vec![PUBLIC_SELECT],
462        ontology: Some(Ontology {
463            entity_name: "network_policy",
464            description: "Network access policies",
465            links: &const {
466                [OntologyLink {
467                    name: "owned_by",
468                    target: "role",
469                    properties: LinkProperties::fk("owner_id", "id", Cardinality::ManyToOne),
470                }]
471            },
472            column_semantic_types: &const {
473                [
474                    ("id", SemanticType::NetworkPolicyId),
475                    ("owner_id", SemanticType::RoleId),
476                    ("oid", SemanticType::OID),
477                ]
478            },
479        }),
480    }
481});
482
483pub static MZ_NETWORK_POLICY_RULES: LazyLock<BuiltinMaterializedView> = LazyLock::new(|| {
484    BuiltinMaterializedView {
485        name: "mz_network_policy_rules",
486        schema: MZ_INTERNAL_SCHEMA,
487        oid: oid::MV_MZ_NETWORK_POLICY_RULES_OID,
488        desc: RelationDesc::builder()
489            .with_column("name", SqlScalarType::String.nullable(false))
490            .with_column("policy_id", SqlScalarType::String.nullable(false))
491            .with_column("action", SqlScalarType::String.nullable(false))
492            .with_column("address", SqlScalarType::String.nullable(false))
493            .with_column("direction", SqlScalarType::String.nullable(false))
494            .finish(),
495        column_comments: BTreeMap::from_iter([
496            (
497                "name",
498                "The name of the network policy rule. Can be combined with `policy_id` to form a unique identifier.",
499            ),
500            (
501                "policy_id",
502                "The ID the network policy the rule is part of. Corresponds to `mz_internal.mz_network_policies.id`.",
503            ),
504            (
505                "action",
506                "The action of the rule. `allow` is the only supported action.",
507            ),
508            ("address", "The address the rule will take action on."),
509            (
510                "direction",
511                "The direction of traffic the rule applies to. `ingress` is the only supported direction.",
512            ),
513        ]),
514        sql: "
515IN CLUSTER mz_catalog_server
516WITH (
517    ASSERT NOT NULL name,
518    ASSERT NOT NULL policy_id,
519    ASSERT NOT NULL action,
520    ASSERT NOT NULL address,
521    ASSERT NOT NULL direction
522) AS
523SELECT
524    rule->>'name' AS name,
525    mz_internal.parse_catalog_id(data->'key'->'id') AS policy_id,
526    lower(rule->>'action') AS action,
527    rule->>'address' AS address,
528    lower(rule->>'direction') AS direction
529FROM
530    mz_internal.mz_catalog_raw,
531    jsonb_array_elements(data->'value'->'rules') AS rule
532WHERE data->>'kind' = 'NetworkPolicy'",
533        is_retained_metrics_object: false,
534        access: vec![PUBLIC_SELECT],
535        ontology: Some(Ontology {
536            entity_name: "network_policy_rule",
537            description: "Individual rules within a network policy",
538            links: &const {
539                [OntologyLink {
540                    name: "belongs_to_policy",
541                    target: "network_policy",
542                    properties: LinkProperties::fk("policy_id", "id", Cardinality::ManyToOne),
543                }]
544            },
545            column_semantic_types: &[],
546        }),
547    }
548});
549
550/// PostgreSQL-specific metadata about types that doesn't make sense to expose
551/// in the `mz_types` table as part of our public, stable API.
552pub static MZ_TYPE_PG_METADATA: LazyLock<BuiltinTable> = LazyLock::new(|| BuiltinTable {
553    name: "mz_type_pg_metadata",
554    schema: MZ_INTERNAL_SCHEMA,
555    oid: oid::TABLE_MZ_TYPE_PG_METADATA_OID,
556    desc: RelationDesc::builder()
557        .with_column("id", SqlScalarType::String.nullable(false))
558        .with_column("typinput", SqlScalarType::Oid.nullable(false))
559        .with_column("typreceive", SqlScalarType::Oid.nullable(false))
560        .finish(),
561    column_comments: BTreeMap::new(),
562    is_retained_metrics_object: false,
563    access: vec![PUBLIC_SELECT],
564    ontology: None,
565});
566pub static MZ_AGGREGATES: LazyLock<BuiltinTable> = LazyLock::new(|| BuiltinTable {
567    name: "mz_aggregates",
568    schema: MZ_INTERNAL_SCHEMA,
569    oid: oid::TABLE_MZ_AGGREGATES_OID,
570    desc: RelationDesc::builder()
571        .with_column("oid", SqlScalarType::Oid.nullable(false))
572        .with_column("agg_kind", SqlScalarType::String.nullable(false))
573        .with_column("agg_num_direct_args", SqlScalarType::Int16.nullable(false))
574        .finish(),
575    column_comments: BTreeMap::new(),
576    is_retained_metrics_object: false,
577    access: vec![PUBLIC_SELECT],
578    ontology: Some(Ontology {
579        entity_name: "aggregate",
580        description: "Aggregate function metadata",
581        links: &const { [] },
582        column_semantic_types: &[("oid", SemanticType::OID)],
583    }),
584});
585
586pub static MZ_CLUSTER_WORKLOAD_CLASSES: LazyLock<BuiltinMaterializedView> =
587    LazyLock::new(|| BuiltinMaterializedView {
588        name: "mz_cluster_workload_classes",
589        schema: MZ_INTERNAL_SCHEMA,
590        oid: oid::MV_MZ_CLUSTER_WORKLOAD_CLASSES_OID,
591        desc: RelationDesc::builder()
592            .with_column("id", SqlScalarType::String.nullable(false))
593            .with_column("workload_class", SqlScalarType::String.nullable(true))
594            .with_key(vec![0])
595            .finish(),
596        column_comments: BTreeMap::new(),
597        sql: "
598IN CLUSTER mz_catalog_server
599WITH (
600    ASSERT NOT NULL id
601) AS
602SELECT
603    mz_internal.parse_catalog_id(data->'key'->'id') AS id,
604    CASE WHEN data->'value'->'config'->'workload_class' != 'null'
605         THEN data->'value'->'config'->>'workload_class'
606    END AS workload_class
607FROM mz_internal.mz_catalog_raw
608WHERE data->>'kind' = 'Cluster'",
609        is_retained_metrics_object: false,
610        access: vec![PUBLIC_SELECT],
611        ontology: None,
612    });
613
614pub const MZ_CLUSTER_WORKLOAD_CLASSES_IND: BuiltinIndex = BuiltinIndex {
615    name: "mz_cluster_workload_classes_ind",
616    schema: MZ_INTERNAL_SCHEMA,
617    oid: oid::INDEX_MZ_CLUSTER_WORKLOAD_CLASSES_IND_OID,
618    sql: "IN CLUSTER mz_catalog_server
619ON mz_internal.mz_cluster_workload_classes (id)",
620    is_retained_metrics_object: false,
621};
622
623pub static MZ_CLUSTER_SCHEDULES: LazyLock<BuiltinTable> = LazyLock::new(|| BuiltinTable {
624    name: "mz_cluster_schedules",
625    schema: MZ_INTERNAL_SCHEMA,
626    oid: oid::TABLE_MZ_CLUSTER_SCHEDULES_OID,
627    desc: RelationDesc::builder()
628        .with_column("cluster_id", SqlScalarType::String.nullable(false))
629        .with_column("type", SqlScalarType::String.nullable(false))
630        .with_column(
631            "refresh_hydration_time_estimate",
632            SqlScalarType::Interval.nullable(true),
633        )
634        .finish(),
635    column_comments: BTreeMap::from_iter([
636        (
637            "cluster_id",
638            "The ID of the cluster. Corresponds to `mz_clusters.id`.",
639        ),
640        ("type", "`on-refresh`, or `manual`. Default: `manual`"),
641        (
642            "refresh_hydration_time_estimate",
643            "The interval given in the `HYDRATION TIME ESTIMATE` option.",
644        ),
645    ]),
646    is_retained_metrics_object: false,
647    access: vec![PUBLIC_SELECT],
648    ontology: Some(Ontology {
649        entity_name: "cluster_schedule",
650        description: "Cluster scheduling configuration",
651        links: &const {
652            [OntologyLink {
653                name: "belongs_to_cluster",
654                target: "cluster",
655                properties: LinkProperties::fk("cluster_id", "id", Cardinality::ManyToOne),
656            }]
657        },
658        column_semantic_types: &[("cluster_id", SemanticType::ClusterId)],
659    }),
660});
661
662pub static MZ_INTERNAL_CLUSTER_REPLICAS: LazyLock<BuiltinMaterializedView> =
663    LazyLock::new(|| BuiltinMaterializedView {
664        name: "mz_internal_cluster_replicas",
665        schema: MZ_INTERNAL_SCHEMA,
666        oid: oid::MV_MZ_INTERNAL_CLUSTER_REPLICAS_OID,
667        desc: RelationDesc::builder()
668            .with_column("id", SqlScalarType::String.nullable(false))
669            .with_key(vec![0])
670            .finish(),
671        column_comments: BTreeMap::from_iter([(
672            "id",
673            "The ID of a cluster replica. Corresponds to `mz_cluster_replicas.id`.",
674        )]),
675        sql: "
676IN CLUSTER mz_catalog_server
677WITH (
678    ASSERT NOT NULL id
679) AS
680SELECT mz_internal.parse_catalog_id(data->'key'->'id') AS id
681FROM mz_internal.mz_catalog_raw
682WHERE
683    data->>'kind' = 'ClusterReplica' AND
684    (data->'value'->'config'->'location'->'Managed'->>'internal')::bool = true",
685        is_retained_metrics_object: false,
686        access: vec![PUBLIC_SELECT],
687        ontology: None,
688    });
689
690pub static MZ_PENDING_CLUSTER_REPLICAS: LazyLock<BuiltinMaterializedView> =
691    LazyLock::new(|| BuiltinMaterializedView {
692        name: "mz_pending_cluster_replicas",
693        schema: MZ_INTERNAL_SCHEMA,
694        oid: oid::MV_MZ_PENDING_CLUSTER_REPLICAS_OID,
695        desc: RelationDesc::builder()
696            .with_column("id", SqlScalarType::String.nullable(false))
697            .with_key(vec![0])
698            .finish(),
699        column_comments: BTreeMap::from_iter([(
700            "id",
701            "The ID of a cluster replica. Corresponds to `mz_cluster_replicas.id`.",
702        )]),
703        sql: "
704IN CLUSTER mz_catalog_server
705WITH (
706    ASSERT NOT NULL id
707) AS
708SELECT mz_internal.parse_catalog_id(data->'key'->'id') AS id
709FROM mz_internal.mz_catalog_raw
710WHERE
711    data->>'kind' = 'ClusterReplica' AND
712    (data->'value'->'config'->'location'->'Managed'->>'pending')::bool = true",
713        is_retained_metrics_object: false,
714        access: vec![PUBLIC_SELECT],
715        ontology: None,
716    });
717
718pub static MZ_CLUSTER_REPLICA_STATUS_HISTORY: LazyLock<BuiltinSource> = LazyLock::new(|| {
719    BuiltinSource {
720        name: "mz_cluster_replica_status_history",
721        schema: MZ_INTERNAL_SCHEMA,
722        oid: oid::SOURCE_MZ_CLUSTER_REPLICA_STATUS_HISTORY_OID,
723        data_source: IntrospectionType::ReplicaStatusHistory.into(),
724        desc: REPLICA_STATUS_HISTORY_DESC.clone(),
725        column_comments: BTreeMap::from_iter([
726            ("replica_id", "The ID of a cluster replica."),
727            ("process_id", "The ID of a process within the replica."),
728            (
729                "status",
730                "The status of the cluster replica: `online` or `offline`.",
731            ),
732            (
733                "reason",
734                "If the cluster replica is in an `offline` state, the reason (if available). For example, `oom-killed`.",
735            ),
736            (
737                "occurred_at",
738                "Wall-clock timestamp at which the event occurred.",
739            ),
740        ]),
741        is_retained_metrics_object: false,
742        access: vec![PUBLIC_SELECT],
743        ontology: Some(Ontology {
744            entity_name: "replica_status_event",
745            description: "Historical replica status events (ready, not-ready, etc.)",
746            links: &const {
747                [OntologyLink {
748                    name: "status_event_of_replica",
749                    target: "replica",
750                    properties: LinkProperties::fk_typed(
751                        "replica_id",
752                        "id",
753                        Cardinality::ManyToOne,
754                        mz_repr::SemanticType::CatalogItemId,
755                    ),
756                }]
757            },
758            column_semantic_types: &[("replica_id", SemanticType::ReplicaId)],
759        }),
760    }
761});
762
763pub static MZ_CLUSTER_REPLICA_STATUSES: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
764    name: "mz_cluster_replica_statuses",
765    schema: MZ_INTERNAL_SCHEMA,
766    oid: oid::VIEW_MZ_CLUSTER_REPLICA_STATUSES_OID,
767    desc: RelationDesc::builder()
768        .with_column("replica_id", SqlScalarType::String.nullable(false))
769        .with_column("process_id", SqlScalarType::UInt64.nullable(false))
770        .with_column("status", SqlScalarType::String.nullable(false))
771        .with_column("reason", SqlScalarType::String.nullable(true))
772        .with_column(
773            "updated_at",
774            SqlScalarType::TimestampTz { precision: None }.nullable(false),
775        )
776        .with_key(vec![0, 1])
777        .finish(),
778    column_comments: BTreeMap::from_iter([
779        (
780            "replica_id",
781            "Materialize's unique ID for the cluster replica.",
782        ),
783        (
784            "process_id",
785            "The ID of the process within the cluster replica.",
786        ),
787        (
788            "status",
789            "The status of the cluster replica: `online` or `offline`.",
790        ),
791        (
792            "reason",
793            "If the cluster replica is in a `offline` state, the reason (if available). For example, `oom-killed`.",
794        ),
795        (
796            "updated_at",
797            "The time at which the status was last updated.",
798        ),
799    ]),
800    sql: "
801SELECT
802    DISTINCT ON (replica_id, process_id)
803    replica_id,
804    process_id,
805    status,
806    reason,
807    occurred_at as updated_at
808FROM mz_internal.mz_cluster_replica_status_history
809JOIN mz_cluster_replicas r ON r.id = replica_id
810ORDER BY replica_id, process_id, occurred_at DESC",
811    access: vec![PUBLIC_SELECT],
812    ontology: Some(Ontology {
813        entity_name: "replica_status",
814        description: "Current status of each replica",
815        links: &const {
816            [OntologyLink {
817                name: "status_of_replica",
818                target: "replica",
819                properties: LinkProperties::fk_typed(
820                    "replica_id",
821                    "id",
822                    Cardinality::ManyToOne,
823                    mz_repr::SemanticType::ReplicaId,
824                ),
825            }]
826        },
827        column_semantic_types: &const {
828            [
829                ("replica_id", SemanticType::ReplicaId),
830                ("updated_at", SemanticType::WallclockTimestamp),
831            ]
832        },
833    }),
834});
835
836pub static MZ_SOURCE_STATUS_HISTORY: LazyLock<BuiltinSource> = LazyLock::new(|| BuiltinSource {
837    name: "mz_source_status_history",
838    schema: MZ_INTERNAL_SCHEMA,
839    oid: oid::SOURCE_MZ_SOURCE_STATUS_HISTORY_OID,
840    data_source: IntrospectionType::SourceStatusHistory.into(),
841    desc: MZ_SOURCE_STATUS_HISTORY_DESC.clone(),
842    column_comments: BTreeMap::from_iter([
843        (
844            "occurred_at",
845            "Wall-clock timestamp of the source status change.",
846        ),
847        (
848            "source_id",
849            "The ID of the source. Corresponds to `mz_catalog.mz_sources.id`.",
850        ),
851        (
852            "status",
853            "The status of the source: one of `created`, `starting`, `running`, `paused`, `stalled`, `failed`, or `dropped`.",
854        ),
855        (
856            "error",
857            "If the source is in an error state, the error message.",
858        ),
859        (
860            "details",
861            "Additional metadata provided by the source. In case of error, may contain a `hint` field with helpful suggestions.",
862        ),
863        (
864            "replica_id",
865            "The ID of the replica that an instance of a source is running on.",
866        ),
867    ]),
868    is_retained_metrics_object: false,
869    access: vec![PUBLIC_SELECT],
870    ontology: Some(Ontology {
871        entity_name: "source_status_event",
872        description: "Historical source status events",
873        links: &const {
874            [
875                OntologyLink {
876                    name: "status_event_of_source",
877                    target: "source",
878                    properties: LinkProperties::fk_mapped(
879                        "source_id",
880                        "id",
881                        Cardinality::ManyToOne,
882                        mz_repr::SemanticType::GlobalId,
883                        "mz_internal.mz_object_global_ids",
884                    ),
885                },
886                OntologyLink {
887                    name: "on_replica",
888                    target: "replica",
889                    properties: LinkProperties::fk_nullable(
890                        "replica_id",
891                        "id",
892                        Cardinality::ManyToOne,
893                    ),
894                },
895            ]
896        },
897        column_semantic_types: &const {
898            [
899                ("occurred_at", SemanticType::WallclockTimestamp),
900                ("source_id", SemanticType::GlobalId),
901                ("replica_id", SemanticType::ReplicaId),
902            ]
903        },
904    }),
905});
906
907pub static MZ_AWS_PRIVATELINK_CONNECTION_STATUS_HISTORY: LazyLock<BuiltinSource> = LazyLock::new(
908    || BuiltinSource {
909        name: "mz_aws_privatelink_connection_status_history",
910        schema: MZ_INTERNAL_SCHEMA,
911        oid: oid::SOURCE_MZ_AWS_PRIVATELINK_CONNECTION_STATUS_HISTORY_OID,
912        data_source: DataSourceDesc::Introspection(
913            IntrospectionType::PrivatelinkConnectionStatusHistory,
914        ),
915        desc: MZ_AWS_PRIVATELINK_CONNECTION_STATUS_HISTORY_DESC.clone(),
916        column_comments: BTreeMap::from_iter([
917            ("occurred_at", "Wall-clock timestamp of the status change."),
918            (
919                "connection_id",
920                "The unique identifier of the AWS PrivateLink connection. Corresponds to `mz_catalog.mz_connections.id`.",
921            ),
922            (
923                "status",
924                "The status of the connection: one of `pending-service-discovery`, `creating-endpoint`, `recreating-endpoint`, `updating-endpoint`, `available`, `deleted`, `deleting`, `expired`, `failed`, `pending`, `pending-acceptance`, `rejected`, or `unknown`.",
925            ),
926        ]),
927        is_retained_metrics_object: false,
928        access: vec![PUBLIC_SELECT],
929        ontology: None,
930    },
931);
932
933pub static MZ_AWS_PRIVATELINK_CONNECTION_STATUSES: LazyLock<BuiltinView> = LazyLock::new(|| {
934    BuiltinView {
935        name: "mz_aws_privatelink_connection_statuses",
936        schema: MZ_INTERNAL_SCHEMA,
937        oid: oid::VIEW_MZ_AWS_PRIVATELINK_CONNECTION_STATUSES_OID,
938        desc: RelationDesc::builder()
939            .with_column("id", SqlScalarType::String.nullable(false))
940            .with_column("name", SqlScalarType::String.nullable(false))
941            .with_column(
942                "last_status_change_at",
943                SqlScalarType::TimestampTz { precision: None }.nullable(true),
944            )
945            .with_column("status", SqlScalarType::String.nullable(true))
946            .with_key(vec![0])
947            .finish(),
948        column_comments: BTreeMap::from_iter([
949            (
950                "id",
951                "The ID of the connection. Corresponds to `mz_catalog.mz_connections.id`.",
952            ),
953            ("name", "The name of the connection."),
954            (
955                "last_status_change_at",
956                "Wall-clock timestamp of the connection status change.",
957            ),
958            (
959                "status",
960                "The status of the connection: one of `pending-service-discovery`, `creating-endpoint`, `recreating-endpoint`, `updating-endpoint`, `available`, `deleted`, `deleting`, `expired`, `failed`, `pending`, `pending-acceptance`, `rejected`, or `unknown`.",
961            ),
962        ]),
963        sql: "
964    WITH statuses_w_last_status AS (
965        SELECT
966            connection_id,
967            occurred_at,
968            status,
969            lag(status) OVER (PARTITION BY connection_id ORDER BY occurred_at) AS last_status
970        FROM mz_internal.mz_aws_privatelink_connection_status_history
971    ),
972    latest_events AS (
973        -- Only take the most recent transition for each ID
974        SELECT DISTINCT ON(connection_id) connection_id, occurred_at, status
975        FROM statuses_w_last_status
976        -- Only keep first status transitions
977        WHERE status <> last_status OR last_status IS NULL
978        ORDER BY connection_id, occurred_at DESC
979    )
980    SELECT
981        conns.id,
982        name,
983        occurred_at as last_status_change_at,
984        status
985    FROM latest_events
986    JOIN mz_catalog.mz_connections AS conns
987    ON conns.id = latest_events.connection_id",
988        access: vec![PUBLIC_SELECT],
989        ontology: Some(Ontology {
990            entity_name: "privatelink_status",
991            description: "PrivateLink connection health status",
992            links: &const {
993                [OntologyLink {
994                    name: "status_of",
995                    target: "connection",
996                    properties: LinkProperties::fk("id", "id", Cardinality::OneToOne),
997                }]
998            },
999            column_semantic_types: &[("id", SemanticType::CatalogItemId)],
1000        }),
1001    }
1002});
1003
1004pub static MZ_STATEMENT_EXECUTION_HISTORY: LazyLock<BuiltinSource> =
1005    LazyLock::new(|| BuiltinSource {
1006        name: "mz_statement_execution_history",
1007        schema: MZ_INTERNAL_SCHEMA,
1008        oid: oid::SOURCE_MZ_STATEMENT_EXECUTION_HISTORY_OID,
1009        data_source: IntrospectionType::StatementExecutionHistory.into(),
1010        desc: MZ_STATEMENT_EXECUTION_HISTORY_DESC.clone(),
1011        column_comments: BTreeMap::new(),
1012        is_retained_metrics_object: false,
1013        access: vec![MONITOR_SELECT],
1014        ontology: None,
1015    });
1016
1017pub static MZ_STATEMENT_EXECUTION_HISTORY_REDACTED: LazyLock<BuiltinView> = LazyLock::new(|| {
1018    BuiltinView {
1019    name: "mz_statement_execution_history_redacted",
1020    schema: MZ_INTERNAL_SCHEMA,
1021    oid: oid::VIEW_MZ_STATEMENT_EXECUTION_HISTORY_REDACTED_OID,
1022    // everything but `params` and `error_message`
1023    desc: RelationDesc::builder()
1024        .with_column("id", SqlScalarType::Uuid.nullable(false))
1025        .with_column("prepared_statement_id", SqlScalarType::Uuid.nullable(false))
1026        .with_column("sample_rate", SqlScalarType::Float64.nullable(false))
1027        .with_column("cluster_id", SqlScalarType::String.nullable(true))
1028        .with_column("application_name", SqlScalarType::String.nullable(false))
1029        .with_column("cluster_name", SqlScalarType::String.nullable(true))
1030        .with_column("database_name", SqlScalarType::String.nullable(false))
1031        .with_column("search_path", SqlScalarType::List { element_type: Box::new(SqlScalarType::String), custom_id: None }.nullable(false))
1032        .with_column("transaction_isolation", SqlScalarType::String.nullable(false))
1033        .with_column("execution_timestamp", SqlScalarType::UInt64.nullable(true))
1034        .with_column("transaction_id", SqlScalarType::UInt64.nullable(false))
1035        .with_column("transient_index_id", SqlScalarType::String.nullable(true))
1036        .with_column("mz_version", SqlScalarType::String.nullable(false))
1037        .with_column("began_at", SqlScalarType::TimestampTz { precision: None }.nullable(false))
1038        .with_column("finished_at", SqlScalarType::TimestampTz { precision: None }.nullable(true))
1039        .with_column("finished_status", SqlScalarType::String.nullable(true))
1040        .with_column("result_size", SqlScalarType::Int64.nullable(true))
1041        .with_column("rows_returned", SqlScalarType::Int64.nullable(true))
1042        .with_column("execution_strategy", SqlScalarType::String.nullable(true))
1043        .finish(),
1044    column_comments: BTreeMap::new(),
1045    sql: "
1046SELECT id, prepared_statement_id, sample_rate, cluster_id, application_name,
1047cluster_name, database_name, search_path, transaction_isolation, execution_timestamp, transaction_id,
1048transient_index_id, mz_version, began_at, finished_at, finished_status,
1049result_size, rows_returned, execution_strategy
1050FROM mz_internal.mz_statement_execution_history",
1051    access: vec![SUPPORT_SELECT, ANALYTICS_SELECT, MONITOR_REDACTED_SELECT, MONITOR_SELECT],
1052    ontology: None,
1053}
1054});
1055
1056pub static MZ_PREPARED_STATEMENT_HISTORY: LazyLock<BuiltinSource> =
1057    LazyLock::new(|| BuiltinSource {
1058        name: "mz_prepared_statement_history",
1059        schema: MZ_INTERNAL_SCHEMA,
1060        oid: oid::SOURCE_MZ_PREPARED_STATEMENT_HISTORY_OID,
1061        data_source: IntrospectionType::PreparedStatementHistory.into(),
1062        desc: MZ_PREPARED_STATEMENT_HISTORY_DESC.clone(),
1063        column_comments: BTreeMap::new(),
1064        is_retained_metrics_object: false,
1065        access: vec![
1066            SUPPORT_SELECT,
1067            ANALYTICS_SELECT,
1068            MONITOR_REDACTED_SELECT,
1069            MONITOR_SELECT,
1070        ],
1071        ontology: None,
1072    });
1073
1074pub static MZ_SQL_TEXT: LazyLock<BuiltinSource> = LazyLock::new(|| BuiltinSource {
1075    name: "mz_sql_text",
1076    schema: MZ_INTERNAL_SCHEMA,
1077    oid: oid::SOURCE_MZ_SQL_TEXT_OID,
1078    desc: MZ_SQL_TEXT_DESC.clone(),
1079    data_source: IntrospectionType::SqlText.into(),
1080    column_comments: BTreeMap::new(),
1081    is_retained_metrics_object: false,
1082    access: vec![MONITOR_SELECT],
1083    ontology: Some(Ontology {
1084        entity_name: "sql_text",
1085        description: "Raw SQL text of executed statements",
1086        links: &const { [] },
1087        column_semantic_types: &[],
1088    }),
1089});
1090
1091pub static MZ_SQL_TEXT_REDACTED: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
1092    name: "mz_sql_text_redacted",
1093    schema: MZ_INTERNAL_SCHEMA,
1094    oid: oid::VIEW_MZ_SQL_TEXT_REDACTED_OID,
1095    desc: RelationDesc::builder()
1096        .with_column("sql_hash", SqlScalarType::Bytes.nullable(false))
1097        .with_column("redacted_sql", SqlScalarType::String.nullable(false))
1098        .finish(),
1099    column_comments: BTreeMap::new(),
1100    sql: "SELECT sql_hash, redacted_sql FROM mz_internal.mz_sql_text",
1101    access: vec![
1102        MONITOR_SELECT,
1103        MONITOR_REDACTED_SELECT,
1104        SUPPORT_SELECT,
1105        ANALYTICS_SELECT,
1106    ],
1107    ontology: None,
1108});
1109
1110pub static MZ_RECENT_SQL_TEXT: LazyLock<BuiltinView> = LazyLock::new(|| {
1111    BuiltinView {
1112        name: "mz_recent_sql_text",
1113        schema: MZ_INTERNAL_SCHEMA,
1114        oid: oid::VIEW_MZ_RECENT_SQL_TEXT_OID,
1115        // This should always be 1 day more than the interval in
1116        // `MZ_RECENT_THINNED_ACTIVITY_LOG` , because `prepared_day`
1117        // is rounded down to the nearest day.  Thus something that actually happened three days ago
1118        // could have a `prepared day` anywhere from 3 to 4 days back.
1119        desc: RelationDesc::builder()
1120            .with_column("sql_hash", SqlScalarType::Bytes.nullable(false))
1121            .with_column("sql", SqlScalarType::String.nullable(false))
1122            .with_column("redacted_sql", SqlScalarType::String.nullable(false))
1123            .with_key(vec![0, 1, 2])
1124            .finish(),
1125        column_comments: BTreeMap::new(),
1126        sql: "SELECT DISTINCT sql_hash, sql, redacted_sql FROM mz_internal.mz_sql_text WHERE prepared_day + INTERVAL '4 days' >= mz_now()",
1127        access: vec![MONITOR_SELECT],
1128        ontology: Some(Ontology {
1129            entity_name: "recent_sql_text",
1130            description: "Recent SQL text (indexed, last ~3-4 days)",
1131            links: &const { [] },
1132            column_semantic_types: &[("sql", SemanticType::SqlDefinition)],
1133        }),
1134    }
1135});
1136
1137pub static MZ_RECENT_SQL_TEXT_REDACTED: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
1138    name: "mz_recent_sql_text_redacted",
1139    schema: MZ_INTERNAL_SCHEMA,
1140    oid: oid::VIEW_MZ_RECENT_SQL_TEXT_REDACTED_OID,
1141    desc: RelationDesc::builder()
1142        .with_column("sql_hash", SqlScalarType::Bytes.nullable(false))
1143        .with_column("redacted_sql", SqlScalarType::String.nullable(false))
1144        .finish(),
1145    column_comments: BTreeMap::new(),
1146    sql: "SELECT sql_hash, redacted_sql FROM mz_internal.mz_recent_sql_text",
1147    access: vec![
1148        MONITOR_SELECT,
1149        MONITOR_REDACTED_SELECT,
1150        SUPPORT_SELECT,
1151        ANALYTICS_SELECT,
1152    ],
1153    ontology: None,
1154});
1155
1156pub static MZ_RECENT_SQL_TEXT_IND: LazyLock<BuiltinIndex> = LazyLock::new(|| BuiltinIndex {
1157    name: "mz_recent_sql_text_ind",
1158    schema: MZ_INTERNAL_SCHEMA,
1159    oid: oid::INDEX_MZ_RECENT_SQL_TEXT_IND_OID,
1160    sql: "IN CLUSTER mz_catalog_server ON mz_internal.mz_recent_sql_text (sql_hash)",
1161    is_retained_metrics_object: false,
1162});
1163
1164pub static MZ_SESSION_HISTORY: LazyLock<BuiltinSource> = LazyLock::new(|| BuiltinSource {
1165    name: "mz_session_history",
1166    schema: MZ_INTERNAL_SCHEMA,
1167    oid: oid::SOURCE_MZ_SESSION_HISTORY_OID,
1168    data_source: IntrospectionType::SessionHistory.into(),
1169    desc: MZ_SESSION_HISTORY_DESC.clone(),
1170    column_comments: BTreeMap::from_iter([
1171        (
1172            "session_id",
1173            "The globally unique ID of the session. Corresponds to `mz_sessions.id`.",
1174        ),
1175        (
1176            "connected_at",
1177            "The time at which the session was established.",
1178        ),
1179        (
1180            "initial_application_name",
1181            "The `application_name` session metadata field.",
1182        ),
1183        (
1184            "authenticated_user",
1185            "The name of the user for which the session was established.",
1186        ),
1187    ]),
1188    is_retained_metrics_object: false,
1189    access: vec![PUBLIC_SELECT],
1190    ontology: Some(Ontology {
1191        entity_name: "session",
1192        description: "Historical session connection events",
1193        links: &const {
1194            [OntologyLink {
1195                name: "active_as",
1196                target: "active_session",
1197                properties: LinkProperties::fk_nullable("session_id", "id", Cardinality::ManyToOne),
1198            }]
1199        },
1200        column_semantic_types: &[("connected_at", SemanticType::WallclockTimestamp)],
1201    }),
1202});
1203
1204pub static MZ_ACTIVITY_LOG_THINNED: LazyLock<BuiltinView> = LazyLock::new(|| {
1205    BuiltinView {
1206        name: "mz_activity_log_thinned",
1207        schema: MZ_INTERNAL_SCHEMA,
1208        oid: oid::VIEW_MZ_ACTIVITY_LOG_THINNED_OID,
1209        desc: RelationDesc::builder()
1210            .with_column("execution_id", SqlScalarType::Uuid.nullable(false))
1211            .with_column("sample_rate", SqlScalarType::Float64.nullable(false))
1212            .with_column("cluster_id", SqlScalarType::String.nullable(true))
1213            .with_column("application_name", SqlScalarType::String.nullable(false))
1214            .with_column("cluster_name", SqlScalarType::String.nullable(true))
1215            .with_column("database_name", SqlScalarType::String.nullable(false))
1216            .with_column("search_path", SqlScalarType::List { element_type: Box::new(SqlScalarType::String), custom_id: None }.nullable(false))
1217            .with_column("transaction_isolation", SqlScalarType::String.nullable(false))
1218            .with_column("execution_timestamp", SqlScalarType::UInt64.nullable(true))
1219            .with_column("transient_index_id", SqlScalarType::String.nullable(true))
1220            .with_column("params", SqlScalarType::Array(Box::new(SqlScalarType::String)).nullable(false))
1221            .with_column("mz_version", SqlScalarType::String.nullable(false))
1222            .with_column("began_at", SqlScalarType::TimestampTz { precision: None }.nullable(false))
1223            .with_column("finished_at", SqlScalarType::TimestampTz { precision: None }.nullable(true))
1224            .with_column("finished_status", SqlScalarType::String.nullable(true))
1225            .with_column("error_message", SqlScalarType::String.nullable(true))
1226            .with_column("result_size", SqlScalarType::Int64.nullable(true))
1227            .with_column("rows_returned", SqlScalarType::Int64.nullable(true))
1228            .with_column("execution_strategy", SqlScalarType::String.nullable(true))
1229            .with_column("transaction_id", SqlScalarType::UInt64.nullable(false))
1230            .with_column("prepared_statement_id", SqlScalarType::Uuid.nullable(false))
1231            .with_column("sql_hash", SqlScalarType::Bytes.nullable(false))
1232            .with_column("prepared_statement_name", SqlScalarType::String.nullable(false))
1233            .with_column("session_id", SqlScalarType::Uuid.nullable(false))
1234            .with_column("prepared_at", SqlScalarType::TimestampTz { precision: None }.nullable(false))
1235            .with_column("statement_type", SqlScalarType::String.nullable(true))
1236            .with_column("throttled_count", SqlScalarType::UInt64.nullable(false))
1237            .with_column("connected_at", SqlScalarType::TimestampTz { precision: None }.nullable(false))
1238            .with_column("initial_application_name", SqlScalarType::String.nullable(false))
1239            .with_column("authenticated_user", SqlScalarType::String.nullable(false))
1240            .finish(),
1241        column_comments: BTreeMap::new(),
1242        sql: "
1243SELECT mseh.id AS execution_id, sample_rate, cluster_id, application_name, cluster_name, database_name, search_path,
1244transaction_isolation, execution_timestamp, transient_index_id, params, mz_version, began_at, finished_at, finished_status,
1245error_message, result_size, rows_returned, execution_strategy, transaction_id,
1246mpsh.id AS prepared_statement_id, sql_hash, mpsh.name AS prepared_statement_name,
1247mpsh.session_id, prepared_at, statement_type, throttled_count,
1248connected_at, initial_application_name, authenticated_user
1249FROM mz_internal.mz_statement_execution_history mseh,
1250     mz_internal.mz_prepared_statement_history mpsh,
1251     mz_internal.mz_session_history msh
1252WHERE mseh.prepared_statement_id = mpsh.id
1253AND mpsh.session_id = msh.session_id",
1254        access: vec![MONITOR_SELECT],
1255        ontology: None,
1256    }
1257});
1258
1259pub static MZ_RECENT_ACTIVITY_LOG_THINNED: LazyLock<BuiltinView> = LazyLock::new(|| {
1260    BuiltinView {
1261        name: "mz_recent_activity_log_thinned",
1262        schema: MZ_INTERNAL_SCHEMA,
1263        oid: oid::VIEW_MZ_RECENT_ACTIVITY_LOG_THINNED_OID,
1264        desc: RelationDesc::builder()
1265            .with_column("execution_id", SqlScalarType::Uuid.nullable(false))
1266            .with_column("sample_rate", SqlScalarType::Float64.nullable(false))
1267            .with_column("cluster_id", SqlScalarType::String.nullable(true))
1268            .with_column("application_name", SqlScalarType::String.nullable(false))
1269            .with_column("cluster_name", SqlScalarType::String.nullable(true))
1270            .with_column("database_name", SqlScalarType::String.nullable(false))
1271            .with_column("search_path", SqlScalarType::List { element_type: Box::new(SqlScalarType::String), custom_id: None }.nullable(false))
1272            .with_column("transaction_isolation", SqlScalarType::String.nullable(false))
1273            .with_column("execution_timestamp", SqlScalarType::UInt64.nullable(true))
1274            .with_column("transient_index_id", SqlScalarType::String.nullable(true))
1275            .with_column("params", SqlScalarType::Array(Box::new(SqlScalarType::String)).nullable(false))
1276            .with_column("mz_version", SqlScalarType::String.nullable(false))
1277            .with_column("began_at", SqlScalarType::TimestampTz { precision: None }.nullable(false))
1278            .with_column("finished_at", SqlScalarType::TimestampTz { precision: None }.nullable(true))
1279            .with_column("finished_status", SqlScalarType::String.nullable(true))
1280            .with_column("error_message", SqlScalarType::String.nullable(true))
1281            .with_column("result_size", SqlScalarType::Int64.nullable(true))
1282            .with_column("rows_returned", SqlScalarType::Int64.nullable(true))
1283            .with_column("execution_strategy", SqlScalarType::String.nullable(true))
1284            .with_column("transaction_id", SqlScalarType::UInt64.nullable(false))
1285            .with_column("prepared_statement_id", SqlScalarType::Uuid.nullable(false))
1286            .with_column("sql_hash", SqlScalarType::Bytes.nullable(false))
1287            .with_column("prepared_statement_name", SqlScalarType::String.nullable(false))
1288            .with_column("session_id", SqlScalarType::Uuid.nullable(false))
1289            .with_column("prepared_at", SqlScalarType::TimestampTz { precision: None }.nullable(false))
1290            .with_column("statement_type", SqlScalarType::String.nullable(true))
1291            .with_column("throttled_count", SqlScalarType::UInt64.nullable(false))
1292            .with_column("connected_at", SqlScalarType::TimestampTz { precision: None }.nullable(false))
1293            .with_column("initial_application_name", SqlScalarType::String.nullable(false))
1294            .with_column("authenticated_user", SqlScalarType::String.nullable(false))
1295            .finish(),
1296        column_comments: BTreeMap::new(),
1297        // We use a temporal window of 2 days rather than 1 day for `mz_session_history`'s `connected_at` since a statement execution at
1298        // the edge of the 1 day temporal window could've been executed in a session that was established an hour before the 1 day window.
1299        sql:
1300        "SELECT * FROM mz_internal.mz_activity_log_thinned WHERE prepared_at + INTERVAL '1 day' > mz_now()
1301AND began_at + INTERVAL '1 day' > mz_now() AND connected_at + INTERVAL '2 days' > mz_now()",
1302        access: vec![MONITOR_SELECT],
1303        ontology: None,
1304    }
1305});
1306
1307pub static MZ_RECENT_ACTIVITY_LOG: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
1308    name: "mz_recent_activity_log",
1309    schema: MZ_INTERNAL_SCHEMA,
1310    oid: oid::VIEW_MZ_RECENT_ACTIVITY_LOG_OID,
1311    desc: RelationDesc::builder()
1312        .with_column("execution_id", SqlScalarType::Uuid.nullable(false))
1313        .with_column("sample_rate", SqlScalarType::Float64.nullable(false))
1314        .with_column("cluster_id", SqlScalarType::String.nullable(true))
1315        .with_column("application_name", SqlScalarType::String.nullable(false))
1316        .with_column("cluster_name", SqlScalarType::String.nullable(true))
1317        .with_column("database_name", SqlScalarType::String.nullable(false))
1318        .with_column(
1319            "search_path",
1320            SqlScalarType::List {
1321                element_type: Box::new(SqlScalarType::String),
1322                custom_id: None,
1323            }
1324            .nullable(false),
1325        )
1326        .with_column(
1327            "transaction_isolation",
1328            SqlScalarType::String.nullable(false),
1329        )
1330        .with_column("execution_timestamp", SqlScalarType::UInt64.nullable(true))
1331        .with_column("transient_index_id", SqlScalarType::String.nullable(true))
1332        .with_column(
1333            "params",
1334            SqlScalarType::Array(Box::new(SqlScalarType::String)).nullable(false),
1335        )
1336        .with_column("mz_version", SqlScalarType::String.nullable(false))
1337        .with_column(
1338            "began_at",
1339            SqlScalarType::TimestampTz { precision: None }.nullable(false),
1340        )
1341        .with_column(
1342            "finished_at",
1343            SqlScalarType::TimestampTz { precision: None }.nullable(true),
1344        )
1345        .with_column("finished_status", SqlScalarType::String.nullable(true))
1346        .with_column("error_message", SqlScalarType::String.nullable(true))
1347        .with_column("result_size", SqlScalarType::Int64.nullable(true))
1348        .with_column("rows_returned", SqlScalarType::Int64.nullable(true))
1349        .with_column("execution_strategy", SqlScalarType::String.nullable(true))
1350        .with_column("transaction_id", SqlScalarType::UInt64.nullable(false))
1351        .with_column("prepared_statement_id", SqlScalarType::Uuid.nullable(false))
1352        .with_column("sql_hash", SqlScalarType::Bytes.nullable(false))
1353        .with_column(
1354            "prepared_statement_name",
1355            SqlScalarType::String.nullable(false),
1356        )
1357        .with_column("session_id", SqlScalarType::Uuid.nullable(false))
1358        .with_column(
1359            "prepared_at",
1360            SqlScalarType::TimestampTz { precision: None }.nullable(false),
1361        )
1362        .with_column("statement_type", SqlScalarType::String.nullable(true))
1363        .with_column("throttled_count", SqlScalarType::UInt64.nullable(false))
1364        .with_column(
1365            "connected_at",
1366            SqlScalarType::TimestampTz { precision: None }.nullable(false),
1367        )
1368        .with_column(
1369            "initial_application_name",
1370            SqlScalarType::String.nullable(false),
1371        )
1372        .with_column("authenticated_user", SqlScalarType::String.nullable(false))
1373        .with_column("sql", SqlScalarType::String.nullable(false))
1374        .finish(),
1375    column_comments: BTreeMap::from_iter([
1376        (
1377            "execution_id",
1378            "An ID that is unique for each executed statement.",
1379        ),
1380        (
1381            "sample_rate",
1382            "The actual rate at which the statement was sampled.",
1383        ),
1384        (
1385            "cluster_id",
1386            "The ID of the cluster the statement execution was directed to. Corresponds to mz_clusters.id.",
1387        ),
1388        (
1389            "application_name",
1390            "The value of the `application_name` configuration parameter at execution time.",
1391        ),
1392        (
1393            "cluster_name",
1394            "The name of the cluster with ID `cluster_id` at execution time.",
1395        ),
1396        (
1397            "database_name",
1398            "The value of the `database` configuration parameter at execution time.",
1399        ),
1400        (
1401            "search_path",
1402            "The value of the `search_path` configuration parameter at execution time.",
1403        ),
1404        (
1405            "transaction_isolation",
1406            "The value of the `transaction_isolation` configuration parameter at execution time.",
1407        ),
1408        (
1409            "execution_timestamp",
1410            "The logical timestamp at which execution was scheduled.",
1411        ),
1412        (
1413            "transient_index_id",
1414            "The internal index of the compute dataflow created for the query, if any.",
1415        ),
1416        (
1417            "params",
1418            "The parameters with which the statement was executed.",
1419        ),
1420        (
1421            "mz_version",
1422            "The version of Materialize that was running when the statement was executed.",
1423        ),
1424        (
1425            "began_at",
1426            "The wall-clock time at which the statement began executing.",
1427        ),
1428        (
1429            "finished_at",
1430            "The wall-clock time at which the statement finished executing.",
1431        ),
1432        (
1433            "finished_status",
1434            "The final status of the statement (e.g., `success`, `canceled`, `error`, or `aborted`). \
1435            `aborted` means that the client disconnected before the statement finished executing.",
1436        ),
1437        (
1438            "error_message",
1439            "The error message, if the statement failed.",
1440        ),
1441        (
1442            "result_size",
1443            "The size in bytes of the result, for statements that return rows.",
1444        ),
1445        (
1446            "rows_returned",
1447            "The number of rows returned, for statements that return rows.",
1448        ),
1449        (
1450            "execution_strategy",
1451            "For `SELECT` statements (and similar statement types), the strategy for executing the query. \
1452             `standard` means computed by a temporary dataflow, \
1453             `fast-path` means read by a cluster directly from an in-memory index, \
1454             `persist-fast-path` means read a source, table, or materialized view from blob storage (without an index or dataflow), \
1455             and `constant` means computed in the control plane without the involvement of a cluster. \
1456             (It's `NULL` for statements that errored/canceled/aborted and for non-query-like statement types.)",
1457        ),
1458        (
1459            "transaction_id",
1460            "The ID of the transaction that the statement was part of. Note that transaction IDs are only unique per session.",
1461        ),
1462        (
1463            "prepared_statement_id",
1464            "An ID that is unique for each prepared statement. For example, if a statement is prepared once and then executed multiple times, all executions will have the same value for this column (but different values for `execution_id`).",
1465        ),
1466        (
1467            "sql_hash",
1468            "An opaque value uniquely identifying the text of the query.",
1469        ),
1470        (
1471            "prepared_statement_name",
1472            "The name given by the client library to the prepared statement.",
1473        ),
1474        (
1475            "session_id",
1476            "An ID that is unique for each session. Corresponds to mz_sessions.id.",
1477        ),
1478        (
1479            "prepared_at",
1480            "The time at which the statement was prepared.",
1481        ),
1482        (
1483            "statement_type",
1484            "The _type_ of the statement, e.g. `select` for a `SELECT` query, or `NULL` if the statement was empty.",
1485        ),
1486        (
1487            "throttled_count",
1488            "The number of statement executions dropped due to throttling between the previously logged statement and this one. If you have a very high volume of queries and need to log them without throttling, contact our team.",
1489        ),
1490        (
1491            "connected_at",
1492            "The time at which the session was established.",
1493        ),
1494        (
1495            "initial_application_name",
1496            "The initial value of `application_name` at the beginning of the session.",
1497        ),
1498        (
1499            "authenticated_user",
1500            "The name of the user for which the session was established.",
1501        ),
1502        ("sql", "The SQL text of the statement."),
1503    ]),
1504    sql: "SELECT mralt.*, mrst.sql
1505FROM mz_internal.mz_recent_activity_log_thinned mralt,
1506     mz_internal.mz_recent_sql_text mrst
1507WHERE mralt.sql_hash = mrst.sql_hash",
1508    access: vec![MONITOR_SELECT],
1509    ontology: Some(Ontology {
1510        entity_name: "activity_log",
1511        description: "Recent query activity with execution stats",
1512        links: &const {
1513            [
1514                OntologyLink {
1515                    name: "in_session",
1516                    target: "session",
1517                    properties: LinkProperties::fk("session_id", "id", Cardinality::ManyToOne),
1518                },
1519                OntologyLink {
1520                    name: "in_active_session",
1521                    target: "active_session",
1522                    properties: LinkProperties::fk_nullable(
1523                        "session_id",
1524                        "id",
1525                        Cardinality::ManyToOne,
1526                    ),
1527                },
1528                OntologyLink {
1529                    name: "ran_on_cluster",
1530                    target: "cluster",
1531                    properties: LinkProperties::fk_nullable(
1532                        "cluster_id",
1533                        "id",
1534                        Cardinality::ManyToOne,
1535                    ),
1536                },
1537                OntologyLink {
1538                    name: "used_transient_index",
1539                    target: "object",
1540                    properties: LinkProperties::ForeignKey {
1541                        source_column: "transient_index_id",
1542                        target_column: "id",
1543                        cardinality: Cardinality::ManyToOne,
1544                        source_id_type: Some(mz_repr::SemanticType::GlobalId),
1545                        requires_mapping: Some("mz_internal.mz_object_global_ids"),
1546                        nullable: true,
1547                        note: None,
1548                        extra_key_columns: None,
1549                    },
1550                },
1551            ]
1552        },
1553        column_semantic_types: &const {
1554            [
1555                ("cluster_id", SemanticType::ClusterId),
1556                ("execution_timestamp", SemanticType::MzTimestamp),
1557                ("transient_index_id", SemanticType::GlobalId),
1558                ("began_at", SemanticType::WallclockTimestamp),
1559                ("finished_at", SemanticType::WallclockTimestamp),
1560                ("prepared_at", SemanticType::WallclockTimestamp),
1561                ("connected_at", SemanticType::WallclockTimestamp),
1562                ("sql", SemanticType::SqlDefinition),
1563            ]
1564        },
1565    }),
1566});
1567
1568pub static MZ_RECENT_ACTIVITY_LOG_REDACTED: LazyLock<BuiltinView> = LazyLock::new(|| {
1569    BuiltinView {
1570    name: "mz_recent_activity_log_redacted",
1571    schema: MZ_INTERNAL_SCHEMA,
1572    oid: oid::VIEW_MZ_RECENT_ACTIVITY_LOG_REDACTED_OID,
1573    // Includes all the columns in mz_recent_activity_log_thinned except 'error_message'.
1574    desc: RelationDesc::builder()
1575        .with_column("execution_id", SqlScalarType::Uuid.nullable(false))
1576        .with_column("sample_rate", SqlScalarType::Float64.nullable(false))
1577        .with_column("cluster_id", SqlScalarType::String.nullable(true))
1578        .with_column("application_name", SqlScalarType::String.nullable(false))
1579        .with_column("cluster_name", SqlScalarType::String.nullable(true))
1580        .with_column("database_name", SqlScalarType::String.nullable(false))
1581        .with_column("search_path", SqlScalarType::List { element_type: Box::new(SqlScalarType::String), custom_id: None }.nullable(false))
1582        .with_column("transaction_isolation", SqlScalarType::String.nullable(false))
1583        .with_column("execution_timestamp", SqlScalarType::UInt64.nullable(true))
1584        .with_column("transient_index_id", SqlScalarType::String.nullable(true))
1585        .with_column("mz_version", SqlScalarType::String.nullable(false))
1586        .with_column("began_at", SqlScalarType::TimestampTz { precision: None }.nullable(false))
1587        .with_column("finished_at", SqlScalarType::TimestampTz { precision: None }.nullable(true))
1588        .with_column("finished_status", SqlScalarType::String.nullable(true))
1589        .with_column("result_size", SqlScalarType::Int64.nullable(true))
1590        .with_column("rows_returned", SqlScalarType::Int64.nullable(true))
1591        .with_column("execution_strategy", SqlScalarType::String.nullable(true))
1592        .with_column("transaction_id", SqlScalarType::UInt64.nullable(false))
1593        .with_column("prepared_statement_id", SqlScalarType::Uuid.nullable(false))
1594        .with_column("sql_hash", SqlScalarType::Bytes.nullable(false))
1595        .with_column("prepared_statement_name", SqlScalarType::String.nullable(false))
1596        .with_column("session_id", SqlScalarType::Uuid.nullable(false))
1597        .with_column("prepared_at", SqlScalarType::TimestampTz { precision: None }.nullable(false))
1598        .with_column("statement_type", SqlScalarType::String.nullable(true))
1599        .with_column("throttled_count", SqlScalarType::UInt64.nullable(false))
1600        .with_column("initial_application_name", SqlScalarType::String.nullable(false))
1601        .with_column("authenticated_user", SqlScalarType::String.nullable(false))
1602        .with_column("redacted_sql", SqlScalarType::String.nullable(false))
1603        .finish(),
1604    column_comments: BTreeMap::new(),
1605    sql: "SELECT mralt.execution_id, mralt.sample_rate, mralt.cluster_id, mralt.application_name,
1606    mralt.cluster_name, mralt.database_name, mralt.search_path, mralt.transaction_isolation, mralt.execution_timestamp,
1607    mralt.transient_index_id, mralt.mz_version, mralt.began_at, mralt.finished_at,
1608    mralt.finished_status, mralt.result_size, mralt.rows_returned, mralt.execution_strategy, mralt.transaction_id,
1609    mralt.prepared_statement_id, mralt.sql_hash, mralt.prepared_statement_name, mralt.session_id,
1610    mralt.prepared_at, mralt.statement_type, mralt.throttled_count,
1611    mralt.initial_application_name, mralt.authenticated_user,
1612    mrst.redacted_sql
1613FROM mz_internal.mz_recent_activity_log_thinned mralt,
1614     mz_internal.mz_recent_sql_text mrst
1615WHERE mralt.sql_hash = mrst.sql_hash",
1616    access: vec![MONITOR_SELECT, MONITOR_REDACTED_SELECT, SUPPORT_SELECT, ANALYTICS_SELECT],
1617    ontology: None,
1618}
1619});
1620
1621pub static MZ_STATEMENT_LIFECYCLE_HISTORY: LazyLock<BuiltinSource> = LazyLock::new(|| {
1622    BuiltinSource {
1623        name: "mz_statement_lifecycle_history",
1624        schema: MZ_INTERNAL_SCHEMA,
1625        oid: oid::SOURCE_MZ_STATEMENT_LIFECYCLE_HISTORY_OID,
1626        desc: RelationDesc::builder()
1627            .with_column("statement_id", SqlScalarType::Uuid.nullable(false))
1628            .with_column("event_type", SqlScalarType::String.nullable(false))
1629            .with_column(
1630                "occurred_at",
1631                SqlScalarType::TimestampTz { precision: None }.nullable(false),
1632            )
1633            .finish(),
1634        data_source: IntrospectionType::StatementLifecycleHistory.into(),
1635        column_comments: BTreeMap::from_iter([
1636            (
1637                "statement_id",
1638                "The ID of the execution event. Corresponds to `mz_recent_activity_log.execution_id`",
1639            ),
1640            (
1641                "event_type",
1642                "The type of lifecycle event, e.g. `'execution-began'`, `'storage-dependencies-finished'`, `'compute-dependencies-finished'`, or `'execution-finished'`",
1643            ),
1644            ("occurred_at", "The time at which the event took place."),
1645        ]),
1646        is_retained_metrics_object: false,
1647        // TODO[btv]: Maybe this should be public instead of
1648        // `MONITOR_REDACTED`, but since that would be a backwards-compatible
1649        // change, we probably don't need to worry about it now.
1650        access: vec![
1651            SUPPORT_SELECT,
1652            ANALYTICS_SELECT,
1653            MONITOR_REDACTED_SELECT,
1654            MONITOR_SELECT,
1655        ],
1656        ontology: Some(Ontology {
1657            entity_name: "statement_lifecycle_event",
1658            description: "Statement lifecycle events (parse, bind, execute)",
1659            links: &const {
1660                [OntologyLink {
1661                    name: "for_execution",
1662                    target: "activity_log",
1663                    properties: LinkProperties::fk(
1664                        "statement_id",
1665                        "execution_id",
1666                        Cardinality::ManyToOne,
1667                    ),
1668                }]
1669            },
1670            column_semantic_types: &[],
1671        }),
1672    }
1673});
1674
1675pub static MZ_SOURCE_STATUSES: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
1676    name: "mz_source_statuses",
1677    schema: MZ_INTERNAL_SCHEMA,
1678    oid: oid::VIEW_MZ_SOURCE_STATUSES_OID,
1679    desc: RelationDesc::builder()
1680        .with_column("id", SqlScalarType::String.nullable(false))
1681        .with_column("name", SqlScalarType::String.nullable(false))
1682        .with_column("type", SqlScalarType::String.nullable(false))
1683        .with_column(
1684            "last_status_change_at",
1685            SqlScalarType::TimestampTz { precision: None }.nullable(true),
1686        )
1687        .with_column("status", SqlScalarType::String.nullable(false))
1688        .with_column("error", SqlScalarType::String.nullable(true))
1689        .with_column("details", SqlScalarType::Jsonb.nullable(true))
1690        .finish(),
1691    column_comments: BTreeMap::from_iter([
1692        (
1693            "id",
1694            "The ID of the source. Corresponds to `mz_catalog.mz_sources.id`.",
1695        ),
1696        ("name", "The name of the source."),
1697        ("type", "The type of the source."),
1698        (
1699            "last_status_change_at",
1700            "Wall-clock timestamp of the source status change.",
1701        ),
1702        (
1703            "status",
1704            "The status of the source: one of `created`, `starting`, `running`, `paused`, `stalled`, `failed`, or `dropped`.",
1705        ),
1706        (
1707            "error",
1708            "If the source is in an error state, the error message.",
1709        ),
1710        (
1711            "details",
1712            "Additional metadata provided by the source. In case of error, may contain a `hint` field with helpful suggestions.",
1713        ),
1714    ]),
1715    sql: "
1716    WITH
1717    -- The status history contains per-replica events and source-global events.
1718    -- For the latter, replica_id is NULL. We turn these into '<source>', so that
1719    -- we can treat them uniformly below.
1720    uniform_status_history AS
1721    (
1722        SELECT
1723            s.source_id,
1724            COALESCE(s.replica_id, '<source>') as replica_id,
1725            s.occurred_at,
1726            s.status,
1727            s.error,
1728            s.details
1729        FROM mz_internal.mz_source_status_history s
1730    ),
1731    -- For getting the latest events, we first determine the latest per-replica
1732    -- events here and then apply precedence rules below.
1733    latest_per_replica_events AS
1734    (
1735        SELECT DISTINCT ON (source_id, replica_id)
1736            occurred_at, source_id, replica_id, status, error, details
1737        FROM uniform_status_history
1738        ORDER BY source_id, replica_id, occurred_at DESC
1739    ),
1740    -- We have a precedence list that determines the overall status in case
1741    -- there is differing per-replica (including source-global) statuses. If
1742    -- there is no 'dropped' status, and any replica reports 'running', the
1743    -- overall status is 'running' even if there might be some replica that has
1744    -- errors or is paused.
1745    latest_events AS
1746    (
1747       SELECT DISTINCT ON (source_id)
1748            source_id,
1749            occurred_at,
1750            status,
1751            error,
1752            details
1753        FROM latest_per_replica_events
1754        ORDER BY source_id, CASE status
1755                    WHEN 'dropped' THEN 1
1756                    WHEN 'running' THEN 2
1757                    WHEN 'stalled' THEN 3
1758                    WHEN 'starting' THEN 4
1759                    WHEN 'paused' THEN 5
1760                    WHEN 'ceased' THEN 6
1761                    ELSE 7  -- For any other status values
1762                END
1763    ),
1764    -- Determine which sources are subsources and which are parent sources
1765    subsources AS
1766    (
1767        SELECT subsources.id AS self, sources.id AS parent
1768        FROM
1769            mz_catalog.mz_sources AS subsources
1770                JOIN
1771                    mz_internal.mz_object_dependencies AS deps
1772                    ON subsources.id = deps.object_id
1773                JOIN mz_catalog.mz_sources AS sources ON sources.id = deps.referenced_object_id
1774    ),
1775    -- Determine which sources are source tables
1776    tables AS
1777    (
1778        SELECT tables.id AS self, tables.source_id AS parent, tables.name
1779        FROM mz_catalog.mz_tables AS tables
1780        WHERE tables.source_id IS NOT NULL
1781    ),
1782    -- Determine which collection's ID to use for the status
1783    id_of_status_to_use AS
1784    (
1785        SELECT
1786            self_events.source_id,
1787            -- If self not errored, but parent is, use parent; else self
1788            CASE
1789                WHEN
1790                    self_events.status <> 'ceased' AND
1791                    parent_events.status = 'stalled'
1792                THEN parent_events.source_id
1793                ELSE self_events.source_id
1794            END AS id_to_use
1795        FROM
1796            latest_events AS self_events
1797                LEFT JOIN subsources ON self_events.source_id = subsources.self
1798                LEFT JOIN tables ON self_events.source_id = tables.self
1799                LEFT JOIN
1800                    latest_events AS parent_events
1801                    ON parent_events.source_id = COALESCE(subsources.parent, tables.parent)
1802    ),
1803    -- Swap out events for the ID of the event we plan to use instead
1804    latest_events_to_use AS
1805    (
1806        SELECT occurred_at, s.source_id, status, error, details
1807        FROM
1808            id_of_status_to_use AS s
1809                JOIN latest_events AS e ON e.source_id = s.id_to_use
1810    ),
1811    combined AS (
1812        SELECT
1813            mz_sources.id,
1814            mz_sources.name,
1815            mz_sources.type,
1816            occurred_at,
1817            status,
1818            error,
1819            details
1820        FROM
1821            mz_catalog.mz_sources
1822            LEFT JOIN latest_events_to_use AS e ON mz_sources.id = e.source_id
1823        UNION ALL
1824        SELECT
1825            tables.self AS id,
1826            tables.name,
1827            'table' AS type,
1828            occurred_at,
1829            status,
1830            error,
1831            details
1832        FROM
1833            tables
1834            LEFT JOIN latest_events_to_use AS e ON tables.self = e.source_id
1835    )
1836SELECT
1837    id,
1838    name,
1839    type,
1840    occurred_at AS last_status_change_at,
1841    -- TODO(parkmycar): Report status of webhook source once database-issues#5986 is closed.
1842    CASE
1843        WHEN
1844            type = 'webhook' OR
1845            type = 'progress'
1846        THEN 'running'
1847        ELSE COALESCE(status, 'created')
1848    END AS status,
1849    error,
1850    details
1851FROM combined
1852WHERE id NOT LIKE 's%';",
1853    access: vec![PUBLIC_SELECT],
1854    ontology: Some(Ontology {
1855        entity_name: "source_status",
1856        description: "Current source status (running, stalled, etc.)",
1857        links: &const {
1858            [OntologyLink {
1859                name: "status_of_source",
1860                target: "source",
1861                properties: LinkProperties::fk("id", "id", Cardinality::OneToOne),
1862            }]
1863        },
1864        column_semantic_types: &const {
1865            [
1866                ("id", SemanticType::CatalogItemId),
1867                ("type", SemanticType::SourceType),
1868                ("last_status_change_at", SemanticType::WallclockTimestamp),
1869            ]
1870        },
1871    }),
1872});
1873
1874pub static MZ_SINK_STATUS_HISTORY: LazyLock<BuiltinSource> = LazyLock::new(|| BuiltinSource {
1875    name: "mz_sink_status_history",
1876    schema: MZ_INTERNAL_SCHEMA,
1877    oid: oid::SOURCE_MZ_SINK_STATUS_HISTORY_OID,
1878    data_source: IntrospectionType::SinkStatusHistory.into(),
1879    desc: MZ_SINK_STATUS_HISTORY_DESC.clone(),
1880    column_comments: BTreeMap::from_iter([
1881        (
1882            "occurred_at",
1883            "Wall-clock timestamp of the sink status change.",
1884        ),
1885        (
1886            "sink_id",
1887            "The ID of the sink. Corresponds to `mz_catalog.mz_sinks.id`.",
1888        ),
1889        (
1890            "status",
1891            "The status of the sink: one of `created`, `starting`, `running`, `stalled`, `failed`, or `dropped`.",
1892        ),
1893        (
1894            "error",
1895            "If the sink is in an error state, the error message.",
1896        ),
1897        (
1898            "details",
1899            "Additional metadata provided by the sink. In case of error, may contain a `hint` field with helpful suggestions.",
1900        ),
1901        (
1902            "replica_id",
1903            "The ID of the replica that an instance of a sink is running on.",
1904        ),
1905    ]),
1906    is_retained_metrics_object: false,
1907    access: vec![PUBLIC_SELECT],
1908    ontology: Some(Ontology {
1909        entity_name: "sink_status_event",
1910        description: "Historical sink status events",
1911        links: &const {
1912            [
1913                OntologyLink {
1914                    name: "status_event_of_sink",
1915                    target: "sink",
1916                    properties: LinkProperties::fk_mapped(
1917                        "sink_id",
1918                        "id",
1919                        Cardinality::ManyToOne,
1920                        mz_repr::SemanticType::GlobalId,
1921                        "mz_internal.mz_object_global_ids",
1922                    ),
1923                },
1924                OntologyLink {
1925                    name: "on_replica",
1926                    target: "replica",
1927                    properties: LinkProperties::fk_nullable(
1928                        "replica_id",
1929                        "id",
1930                        Cardinality::ManyToOne,
1931                    ),
1932                },
1933            ]
1934        },
1935        column_semantic_types: &const {
1936            [
1937                ("occurred_at", SemanticType::WallclockTimestamp),
1938                ("sink_id", SemanticType::GlobalId),
1939                ("replica_id", SemanticType::ReplicaId),
1940            ]
1941        },
1942    }),
1943});
1944
1945pub static MZ_SINK_STATUSES: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
1946    name: "mz_sink_statuses",
1947    schema: MZ_INTERNAL_SCHEMA,
1948    oid: oid::VIEW_MZ_SINK_STATUSES_OID,
1949    desc: RelationDesc::builder()
1950        .with_column("id", SqlScalarType::String.nullable(false))
1951        .with_column("name", SqlScalarType::String.nullable(false))
1952        .with_column("type", SqlScalarType::String.nullable(false))
1953        .with_column(
1954            "last_status_change_at",
1955            SqlScalarType::TimestampTz { precision: None }.nullable(true),
1956        )
1957        .with_column("status", SqlScalarType::String.nullable(false))
1958        .with_column("error", SqlScalarType::String.nullable(true))
1959        .with_column("details", SqlScalarType::Jsonb.nullable(true))
1960        .finish(),
1961    column_comments: BTreeMap::from_iter([
1962        (
1963            "id",
1964            "The ID of the sink. Corresponds to `mz_catalog.mz_sinks.id`.",
1965        ),
1966        ("name", "The name of the sink."),
1967        ("type", "The type of the sink."),
1968        (
1969            "last_status_change_at",
1970            "Wall-clock timestamp of the sink status change.",
1971        ),
1972        (
1973            "status",
1974            "The status of the sink: one of `created`, `starting`, `running`, `stalled`, `failed`, or `dropped`.",
1975        ),
1976        (
1977            "error",
1978            "If the sink is in an error state, the error message.",
1979        ),
1980        (
1981            "details",
1982            "Additional metadata provided by the sink. In case of error, may contain a `hint` field with helpful suggestions.",
1983        ),
1984    ]),
1985    sql: "
1986WITH
1987-- The status history contains per-replica events and sink-global events.
1988-- For the latter, replica_id is NULL. We turn these into '<sink>', so that
1989-- we can treat them uniformly below.
1990uniform_status_history AS
1991(
1992    SELECT
1993        s.sink_id,
1994        COALESCE(s.replica_id, '<sink>') as replica_id,
1995        s.occurred_at,
1996        s.status,
1997        s.error,
1998        s.details
1999    FROM mz_internal.mz_sink_status_history s
2000),
2001-- For getting the latest events, we first determine the latest per-replica
2002-- events here and then apply precedence rules below.
2003latest_per_replica_events AS
2004(
2005    SELECT DISTINCT ON (sink_id, replica_id)
2006        occurred_at, sink_id, replica_id, status, error, details
2007    FROM uniform_status_history
2008    ORDER BY sink_id, replica_id, occurred_at DESC
2009),
2010-- We have a precedence list that determines the overall status in case
2011-- there is differing per-replica (including sink-global) statuses. If
2012-- there is no 'dropped' status, and any replica reports 'running', the
2013-- overall status is 'running' even if there might be some replica that has
2014-- errors or is paused.
2015latest_events AS
2016(
2017    SELECT DISTINCT ON (sink_id)
2018        sink_id,
2019        occurred_at,
2020        status,
2021        error,
2022        details
2023    FROM latest_per_replica_events
2024    ORDER BY sink_id, CASE status
2025                WHEN 'dropped' THEN 1
2026                WHEN 'running' THEN 2
2027                WHEN 'stalled' THEN 3
2028                WHEN 'starting' THEN 4
2029                WHEN 'paused' THEN 5
2030                WHEN 'ceased' THEN 6
2031                ELSE 7  -- For any other status values
2032            END
2033)
2034SELECT
2035    mz_sinks.id,
2036    name,
2037    mz_sinks.type,
2038    occurred_at as last_status_change_at,
2039    coalesce(status, 'created') as status,
2040    error,
2041    details
2042FROM mz_catalog.mz_sinks
2043LEFT JOIN latest_events ON mz_sinks.id = latest_events.sink_id
2044WHERE
2045    -- This is a convenient way to filter out system sinks, like the status_history table itself.
2046    mz_sinks.id NOT LIKE 's%'",
2047    access: vec![PUBLIC_SELECT],
2048    ontology: Some(Ontology {
2049        entity_name: "sink_status",
2050        description: "Current sink status",
2051        links: &const {
2052            [OntologyLink {
2053                name: "status_of_sink",
2054                target: "sink",
2055                properties: LinkProperties::fk_typed(
2056                    "id",
2057                    "id",
2058                    Cardinality::OneToOne,
2059                    mz_repr::SemanticType::CatalogItemId,
2060                ),
2061            }]
2062        },
2063        column_semantic_types: &const {
2064            [
2065                ("id", SemanticType::CatalogItemId),
2066                ("last_status_change_at", SemanticType::WallclockTimestamp),
2067            ]
2068        },
2069    }),
2070});
2071
2072pub static MZ_STORAGE_USAGE_BY_SHARD: LazyLock<BuiltinTable> = LazyLock::new(|| BuiltinTable {
2073    name: "mz_storage_usage_by_shard",
2074    schema: MZ_INTERNAL_SCHEMA,
2075    oid: oid::TABLE_MZ_STORAGE_USAGE_BY_SHARD_OID,
2076    desc: RelationDesc::builder()
2077        .with_column("id", SqlScalarType::UInt64.nullable(false))
2078        .with_column("shard_id", SqlScalarType::String.nullable(true))
2079        .with_column("size_bytes", SqlScalarType::UInt64.nullable(false))
2080        .with_column(
2081            "collection_timestamp",
2082            SqlScalarType::TimestampTz { precision: None }.nullable(false),
2083        )
2084        .finish(),
2085    column_comments: BTreeMap::new(),
2086    is_retained_metrics_object: false,
2087    access: vec![PUBLIC_SELECT],
2088    ontology: Some(Ontology {
2089        entity_name: "storage_usage_by_shard",
2090        description: "Storage usage broken down by shard",
2091        links: &const { [] },
2092        column_semantic_types: &const {
2093            [
2094                ("shard_id", SemanticType::ShardId),
2095                ("size_bytes", SemanticType::ByteCount),
2096                ("collection_timestamp", SemanticType::WallclockTimestamp),
2097            ]
2098        },
2099    }),
2100});
2101
2102pub static MZ_AWS_CONNECTIONS: LazyLock<BuiltinTable> = LazyLock::new(|| BuiltinTable {
2103    name: "mz_aws_connections",
2104    schema: MZ_INTERNAL_SCHEMA,
2105    oid: oid::TABLE_MZ_AWS_CONNECTIONS_OID,
2106    desc: RelationDesc::builder()
2107        .with_column("id", SqlScalarType::String.nullable(false))
2108        .with_column("endpoint", SqlScalarType::String.nullable(true))
2109        .with_column("region", SqlScalarType::String.nullable(true))
2110        .with_column("access_key_id", SqlScalarType::String.nullable(true))
2111        .with_column(
2112            "access_key_id_secret_id",
2113            SqlScalarType::String.nullable(true),
2114        )
2115        .with_column(
2116            "secret_access_key_secret_id",
2117            SqlScalarType::String.nullable(true),
2118        )
2119        .with_column("session_token", SqlScalarType::String.nullable(true))
2120        .with_column(
2121            "session_token_secret_id",
2122            SqlScalarType::String.nullable(true),
2123        )
2124        .with_column("assume_role_arn", SqlScalarType::String.nullable(true))
2125        .with_column(
2126            "assume_role_session_name",
2127            SqlScalarType::String.nullable(true),
2128        )
2129        .with_column("principal", SqlScalarType::String.nullable(true))
2130        .with_column("external_id", SqlScalarType::String.nullable(true))
2131        .with_column("example_trust_policy", SqlScalarType::Jsonb.nullable(true))
2132        .finish(),
2133    column_comments: BTreeMap::from_iter([
2134        ("id", "The ID of the connection."),
2135        ("endpoint", "The value of the `ENDPOINT` option, if set."),
2136        ("region", "The value of the `REGION` option, if set."),
2137        (
2138            "access_key_id",
2139            "The value of the `ACCESS KEY ID` option, if provided in line.",
2140        ),
2141        (
2142            "access_key_id_secret_id",
2143            "The ID of the secret referenced by the `ACCESS KEY ID` option, if provided via a secret.",
2144        ),
2145        (
2146            "secret_access_key_secret_id",
2147            "The ID of the secret referenced by the `SECRET ACCESS KEY` option, if set.",
2148        ),
2149        (
2150            "session_token",
2151            "The value of the `SESSION TOKEN` option, if provided in line.",
2152        ),
2153        (
2154            "session_token_secret_id",
2155            "The ID of the secret referenced by the `SESSION TOKEN` option, if provided via a secret.",
2156        ),
2157        (
2158            "assume_role_arn",
2159            "The value of the `ASSUME ROLE ARN` option, if set.",
2160        ),
2161        (
2162            "assume_role_session_name",
2163            "The value of the `ASSUME ROLE SESSION NAME` option, if set.",
2164        ),
2165        (
2166            "principal",
2167            "The ARN of the AWS principal Materialize will use when assuming the provided role, if the connection is configured to use role assumption.",
2168        ),
2169        (
2170            "external_id",
2171            "The external ID Materialize will use when assuming the provided role, if the connection is configured to use role assumption.",
2172        ),
2173        (
2174            "example_trust_policy",
2175            "An example of an IAM role trust policy that allows this connection's principal and external ID to assume the role.",
2176        ),
2177    ]),
2178    is_retained_metrics_object: false,
2179    access: vec![PUBLIC_SELECT],
2180    ontology: Some(Ontology {
2181        entity_name: "aws_connection",
2182        description: "AWS connection configuration details",
2183        links: &const {
2184            [OntologyLink {
2185                name: "details_of",
2186                target: "connection",
2187                properties: LinkProperties::fk("id", "id", Cardinality::OneToOne),
2188            }]
2189        },
2190        column_semantic_types: &[],
2191    }),
2192});
2193
2194pub static MZ_CLUSTER_REPLICA_METRICS_HISTORY: LazyLock<BuiltinSource> =
2195    LazyLock::new(|| BuiltinSource {
2196        name: "mz_cluster_replica_metrics_history",
2197        schema: MZ_INTERNAL_SCHEMA,
2198        oid: oid::SOURCE_MZ_CLUSTER_REPLICA_METRICS_HISTORY_OID,
2199        data_source: IntrospectionType::ReplicaMetricsHistory.into(),
2200        desc: REPLICA_METRICS_HISTORY_DESC.clone(),
2201        column_comments: BTreeMap::from_iter([
2202            ("replica_id", "The ID of a cluster replica."),
2203            ("process_id", "The ID of a process within the replica."),
2204            (
2205                "cpu_nano_cores",
2206                "Approximate CPU usage, in billionths of a vCPU core.",
2207            ),
2208            ("memory_bytes", "Approximate memory usage, in bytes."),
2209            ("disk_bytes", "Approximate disk usage, in bytes."),
2210            (
2211                "occurred_at",
2212                "Wall-clock timestamp at which the event occurred.",
2213            ),
2214            (
2215                "heap_bytes",
2216                "Approximate heap (RAM + swap) usage, in bytes.",
2217            ),
2218            ("heap_limit", "Available heap (RAM + swap) space, in bytes."),
2219        ]),
2220        is_retained_metrics_object: false,
2221        access: vec![PUBLIC_SELECT],
2222        ontology: None,
2223    });
2224
2225pub static MZ_CLUSTER_REPLICA_METRICS: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
2226    name: "mz_cluster_replica_metrics",
2227    schema: MZ_INTERNAL_SCHEMA,
2228    oid: oid::VIEW_MZ_CLUSTER_REPLICA_METRICS_OID,
2229    desc: RelationDesc::builder()
2230        .with_column("replica_id", SqlScalarType::String.nullable(false))
2231        .with_column("process_id", SqlScalarType::UInt64.nullable(false))
2232        .with_column("cpu_nano_cores", SqlScalarType::UInt64.nullable(true))
2233        .with_column("memory_bytes", SqlScalarType::UInt64.nullable(true))
2234        .with_column("disk_bytes", SqlScalarType::UInt64.nullable(true))
2235        .with_column("heap_bytes", SqlScalarType::UInt64.nullable(true))
2236        .with_column("heap_limit", SqlScalarType::UInt64.nullable(true))
2237        .with_key(vec![0, 1])
2238        .finish(),
2239    column_comments: BTreeMap::from_iter([
2240        ("replica_id", "The ID of a cluster replica."),
2241        ("process_id", "The ID of a process within the replica."),
2242        (
2243            "cpu_nano_cores",
2244            "Approximate CPU usage, in billionths of a vCPU core.",
2245        ),
2246        ("memory_bytes", "Approximate RAM usage, in bytes."),
2247        ("disk_bytes", "Approximate disk usage, in bytes."),
2248        (
2249            "heap_bytes",
2250            "Approximate heap (RAM + swap) usage, in bytes.",
2251        ),
2252        ("heap_limit", "Available heap (RAM + swap) space, in bytes."),
2253    ]),
2254    sql: "
2255SELECT
2256    DISTINCT ON (replica_id, process_id)
2257    replica_id,
2258    process_id,
2259    cpu_nano_cores,
2260    memory_bytes,
2261    disk_bytes,
2262    heap_bytes,
2263    heap_limit
2264FROM mz_internal.mz_cluster_replica_metrics_history
2265JOIN mz_cluster_replicas r ON r.id = replica_id
2266ORDER BY replica_id, process_id, occurred_at DESC",
2267    access: vec![PUBLIC_SELECT],
2268    ontology: Some(Ontology {
2269        entity_name: "replica_metrics",
2270        description: "CPU and memory metrics per replica",
2271        links: &const {
2272            [OntologyLink {
2273                name: "metrics_of_replica",
2274                target: "replica",
2275                properties: LinkProperties::fk_typed(
2276                    "replica_id",
2277                    "id",
2278                    Cardinality::OneToOne,
2279                    mz_repr::SemanticType::CatalogItemId,
2280                ),
2281            }]
2282        },
2283        column_semantic_types: &const {
2284            [
2285                ("replica_id", SemanticType::ReplicaId),
2286                ("memory_bytes", SemanticType::ByteCount),
2287                ("disk_bytes", SemanticType::ByteCount),
2288                ("heap_bytes", SemanticType::ByteCount),
2289                ("heap_limit", SemanticType::ByteCount),
2290            ]
2291        },
2292    }),
2293});
2294
2295pub static MZ_FRONTIERS: LazyLock<BuiltinSource> = LazyLock::new(|| BuiltinSource {
2296    name: "mz_frontiers",
2297    schema: MZ_INTERNAL_SCHEMA,
2298    oid: oid::SOURCE_MZ_FRONTIERS_OID,
2299    data_source: IntrospectionType::Frontiers.into(),
2300    desc: RelationDesc::builder()
2301        .with_column("object_id", SqlScalarType::String.nullable(false))
2302        .with_column("read_frontier", SqlScalarType::MzTimestamp.nullable(true))
2303        .with_column("write_frontier", SqlScalarType::MzTimestamp.nullable(true))
2304        .finish(),
2305    column_comments: BTreeMap::from_iter([
2306        (
2307            "object_id",
2308            "The ID of the source, sink, table, index, materialized view, or subscription.",
2309        ),
2310        (
2311            "read_frontier",
2312            "The earliest timestamp at which the output is still readable.",
2313        ),
2314        (
2315            "write_frontier",
2316            "The next timestamp at which the output may change.",
2317        ),
2318    ]),
2319    is_retained_metrics_object: false,
2320    access: vec![PUBLIC_SELECT],
2321    ontology: Some(Ontology {
2322        entity_name: "frontier",
2323        description: "Current read/write frontiers for sources, sinks, tables, materialized views, indexes, and subscriptions",
2324        links: &const {
2325            [OntologyLink {
2326                name: "frontier_of",
2327                target: "object",
2328                properties: LinkProperties::fk_mapped(
2329                    "object_id",
2330                    "id",
2331                    Cardinality::ManyToOne,
2332                    mz_repr::SemanticType::GlobalId,
2333                    "mz_internal.mz_object_global_ids",
2334                ),
2335            }]
2336        },
2337        column_semantic_types: &const {
2338            [
2339                ("object_id", SemanticType::GlobalId),
2340                ("read_frontier", SemanticType::MzTimestamp),
2341                ("write_frontier", SemanticType::MzTimestamp),
2342            ]
2343        },
2344    }),
2345});
2346
2347/// DEPRECATED and scheduled for removal! Use `mz_frontiers` instead.
2348pub static MZ_GLOBAL_FRONTIERS: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
2349    name: "mz_global_frontiers",
2350    schema: MZ_INTERNAL_SCHEMA,
2351    oid: oid::VIEW_MZ_GLOBAL_FRONTIERS_OID,
2352    desc: RelationDesc::builder()
2353        .with_column("object_id", SqlScalarType::String.nullable(false))
2354        .with_column("time", SqlScalarType::MzTimestamp.nullable(false))
2355        .finish(),
2356    column_comments: BTreeMap::new(),
2357    sql: "
2358SELECT object_id, write_frontier AS time
2359FROM mz_internal.mz_frontiers
2360WHERE write_frontier IS NOT NULL",
2361    access: vec![PUBLIC_SELECT],
2362    ontology: None,
2363});
2364
2365pub static MZ_WALLCLOCK_LAG_HISTORY: LazyLock<BuiltinSource> = LazyLock::new(|| BuiltinSource {
2366    name: "mz_wallclock_lag_history",
2367    schema: MZ_INTERNAL_SCHEMA,
2368    oid: oid::SOURCE_MZ_WALLCLOCK_LAG_HISTORY_OID,
2369    desc: WALLCLOCK_LAG_HISTORY_DESC.clone(),
2370    data_source: IntrospectionType::WallclockLagHistory.into(),
2371    column_comments: BTreeMap::from_iter([
2372        (
2373            "object_id",
2374            "The ID of the table, source, materialized view, index, or sink. Corresponds to `mz_objects.id`.",
2375        ),
2376        (
2377            "replica_id",
2378            "The ID of a replica computing the object, or `NULL` for persistent objects. Corresponds to `mz_cluster_replicas.id`.",
2379        ),
2380        (
2381            "lag",
2382            "The amount of time the object's write frontier lags behind wallclock time.",
2383        ),
2384        (
2385            "occurred_at",
2386            "Wall-clock timestamp at which the event occurred.",
2387        ),
2388    ]),
2389    is_retained_metrics_object: false,
2390    access: vec![PUBLIC_SELECT],
2391    ontology: Some(Ontology {
2392        entity_name: "wallclock_lag_event",
2393        description: "Historical wallclock lag per object",
2394        links: &const {
2395            [
2396                OntologyLink {
2397                    name: "measures_lag_of",
2398                    target: "object",
2399                    properties: LinkProperties::measures_mapped(
2400                        "object_id",
2401                        "id",
2402                        "wallclock_lag",
2403                        mz_repr::SemanticType::GlobalId,
2404                        "mz_internal.mz_object_global_ids",
2405                    ),
2406                },
2407                OntologyLink {
2408                    name: "on_replica",
2409                    target: "replica",
2410                    properties: LinkProperties::fk_nullable(
2411                        "replica_id",
2412                        "id",
2413                        Cardinality::ManyToOne,
2414                    ),
2415                },
2416            ]
2417        },
2418        column_semantic_types: &const {
2419            [
2420                ("object_id", SemanticType::GlobalId),
2421                ("replica_id", SemanticType::ReplicaId),
2422                ("occurred_at", SemanticType::WallclockTimestamp),
2423            ]
2424        },
2425    }),
2426});
2427
2428pub static MZ_WALLCLOCK_GLOBAL_LAG_HISTORY: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
2429    name: "mz_wallclock_global_lag_history",
2430    schema: MZ_INTERNAL_SCHEMA,
2431    oid: oid::VIEW_MZ_WALLCLOCK_GLOBAL_LAG_HISTORY_OID,
2432    desc: RelationDesc::builder()
2433        .with_column("object_id", SqlScalarType::String.nullable(false))
2434        .with_column("lag", SqlScalarType::Interval.nullable(true))
2435        .with_column(
2436            "occurred_at",
2437            SqlScalarType::TimestampTz { precision: None }.nullable(false),
2438        )
2439        .with_key(vec![0, 2])
2440        .finish(),
2441    column_comments: BTreeMap::from_iter([
2442        (
2443            "object_id",
2444            "The ID of the table, source, materialized view, index, or sink. Corresponds to `mz_objects.id`.",
2445        ),
2446        (
2447            "lag",
2448            "The minimum wallclock lag observed for the object during the minute.",
2449        ),
2450        (
2451            "occurred_at",
2452            "The minute-aligned timestamp of the observation.",
2453        ),
2454    ]),
2455    sql: "
2456WITH times_binned AS (
2457    SELECT
2458        object_id,
2459        lag,
2460        date_trunc('minute', occurred_at) AS occurred_at
2461    FROM mz_internal.mz_wallclock_lag_history
2462)
2463SELECT
2464    object_id,
2465    min(lag) AS lag,
2466    occurred_at
2467FROM times_binned
2468GROUP BY object_id, occurred_at
2469OPTIONS (AGGREGATE INPUT GROUP SIZE = 1)",
2470    access: vec![PUBLIC_SELECT],
2471    ontology: Some(Ontology {
2472        entity_name: "wallclock_global_lag_event",
2473        description: "Historical global wallclock lag",
2474        links: &const {
2475            [OntologyLink {
2476                name: "lag_of",
2477                target: "object_global_id",
2478                properties: LinkProperties::fk("object_id", "global_id", Cardinality::ManyToOne),
2479            }]
2480        },
2481        column_semantic_types: &const {
2482            [
2483                ("object_id", SemanticType::GlobalId),
2484                ("occurred_at", SemanticType::WallclockTimestamp),
2485            ]
2486        },
2487    }),
2488});
2489
2490pub static MZ_WALLCLOCK_GLOBAL_LAG_RECENT_HISTORY: LazyLock<BuiltinView> = LazyLock::new(|| {
2491    BuiltinView {
2492        name: "mz_wallclock_global_lag_recent_history",
2493        schema: MZ_INTERNAL_SCHEMA,
2494        oid: oid::VIEW_MZ_WALLCLOCK_GLOBAL_LAG_RECENT_HISTORY_OID,
2495        desc: RelationDesc::builder()
2496            .with_column("object_id", SqlScalarType::String.nullable(false))
2497            .with_column("lag", SqlScalarType::Interval.nullable(true))
2498            .with_column(
2499                "occurred_at",
2500                SqlScalarType::TimestampTz { precision: None }.nullable(false),
2501            )
2502            .with_key(vec![0, 2])
2503            .finish(),
2504        column_comments: BTreeMap::from_iter([
2505            (
2506                "object_id",
2507                "The ID of the table, source, materialized view, index, or sink. Corresponds to `mz_objects.id`.",
2508            ),
2509            (
2510                "lag",
2511                "The minimum wallclock lag observed for the object during the minute.",
2512            ),
2513            (
2514                "occurred_at",
2515                "The minute-aligned timestamp of the observation.",
2516            ),
2517        ]),
2518        sql: "
2519SELECT object_id, lag, occurred_at
2520FROM mz_internal.mz_wallclock_global_lag_history
2521WHERE occurred_at + '1 day' > mz_now()",
2522        access: vec![PUBLIC_SELECT],
2523        ontology: None,
2524    }
2525});
2526
2527pub static MZ_WALLCLOCK_GLOBAL_LAG: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
2528    name: "mz_wallclock_global_lag",
2529    schema: MZ_INTERNAL_SCHEMA,
2530    oid: oid::VIEW_MZ_WALLCLOCK_GLOBAL_LAG_OID,
2531    desc: RelationDesc::builder()
2532        .with_column("object_id", SqlScalarType::String.nullable(false))
2533        .with_column("lag", SqlScalarType::Interval.nullable(true))
2534        .with_key(vec![0])
2535        .finish(),
2536    column_comments: BTreeMap::from_iter([
2537        (
2538            "object_id",
2539            "The ID of the table, source, materialized view, index, or sink. Corresponds to `mz_objects.id`.",
2540        ),
2541        (
2542            "lag",
2543            "The amount of time the object's write frontier lags behind wallclock time.",
2544        ),
2545    ]),
2546    sql: "
2547SELECT DISTINCT ON (object_id) object_id, lag
2548FROM mz_internal.mz_wallclock_global_lag_recent_history
2549WHERE occurred_at + '5 minutes' > mz_now()
2550ORDER BY object_id, occurred_at DESC",
2551    access: vec![PUBLIC_SELECT],
2552    ontology: Some(Ontology {
2553        entity_name: "wallclock_global_lag",
2554        description: "Current wallclock lag aggregated across replicas",
2555        links: &const {
2556            [OntologyLink {
2557                name: "measures_global_lag_of",
2558                target: "object",
2559                properties: LinkProperties::measures_mapped(
2560                    "object_id",
2561                    "id",
2562                    "wallclock_lag_global",
2563                    mz_repr::SemanticType::GlobalId,
2564                    "mz_internal.mz_object_global_ids",
2565                ),
2566            }]
2567        },
2568        column_semantic_types: &[("object_id", SemanticType::GlobalId)],
2569    }),
2570});
2571
2572pub static MZ_WALLCLOCK_GLOBAL_LAG_HISTOGRAM_RAW: LazyLock<BuiltinSource> =
2573    LazyLock::new(|| BuiltinSource {
2574        name: "mz_wallclock_global_lag_histogram_raw",
2575        schema: MZ_INTERNAL_SCHEMA,
2576        oid: oid::SOURCE_MZ_WALLCLOCK_GLOBAL_LAG_HISTOGRAM_RAW_OID,
2577        desc: WALLCLOCK_GLOBAL_LAG_HISTOGRAM_RAW_DESC.clone(),
2578        column_comments: BTreeMap::new(),
2579        data_source: IntrospectionType::WallclockLagHistogram.into(),
2580        is_retained_metrics_object: false,
2581        access: vec![PUBLIC_SELECT],
2582        ontology: None,
2583    });
2584
2585pub static MZ_WALLCLOCK_GLOBAL_LAG_HISTOGRAM: LazyLock<BuiltinView> =
2586    LazyLock::new(|| BuiltinView {
2587        name: "mz_wallclock_global_lag_histogram",
2588        schema: MZ_INTERNAL_SCHEMA,
2589        oid: oid::VIEW_MZ_WALLCLOCK_GLOBAL_LAG_HISTOGRAM_OID,
2590        desc: RelationDesc::builder()
2591            .with_column(
2592                "period_start",
2593                SqlScalarType::TimestampTz { precision: None }.nullable(false),
2594            )
2595            .with_column(
2596                "period_end",
2597                SqlScalarType::TimestampTz { precision: None }.nullable(false),
2598            )
2599            .with_column("object_id", SqlScalarType::String.nullable(false))
2600            .with_column("lag_seconds", SqlScalarType::UInt64.nullable(true))
2601            .with_column("labels", SqlScalarType::Jsonb.nullable(false))
2602            .with_column("count", SqlScalarType::Int64.nullable(false))
2603            .with_key(vec![0, 1, 2, 3, 4])
2604            .finish(),
2605        column_comments: BTreeMap::new(),
2606        sql: "
2607SELECT *, count(*) AS count
2608FROM mz_internal.mz_wallclock_global_lag_histogram_raw
2609GROUP BY period_start, period_end, object_id, lag_seconds, labels",
2610        access: vec![PUBLIC_SELECT],
2611        ontology: None,
2612    });
2613
2614pub static MZ_MATERIALIZED_VIEW_REFRESHES: LazyLock<BuiltinSource> = LazyLock::new(|| {
2615    BuiltinSource {
2616        name: "mz_materialized_view_refreshes",
2617        schema: MZ_INTERNAL_SCHEMA,
2618        oid: oid::SOURCE_MZ_MATERIALIZED_VIEW_REFRESHES_OID,
2619        data_source: DataSourceDesc::Introspection(
2620            IntrospectionType::ComputeMaterializedViewRefreshes,
2621        ),
2622        desc: RelationDesc::builder()
2623            .with_column(
2624                "materialized_view_id",
2625                SqlScalarType::String.nullable(false),
2626            )
2627            .with_column(
2628                "last_completed_refresh",
2629                SqlScalarType::MzTimestamp.nullable(true),
2630            )
2631            .with_column("next_refresh", SqlScalarType::MzTimestamp.nullable(true))
2632            .finish(),
2633        column_comments: BTreeMap::from_iter([
2634            (
2635                "materialized_view_id",
2636                "The ID of the materialized view. Corresponds to `mz_catalog.mz_materialized_views.id`",
2637            ),
2638            (
2639                "last_completed_refresh",
2640                "The time of the last successfully completed refresh. `NULL` if the materialized view hasn't completed any refreshes yet.",
2641            ),
2642            (
2643                "next_refresh",
2644                "The time of the next scheduled refresh. `NULL` if the materialized view has no future scheduled refreshes.",
2645            ),
2646        ]),
2647        is_retained_metrics_object: false,
2648        access: vec![PUBLIC_SELECT],
2649        ontology: None,
2650    }
2651});
2652
2653pub static MZ_SUBSCRIPTIONS: LazyLock<BuiltinTable> = LazyLock::new(|| BuiltinTable {
2654    name: "mz_subscriptions",
2655    schema: MZ_INTERNAL_SCHEMA,
2656    oid: oid::TABLE_MZ_SUBSCRIPTIONS_OID,
2657    desc: RelationDesc::builder()
2658        .with_column("id", SqlScalarType::String.nullable(false))
2659        .with_column("session_id", SqlScalarType::Uuid.nullable(false))
2660        .with_column("cluster_id", SqlScalarType::String.nullable(false))
2661        .with_column(
2662            "created_at",
2663            SqlScalarType::TimestampTz { precision: None }.nullable(false),
2664        )
2665        .with_column(
2666            "referenced_object_ids",
2667            SqlScalarType::List {
2668                element_type: Box::new(SqlScalarType::String),
2669                custom_id: None,
2670            }
2671            .nullable(false),
2672        )
2673        .finish(),
2674    column_comments: BTreeMap::from_iter([
2675        ("id", "The ID of the subscription."),
2676        (
2677            "session_id",
2678            "The ID of the session that runs the subscription. Corresponds to `mz_sessions.id`.",
2679        ),
2680        (
2681            "cluster_id",
2682            "The ID of the cluster on which the subscription is running. Corresponds to `mz_clusters.id`.",
2683        ),
2684        (
2685            "created_at",
2686            "The time at which the subscription was created.",
2687        ),
2688        (
2689            "referenced_object_ids",
2690            "The IDs of objects referenced by the subscription. Corresponds to `mz_objects.id`",
2691        ),
2692    ]),
2693    is_retained_metrics_object: false,
2694    access: vec![PUBLIC_SELECT],
2695    ontology: Some(Ontology {
2696        entity_name: "subscription",
2697        description: "Active SUBSCRIBE operations",
2698        links: &const {
2699            [
2700                OntologyLink {
2701                    name: "uses_session",
2702                    target: "session",
2703                    properties: LinkProperties::fk("session_id", "id", Cardinality::ManyToOne),
2704                },
2705                OntologyLink {
2706                    name: "in_active_session",
2707                    target: "active_session",
2708                    properties: LinkProperties::fk_nullable(
2709                        "session_id",
2710                        "id",
2711                        Cardinality::ManyToOne,
2712                    ),
2713                },
2714                OntologyLink {
2715                    name: "belongs_to_cluster",
2716                    target: "cluster",
2717                    properties: LinkProperties::fk("cluster_id", "id", Cardinality::ManyToOne),
2718                },
2719            ]
2720        },
2721        column_semantic_types: &const {
2722            [
2723                ("id", SemanticType::CatalogItemId),
2724                ("cluster_id", SemanticType::ClusterId),
2725            ]
2726        },
2727    }),
2728});
2729
2730pub static MZ_SESSIONS: LazyLock<BuiltinTable> = LazyLock::new(|| BuiltinTable {
2731    name: "mz_sessions",
2732    schema: MZ_INTERNAL_SCHEMA,
2733    oid: oid::TABLE_MZ_SESSIONS_OID,
2734    desc: RelationDesc::builder()
2735        .with_column("id", SqlScalarType::Uuid.nullable(false))
2736        .with_column("connection_id", SqlScalarType::UInt32.nullable(false))
2737        .with_column("role_id", SqlScalarType::String.nullable(false))
2738        .with_column("client_ip", SqlScalarType::String.nullable(true))
2739        .with_column(
2740            "connected_at",
2741            SqlScalarType::TimestampTz { precision: None }.nullable(false),
2742        )
2743        .finish(),
2744    column_comments: BTreeMap::from_iter([
2745        ("id", "The globally unique ID of the session."),
2746        (
2747            "connection_id",
2748            "The connection ID of the session. Unique only for active sessions and can be recycled. Corresponds to `pg_backend_pid()`.",
2749        ),
2750        (
2751            "role_id",
2752            "The role ID of the role that the session is logged in as. Corresponds to `mz_catalog.mz_roles`.",
2753        ),
2754        (
2755            "client_ip",
2756            "The IP address of the client that initiated the session.",
2757        ),
2758        (
2759            "connected_at",
2760            "The time at which the session connected to the system.",
2761        ),
2762    ]),
2763    is_retained_metrics_object: false,
2764    access: vec![PUBLIC_SELECT],
2765    ontology: Some(Ontology {
2766        entity_name: "active_session",
2767        description: "Currently active sessions",
2768        links: &const {
2769            [OntologyLink {
2770                name: "logged_in_as",
2771                target: "role",
2772                properties: LinkProperties::fk("role_id", "id", Cardinality::ManyToOne),
2773            }]
2774        },
2775        column_semantic_types: &[("role_id", SemanticType::RoleId)],
2776    }),
2777});
2778
2779pub static MZ_COMMENTS: LazyLock<BuiltinTable> = LazyLock::new(|| BuiltinTable {
2780    name: "mz_comments",
2781    schema: MZ_INTERNAL_SCHEMA,
2782    oid: oid::TABLE_MZ_COMMENTS_OID,
2783    desc: RelationDesc::builder()
2784        .with_column("id", SqlScalarType::String.nullable(false))
2785        .with_column("object_type", SqlScalarType::String.nullable(false))
2786        .with_column("object_sub_id", SqlScalarType::Int32.nullable(true))
2787        .with_column("comment", SqlScalarType::String.nullable(false))
2788        .finish(),
2789    column_comments: BTreeMap::from_iter([
2790        (
2791            "id",
2792            "The ID of the object. Corresponds to `mz_objects.id`.",
2793        ),
2794        (
2795            "object_type",
2796            "The type of object the comment is associated with.",
2797        ),
2798        (
2799            "object_sub_id",
2800            "For a comment on a column of a relation, the column number. `NULL` for other object types.",
2801        ),
2802        ("comment", "The comment itself."),
2803    ]),
2804    is_retained_metrics_object: false,
2805    access: vec![PUBLIC_SELECT],
2806    ontology: Some(Ontology {
2807        entity_name: "comment",
2808        description: "A COMMENT ON annotation for a catalog object or column",
2809        links: &const {
2810            [OntologyLink {
2811                name: "comment_on",
2812                target: "object",
2813                properties: LinkProperties::fk_typed(
2814                    "id",
2815                    "id",
2816                    Cardinality::ManyToOne,
2817                    mz_repr::SemanticType::CatalogItemId,
2818                ),
2819            }]
2820        },
2821        column_semantic_types: &const {
2822            [
2823                ("id", SemanticType::CatalogItemId),
2824                ("object_type", SemanticType::ObjectType),
2825            ]
2826        },
2827    }),
2828});
2829
2830pub static MZ_SOURCE_REFERENCES: LazyLock<BuiltinTable> = LazyLock::new(|| BuiltinTable {
2831    name: "mz_source_references",
2832    schema: MZ_INTERNAL_SCHEMA,
2833    oid: oid::TABLE_MZ_SOURCE_REFERENCES_OID,
2834    desc: RelationDesc::builder()
2835        .with_column("source_id", SqlScalarType::String.nullable(false))
2836        .with_column("namespace", SqlScalarType::String.nullable(true))
2837        .with_column("name", SqlScalarType::String.nullable(false))
2838        .with_column(
2839            "updated_at",
2840            SqlScalarType::TimestampTz { precision: None }.nullable(false),
2841        )
2842        .with_column(
2843            "columns",
2844            SqlScalarType::Array(Box::new(SqlScalarType::String)).nullable(true),
2845        )
2846        .finish(),
2847    column_comments: BTreeMap::new(),
2848    is_retained_metrics_object: false,
2849    access: vec![PUBLIC_SELECT],
2850    ontology: Some(Ontology {
2851        entity_name: "source_reference",
2852        description: "External references tracked by sources",
2853        links: &const {
2854            [OntologyLink {
2855                name: "references_source",
2856                target: "source",
2857                properties: LinkProperties::fk("source_id", "id", Cardinality::ManyToOne),
2858            }]
2859        },
2860        column_semantic_types: &[("source_id", SemanticType::CatalogItemId)],
2861    }),
2862});
2863
2864pub static MZ_WEBHOOKS_SOURCES: LazyLock<BuiltinTable> = LazyLock::new(|| BuiltinTable {
2865    name: "mz_webhook_sources",
2866    schema: MZ_INTERNAL_SCHEMA,
2867    oid: oid::TABLE_MZ_WEBHOOK_SOURCES_OID,
2868    desc: RelationDesc::builder()
2869        .with_column("id", SqlScalarType::String.nullable(false))
2870        .with_column("name", SqlScalarType::String.nullable(false))
2871        .with_column("url", SqlScalarType::String.nullable(false))
2872        .finish(),
2873    column_comments: BTreeMap::from_iter([
2874        (
2875            "id",
2876            "The ID of the webhook source. Corresponds to `mz_sources.id`.",
2877        ),
2878        ("name", "The name of the webhook source."),
2879        (
2880            "url",
2881            "The URL which can be used to send events to the source.",
2882        ),
2883    ]),
2884    is_retained_metrics_object: false,
2885    access: vec![PUBLIC_SELECT],
2886    ontology: Some(Ontology {
2887        entity_name: "webhook_source",
2888        description: "Webhook source configuration",
2889        links: &const {
2890            [OntologyLink {
2891                name: "details_of",
2892                target: "source",
2893                properties: LinkProperties::fk("id", "id", Cardinality::OneToOne),
2894            }]
2895        },
2896        column_semantic_types: &[("id", SemanticType::CatalogItemId)],
2897    }),
2898});
2899
2900pub static MZ_HISTORY_RETENTION_STRATEGIES: LazyLock<BuiltinTable> = LazyLock::new(|| {
2901    BuiltinTable {
2902        name: "mz_history_retention_strategies",
2903        schema: MZ_INTERNAL_SCHEMA,
2904        oid: oid::TABLE_MZ_HISTORY_RETENTION_STRATEGIES_OID,
2905        desc: RelationDesc::builder()
2906            .with_column("id", SqlScalarType::String.nullable(false))
2907            .with_column("strategy", SqlScalarType::String.nullable(false))
2908            .with_column("value", SqlScalarType::Jsonb.nullable(false))
2909            .finish(),
2910        column_comments: BTreeMap::from_iter([
2911            ("id", "The ID of the object."),
2912            (
2913                "strategy",
2914                "The strategy. `FOR` is the only strategy, and means the object's compaction window is the duration of the `value` field.",
2915            ),
2916            (
2917                "value",
2918                "The value of the strategy. For `FOR`, is a number of milliseconds.",
2919            ),
2920        ]),
2921        is_retained_metrics_object: false,
2922        access: vec![PUBLIC_SELECT],
2923        ontology: Some(Ontology {
2924            entity_name: "history_retention",
2925            description: "History retention strategy for an object",
2926            links: &const { [] },
2927            column_semantic_types: &[("id", SemanticType::CatalogItemId)],
2928        }),
2929    }
2930});
2931
2932pub static MZ_LICENSE_KEYS: LazyLock<BuiltinTable> = LazyLock::new(|| BuiltinTable {
2933    name: "mz_license_keys",
2934    schema: MZ_INTERNAL_SCHEMA,
2935    oid: oid::TABLE_MZ_LICENSE_KEYS_OID,
2936    desc: RelationDesc::builder()
2937        .with_column("id", SqlScalarType::String.nullable(false))
2938        .with_column("organization", SqlScalarType::String.nullable(false))
2939        .with_column("environment_id", SqlScalarType::String.nullable(false))
2940        .with_column(
2941            "expiration",
2942            SqlScalarType::TimestampTz { precision: None }.nullable(false),
2943        )
2944        .with_column(
2945            "not_before",
2946            SqlScalarType::TimestampTz { precision: None }.nullable(false),
2947        )
2948        .finish(),
2949    column_comments: BTreeMap::from_iter([
2950        ("id", "The identifier of the license key."),
2951        (
2952            "organization",
2953            "The name of the organization that this license key was issued to.",
2954        ),
2955        (
2956            "environment_id",
2957            "The environment ID that this license key was issued for.",
2958        ),
2959        (
2960            "expiration",
2961            "The date and time when this license key expires.",
2962        ),
2963        (
2964            "not_before",
2965            "The start of the validity period for this license key.",
2966        ),
2967    ]),
2968    is_retained_metrics_object: false,
2969    access: vec![PUBLIC_SELECT],
2970    ontology: Some(Ontology {
2971        entity_name: "license_key",
2972        description: "License key metadata",
2973        links: &const { [] },
2974        column_semantic_types: &[("id", SemanticType::CatalogItemId)],
2975    }),
2976});
2977
2978pub static MZ_REPLACEMENTS: LazyLock<BuiltinTable> = LazyLock::new(|| BuiltinTable {
2979    name: "mz_replacements",
2980    schema: MZ_INTERNAL_SCHEMA,
2981    oid: oid::TABLE_MZ_REPLACEMENTS_OID,
2982    desc: RelationDesc::builder()
2983        .with_column("id", SqlScalarType::String.nullable(false))
2984        .with_column("target_id", SqlScalarType::String.nullable(false))
2985        .finish(),
2986    column_comments: BTreeMap::from_iter([
2987        (
2988            "id",
2989            "The ID of the replacement object. Corresponds to `mz_objects.id`.",
2990        ),
2991        (
2992            "target_id",
2993            "The ID of the replacement target. Corresponds to `mz_objects.id`.",
2994        ),
2995    ]),
2996    is_retained_metrics_object: false,
2997    access: vec![PUBLIC_SELECT],
2998    ontology: Some(Ontology {
2999        entity_name: "replacement",
3000        description: "A record of an object replacement (ALTER ... SWAP)",
3001        links: &const {
3002            [
3003                OntologyLink {
3004                    name: "replacement_object",
3005                    target: "object",
3006                    properties: LinkProperties::fk("id", "id", Cardinality::ManyToOne),
3007                },
3008                OntologyLink {
3009                    name: "replacement_target",
3010                    target: "object",
3011                    properties: LinkProperties::fk("target_id", "id", Cardinality::ManyToOne),
3012                },
3013            ]
3014        },
3015        column_semantic_types: &[("id", SemanticType::CatalogItemId)],
3016    }),
3017});
3018
3019// These will be replaced with per-replica tables once source/sink multiplexing on
3020// a single cluster is supported.
3021pub static MZ_SOURCE_STATISTICS_RAW: LazyLock<BuiltinSource> = LazyLock::new(|| BuiltinSource {
3022    name: "mz_source_statistics_raw",
3023    schema: MZ_INTERNAL_SCHEMA,
3024    oid: oid::SOURCE_MZ_SOURCE_STATISTICS_RAW_OID,
3025    data_source: IntrospectionType::StorageSourceStatistics.into(),
3026    desc: MZ_SOURCE_STATISTICS_RAW_DESC.clone(),
3027    column_comments: BTreeMap::new(),
3028    is_retained_metrics_object: true,
3029    access: vec![PUBLIC_SELECT],
3030    ontology: None,
3031});
3032pub static MZ_SINK_STATISTICS_RAW: LazyLock<BuiltinSource> = LazyLock::new(|| BuiltinSource {
3033    name: "mz_sink_statistics_raw",
3034    schema: MZ_INTERNAL_SCHEMA,
3035    oid: oid::SOURCE_MZ_SINK_STATISTICS_RAW_OID,
3036    data_source: IntrospectionType::StorageSinkStatistics.into(),
3037    desc: MZ_SINK_STATISTICS_RAW_DESC.clone(),
3038    column_comments: BTreeMap::new(),
3039    is_retained_metrics_object: true,
3040    access: vec![PUBLIC_SELECT],
3041    ontology: None,
3042});
3043
3044pub static MZ_STORAGE_SHARDS: LazyLock<BuiltinSource> = LazyLock::new(|| BuiltinSource {
3045    name: "mz_storage_shards",
3046    schema: MZ_INTERNAL_SCHEMA,
3047    oid: oid::SOURCE_MZ_STORAGE_SHARDS_OID,
3048    data_source: IntrospectionType::ShardMapping.into(),
3049    desc: RelationDesc::builder()
3050        .with_column("object_id", SqlScalarType::String.nullable(false))
3051        .with_column("shard_id", SqlScalarType::String.nullable(false))
3052        .finish(),
3053    column_comments: BTreeMap::new(),
3054    is_retained_metrics_object: false,
3055    access: vec![PUBLIC_SELECT],
3056    ontology: Some(Ontology {
3057        entity_name: "storage_shard",
3058        description: "Persist shards used by storage objects",
3059        links: &const {
3060            [OntologyLink {
3061                name: "shard_of",
3062                target: "object",
3063                properties: LinkProperties::fk_mapped(
3064                    "object_id",
3065                    "id",
3066                    Cardinality::ManyToOne,
3067                    mz_repr::SemanticType::GlobalId,
3068                    "mz_internal.mz_object_global_ids",
3069                ),
3070            }]
3071        },
3072        column_semantic_types: &const {
3073            [
3074                ("object_id", SemanticType::GlobalId),
3075                ("shard_id", SemanticType::ShardId),
3076            ]
3077        },
3078    }),
3079});
3080
3081pub static MZ_OBJECTS_ID_NAMESPACE_TYPES: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
3082    name: "mz_objects_id_namespace_types",
3083    schema: MZ_INTERNAL_SCHEMA,
3084    oid: oid::VIEW_MZ_OBJECTS_ID_NAMESPACE_TYPES_OID,
3085    desc: RelationDesc::builder()
3086        .with_column("object_type", SqlScalarType::String.nullable(false))
3087        .with_key(vec![0])
3088        .finish(),
3089    column_comments: BTreeMap::new(),
3090    sql: r#"SELECT *
3091    FROM (
3092        VALUES
3093            ('table'),
3094            ('view'),
3095            ('materialized-view'),
3096            ('source'),
3097            ('sink'),
3098            ('index'),
3099            ('connection'),
3100            ('type'),
3101            ('function'),
3102            ('secret')
3103    )
3104    AS _ (object_type)"#,
3105    access: vec![PUBLIC_SELECT],
3106    ontology: None,
3107});
3108
3109pub static MZ_OBJECT_OID_ALIAS: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
3110    name: "mz_object_oid_alias",
3111    schema: MZ_INTERNAL_SCHEMA,
3112    oid: oid::VIEW_MZ_OBJECT_OID_ALIAS_OID,
3113    desc: RelationDesc::builder()
3114        .with_column("object_type", SqlScalarType::String.nullable(false))
3115        .with_column("oid_alias", SqlScalarType::String.nullable(false))
3116        .with_key(vec![0])
3117        .finish(),
3118    column_comments: BTreeMap::new(),
3119    sql: "SELECT object_type, oid_alias
3120    FROM (
3121        VALUES
3122            (
3123                'table'::pg_catalog.text,
3124                'regclass'::pg_catalog.text
3125            ),
3126            ('source', 'regclass'),
3127            ('view', 'regclass'),
3128            ('materialized-view', 'regclass'),
3129            ('index', 'regclass'),
3130            ('type', 'regtype'),
3131            ('function', 'regproc')
3132    )
3133    AS _ (object_type, oid_alias);",
3134    access: vec![PUBLIC_SELECT],
3135    ontology: None,
3136});
3137
3138pub static MZ_OBJECT_FULLY_QUALIFIED_NAMES: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
3139    name: "mz_object_fully_qualified_names",
3140    schema: MZ_INTERNAL_SCHEMA,
3141    oid: oid::VIEW_MZ_OBJECT_FULLY_QUALIFIED_NAMES_OID,
3142    desc: RelationDesc::builder()
3143        .with_column("id", SqlScalarType::String.nullable(false))
3144        .with_column("name", SqlScalarType::String.nullable(false))
3145        .with_column("object_type", SqlScalarType::String.nullable(false))
3146        .with_column("schema_id", SqlScalarType::String.nullable(false))
3147        .with_column("schema_name", SqlScalarType::String.nullable(false))
3148        .with_column("database_id", SqlScalarType::String.nullable(true))
3149        .with_column("database_name", SqlScalarType::String.nullable(true))
3150        .with_column("cluster_id", SqlScalarType::String.nullable(true))
3151        .finish(),
3152    column_comments: BTreeMap::from_iter([
3153        ("id", "Materialize's unique ID for the object."),
3154        ("name", "The name of the object."),
3155        (
3156            "object_type",
3157            "The type of the object: one of `table`, `source`, `view`, `materialized-view`, `sink`, `index`, `connection`, `secret`, `type`, or `function`.",
3158        ),
3159        (
3160            "schema_id",
3161            "The ID of the schema to which the object belongs. Corresponds to `mz_schemas.id`.",
3162        ),
3163        (
3164            "schema_name",
3165            "The name of the schema to which the object belongs. Corresponds to `mz_schemas.name`.",
3166        ),
3167        (
3168            "database_id",
3169            "The ID of the database to which the object belongs. Corresponds to `mz_databases.id`.",
3170        ),
3171        (
3172            "database_name",
3173            "The name of the database to which the object belongs. Corresponds to `mz_databases.name`.",
3174        ),
3175        (
3176            "cluster_id",
3177            "The ID of the cluster maintaining the source, materialized view, index, or sink. Corresponds to `mz_clusters.id`. `NULL` for other object types.",
3178        ),
3179    ]),
3180    sql: "
3181    SELECT o.id,
3182        o.name,
3183        o.type as object_type,
3184        sc.id as schema_id,
3185        sc.name as schema_name,
3186        db.id as database_id,
3187        db.name as database_name,
3188        o.cluster_id
3189    FROM mz_catalog.mz_objects o
3190    INNER JOIN mz_catalog.mz_schemas sc ON sc.id = o.schema_id
3191    -- LEFT JOIN accounts for objects in the ambient database.
3192    LEFT JOIN mz_catalog.mz_databases db ON db.id = sc.database_id",
3193    access: vec![PUBLIC_SELECT],
3194    ontology: Some(Ontology {
3195        entity_name: "object_fqn",
3196        description: "Fully qualified name (database.schema.name) for objects",
3197        links: &const {
3198            [
3199                OntologyLink {
3200                    name: "details_of",
3201                    target: "object",
3202                    properties: LinkProperties::fk("id", "id", Cardinality::OneToOne),
3203                },
3204                OntologyLink {
3205                    name: "in_schema",
3206                    target: "schema",
3207                    properties: LinkProperties::fk("schema_id", "id", Cardinality::ManyToOne),
3208                },
3209                OntologyLink {
3210                    name: "in_database",
3211                    target: "database",
3212                    properties: LinkProperties::fk("database_id", "id", Cardinality::ManyToOne),
3213                },
3214                OntologyLink {
3215                    name: "belongs_to_cluster",
3216                    target: "cluster",
3217                    properties: LinkProperties::fk("cluster_id", "id", Cardinality::ManyToOne),
3218                },
3219            ]
3220        },
3221        column_semantic_types: &const {
3222            [
3223                ("id", SemanticType::CatalogItemId),
3224                ("object_type", SemanticType::ObjectType),
3225                ("schema_id", SemanticType::SchemaId),
3226                ("database_id", SemanticType::DatabaseId),
3227                ("cluster_id", SemanticType::ClusterId),
3228            ]
3229        },
3230    }),
3231});
3232
3233pub static MZ_OBJECT_GLOBAL_IDS: LazyLock<BuiltinTable> = LazyLock::new(|| BuiltinTable {
3234    name: "mz_object_global_ids",
3235    schema: MZ_INTERNAL_SCHEMA,
3236    oid: oid::VIEW_MZ_OBJECT_GLOBAL_IDS_OID,
3237    desc: RelationDesc::builder()
3238        .with_column("id", SqlScalarType::String.nullable(false))
3239        .with_column("global_id", SqlScalarType::String.nullable(false))
3240        .finish(),
3241    column_comments: BTreeMap::from_iter([
3242        (
3243            "id",
3244            "The ID of the object. Corresponds to `mz_objects.id`.",
3245        ),
3246        ("global_id", "The global ID of the object."),
3247    ]),
3248    is_retained_metrics_object: false,
3249    access: vec![PUBLIC_SELECT],
3250    ontology: Some(Ontology {
3251        entity_name: "object_global_id",
3252        description: "Mapping between CatalogItemId (SQL layer) and GlobalId (runtime layer)",
3253        links: &const {
3254            [OntologyLink {
3255                name: "id_references",
3256                target: "object",
3257                properties: LinkProperties::fk("id", "id", Cardinality::ManyToOne),
3258            }]
3259        },
3260        column_semantic_types: &[("id", SemanticType::CatalogItemId)],
3261    }),
3262});
3263
3264// TODO (SangJunBak): Remove once mz_object_history is released and used in the Console https://github.com/MaterializeInc/console/issues/3342
3265pub static MZ_OBJECT_LIFETIMES: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
3266    name: "mz_object_lifetimes",
3267    schema: MZ_INTERNAL_SCHEMA,
3268    oid: oid::VIEW_MZ_OBJECT_LIFETIMES_OID,
3269    desc: RelationDesc::builder()
3270        .with_column("id", SqlScalarType::String.nullable(true))
3271        .with_column("previous_id", SqlScalarType::String.nullable(true))
3272        .with_column("object_type", SqlScalarType::String.nullable(false))
3273        .with_column("event_type", SqlScalarType::String.nullable(false))
3274        .with_column(
3275            "occurred_at",
3276            SqlScalarType::TimestampTz { precision: None }.nullable(false),
3277        )
3278        .finish(),
3279    column_comments: BTreeMap::from_iter([
3280        ("id", "Materialize's unique ID for the object."),
3281        ("previous_id", "The object's previous ID, if one exists."),
3282        (
3283            "object_type",
3284            "The type of the object: one of `table`, `source`, `view`, `materialized-view`, `sink`, `index`, `connection`, `secret`, `type`, or `function`.",
3285        ),
3286        (
3287            "event_type",
3288            "The lifetime event, either `create` or `drop`.",
3289        ),
3290        (
3291            "occurred_at",
3292            "Wall-clock timestamp of when the event occurred.",
3293        ),
3294    ]),
3295    sql: "
3296    SELECT
3297        CASE
3298            WHEN a.object_type = 'cluster-replica' THEN a.details ->> 'replica_id'
3299            ELSE a.details ->> 'id'
3300        END id,
3301        a.details ->> 'previous_id' as previous_id,
3302        a.object_type,
3303        a.event_type,
3304        a.occurred_at
3305    FROM mz_catalog.mz_audit_events a
3306    WHERE a.event_type = 'create' OR a.event_type = 'drop'",
3307    access: vec![PUBLIC_SELECT],
3308    ontology: Some(Ontology {
3309        entity_name: "object_lifetime_event",
3310        description: "Create or drop lifecycle event for a catalog object",
3311        links: &const {
3312            [OntologyLink {
3313                name: "lifetime_event_of",
3314                target: "object",
3315                properties: LinkProperties::fk_typed(
3316                    "id",
3317                    "id",
3318                    Cardinality::ManyToOne,
3319                    mz_repr::SemanticType::CatalogItemId,
3320                ),
3321            }]
3322        },
3323        column_semantic_types: &const {
3324            [
3325                ("id", SemanticType::CatalogItemId),
3326                ("object_type", SemanticType::ObjectType),
3327            ]
3328        },
3329    }),
3330});
3331
3332pub static MZ_OBJECT_HISTORY: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
3333    name: "mz_object_history",
3334    schema: MZ_INTERNAL_SCHEMA,
3335    oid: oid::VIEW_MZ_OBJECT_HISTORY_OID,
3336    desc: RelationDesc::builder()
3337        .with_column("id", SqlScalarType::String.nullable(true))
3338        .with_column("cluster_id", SqlScalarType::String.nullable(true))
3339        .with_column("object_type", SqlScalarType::String.nullable(false))
3340        .with_column(
3341            "created_at",
3342            SqlScalarType::TimestampTz { precision: None }.nullable(true),
3343        )
3344        .with_column(
3345            "dropped_at",
3346            SqlScalarType::TimestampTz { precision: None }.nullable(true),
3347        )
3348        .finish(),
3349    column_comments: BTreeMap::from_iter([
3350        ("id", "Materialize's unique ID for the object."),
3351        (
3352            "cluster_id",
3353            "The object's cluster ID. `NULL` if the object has no associated cluster.",
3354        ),
3355        (
3356            "object_type",
3357            "The type of the object: one of `table`, `source`, `view`, `materialized-view`, `sink`, `index`, `connection`, `secret`, `type`, or `function`.",
3358        ),
3359        (
3360            "created_at",
3361            "Wall-clock timestamp of when the object was created. `NULL` for built in system objects.",
3362        ),
3363        (
3364            "dropped_at",
3365            "Wall-clock timestamp of when the object was dropped. `NULL` for built in system objects or if the object hasn't been dropped.",
3366        ),
3367    ]),
3368    sql: r#"
3369    WITH
3370        creates AS
3371        (
3372            SELECT
3373                details ->> 'id' AS id,
3374                -- We need to backfill cluster_id since older object create events don't include the cluster ID in the audit log
3375                COALESCE(details ->> 'cluster_id', objects.cluster_id) AS cluster_id,
3376                object_type,
3377                occurred_at
3378            FROM
3379                mz_catalog.mz_audit_events AS events
3380                    LEFT JOIN mz_catalog.mz_objects AS objects ON details ->> 'id' = objects.id
3381            WHERE event_type = 'create' AND object_type IN ( SELECT object_type FROM mz_internal.mz_objects_id_namespace_types )
3382        ),
3383        drops AS
3384        (
3385            SELECT details ->> 'id' AS id, occurred_at
3386            FROM mz_catalog.mz_audit_events
3387            WHERE event_type = 'drop' AND object_type IN ( SELECT object_type FROM mz_internal.mz_objects_id_namespace_types )
3388        ),
3389        user_object_history AS
3390        (
3391            SELECT
3392                creates.id,
3393                creates.cluster_id,
3394                creates.object_type,
3395                creates.occurred_at AS created_at,
3396                drops.occurred_at AS dropped_at
3397            FROM creates LEFT JOIN drops ON creates.id = drops.id
3398            WHERE creates.id LIKE 'u%'
3399        ),
3400        -- We need to union built in objects since they aren't in the audit log
3401        built_in_objects AS
3402        (
3403            -- Functions that accept different arguments have different oids but the same id. We deduplicate in this case.
3404            SELECT DISTINCT ON (objects.id)
3405                objects.id,
3406                objects.cluster_id,
3407                objects.type AS object_type,
3408                NULL::timestamptz AS created_at,
3409                NULL::timestamptz AS dropped_at
3410            FROM mz_catalog.mz_objects AS objects
3411            WHERE objects.id LIKE 's%'
3412        )
3413    SELECT * FROM user_object_history UNION ALL (SELECT * FROM built_in_objects)"#,
3414    access: vec![PUBLIC_SELECT],
3415    ontology: Some(Ontology {
3416        entity_name: "object_history",
3417        description: "Historical record of object creation and drops",
3418        links: &const {
3419            [OntologyLink {
3420                name: "history_of",
3421                target: "object",
3422                properties: LinkProperties::fk("id", "id", Cardinality::ManyToOne),
3423            }]
3424        },
3425        column_semantic_types: &[("id", SemanticType::CatalogItemId)],
3426    }),
3427});
3428
3429pub static MZ_OBJECT_TRANSITIVE_DEPENDENCIES: LazyLock<BuiltinView> = LazyLock::new(|| {
3430    BuiltinView {
3431        name: "mz_object_transitive_dependencies",
3432        schema: MZ_INTERNAL_SCHEMA,
3433        oid: oid::VIEW_MZ_OBJECT_TRANSITIVE_DEPENDENCIES_OID,
3434        desc: RelationDesc::builder()
3435            .with_column("object_id", SqlScalarType::String.nullable(false))
3436            .with_column(
3437                "referenced_object_id",
3438                SqlScalarType::String.nullable(false),
3439            )
3440            .with_key(vec![0, 1])
3441            .finish(),
3442        column_comments: BTreeMap::from_iter([
3443            (
3444                "object_id",
3445                "The ID of the dependent object. Corresponds to `mz_objects.id`.",
3446            ),
3447            (
3448                "referenced_object_id",
3449                "The ID of the (possibly transitively) referenced object. Corresponds to `mz_objects.id`.",
3450            ),
3451        ]),
3452        sql: "
3453WITH MUTUALLY RECURSIVE
3454  reach(object_id text, referenced_object_id text) AS (
3455    SELECT object_id, referenced_object_id FROM mz_internal.mz_object_dependencies
3456    UNION
3457    SELECT x, z FROM reach r1(x, y) JOIN reach r2(y, z) USING(y)
3458  )
3459SELECT object_id, referenced_object_id FROM reach;",
3460        access: vec![PUBLIC_SELECT],
3461        ontology: Some(Ontology {
3462            entity_name: "transitive_dependency",
3463            description: "Transitive closure of object dependencies — all direct and indirect dependencies",
3464            links: &const {
3465                [
3466                    OntologyLink {
3467                        name: "depends_on",
3468                        target: "object",
3469                        properties: LinkProperties::DependsOn {
3470                            source_column: "object_id",
3471                            target_column: "id",
3472                            source_id_type: Some(mz_repr::SemanticType::CatalogItemId),
3473                            requires_mapping: None,
3474                        },
3475                    },
3476                    OntologyLink {
3477                        name: "dependency_is",
3478                        target: "object",
3479                        properties: LinkProperties::DependsOn {
3480                            source_column: "referenced_object_id",
3481                            target_column: "id",
3482                            source_id_type: Some(mz_repr::SemanticType::CatalogItemId),
3483                            requires_mapping: None,
3484                        },
3485                    },
3486                ]
3487            },
3488            column_semantic_types: &const {
3489                [
3490                    ("object_id", SemanticType::CatalogItemId),
3491                    ("referenced_object_id", SemanticType::CatalogItemId),
3492                ]
3493            },
3494        }),
3495    }
3496});
3497
3498/// Peeled version of `PG_NAMESPACE`:
3499/// - This doesn't check `mz_schemas.database_id IS NULL OR d.name = pg_catalog.current_database()`,
3500///   in order to make this view indexable.
3501/// - This has the database name as an extra column, so that downstream views can check it against
3502///  `current_database()`.
3503pub static PG_NAMESPACE_ALL_DATABASES: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
3504    name: "pg_namespace_all_databases",
3505    schema: MZ_INTERNAL_SCHEMA,
3506    oid: oid::VIEW_PG_NAMESPACE_ALL_DATABASES_OID,
3507    desc: RelationDesc::builder()
3508        .with_column("oid", SqlScalarType::Oid.nullable(false))
3509        .with_column("nspname", SqlScalarType::String.nullable(false))
3510        .with_column("nspowner", SqlScalarType::Oid.nullable(false))
3511        .with_column(
3512            "nspacl",
3513            SqlScalarType::Array(Box::new(SqlScalarType::String)).nullable(true),
3514        )
3515        .with_column("database_name", SqlScalarType::String.nullable(true))
3516        .finish(),
3517    column_comments: BTreeMap::new(),
3518    sql: "
3519SELECT
3520    s.oid AS oid,
3521    s.name AS nspname,
3522    role_owner.oid AS nspowner,
3523    NULL::pg_catalog.text[] AS nspacl,
3524    d.name as database_name
3525FROM mz_catalog.mz_schemas s
3526LEFT JOIN mz_catalog.mz_databases d ON d.id = s.database_id
3527JOIN mz_catalog.mz_roles role_owner ON role_owner.id = s.owner_id",
3528    access: vec![PUBLIC_SELECT],
3529    ontology: None,
3530});
3531
3532pub const PG_NAMESPACE_ALL_DATABASES_IND: BuiltinIndex = BuiltinIndex {
3533    name: "pg_namespace_all_databases_ind",
3534    schema: MZ_INTERNAL_SCHEMA,
3535    oid: oid::INDEX_PG_NAMESPACE_ALL_DATABASES_IND_OID,
3536    sql: "IN CLUSTER mz_catalog_server
3537ON mz_internal.pg_namespace_all_databases (nspname)",
3538    is_retained_metrics_object: false,
3539};
3540
3541/// Peeled version of `PG_CLASS`:
3542/// - This doesn't check `mz_schemas.database_id IS NULL OR d.name = pg_catalog.current_database()`,
3543///   in order to make this view indexable.
3544/// - This has the database name as an extra column, so that downstream views can check it against
3545///  `current_database()`.
3546pub static PG_CLASS_ALL_DATABASES: LazyLock<BuiltinView> = LazyLock::new(|| {
3547    BuiltinView {
3548        name: "pg_class_all_databases",
3549        schema: MZ_INTERNAL_SCHEMA,
3550        oid: oid::VIEW_PG_CLASS_ALL_DATABASES_OID,
3551        desc: RelationDesc::builder()
3552            .with_column("oid", SqlScalarType::Oid.nullable(false))
3553            .with_column("relname", SqlScalarType::String.nullable(false))
3554            .with_column("relnamespace", SqlScalarType::Oid.nullable(false))
3555            .with_column("reloftype", SqlScalarType::Oid.nullable(false))
3556            .with_column("relowner", SqlScalarType::Oid.nullable(false))
3557            .with_column("relam", SqlScalarType::Oid.nullable(false))
3558            .with_column("reltablespace", SqlScalarType::Oid.nullable(false))
3559            .with_column("reltuples", SqlScalarType::Float32.nullable(false))
3560            .with_column("reltoastrelid", SqlScalarType::Oid.nullable(false))
3561            .with_column("relhasindex", SqlScalarType::Bool.nullable(false))
3562            .with_column("relpersistence", SqlScalarType::PgLegacyChar.nullable(false))
3563            .with_column("relkind", SqlScalarType::String.nullable(true))
3564            .with_column("relnatts", SqlScalarType::Int16.nullable(false))
3565            .with_column("relchecks", SqlScalarType::Int16.nullable(false))
3566            .with_column("relhasrules", SqlScalarType::Bool.nullable(false))
3567            .with_column("relhastriggers", SqlScalarType::Bool.nullable(false))
3568            .with_column("relhassubclass", SqlScalarType::Bool.nullable(false))
3569            .with_column("relrowsecurity", SqlScalarType::Bool.nullable(false))
3570            .with_column("relforcerowsecurity", SqlScalarType::Bool.nullable(false))
3571            .with_column("relreplident", SqlScalarType::PgLegacyChar.nullable(false))
3572            .with_column("relispartition", SqlScalarType::Bool.nullable(false))
3573            .with_column("relhasoids", SqlScalarType::Bool.nullable(false))
3574            .with_column("reloptions", SqlScalarType::Array(Box::new(SqlScalarType::String)).nullable(true))
3575            .with_column("database_name", SqlScalarType::String.nullable(true))
3576            .finish(),
3577        column_comments: BTreeMap::new(),
3578        sql: "
3579SELECT
3580    class_objects.oid,
3581    class_objects.name AS relname,
3582    mz_schemas.oid AS relnamespace,
3583    -- MZ doesn't support typed tables so reloftype is filled with 0
3584    0::pg_catalog.oid AS reloftype,
3585    role_owner.oid AS relowner,
3586    0::pg_catalog.oid AS relam,
3587    -- MZ doesn't have tablespaces so reltablespace is filled in with 0 implying the default tablespace
3588    0::pg_catalog.oid AS reltablespace,
3589    -- MZ doesn't support (estimated) row counts currently.
3590    -- Postgres defines a value of -1 as unknown.
3591    -1::float4 as reltuples,
3592    -- MZ doesn't use TOAST tables so reltoastrelid is filled with 0
3593    0::pg_catalog.oid AS reltoastrelid,
3594    EXISTS (SELECT id, oid, name, on_id, cluster_id FROM mz_catalog.mz_indexes where mz_indexes.on_id = class_objects.id) AS relhasindex,
3595    -- MZ doesn't have unlogged tables and because of (https://github.com/MaterializeInc/database-issues/issues/2689)
3596    -- temporary objects don't show up here, so relpersistence is filled with 'p' for permanent.
3597    -- TODO(jkosh44): update this column when issue is resolved.
3598    'p'::pg_catalog.\"char\" AS relpersistence,
3599    CASE
3600        WHEN class_objects.type = 'table' THEN 'r'
3601        WHEN class_objects.type = 'source' THEN 'r'
3602        WHEN class_objects.type = 'index' THEN 'i'
3603        WHEN class_objects.type = 'view' THEN 'v'
3604        WHEN class_objects.type = 'materialized-view' THEN 'm'
3605    END relkind,
3606    CASE
3607        WHEN class_objects.type = 'index' THEN COALESCE(
3608            (
3609                SELECT count(*)::pg_catalog.int2
3610                FROM mz_catalog.mz_index_columns
3611                WHERE mz_index_columns.index_id = class_objects.id
3612            ),
3613            0::pg_catalog.int2
3614        )
3615        ELSE COALESCE(
3616            (
3617                SELECT count(*)::pg_catalog.int2
3618                FROM mz_catalog.mz_columns
3619                WHERE mz_columns.id = class_objects.id
3620            ),
3621            0::pg_catalog.int2
3622        )
3623    END AS relnatts,
3624    -- MZ doesn't support CHECK constraints so relchecks is filled with 0
3625    0::pg_catalog.int2 AS relchecks,
3626    -- MZ doesn't support creating rules so relhasrules is filled with false
3627    false AS relhasrules,
3628    -- MZ doesn't support creating triggers so relhastriggers is filled with false
3629    false AS relhastriggers,
3630    -- MZ doesn't support table inheritance or partitions so relhassubclass is filled with false
3631    false AS relhassubclass,
3632    -- MZ doesn't have row level security so relrowsecurity and relforcerowsecurity is filled with false
3633    false AS relrowsecurity,
3634    false AS relforcerowsecurity,
3635    -- MZ doesn't support replication so relreplident is filled with 'd' for default
3636    'd'::pg_catalog.\"char\" AS relreplident,
3637    -- MZ doesn't support table partitioning so relispartition is filled with false
3638    false AS relispartition,
3639    -- PG removed relhasoids in v12 so it's filled with false
3640    false AS relhasoids,
3641    -- MZ doesn't support options for relations
3642    NULL::pg_catalog.text[] as reloptions,
3643    d.name as database_name
3644FROM (
3645    -- pg_class catalogs relations and indexes
3646    SELECT id, oid, schema_id, name, type, owner_id FROM mz_catalog.mz_relations
3647    UNION ALL
3648        SELECT mz_indexes.id, mz_indexes.oid, mz_relations.schema_id, mz_indexes.name, 'index' AS type, mz_indexes.owner_id
3649        FROM mz_catalog.mz_indexes
3650        JOIN mz_catalog.mz_relations ON mz_indexes.on_id = mz_relations.id
3651) AS class_objects
3652JOIN mz_catalog.mz_schemas ON mz_schemas.id = class_objects.schema_id
3653LEFT JOIN mz_catalog.mz_databases d ON d.id = mz_schemas.database_id
3654JOIN mz_catalog.mz_roles role_owner ON role_owner.id = class_objects.owner_id",
3655        access: vec![PUBLIC_SELECT],
3656        ontology: None,
3657    }
3658});
3659
3660pub const PG_CLASS_ALL_DATABASES_IND: BuiltinIndex = BuiltinIndex {
3661    name: "pg_class_all_databases_ind",
3662    schema: MZ_INTERNAL_SCHEMA,
3663    oid: oid::INDEX_PG_CLASS_ALL_DATABASES_IND_OID,
3664    sql: "IN CLUSTER mz_catalog_server
3665ON mz_internal.pg_class_all_databases (relname)",
3666    is_retained_metrics_object: false,
3667};
3668
3669/// Peeled version of `PG_DESCRIPTION`:
3670/// - This doesn't check `mz_schemas.database_id IS NULL OR d.name = pg_catalog.current_database()`,
3671///   in order to make this view indexable.
3672/// - This has 2 extra columns for the database names, so that downstream views can check them
3673///   against `current_database()`.
3674pub static PG_DESCRIPTION_ALL_DATABASES: LazyLock<BuiltinView> = LazyLock::new(|| {
3675    BuiltinView {
3676        name: "pg_description_all_databases",
3677        schema: MZ_INTERNAL_SCHEMA,
3678        oid: oid::VIEW_PG_DESCRIPTION_ALL_DATABASES_OID,
3679        desc: RelationDesc::builder()
3680            .with_column("objoid", SqlScalarType::Oid.nullable(false))
3681            .with_column("classoid", SqlScalarType::Oid.nullable(true))
3682            .with_column("objsubid", SqlScalarType::Int32.nullable(false))
3683            .with_column("description", SqlScalarType::String.nullable(false))
3684            .with_column("oid_database_name", SqlScalarType::String.nullable(true))
3685            .with_column("class_database_name", SqlScalarType::String.nullable(true))
3686            .finish(),
3687        column_comments: BTreeMap::new(),
3688        sql: "
3689(
3690    -- Gather all of the class oid's for objects that can have comments.
3691    WITH pg_classoids AS (
3692        SELECT oid, database_name as oid_database_name,
3693          (SELECT oid FROM mz_internal.pg_class_all_databases WHERE relname = 'pg_class') AS classoid,
3694          (SELECT database_name FROM mz_internal.pg_class_all_databases WHERE relname = 'pg_class') AS class_database_name
3695        FROM mz_internal.pg_class_all_databases
3696        UNION ALL
3697        SELECT oid, database_name as oid_database_name,
3698          (SELECT oid FROM mz_internal.pg_class_all_databases WHERE relname = 'pg_type') AS classoid,
3699          (SELECT database_name FROM mz_internal.pg_class_all_databases WHERE relname = 'pg_type') AS class_database_name
3700        FROM mz_internal.pg_type_all_databases
3701        UNION ALL
3702        SELECT oid, database_name as oid_database_name,
3703          (SELECT oid FROM mz_internal.pg_class_all_databases WHERE relname = 'pg_namespace') AS classoid,
3704          (SELECT database_name FROM mz_internal.pg_class_all_databases WHERE relname = 'pg_namespace') AS class_database_name
3705        FROM mz_internal.pg_namespace_all_databases
3706    ),
3707
3708    -- Gather all of the MZ ids for objects that can have comments.
3709    mz_objects AS (
3710        SELECT id, oid, type FROM mz_catalog.mz_objects
3711        UNION ALL
3712        SELECT id, oid, 'schema' AS type FROM mz_catalog.mz_schemas
3713    )
3714    SELECT
3715        pg_classoids.oid AS objoid,
3716        pg_classoids.classoid as classoid,
3717        COALESCE(cmt.object_sub_id, 0) AS objsubid,
3718        cmt.comment AS description,
3719        -- Columns added because of the peeling. (Note that there are 2 of these here.)
3720        oid_database_name,
3721        class_database_name
3722    FROM
3723        pg_classoids
3724    JOIN
3725        mz_objects ON pg_classoids.oid = mz_objects.oid
3726    JOIN
3727        mz_internal.mz_comments AS cmt ON mz_objects.id = cmt.id AND lower(mz_objects.type) = lower(cmt.object_type)
3728)",
3729        access: vec![PUBLIC_SELECT],
3730        ontology: None,
3731    }
3732});
3733
3734pub const PG_DESCRIPTION_ALL_DATABASES_IND: BuiltinIndex = BuiltinIndex {
3735    name: "pg_description_all_databases_ind",
3736    schema: MZ_INTERNAL_SCHEMA,
3737    oid: oid::INDEX_PG_DESCRIPTION_ALL_DATABASES_IND_OID,
3738    sql: "IN CLUSTER mz_catalog_server
3739ON mz_internal.pg_description_all_databases (objoid, classoid, objsubid, description, oid_database_name, class_database_name)",
3740    is_retained_metrics_object: false,
3741};
3742
3743/// Peeled version of `PG_TYPE`:
3744/// - This doesn't check `mz_schemas.database_id IS NULL OR d.name = pg_catalog.current_database()`,
3745///   in order to make this view indexable.
3746/// - This has the database name as an extra column, so that downstream views can check it against
3747///  `current_database()`.
3748pub static PG_TYPE_ALL_DATABASES: LazyLock<BuiltinView> = LazyLock::new(|| {
3749    BuiltinView {
3750        name: "pg_type_all_databases",
3751        schema: MZ_INTERNAL_SCHEMA,
3752        oid: oid::VIEW_PG_TYPE_ALL_DATABASES_OID,
3753        desc: RelationDesc::builder()
3754            .with_column("oid", SqlScalarType::Oid.nullable(false))
3755            .with_column("typname", SqlScalarType::String.nullable(false))
3756            .with_column("typnamespace", SqlScalarType::Oid.nullable(false))
3757            .with_column("typowner", SqlScalarType::Oid.nullable(false))
3758            .with_column("typlen", SqlScalarType::Int16.nullable(true))
3759            .with_column("typtype", SqlScalarType::PgLegacyChar.nullable(false))
3760            .with_column("typcategory", SqlScalarType::PgLegacyChar.nullable(true))
3761            .with_column("typdelim", SqlScalarType::PgLegacyChar.nullable(false))
3762            .with_column("typrelid", SqlScalarType::Oid.nullable(false))
3763            .with_column("typelem", SqlScalarType::Oid.nullable(false))
3764            .with_column("typarray", SqlScalarType::Oid.nullable(false))
3765            .with_column("typinput", SqlScalarType::RegProc.nullable(true))
3766            .with_column("typreceive", SqlScalarType::Oid.nullable(false))
3767            .with_column("typnotnull", SqlScalarType::Bool.nullable(false))
3768            .with_column("typbasetype", SqlScalarType::Oid.nullable(false))
3769            .with_column("typtypmod", SqlScalarType::Int32.nullable(false))
3770            .with_column("typcollation", SqlScalarType::Oid.nullable(false))
3771            .with_column("typdefault", SqlScalarType::String.nullable(true))
3772            .with_column("database_name", SqlScalarType::String.nullable(true))
3773            .finish(),
3774        column_comments: BTreeMap::new(),
3775        sql: "
3776SELECT
3777    mz_types.oid,
3778    mz_types.name AS typname,
3779    mz_schemas.oid AS typnamespace,
3780    role_owner.oid AS typowner,
3781    NULL::pg_catalog.int2 AS typlen,
3782    -- 'a' is used internally to denote an array type, but in postgres they show up
3783    -- as 'b'.
3784    (CASE mztype WHEN 'a' THEN 'b' ELSE mztype END)::pg_catalog.char AS typtype,
3785    (CASE category
3786        WHEN 'array' THEN 'A'
3787        WHEN 'bit-string' THEN 'V'
3788        WHEN 'boolean' THEN 'B'
3789        WHEN 'composite' THEN 'C'
3790        WHEN 'date-time' THEN 'D'
3791        WHEN 'enum' THEN 'E'
3792        WHEN 'geometric' THEN 'G'
3793        WHEN 'list' THEN 'U' -- List types are user-defined from PostgreSQL's perspective.
3794        WHEN 'network-address' THEN 'I'
3795        WHEN 'numeric' THEN 'N'
3796        WHEN 'pseudo' THEN 'P'
3797        WHEN 'string' THEN 'S'
3798        WHEN 'timespan' THEN 'T'
3799        WHEN 'user-defined' THEN 'U'
3800        WHEN 'unknown' THEN 'X'
3801    END)::pg_catalog.char AS typcategory,
3802    -- In pg only the 'box' type is not ','.
3803    ','::pg_catalog.char AS typdelim,
3804    0::pg_catalog.oid AS typrelid,
3805    coalesce(
3806        (
3807            SELECT t.oid
3808            FROM mz_catalog.mz_array_types a
3809            JOIN mz_catalog.mz_types t ON a.element_id = t.id
3810            WHERE a.id = mz_types.id
3811        ),
3812        (
3813            SELECT t.oid
3814            FROM mz_catalog.mz_list_types l
3815            JOIN mz_catalog.mz_types t ON l.element_id = t.id
3816            WHERE l.id = mz_types.id
3817        ),
3818        0
3819    ) AS typelem,
3820    coalesce(
3821        (
3822            SELECT
3823                t.oid
3824            FROM
3825                mz_catalog.mz_array_types AS a
3826                JOIN mz_catalog.mz_types AS t ON a.id = t.id
3827            WHERE
3828                a.element_id = mz_types.id
3829        ),
3830        0
3831    )
3832        AS typarray,
3833    mz_internal.mz_type_pg_metadata.typinput::pg_catalog.regproc AS typinput,
3834    COALESCE(mz_internal.mz_type_pg_metadata.typreceive, 0) AS typreceive,
3835    false::pg_catalog.bool AS typnotnull,
3836    0::pg_catalog.oid AS typbasetype,
3837    -1::pg_catalog.int4 AS typtypmod,
3838    -- MZ doesn't support COLLATE so typcollation is filled with 0
3839    0::pg_catalog.oid AS typcollation,
3840    NULL::pg_catalog.text AS typdefault,
3841    d.name as database_name
3842FROM
3843    mz_catalog.mz_types
3844    LEFT JOIN mz_internal.mz_type_pg_metadata ON mz_catalog.mz_types.id = mz_internal.mz_type_pg_metadata.id
3845    JOIN mz_catalog.mz_schemas ON mz_schemas.id = mz_types.schema_id
3846    JOIN (
3847            -- 'a' is not a supported typtype, but we use it to denote an array. It is
3848            -- converted to the correct value above.
3849            SELECT id, 'a' AS mztype FROM mz_catalog.mz_array_types
3850            UNION ALL SELECT id, 'b' FROM mz_catalog.mz_base_types
3851            UNION ALL SELECT id, 'l' FROM mz_catalog.mz_list_types
3852            UNION ALL SELECT id, 'm' FROM mz_catalog.mz_map_types
3853            UNION ALL SELECT id, 'p' FROM mz_catalog.mz_pseudo_types
3854        )
3855            AS t ON mz_types.id = t.id
3856    LEFT JOIN mz_catalog.mz_databases d ON d.id = mz_schemas.database_id
3857    JOIN mz_catalog.mz_roles role_owner ON role_owner.id = mz_types.owner_id",
3858        access: vec![PUBLIC_SELECT],
3859        ontology: None,
3860    }
3861});
3862
3863pub const PG_TYPE_ALL_DATABASES_IND: BuiltinIndex = BuiltinIndex {
3864    name: "pg_type_all_databases_ind",
3865    schema: MZ_INTERNAL_SCHEMA,
3866    oid: oid::INDEX_PG_TYPE_ALL_DATABASES_IND_OID,
3867    sql: "IN CLUSTER mz_catalog_server
3868ON mz_internal.pg_type_all_databases (oid)",
3869    is_retained_metrics_object: false,
3870};
3871
3872/// Peeled version of `PG_ATTRIBUTE`:
3873/// - This doesn't check `mz_schemas.database_id IS NULL OR d.name = pg_catalog.current_database()`,
3874///   in order to make this view indexable.
3875/// - This has 2 extra columns for the database names, so that downstream views can check them
3876///   against `current_database()`.
3877pub static PG_ATTRIBUTE_ALL_DATABASES: LazyLock<BuiltinView> = LazyLock::new(|| {
3878    BuiltinView {
3879        name: "pg_attribute_all_databases",
3880        schema: MZ_INTERNAL_SCHEMA,
3881        oid: oid::VIEW_PG_ATTRIBUTE_ALL_DATABASES_OID,
3882        desc: RelationDesc::builder()
3883            .with_column("attrelid", SqlScalarType::Oid.nullable(false))
3884            .with_column("attname", SqlScalarType::String.nullable(false))
3885            .with_column("atttypid", SqlScalarType::Oid.nullable(false))
3886            .with_column("attlen", SqlScalarType::Int16.nullable(true))
3887            .with_column("attnum", SqlScalarType::Int16.nullable(false))
3888            .with_column("atttypmod", SqlScalarType::Int32.nullable(false))
3889            .with_column("attndims", SqlScalarType::Int16.nullable(false))
3890            .with_column("attnotnull", SqlScalarType::Bool.nullable(false))
3891            .with_column("atthasdef", SqlScalarType::Bool.nullable(false))
3892            .with_column("attidentity", SqlScalarType::PgLegacyChar.nullable(false))
3893            .with_column("attgenerated", SqlScalarType::PgLegacyChar.nullable(false))
3894            .with_column("attisdropped", SqlScalarType::Bool.nullable(false))
3895            .with_column("attcollation", SqlScalarType::Oid.nullable(false))
3896            .with_column("database_name", SqlScalarType::String.nullable(true))
3897            .with_column("pg_type_database_name", SqlScalarType::String.nullable(true))
3898            .finish(),
3899        column_comments: BTreeMap::new(),
3900        sql: "
3901SELECT
3902    class_objects.oid as attrelid,
3903    mz_columns.name as attname,
3904    mz_columns.type_oid AS atttypid,
3905    pg_type_all_databases.typlen AS attlen,
3906    position::int8::int2 as attnum,
3907    mz_columns.type_mod as atttypmod,
3908    -- dummy value, just to make go-jet's workaround work for now. Discussion:
3909    -- https://github.com/MaterializeInc/materialize/pull/34649#issuecomment-3714291409
3910    0::int2 as attndims,
3911    NOT nullable as attnotnull,
3912    mz_columns.default IS NOT NULL as atthasdef,
3913    ''::pg_catalog.\"char\" as attidentity,
3914    -- MZ doesn't support generated columns so attgenerated is filled with ''
3915    ''::pg_catalog.\"char\" as attgenerated,
3916    FALSE as attisdropped,
3917    -- MZ doesn't support COLLATE so attcollation is filled with 0
3918    0::pg_catalog.oid as attcollation,
3919    -- Columns added because of the peeling. (Note that there are 2 of these here.)
3920    d.name as database_name,
3921    pg_type_all_databases.database_name as pg_type_database_name
3922FROM (
3923    -- pg_attribute catalogs columns on relations and indexes
3924    SELECT id, oid, schema_id, name, type FROM mz_catalog.mz_relations
3925    UNION ALL
3926        SELECT mz_indexes.id, mz_indexes.oid, mz_relations.schema_id, mz_indexes.name, 'index' AS type
3927        FROM mz_catalog.mz_indexes
3928        JOIN mz_catalog.mz_relations ON mz_indexes.on_id = mz_relations.id
3929) AS class_objects
3930JOIN mz_catalog.mz_columns ON class_objects.id = mz_columns.id
3931JOIN mz_internal.pg_type_all_databases ON pg_type_all_databases.oid = mz_columns.type_oid
3932JOIN mz_catalog.mz_schemas ON mz_schemas.id = class_objects.schema_id
3933LEFT JOIN mz_catalog.mz_databases d ON d.id = mz_schemas.database_id",
3934        // Since this depends on pg_type, its id must be higher due to initialization
3935        // ordering.
3936        access: vec![PUBLIC_SELECT],
3937        ontology: None,
3938    }
3939});
3940
3941pub const PG_ATTRIBUTE_ALL_DATABASES_IND: BuiltinIndex = BuiltinIndex {
3942    name: "pg_attribute_all_databases_ind",
3943    schema: MZ_INTERNAL_SCHEMA,
3944    oid: oid::INDEX_PG_ATTRIBUTE_ALL_DATABASES_IND_OID,
3945    sql: "IN CLUSTER mz_catalog_server
3946ON mz_internal.pg_attribute_all_databases (
3947    attrelid, attname, atttypid, attlen, attnum, atttypmod, attnotnull, atthasdef, attidentity,
3948    attgenerated, attisdropped, attcollation, database_name, pg_type_database_name
3949)",
3950    is_retained_metrics_object: false,
3951};
3952
3953/// Peeled version of `PG_ATTRDEF`:
3954/// - This doesn't check `mz_schemas.database_id IS NULL OR d.name = pg_catalog.current_database()`,
3955///   in order to make this view indexable.
3956pub static PG_ATTRDEF_ALL_DATABASES: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
3957    name: "pg_attrdef_all_databases",
3958    schema: MZ_INTERNAL_SCHEMA,
3959    oid: oid::VIEW_PG_ATTRDEF_ALL_DATABASES_OID,
3960    desc: RelationDesc::builder()
3961        .with_column("oid", SqlScalarType::Oid.nullable(true))
3962        .with_column("adrelid", SqlScalarType::Oid.nullable(false))
3963        .with_column("adnum", SqlScalarType::Int64.nullable(false))
3964        .with_column("adbin", SqlScalarType::String.nullable(false))
3965        .with_column("adsrc", SqlScalarType::String.nullable(false))
3966        .finish(),
3967    column_comments: BTreeMap::new(),
3968    sql: "
3969SELECT
3970    NULL::pg_catalog.oid AS oid,
3971    mz_objects.oid AS adrelid,
3972    mz_columns.position::int8 AS adnum,
3973    mz_columns.default AS adbin,
3974    mz_columns.default AS adsrc
3975FROM mz_catalog.mz_columns
3976    JOIN mz_catalog.mz_objects ON mz_columns.id = mz_objects.id
3977WHERE default IS NOT NULL",
3978    access: vec![PUBLIC_SELECT],
3979    ontology: None,
3980});
3981
3982pub const PG_ATTRDEF_ALL_DATABASES_IND: BuiltinIndex = BuiltinIndex {
3983    name: "pg_attrdef_all_databases_ind",
3984    schema: MZ_INTERNAL_SCHEMA,
3985    oid: oid::INDEX_PG_ATTRDEF_ALL_DATABASES_IND_OID,
3986    sql: "IN CLUSTER mz_catalog_server
3987ON mz_internal.pg_attrdef_all_databases (oid, adrelid, adnum, adbin, adsrc)",
3988    is_retained_metrics_object: false,
3989};
3990
3991pub static MZ_COMPUTE_ERROR_COUNTS_RAW_UNIFIED: LazyLock<BuiltinSource> =
3992    LazyLock::new(|| BuiltinSource {
3993        // TODO(database-issues#8173): Rename this source to `mz_compute_error_counts_raw`. Currently this causes a
3994        // naming conflict because the resolver stumbles over the source with the same name in
3995        // `mz_introspection` due to the automatic schema translation.
3996        name: "mz_compute_error_counts_raw_unified",
3997        schema: MZ_INTERNAL_SCHEMA,
3998        oid: oid::SOURCE_MZ_COMPUTE_ERROR_COUNTS_RAW_UNIFIED_OID,
3999        desc: RelationDesc::builder()
4000            .with_column("replica_id", SqlScalarType::String.nullable(false))
4001            .with_column("object_id", SqlScalarType::String.nullable(false))
4002            .with_column(
4003                "count",
4004                SqlScalarType::Numeric { max_scale: None }.nullable(false),
4005            )
4006            .finish(),
4007        data_source: IntrospectionType::ComputeErrorCounts.into(),
4008        column_comments: BTreeMap::new(),
4009        is_retained_metrics_object: false,
4010        access: vec![PUBLIC_SELECT],
4011        ontology: None,
4012    });
4013
4014pub static MZ_COMPUTE_HYDRATION_TIMES: LazyLock<BuiltinSource> = LazyLock::new(|| BuiltinSource {
4015    name: "mz_compute_hydration_times",
4016    schema: MZ_INTERNAL_SCHEMA,
4017    oid: oid::SOURCE_MZ_COMPUTE_HYDRATION_TIMES_OID,
4018    desc: RelationDesc::builder()
4019        .with_column("replica_id", SqlScalarType::String.nullable(false))
4020        .with_column("object_id", SqlScalarType::String.nullable(false))
4021        .with_column("time_ns", SqlScalarType::UInt64.nullable(true))
4022        .finish(),
4023    data_source: IntrospectionType::ComputeHydrationTimes.into(),
4024    column_comments: BTreeMap::new(),
4025    is_retained_metrics_object: true,
4026    access: vec![PUBLIC_SELECT],
4027    ontology: Some(Ontology {
4028        entity_name: "compute_hydration_time",
4029        description: "Time to hydrate compute objects",
4030        links: &const { [] },
4031        column_semantic_types: &const {
4032            [
4033                ("replica_id", SemanticType::ReplicaId),
4034                ("object_id", SemanticType::CatalogItemId),
4035            ]
4036        },
4037    }),
4038});
4039
4040pub static MZ_COMPUTE_HYDRATION_TIMES_IND: LazyLock<BuiltinIndex> =
4041    LazyLock::new(|| BuiltinIndex {
4042        name: "mz_compute_hydration_times_ind",
4043        schema: MZ_INTERNAL_SCHEMA,
4044        oid: oid::INDEX_MZ_COMPUTE_HYDRATION_TIMES_IND_OID,
4045        sql: "IN CLUSTER mz_catalog_server
4046    ON mz_internal.mz_compute_hydration_times (replica_id)",
4047        is_retained_metrics_object: true,
4048    });
4049
4050pub static MZ_OBJECT_ARRANGEMENT_SIZES_UNIFIED: LazyLock<BuiltinSource> = LazyLock::new(|| {
4051    BuiltinSource {
4052        name: "mz_object_arrangement_sizes",
4053        schema: MZ_INTERNAL_SCHEMA,
4054        oid: oid::SOURCE_MZ_OBJECT_ARRANGEMENT_SIZES_OID,
4055        desc: RelationDesc::builder()
4056            .with_column("replica_id", SqlScalarType::String.nullable(false))
4057            .with_column("object_id", SqlScalarType::String.nullable(false))
4058            .with_column("size", SqlScalarType::Int64.nullable(true))
4059            .finish(),
4060        data_source: IntrospectionType::ComputeObjectArrangementSizes.into(),
4061        column_comments: BTreeMap::from_iter([
4062            (
4063                "replica_id",
4064                "The ID of the cluster replica. Corresponds to `mz_cluster_replicas.id`.",
4065            ),
4066            (
4067                "object_id",
4068                "The ID of the compute object (index or materialized view). Corresponds to `mz_objects.id`.",
4069            ),
4070            (
4071                "size",
4072                "The total arrangement heap and batcher size in bytes for this object on this replica. \
4073                 Objects smaller than 10 MiB are reported at their exact size; objects 10 MiB or larger \
4074                 are rounded to the nearest 10 MiB boundary to reduce per-byte churn in the differential \
4075                 collection.",
4076            ),
4077        ]),
4078        is_retained_metrics_object: true,
4079        access: vec![PUBLIC_SELECT],
4080        ontology: None,
4081    }
4082});
4083
4084pub static MZ_OBJECT_ARRANGEMENT_SIZES_IND: LazyLock<BuiltinIndex> =
4085    LazyLock::new(|| BuiltinIndex {
4086        name: "mz_object_arrangement_sizes_ind",
4087        schema: MZ_INTERNAL_SCHEMA,
4088        oid: oid::INDEX_MZ_OBJECT_ARRANGEMENT_SIZES_IND_OID,
4089        sql: "IN CLUSTER mz_catalog_server
4090    ON mz_internal.mz_object_arrangement_sizes (replica_id)",
4091        is_retained_metrics_object: true,
4092    });
4093
4094pub static MZ_OBJECT_ARRANGEMENT_SIZE_HISTORY: LazyLock<BuiltinTable> = LazyLock::new(|| {
4095    BuiltinTable {
4096        name: "mz_object_arrangement_size_history",
4097        schema: MZ_INTERNAL_SCHEMA,
4098        oid: oid::TABLE_MZ_OBJECT_ARRANGEMENT_SIZE_HISTORY_OID,
4099        desc: RelationDesc::builder()
4100            .with_column("replica_id", SqlScalarType::String.nullable(false))
4101            .with_column("object_id", SqlScalarType::String.nullable(false))
4102            .with_column("size", SqlScalarType::Int64.nullable(false))
4103            .with_column(
4104                "collection_timestamp",
4105                SqlScalarType::TimestampTz { precision: None }.nullable(false),
4106            )
4107            .with_column("hydration_complete", SqlScalarType::Bool.nullable(false))
4108            .finish(),
4109        column_comments: BTreeMap::from_iter([
4110            (
4111                "replica_id",
4112                "The ID of the cluster replica. Corresponds to `mz_cluster_replicas.id`.",
4113            ),
4114            (
4115                "object_id",
4116                "The ID of the compute object (index or materialized view). Corresponds to `mz_objects.id`.",
4117            ),
4118            (
4119                "size",
4120                "The total arrangement heap and batcher size in bytes for this object on this replica \
4121                 at `collection_timestamp`. Objects below 10 MiB are dropped from the snapshot; \
4122                 objects at or above the floor are rounded to the nearest 10 MiB to reduce \
4123                 per-byte churn in the underlying differential collection. May reflect a mid-build \
4124                 size if `hydration_complete` is `false`.",
4125            ),
4126            (
4127                "collection_timestamp",
4128                "The timestamp when this snapshot was collected.",
4129            ),
4130            (
4131                "hydration_complete",
4132                "Whether the arrangement had finished its initial hydration on this replica when \
4133                 the snapshot was collected. Filter for `true` to consider only stable, post-build \
4134                 sizes.",
4135            ),
4136        ]),
4137        is_retained_metrics_object: true,
4138        access: vec![PUBLIC_SELECT],
4139        ontology: None,
4140    }
4141});
4142
4143pub static MZ_OBJECT_ARRANGEMENT_SIZE_HISTORY_OBJECT_IND: LazyLock<BuiltinIndex> =
4144    LazyLock::new(|| BuiltinIndex {
4145        name: "mz_object_arrangement_size_history_object_ind",
4146        schema: MZ_INTERNAL_SCHEMA,
4147        oid: oid::INDEX_MZ_OBJECT_ARRANGEMENT_SIZE_HISTORY_OBJECT_IND_OID,
4148        sql: "IN CLUSTER mz_catalog_server
4149    ON mz_internal.mz_object_arrangement_size_history (object_id)",
4150        is_retained_metrics_object: true,
4151    });
4152
4153pub static MZ_OBJECT_ARRANGEMENT_SIZE_HISTORY_TS_IND: LazyLock<BuiltinIndex> =
4154    LazyLock::new(|| BuiltinIndex {
4155        name: "mz_object_arrangement_size_history_ts_ind",
4156        schema: MZ_INTERNAL_SCHEMA,
4157        oid: oid::INDEX_MZ_OBJECT_ARRANGEMENT_SIZE_HISTORY_TS_IND_OID,
4158        sql: "IN CLUSTER mz_catalog_server
4159    ON mz_internal.mz_object_arrangement_size_history (collection_timestamp)",
4160        is_retained_metrics_object: true,
4161    });
4162
4163pub static MZ_COMPUTE_HYDRATION_STATUSES: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
4164    name: "mz_compute_hydration_statuses",
4165    schema: MZ_INTERNAL_SCHEMA,
4166    oid: oid::SOURCE_MZ_COMPUTE_HYDRATION_STATUSES_OID,
4167    desc: RelationDesc::builder()
4168        .with_column("object_id", SqlScalarType::String.nullable(false))
4169        .with_column("replica_id", SqlScalarType::String.nullable(false))
4170        .with_column("hydrated", SqlScalarType::Bool.nullable(false))
4171        .with_column("hydration_time", SqlScalarType::Interval.nullable(true))
4172        .finish(),
4173    column_comments: BTreeMap::from_iter([
4174        (
4175            "object_id",
4176            "The ID of a compute object. Corresponds to `mz_catalog.mz_indexes.id` or `mz_catalog.mz_materialized_views.id`",
4177        ),
4178        ("replica_id", "The ID of a cluster replica."),
4179        (
4180            "hydrated",
4181            "Whether the compute object is hydrated on the replica.",
4182        ),
4183        (
4184            "hydration_time",
4185            "The amount of time it took for the replica to hydrate the compute object.",
4186        ),
4187    ]),
4188    sql: "
4189WITH
4190    dataflows AS (
4191        SELECT
4192            object_id,
4193            replica_id,
4194            time_ns IS NOT NULL AS hydrated,
4195            ((time_ns / 1000) || 'microseconds')::interval AS hydration_time
4196        FROM mz_internal.mz_compute_hydration_times
4197    ),
4198    -- MVs that have advanced to the empty frontier don't have a dataflow installed anymore and
4199    -- therefore don't show up in `mz_compute_hydration_times`. We still want to show them here to
4200    -- avoid surprises for people joining `mz_materialized_views` against this relation (like the
4201    -- blue-green readiness query does), so we include them as 'hydrated'.
4202    complete_mvs AS (
4203        SELECT
4204            mv.id,
4205            f.replica_id,
4206            true AS hydrated,
4207            NULL::interval AS hydration_time
4208        FROM mz_materialized_views mv
4209        JOIN mz_catalog.mz_cluster_replica_frontiers f ON f.object_id = mv.id
4210        WHERE f.write_frontier IS NULL
4211    )
4212SELECT * FROM dataflows
4213UNION ALL
4214SELECT * FROM complete_mvs",
4215    access: vec![PUBLIC_SELECT],
4216    ontology: Some(Ontology {
4217        entity_name: "compute_hydration_status_view",
4218        description: "Computed hydration status per compute object",
4219        links: &const { [] },
4220        column_semantic_types: &const {
4221            [
4222                ("object_id", SemanticType::GlobalId),
4223                ("replica_id", SemanticType::ReplicaId),
4224            ]
4225        },
4226    }),
4227});
4228
4229pub static MZ_COMPUTE_OPERATOR_HYDRATION_STATUSES: LazyLock<BuiltinSource> = LazyLock::new(|| {
4230    BuiltinSource {
4231        name: "mz_compute_operator_hydration_statuses",
4232        schema: MZ_INTERNAL_SCHEMA,
4233        oid: oid::SOURCE_MZ_COMPUTE_OPERATOR_HYDRATION_STATUSES_OID,
4234        desc: RelationDesc::builder()
4235            .with_column("replica_id", SqlScalarType::String.nullable(false))
4236            .with_column("object_id", SqlScalarType::String.nullable(false))
4237            .with_column(
4238                "physical_plan_node_id",
4239                SqlScalarType::UInt64.nullable(false),
4240            )
4241            .with_column("hydrated", SqlScalarType::Bool.nullable(false))
4242            .with_key(vec![0, 1, 2])
4243            .finish(),
4244        data_source: IntrospectionType::ComputeOperatorHydrationStatus.into(),
4245        column_comments: BTreeMap::from_iter([
4246            ("replica_id", "The ID of a cluster replica."),
4247            (
4248                "object_id",
4249                "The ID of a compute object. Corresponds to `mz_catalog.mz_indexes.id` or `mz_catalog.mz_materialized_views.id`.",
4250            ),
4251            (
4252                "physical_plan_node_id",
4253                "The ID of a node in the physical plan of the compute object. Corresponds to a `node_id` displayed in the output of `EXPLAIN PHYSICAL PLAN WITH (node identifiers)`.",
4254            ),
4255            ("hydrated", "Whether the node is hydrated on the replica."),
4256        ]),
4257        is_retained_metrics_object: false,
4258        access: vec![PUBLIC_SELECT],
4259        ontology: Some(Ontology {
4260            entity_name: "compute_hydration_status",
4261            description: "Hydration status per compute operator",
4262            links: &const { [] },
4263            column_semantic_types: &const {
4264                [
4265                    ("replica_id", SemanticType::ReplicaId),
4266                    ("object_id", SemanticType::CatalogItemId),
4267                ]
4268            },
4269        }),
4270    }
4271});
4272
4273pub static MZ_CLUSTER_REPLICA_UTILIZATION: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
4274    name: "mz_cluster_replica_utilization",
4275    schema: MZ_INTERNAL_SCHEMA,
4276    oid: oid::VIEW_MZ_CLUSTER_REPLICA_UTILIZATION_OID,
4277    desc: RelationDesc::builder()
4278        .with_column("replica_id", SqlScalarType::String.nullable(false))
4279        .with_column("process_id", SqlScalarType::UInt64.nullable(false))
4280        .with_column("cpu_percent", SqlScalarType::Float64.nullable(true))
4281        .with_column("memory_percent", SqlScalarType::Float64.nullable(true))
4282        .with_column("disk_percent", SqlScalarType::Float64.nullable(true))
4283        .with_column("heap_percent", SqlScalarType::Float64.nullable(true))
4284        .finish(),
4285    column_comments: BTreeMap::from_iter([
4286        ("replica_id", "The ID of a cluster replica."),
4287        ("process_id", "The ID of a process within the replica."),
4288        (
4289            "cpu_percent",
4290            "Approximate CPU usage, in percent of the total allocation.",
4291        ),
4292        (
4293            "memory_percent",
4294            "Approximate RAM usage, in percent of the total allocation.",
4295        ),
4296        (
4297            "disk_percent",
4298            "Approximate disk usage, in percent of the total allocation.",
4299        ),
4300        (
4301            "heap_percent",
4302            "Approximate heap (RAM + swap) usage, in percent of the total allocation.",
4303        ),
4304    ]),
4305    sql: "
4306SELECT
4307    r.id AS replica_id,
4308    m.process_id,
4309    m.cpu_nano_cores::float8 / NULLIF(s.cpu_nano_cores, 0) * 100 AS cpu_percent,
4310    m.memory_bytes::float8 / NULLIF(s.memory_bytes, 0) * 100 AS memory_percent,
4311    m.disk_bytes::float8 / NULLIF(s.disk_bytes, 0) * 100 AS disk_percent,
4312    m.heap_bytes::float8 / NULLIF(m.heap_limit, 0) * 100 AS heap_percent
4313FROM
4314    mz_catalog.mz_cluster_replicas AS r
4315        JOIN mz_catalog.mz_cluster_replica_sizes AS s ON r.size = s.size
4316        JOIN mz_internal.mz_cluster_replica_metrics AS m ON m.replica_id = r.id",
4317    access: vec![PUBLIC_SELECT],
4318    ontology: Some(Ontology {
4319        entity_name: "replica_utilization",
4320        description: "Computed utilization metrics per replica",
4321        links: &const {
4322            [OntologyLink {
4323                name: "utilization_of_replica",
4324                target: "replica",
4325                properties: LinkProperties::fk_typed(
4326                    "replica_id",
4327                    "id",
4328                    Cardinality::OneToOne,
4329                    mz_repr::SemanticType::CatalogItemId,
4330                ),
4331            }]
4332        },
4333        column_semantic_types: &[("replica_id", SemanticType::ReplicaId)],
4334    }),
4335});
4336
4337pub static MZ_CLUSTER_REPLICA_UTILIZATION_HISTORY: LazyLock<BuiltinView> =
4338    LazyLock::new(|| BuiltinView {
4339        name: "mz_cluster_replica_utilization_history",
4340        schema: MZ_INTERNAL_SCHEMA,
4341        oid: oid::VIEW_MZ_CLUSTER_REPLICA_UTILIZATION_HISTORY_OID,
4342        desc: RelationDesc::builder()
4343            .with_column("replica_id", SqlScalarType::String.nullable(false))
4344            .with_column("process_id", SqlScalarType::UInt64.nullable(false))
4345            .with_column("cpu_percent", SqlScalarType::Float64.nullable(true))
4346            .with_column("memory_percent", SqlScalarType::Float64.nullable(true))
4347            .with_column("disk_percent", SqlScalarType::Float64.nullable(true))
4348            .with_column("heap_percent", SqlScalarType::Float64.nullable(true))
4349            .with_column(
4350                "occurred_at",
4351                SqlScalarType::TimestampTz { precision: None }.nullable(false),
4352            )
4353            .finish(),
4354        column_comments: BTreeMap::from_iter([
4355            ("replica_id", "The ID of a cluster replica."),
4356            ("process_id", "The ID of a process within the replica."),
4357            (
4358                "cpu_percent",
4359                "Approximate CPU usage, in percent of the total allocation.",
4360            ),
4361            (
4362                "memory_percent",
4363                "Approximate RAM usage, in percent of the total allocation.",
4364            ),
4365            (
4366                "disk_percent",
4367                "Approximate disk usage, in percent of the total allocation.",
4368            ),
4369            (
4370                "heap_percent",
4371                "Approximate heap (RAM + swap) usage, in percent of the total allocation.",
4372            ),
4373            (
4374                "occurred_at",
4375                "Wall-clock timestamp at which the event occurred.",
4376            ),
4377        ]),
4378        sql: "
4379SELECT
4380    r.id AS replica_id,
4381    m.process_id,
4382    m.cpu_nano_cores::float8 / NULLIF(s.cpu_nano_cores, 0) * 100 AS cpu_percent,
4383    m.memory_bytes::float8 / NULLIF(s.memory_bytes, 0) * 100 AS memory_percent,
4384    m.disk_bytes::float8 / NULLIF(s.disk_bytes, 0) * 100 AS disk_percent,
4385    m.heap_bytes::float8 / NULLIF(m.heap_limit, 0) * 100 AS heap_percent,
4386    m.occurred_at
4387FROM
4388    mz_catalog.mz_cluster_replicas AS r
4389        JOIN mz_catalog.mz_cluster_replica_sizes AS s ON r.size = s.size
4390        JOIN mz_internal.mz_cluster_replica_metrics_history AS m ON m.replica_id = r.id",
4391        access: vec![PUBLIC_SELECT],
4392        ontology: None,
4393    });
4394
4395pub static MZ_INDEX_ADVICE: LazyLock<BuiltinView> = LazyLock::new(|| {
4396    BuiltinView {
4397        name: "mz_index_advice",
4398        schema: MZ_INTERNAL_SCHEMA,
4399        oid: oid::VIEW_MZ_INDEX_ADVICE_OID,
4400        desc: RelationDesc::builder()
4401            .with_column("object_id", SqlScalarType::String.nullable(true))
4402            .with_column("hint", SqlScalarType::String.nullable(false))
4403            .with_column("details", SqlScalarType::String.nullable(false))
4404            .with_column("referenced_object_ids", SqlScalarType::List { element_type: Box::new(SqlScalarType::String), custom_id: None }.nullable(true))
4405            .finish(),
4406        column_comments: BTreeMap::from_iter([
4407            ("object_id", "The ID of the object. Corresponds to mz_objects.id."),
4408            ("hint", "A suggestion to either change the object (e.g. create an index, turn a materialized view into an indexed view) or keep the object unchanged."),
4409            ("details", "Additional details on why the `hint` was proposed based on the dependencies of the object."),
4410            ("referenced_object_ids", "The IDs of objects referenced by `details`. Corresponds to mz_objects.id."),
4411        ]),
4412        sql: "
4413-- To avoid confusion with sources and sinks in the materialize sense,
4414-- the following uses the terms leafs (instead of sinks) and roots (instead of sources)
4415-- when referring to the object dependency graph.
4416--
4417-- The basic idea is to walk up the dependency graph to propagate the transitive dependencies
4418-- of maintained objected upwards. The leaves of the dependency graph are maintained objects
4419-- that are not depended on by other maintained objects and have a justification why they must
4420-- be maintained (e.g. a materialized view that is depended on by a sink).
4421-- Starting from these leaves, the dependencies are propagated upwards towards the roots according
4422-- to the object dependencies. Whenever there is a node that is being depended on by multiple
4423-- downstream objects, that node is marked to be converted into a maintained object and this
4424-- node is then propagated further up. Once completed, the list of objects that are marked as
4425-- maintained is checked against all objects to generate appropriate recommendations.
4426--
4427-- Note that the recommendations only incorporate dependencies between objects.
4428-- This can lead to bad recommendations, e.g. filters can no longer be pushed into (or close to)
4429-- a sink if an index is added in between the sink and the filter. For very selective filters,
4430-- this can lead to redundant work: the index is computing stuff only to discarded by the selective
4431-- filter later on. But these kind of aspects cannot be understood by merely looking at the
4432-- dependencies.
4433WITH MUTUALLY RECURSIVE
4434    -- for all objects, understand if they have an index on them and on which cluster they are running
4435    -- this avoids having different cases for views with an index and materialized views later on
4436    objects(id text, type text, cluster_id text, indexes text list) AS (
4437        -- views and materialized views without an index
4438        SELECT
4439            o.id,
4440            o.type,
4441            o.cluster_id,
4442            '{}'::text list AS indexes
4443        FROM mz_catalog.mz_objects o
4444        WHERE o.id LIKE 'u%' AND o.type IN ('materialized-view', 'view') AND NOT EXISTS (
4445            SELECT FROM mz_internal.mz_object_dependencies d
4446            JOIN mz_catalog.mz_objects AS i
4447                ON (i.id = d.object_id AND i.type = 'index')
4448            WHERE (o.id = d.referenced_object_id)
4449        )
4450
4451        UNION ALL
4452
4453        -- views and materialized views with an index
4454        SELECT
4455            o.id,
4456            o.type,
4457            -- o.cluster_id is always NULL for views, so use the cluster of the index instead
4458            COALESCE(o.cluster_id, i.cluster_id) AS cluster_id,
4459            list_agg(i.id) AS indexes
4460        FROM mz_catalog.mz_objects o
4461        JOIN mz_internal.mz_object_dependencies AS d
4462            ON (o.id = d.referenced_object_id)
4463        JOIN mz_catalog.mz_objects AS i
4464            ON (i.id = d.object_id AND i.type = 'index')
4465        WHERE o.id LIKE 'u%' AND o.type IN ('materialized-view', 'view', 'source')
4466        GROUP BY o.id, o.type, o.cluster_id, i.cluster_id
4467    ),
4468
4469    -- maintained objects that are at the leafs of the dependency graph with respect to a specific cluster
4470    maintained_leafs(id text, justification text) AS (
4471        -- materialized views that are connected to a sink
4472        SELECT
4473            m.id,
4474            s.id AS justification
4475        FROM objects AS m
4476        JOIN mz_internal.mz_object_dependencies AS d
4477            ON (m.id = d.referenced_object_id)
4478        JOIN mz_catalog.mz_objects AS s
4479            ON (s.id = d.object_id AND s.type = 'sink')
4480        WHERE m.type = 'materialized-view'
4481
4482        UNION ALL
4483
4484        -- (materialized) views with an index that are not transitively depend on by maintained objects on the same cluster
4485        SELECT
4486            v.id,
4487            unnest(v.indexes) AS justification
4488        FROM objects AS v
4489        WHERE v.type IN ('view', 'materialized-view', 'source') AND NOT EXISTS (
4490            SELECT FROM mz_internal.mz_object_transitive_dependencies AS d
4491            INNER JOIN mz_catalog.mz_objects AS child
4492                ON (d.object_id = child.id)
4493            WHERE d.referenced_object_id = v.id AND child.type IN ('materialized-view', 'index') AND v.cluster_id = child.cluster_id AND NOT v.indexes @> LIST[child.id]
4494        )
4495    ),
4496
4497    -- this is just a helper cte to union multiple lists as part of an aggregation, which is not directly possible in SQL
4498    agg_maintained_children(id text, maintained_children text list) AS (
4499        SELECT
4500            parent_id AS id,
4501            list_agg(maintained_child) AS maintained_leafs
4502        FROM (
4503            SELECT DISTINCT
4504                d.referenced_object_id AS parent_id,
4505                -- it's not possible to union lists in an aggregation, so we have to unnest the list first
4506                unnest(child.maintained_children) AS maintained_child
4507            FROM propagate_dependencies AS child
4508            INNER JOIN mz_internal.mz_object_dependencies AS d
4509                ON (child.id = d.object_id)
4510        )
4511        GROUP BY parent_id
4512    ),
4513
4514    -- propagate dependencies of maintained objects from the leafs to the roots of the dependency graph and
4515    -- record a justification when an object should be maintained, e.g. when it is depended on by more than one maintained object
4516    -- when an object should be maintained, maintained_children will just contain that object so that further upstream objects refer to it in their maintained_children
4517    propagate_dependencies(id text, maintained_children text list, justification text list) AS (
4518        -- base case: start with the leafs
4519        SELECT DISTINCT
4520            id,
4521            LIST[id] AS maintained_children,
4522            list_agg(justification) AS justification
4523        FROM maintained_leafs
4524        GROUP BY id
4525
4526        UNION
4527
4528        -- recursive case: if there is a child with the same dependencies as the parent,
4529        -- the parent is only reused by a single child
4530        SELECT
4531            parent.id,
4532            child.maintained_children,
4533            NULL::text list AS justification
4534        FROM agg_maintained_children AS parent
4535        INNER JOIN mz_internal.mz_object_dependencies AS d
4536            ON (parent.id = d.referenced_object_id)
4537        INNER JOIN propagate_dependencies AS child
4538            ON (d.object_id = child.id)
4539        WHERE parent.maintained_children = child.maintained_children
4540
4541        UNION
4542
4543        -- recursive case: if there is NO child with the same dependencies as the parent,
4544        -- different children are reusing the parent so maintaining the object is justified by itself
4545        SELECT DISTINCT
4546            parent.id,
4547            LIST[parent.id] AS maintained_children,
4548            parent.maintained_children AS justification
4549        FROM agg_maintained_children AS parent
4550        WHERE NOT EXISTS (
4551            SELECT FROM mz_internal.mz_object_dependencies AS d
4552            INNER JOIN propagate_dependencies AS child
4553                ON (d.object_id = child.id AND d.referenced_object_id = parent.id)
4554            WHERE parent.maintained_children = child.maintained_children
4555        )
4556    ),
4557
4558    objects_with_justification(id text, type text, cluster_id text, maintained_children text list, justification text list, indexes text list) AS (
4559        SELECT
4560            p.id,
4561            o.type,
4562            o.cluster_id,
4563            p.maintained_children,
4564            p.justification,
4565            o.indexes
4566        FROM propagate_dependencies p
4567        JOIN objects AS o
4568            ON (p.id = o.id)
4569    ),
4570
4571    hints(id text, hint text, details text, justification text list) AS (
4572        -- materialized views that are not required
4573        SELECT
4574            id,
4575            'convert to a view' AS hint,
4576            'no dependencies from sinks nor from objects on different clusters' AS details,
4577            justification
4578        FROM objects_with_justification
4579        WHERE type = 'materialized-view' AND justification IS NULL
4580
4581        UNION ALL
4582
4583        -- materialized views that are required because a sink or a maintained object from a different cluster depends on them
4584        SELECT
4585            id,
4586            'keep' AS hint,
4587            'dependencies from sinks or objects on different clusters: ' AS details,
4588            justification
4589        FROM objects_with_justification AS m
4590        WHERE type = 'materialized-view' AND justification IS NOT NULL AND EXISTS (
4591            SELECT FROM unnest(justification) AS dependency
4592            JOIN mz_catalog.mz_objects s ON (s.type = 'sink' AND s.id = dependency)
4593
4594            UNION ALL
4595
4596            SELECT FROM unnest(justification) AS dependency
4597            JOIN mz_catalog.mz_objects AS d ON (d.id = dependency)
4598            WHERE d.cluster_id != m.cluster_id
4599        )
4600
4601        UNION ALL
4602
4603        -- materialized views that can be converted to a view with or without an index because NO sink or a maintained object from a different cluster depends on them
4604        SELECT
4605            id,
4606            'convert to a view with an index' AS hint,
4607            'no dependencies from sinks nor from objects on different clusters, but maintained dependencies on the same cluster: ' AS details,
4608            justification
4609        FROM objects_with_justification AS m
4610        WHERE type = 'materialized-view' AND justification IS NOT NULL AND NOT EXISTS (
4611            SELECT FROM unnest(justification) AS dependency
4612            JOIN mz_catalog.mz_objects s ON (s.type = 'sink' AND s.id = dependency)
4613
4614            UNION ALL
4615
4616            SELECT FROM unnest(justification) AS dependency
4617            JOIN mz_catalog.mz_objects AS d ON (d.id = dependency)
4618            WHERE d.cluster_id != m.cluster_id
4619        )
4620
4621        UNION ALL
4622
4623        -- views that have indexes on different clusters should be a materialized view
4624        SELECT
4625            o.id,
4626            'convert to materialized view' AS hint,
4627            'dependencies on multiple clusters: ' AS details,
4628            o.justification
4629        FROM objects_with_justification o,
4630            LATERAL unnest(o.justification) j
4631        LEFT JOIN mz_catalog.mz_objects AS m
4632            ON (m.id = j AND m.type IN ('index', 'materialized-view'))
4633        WHERE o.type = 'view' AND o.justification IS NOT NULL
4634        GROUP BY o.id, o.justification
4635        HAVING count(DISTINCT m.cluster_id) >= 2
4636
4637        UNION ALL
4638
4639        -- views without an index that should be maintained
4640        SELECT
4641            id,
4642            'add index' AS hint,
4643            'multiple downstream dependencies: ' AS details,
4644            justification
4645        FROM objects_with_justification
4646        WHERE type = 'view' AND justification IS NOT NULL AND indexes = '{}'::text list
4647
4648        UNION ALL
4649
4650        -- index inside the dependency graph (not a leaf)
4651        SELECT
4652            unnest(indexes) AS id,
4653            'drop unless queried directly' AS hint,
4654            'fewer than two downstream dependencies: ' AS details,
4655            maintained_children AS justification
4656        FROM objects_with_justification
4657        WHERE type = 'view' AND NOT indexes = '{}'::text list AND justification IS NULL
4658
4659        UNION ALL
4660
4661        -- index on a leaf of the dependency graph
4662        SELECT
4663            unnest(indexes) AS id,
4664            'drop unless queried directly' AS hint,
4665            'associated object does not have any dependencies (maintained or not maintained)' AS details,
4666            NULL::text list AS justification
4667        FROM objects_with_justification
4668        -- indexes can only be part of justification for leaf nodes
4669        WHERE type IN ('view', 'materialized-view') AND NOT indexes = '{}'::text list AND justification @> indexes
4670
4671        UNION ALL
4672
4673        -- index on a source
4674        SELECT
4675            unnest(indexes) AS id,
4676            'drop unless queried directly' AS hint,
4677            'sources do not transform data and can expose data directly' AS details,
4678            NULL::text list AS justification
4679        FROM objects_with_justification
4680        -- indexes can only be part of justification for leaf nodes
4681        WHERE type = 'source' AND NOT indexes = '{}'::text list
4682
4683        UNION ALL
4684
4685        -- indexes on views inside the dependency graph
4686        SELECT
4687            unnest(indexes) AS id,
4688            'keep' AS hint,
4689            'multiple downstream dependencies: ' AS details,
4690            justification
4691        FROM objects_with_justification
4692        -- indexes can only be part of justification for leaf nodes
4693        WHERE type = 'view' AND justification IS NOT NULL AND NOT indexes = '{}'::text list AND NOT justification @> indexes
4694    ),
4695
4696    hints_resolved_ids(id text, hint text, details text, justification text list) AS (
4697        SELECT
4698            h.id,
4699            h.hint,
4700            h.details || list_agg(o.name)::text AS details,
4701            h.justification
4702        FROM hints AS h,
4703            LATERAL unnest(h.justification) j
4704        JOIN mz_catalog.mz_objects AS o
4705            ON (o.id = j)
4706        GROUP BY h.id, h.hint, h.details, h.justification
4707
4708        UNION ALL
4709
4710        SELECT
4711            id,
4712            hint,
4713            details,
4714            justification
4715        FROM hints
4716        WHERE justification IS NULL
4717    )
4718
4719SELECT
4720    h.id AS object_id,
4721    h.hint AS hint,
4722    h.details,
4723    h.justification AS referenced_object_ids
4724FROM hints_resolved_ids AS h",
4725        access: vec![PUBLIC_SELECT],
4726        ontology: None,
4727    }
4728});
4729
4730/// Peeled version of `PG_AUTHID`: Excludes the columns rolcreaterole and rolcreatedb, to make this
4731/// view indexable.
4732pub static PG_AUTHID_CORE: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
4733    name: "pg_authid_core",
4734    schema: MZ_INTERNAL_SCHEMA,
4735    oid: oid::VIEW_PG_AUTHID_CORE_OID,
4736    desc: RelationDesc::builder()
4737        .with_column("oid", SqlScalarType::Oid.nullable(false))
4738        .with_column("rolname", SqlScalarType::String.nullable(false))
4739        .with_column("rolsuper", SqlScalarType::Bool.nullable(true))
4740        .with_column("rolinherit", SqlScalarType::Bool.nullable(false))
4741        .with_column("rolcanlogin", SqlScalarType::Bool.nullable(false))
4742        .with_column("rolreplication", SqlScalarType::Bool.nullable(false))
4743        .with_column("rolbypassrls", SqlScalarType::Bool.nullable(false))
4744        .with_column("rolconnlimit", SqlScalarType::Int32.nullable(false))
4745        .with_column("rolpassword", SqlScalarType::String.nullable(true))
4746        .with_column(
4747            "rolvaliduntil",
4748            SqlScalarType::TimestampTz { precision: None }.nullable(true),
4749        )
4750        .finish(),
4751    column_comments: BTreeMap::new(),
4752    sql: r#"
4753SELECT
4754    r.oid AS oid,
4755    r.name AS rolname,
4756    rolsuper,
4757    inherit AS rolinherit,
4758    COALESCE(r.rolcanlogin, false) AS rolcanlogin,
4759    -- MZ doesn't support replication in the same way Postgres does
4760    false AS rolreplication,
4761    -- MZ doesn't how row level security
4762    false AS rolbypassrls,
4763    -- MZ doesn't have a connection limit
4764    -1 AS rolconnlimit,
4765    a.password_hash AS rolpassword,
4766    NULL::pg_catalog.timestamptz AS rolvaliduntil
4767FROM mz_catalog.mz_roles r
4768LEFT JOIN mz_catalog.mz_role_auth a ON r.oid = a.role_oid"#,
4769    access: vec![rbac::owner_privilege(ObjectType::Table, MZ_SYSTEM_ROLE_ID)],
4770    ontology: None,
4771});
4772
4773pub const PG_AUTHID_CORE_IND: BuiltinIndex = BuiltinIndex {
4774    name: "pg_authid_core_ind",
4775    schema: MZ_INTERNAL_SCHEMA,
4776    oid: oid::INDEX_PG_AUTHID_CORE_IND_OID,
4777    sql: "IN CLUSTER mz_catalog_server
4778ON mz_internal.pg_authid_core (rolname)",
4779    is_retained_metrics_object: false,
4780};
4781
4782pub static MZ_SHOW_ALL_OBJECTS: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
4783    name: "mz_show_all_objects",
4784    schema: MZ_INTERNAL_SCHEMA,
4785    oid: oid::VIEW_MZ_SHOW_ALL_OBJECTS_OID,
4786    desc: RelationDesc::builder()
4787        .with_column("schema_id", SqlScalarType::String.nullable(false))
4788        .with_column("name", SqlScalarType::String.nullable(false))
4789        .with_column("type", SqlScalarType::String.nullable(false))
4790        .with_column("comment", SqlScalarType::String.nullable(false))
4791        .finish(),
4792    column_comments: BTreeMap::new(),
4793    sql: "WITH comments AS (
4794        SELECT id, object_type, comment
4795        FROM mz_internal.mz_comments
4796        WHERE object_sub_id IS NULL
4797    )
4798    SELECT schema_id, name, type, COALESCE(comment, '') AS comment
4799    FROM mz_catalog.mz_objects AS objs
4800    LEFT JOIN comments ON objs.id = comments.id
4801    WHERE (comments.object_type = objs.type OR comments.object_type IS NULL)",
4802    access: vec![PUBLIC_SELECT],
4803    ontology: None,
4804});
4805
4806pub static MZ_SHOW_CLUSTERS: LazyLock<BuiltinView> = LazyLock::new(|| {
4807    BuiltinView {
4808    name: "mz_show_clusters",
4809    schema: MZ_INTERNAL_SCHEMA,
4810    oid: oid::VIEW_MZ_SHOW_CLUSTERS_OID,
4811    desc: RelationDesc::builder()
4812        .with_column("name", SqlScalarType::String.nullable(false))
4813        .with_column("replicas", SqlScalarType::String.nullable(true))
4814        .with_column("comment", SqlScalarType::String.nullable(false))
4815        .finish(),
4816    column_comments: BTreeMap::new(),
4817    sql: "
4818    WITH clusters AS (
4819        SELECT
4820            mc.id,
4821            mc.name,
4822            pg_catalog.string_agg(mcr.name || ' (' || mcr.size || ')', ', ' ORDER BY mcr.name) AS replicas
4823        FROM mz_catalog.mz_clusters mc
4824        LEFT JOIN mz_catalog.mz_cluster_replicas mcr
4825        ON mc.id = mcr.cluster_id
4826        GROUP BY mc.id, mc.name
4827    ),
4828    comments AS (
4829        SELECT id, comment
4830        FROM mz_internal.mz_comments
4831        WHERE object_type = 'cluster' AND object_sub_id IS NULL
4832    )
4833    SELECT name, replicas, COALESCE(comment, '') as comment
4834    FROM clusters
4835    LEFT JOIN comments ON clusters.id = comments.id",
4836    access: vec![PUBLIC_SELECT],
4837    ontology: None,
4838}
4839});
4840
4841pub static MZ_SHOW_SECRETS: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
4842    name: "mz_show_secrets",
4843    schema: MZ_INTERNAL_SCHEMA,
4844    oid: oid::VIEW_MZ_SHOW_SECRETS_OID,
4845    desc: RelationDesc::builder()
4846        .with_column("schema_id", SqlScalarType::String.nullable(false))
4847        .with_column("name", SqlScalarType::String.nullable(false))
4848        .with_column("comment", SqlScalarType::String.nullable(false))
4849        .finish(),
4850    column_comments: BTreeMap::new(),
4851    sql: "WITH comments AS (
4852        SELECT id, comment
4853        FROM mz_internal.mz_comments
4854        WHERE object_type = 'secret' AND object_sub_id IS NULL
4855    )
4856    SELECT schema_id, name, COALESCE(comment, '') as comment
4857    FROM mz_catalog.mz_secrets secrets
4858    LEFT JOIN comments ON secrets.id = comments.id",
4859    access: vec![PUBLIC_SELECT],
4860    ontology: None,
4861});
4862
4863pub static MZ_SHOW_COLUMNS: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
4864    name: "mz_show_columns",
4865    schema: MZ_INTERNAL_SCHEMA,
4866    oid: oid::VIEW_MZ_SHOW_COLUMNS_OID,
4867    desc: RelationDesc::builder()
4868        .with_column("id", SqlScalarType::String.nullable(false))
4869        .with_column("name", SqlScalarType::String.nullable(false))
4870        .with_column("nullable", SqlScalarType::Bool.nullable(false))
4871        .with_column("type", SqlScalarType::String.nullable(false))
4872        .with_column("position", SqlScalarType::UInt64.nullable(false))
4873        .with_column("comment", SqlScalarType::String.nullable(false))
4874        .finish(),
4875    column_comments: BTreeMap::new(),
4876    sql: "
4877    SELECT columns.id, name, nullable, type, position, COALESCE(comment, '') as comment
4878    FROM mz_catalog.mz_columns columns
4879    LEFT JOIN mz_internal.mz_comments comments
4880    ON columns.id = comments.id AND columns.position = comments.object_sub_id",
4881    access: vec![PUBLIC_SELECT],
4882    ontology: None,
4883});
4884
4885pub static MZ_SHOW_DATABASES: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
4886    name: "mz_show_databases",
4887    schema: MZ_INTERNAL_SCHEMA,
4888    oid: oid::VIEW_MZ_SHOW_DATABASES_OID,
4889    desc: RelationDesc::builder()
4890        .with_column("name", SqlScalarType::String.nullable(false))
4891        .with_column("comment", SqlScalarType::String.nullable(false))
4892        .finish(),
4893    column_comments: BTreeMap::new(),
4894    sql: "WITH comments AS (
4895        SELECT id, comment
4896        FROM mz_internal.mz_comments
4897        WHERE object_type = 'database' AND object_sub_id IS NULL
4898    )
4899    SELECT name, COALESCE(comment, '') as comment
4900    FROM mz_catalog.mz_databases databases
4901    LEFT JOIN comments ON databases.id = comments.id",
4902    access: vec![PUBLIC_SELECT],
4903    ontology: None,
4904});
4905
4906pub static MZ_SHOW_SCHEMAS: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
4907    name: "mz_show_schemas",
4908    schema: MZ_INTERNAL_SCHEMA,
4909    oid: oid::VIEW_MZ_SHOW_SCHEMAS_OID,
4910    desc: RelationDesc::builder()
4911        .with_column("database_id", SqlScalarType::String.nullable(true))
4912        .with_column("name", SqlScalarType::String.nullable(false))
4913        .with_column("comment", SqlScalarType::String.nullable(false))
4914        .finish(),
4915    column_comments: BTreeMap::new(),
4916    sql: "WITH comments AS (
4917        SELECT id, comment
4918        FROM mz_internal.mz_comments
4919        WHERE object_type = 'schema' AND object_sub_id IS NULL
4920    )
4921    SELECT database_id, name, COALESCE(comment, '') as comment
4922    FROM mz_catalog.mz_schemas schemas
4923    LEFT JOIN comments ON schemas.id = comments.id",
4924    access: vec![PUBLIC_SELECT],
4925    ontology: None,
4926});
4927
4928pub static MZ_SHOW_ROLES: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
4929    name: "mz_show_roles",
4930    schema: MZ_INTERNAL_SCHEMA,
4931    oid: oid::VIEW_MZ_SHOW_ROLES_OID,
4932    desc: RelationDesc::builder()
4933        .with_column("name", SqlScalarType::String.nullable(false))
4934        .with_column("comment", SqlScalarType::String.nullable(false))
4935        .finish(),
4936    column_comments: BTreeMap::new(),
4937    sql: "WITH comments AS (
4938        SELECT id, comment
4939        FROM mz_internal.mz_comments
4940        WHERE object_type = 'role' AND object_sub_id IS NULL
4941    )
4942    SELECT name, COALESCE(comment, '') as comment
4943    FROM mz_catalog.mz_roles roles
4944    LEFT JOIN comments ON roles.id = comments.id
4945    WHERE roles.id NOT LIKE 's%'
4946      AND roles.id NOT LIKE 'g%'",
4947    access: vec![PUBLIC_SELECT],
4948    ontology: None,
4949});
4950
4951pub static MZ_SHOW_TABLES: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
4952    name: "mz_show_tables",
4953    schema: MZ_INTERNAL_SCHEMA,
4954    oid: oid::VIEW_MZ_SHOW_TABLES_OID,
4955    desc: RelationDesc::builder()
4956        .with_column("schema_id", SqlScalarType::String.nullable(false))
4957        .with_column("name", SqlScalarType::String.nullable(false))
4958        .with_column("comment", SqlScalarType::String.nullable(false))
4959        .with_column("source_id", SqlScalarType::String.nullable(true))
4960        .finish(),
4961    column_comments: BTreeMap::new(),
4962    sql: "WITH comments AS (
4963        SELECT id, comment
4964        FROM mz_internal.mz_comments
4965        WHERE object_type = 'table' AND object_sub_id IS NULL
4966    )
4967    SELECT schema_id, name, COALESCE(comment, '') as comment, source_id
4968    FROM mz_catalog.mz_tables tables
4969    LEFT JOIN comments ON tables.id = comments.id",
4970    access: vec![PUBLIC_SELECT],
4971    ontology: None,
4972});
4973
4974pub static MZ_SHOW_VIEWS: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
4975    name: "mz_show_views",
4976    schema: MZ_INTERNAL_SCHEMA,
4977    oid: oid::VIEW_MZ_SHOW_VIEWS_OID,
4978    desc: RelationDesc::builder()
4979        .with_column("schema_id", SqlScalarType::String.nullable(false))
4980        .with_column("name", SqlScalarType::String.nullable(false))
4981        .with_column("comment", SqlScalarType::String.nullable(false))
4982        .finish(),
4983    column_comments: BTreeMap::new(),
4984    sql: "WITH comments AS (
4985        SELECT id, comment
4986        FROM mz_internal.mz_comments
4987        WHERE object_type = 'view' AND object_sub_id IS NULL
4988    )
4989    SELECT schema_id, name, COALESCE(comment, '') as comment
4990    FROM mz_catalog.mz_views views
4991    LEFT JOIN comments ON views.id = comments.id",
4992    access: vec![PUBLIC_SELECT],
4993    ontology: None,
4994});
4995
4996pub static MZ_SHOW_TYPES: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
4997    name: "mz_show_types",
4998    schema: MZ_INTERNAL_SCHEMA,
4999    oid: oid::VIEW_MZ_SHOW_TYPES_OID,
5000    desc: RelationDesc::builder()
5001        .with_column("schema_id", SqlScalarType::String.nullable(false))
5002        .with_column("name", SqlScalarType::String.nullable(false))
5003        .with_column("comment", SqlScalarType::String.nullable(false))
5004        .finish(),
5005    column_comments: BTreeMap::new(),
5006    sql: "WITH comments AS (
5007        SELECT id, comment
5008        FROM mz_internal.mz_comments
5009        WHERE object_type = 'type' AND object_sub_id IS NULL
5010    )
5011    SELECT schema_id, name, COALESCE(comment, '') as comment
5012    FROM mz_catalog.mz_types types
5013    LEFT JOIN comments ON types.id = comments.id",
5014    access: vec![PUBLIC_SELECT],
5015    ontology: None,
5016});
5017
5018pub static MZ_SHOW_CONNECTIONS: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
5019    name: "mz_show_connections",
5020    schema: MZ_INTERNAL_SCHEMA,
5021    oid: oid::VIEW_MZ_SHOW_CONNECTIONS_OID,
5022    desc: RelationDesc::builder()
5023        .with_column("schema_id", SqlScalarType::String.nullable(false))
5024        .with_column("name", SqlScalarType::String.nullable(false))
5025        .with_column("type", SqlScalarType::String.nullable(false))
5026        .with_column("comment", SqlScalarType::String.nullable(false))
5027        .finish(),
5028    column_comments: BTreeMap::new(),
5029    sql: "WITH comments AS (
5030        SELECT id, comment
5031        FROM mz_internal.mz_comments
5032        WHERE object_type = 'connection' AND object_sub_id IS NULL
5033    )
5034    SELECT schema_id, name, type, COALESCE(comment, '') as comment
5035    FROM mz_catalog.mz_connections connections
5036    LEFT JOIN comments ON connections.id = comments.id",
5037    access: vec![PUBLIC_SELECT],
5038    ontology: None,
5039});
5040
5041pub static MZ_SHOW_SOURCES: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
5042    name: "mz_show_sources",
5043    schema: MZ_INTERNAL_SCHEMA,
5044    oid: oid::VIEW_MZ_SHOW_SOURCES_OID,
5045    desc: RelationDesc::builder()
5046        .with_column("id", SqlScalarType::String.nullable(false))
5047        .with_column("name", SqlScalarType::String.nullable(false))
5048        .with_column("type", SqlScalarType::String.nullable(false))
5049        .with_column("cluster", SqlScalarType::String.nullable(true))
5050        .with_column("schema_id", SqlScalarType::String.nullable(false))
5051        .with_column("cluster_id", SqlScalarType::String.nullable(true))
5052        .with_column("comment", SqlScalarType::String.nullable(false))
5053        .finish(),
5054    column_comments: BTreeMap::new(),
5055    sql: "
5056WITH comments AS (
5057    SELECT id, comment
5058    FROM mz_internal.mz_comments
5059    WHERE object_type = 'source' AND object_sub_id IS NULL
5060)
5061SELECT
5062    sources.id,
5063    sources.name,
5064    sources.type,
5065    clusters.name AS cluster,
5066    schema_id,
5067    cluster_id,
5068    COALESCE(comments.comment, '') as comment
5069FROM
5070    mz_catalog.mz_sources AS sources
5071        LEFT JOIN
5072            mz_catalog.mz_clusters AS clusters
5073            ON clusters.id = sources.cluster_id
5074        LEFT JOIN comments ON sources.id = comments.id",
5075    access: vec![PUBLIC_SELECT],
5076    ontology: None,
5077});
5078
5079pub static MZ_SHOW_SINKS: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
5080    name: "mz_show_sinks",
5081    schema: MZ_INTERNAL_SCHEMA,
5082    oid: oid::VIEW_MZ_SHOW_SINKS_OID,
5083    desc: RelationDesc::builder()
5084        .with_column("id", SqlScalarType::String.nullable(false))
5085        .with_column("name", SqlScalarType::String.nullable(false))
5086        .with_column("type", SqlScalarType::String.nullable(false))
5087        .with_column("cluster", SqlScalarType::String.nullable(false))
5088        .with_column("schema_id", SqlScalarType::String.nullable(false))
5089        .with_column("cluster_id", SqlScalarType::String.nullable(false))
5090        .with_column("comment", SqlScalarType::String.nullable(false))
5091        .finish(),
5092    column_comments: BTreeMap::new(),
5093    sql: "
5094WITH comments AS (
5095    SELECT id, comment
5096    FROM mz_internal.mz_comments
5097    WHERE object_type = 'sink' AND object_sub_id IS NULL
5098)
5099SELECT
5100    sinks.id,
5101    sinks.name,
5102    sinks.type,
5103    clusters.name AS cluster,
5104    schema_id,
5105    cluster_id,
5106    COALESCE(comments.comment, '') as comment
5107FROM
5108    mz_catalog.mz_sinks AS sinks
5109    JOIN
5110        mz_catalog.mz_clusters AS clusters
5111        ON clusters.id = sinks.cluster_id
5112    LEFT JOIN comments ON sinks.id = comments.id",
5113    access: vec![PUBLIC_SELECT],
5114    ontology: None,
5115});
5116
5117pub static MZ_SHOW_MATERIALIZED_VIEWS: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
5118    name: "mz_show_materialized_views",
5119    schema: MZ_INTERNAL_SCHEMA,
5120    oid: oid::VIEW_MZ_SHOW_MATERIALIZED_VIEWS_OID,
5121    desc: RelationDesc::builder()
5122        .with_column("id", SqlScalarType::String.nullable(false))
5123        .with_column("name", SqlScalarType::String.nullable(false))
5124        .with_column("cluster", SqlScalarType::String.nullable(false))
5125        .with_column("schema_id", SqlScalarType::String.nullable(false))
5126        .with_column("cluster_id", SqlScalarType::String.nullable(false))
5127        .with_column("comment", SqlScalarType::String.nullable(false))
5128        .finish(),
5129    column_comments: BTreeMap::new(),
5130    sql: "
5131WITH
5132    comments AS (
5133        SELECT id, comment
5134        FROM mz_internal.mz_comments
5135        WHERE object_type = 'materialized-view' AND object_sub_id IS NULL
5136    )
5137SELECT
5138    mviews.id as id,
5139    mviews.name,
5140    clusters.name AS cluster,
5141    schema_id,
5142    cluster_id,
5143    COALESCE(comments.comment, '') as comment
5144FROM
5145    mz_catalog.mz_materialized_views AS mviews
5146    JOIN mz_catalog.mz_clusters AS clusters ON clusters.id = mviews.cluster_id
5147    LEFT JOIN comments ON mviews.id = comments.id",
5148    access: vec![PUBLIC_SELECT],
5149    ontology: None,
5150});
5151
5152pub static MZ_SHOW_INDEXES: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
5153    name: "mz_show_indexes",
5154    schema: MZ_INTERNAL_SCHEMA,
5155    oid: oid::VIEW_MZ_SHOW_INDEXES_OID,
5156    desc: RelationDesc::builder()
5157        .with_column("id", SqlScalarType::String.nullable(false))
5158        .with_column("name", SqlScalarType::String.nullable(false))
5159        .with_column("on", SqlScalarType::String.nullable(false))
5160        .with_column("cluster", SqlScalarType::String.nullable(false))
5161        .with_column(
5162            "key",
5163            SqlScalarType::Array(Box::new(SqlScalarType::String)).nullable(false),
5164        )
5165        .with_column("on_id", SqlScalarType::String.nullable(false))
5166        .with_column("schema_id", SqlScalarType::String.nullable(false))
5167        .with_column("cluster_id", SqlScalarType::String.nullable(false))
5168        .with_column("comment", SqlScalarType::String.nullable(false))
5169        .finish(),
5170    column_comments: BTreeMap::new(),
5171    sql: "
5172WITH comments AS (
5173    SELECT id, comment
5174    FROM mz_internal.mz_comments
5175    WHERE object_type = 'index' AND object_sub_id IS NULL
5176)
5177SELECT
5178    idxs.id AS id,
5179    idxs.name AS name,
5180    objs.name AS on,
5181    clusters.name AS cluster,
5182    COALESCE(keys.key, '{}'::_text) AS key,
5183    idxs.on_id AS on_id,
5184    objs.schema_id AS schema_id,
5185    clusters.id AS cluster_id,
5186    COALESCE(comments.comment, '') as comment
5187FROM
5188    mz_catalog.mz_indexes AS idxs
5189    JOIN mz_catalog.mz_objects AS objs ON idxs.on_id = objs.id
5190    JOIN mz_catalog.mz_clusters AS clusters ON clusters.id = idxs.cluster_id
5191    LEFT JOIN
5192        (SELECT
5193            idxs.id,
5194            ARRAY_AGG(
5195                CASE
5196                    WHEN idx_cols.on_expression IS NULL THEN obj_cols.name
5197                    ELSE idx_cols.on_expression
5198                END
5199                ORDER BY idx_cols.index_position ASC
5200            ) AS key
5201        FROM
5202            mz_catalog.mz_indexes AS idxs
5203            JOIN mz_catalog.mz_index_columns idx_cols ON idxs.id = idx_cols.index_id
5204            LEFT JOIN mz_catalog.mz_columns obj_cols ON
5205                idxs.on_id = obj_cols.id AND idx_cols.on_position = obj_cols.position
5206        GROUP BY idxs.id) AS keys
5207    ON idxs.id = keys.id
5208    LEFT JOIN comments ON idxs.id = comments.id",
5209    access: vec![PUBLIC_SELECT],
5210    ontology: None,
5211});
5212
5213pub static MZ_SHOW_CLUSTER_REPLICAS: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
5214    name: "mz_show_cluster_replicas",
5215    schema: MZ_INTERNAL_SCHEMA,
5216    oid: oid::VIEW_MZ_SHOW_CLUSTER_REPLICAS_OID,
5217    desc: RelationDesc::builder()
5218        .with_column("cluster", SqlScalarType::String.nullable(false))
5219        .with_column("replica", SqlScalarType::String.nullable(false))
5220        .with_column("replica_id", SqlScalarType::String.nullable(false))
5221        .with_column("size", SqlScalarType::String.nullable(true))
5222        .with_column("ready", SqlScalarType::Bool.nullable(false))
5223        .with_column("comment", SqlScalarType::String.nullable(false))
5224        .finish(),
5225    column_comments: BTreeMap::new(),
5226    sql: r#"SELECT
5227    mz_catalog.mz_clusters.name AS cluster,
5228    mz_catalog.mz_cluster_replicas.name AS replica,
5229    mz_catalog.mz_cluster_replicas.id as replica_id,
5230    mz_catalog.mz_cluster_replicas.size AS size,
5231    coalesce(statuses.ready, FALSE) AS ready,
5232    coalesce(comments.comment, '') as comment
5233FROM
5234    mz_catalog.mz_cluster_replicas
5235        JOIN mz_catalog.mz_clusters
5236            ON mz_catalog.mz_cluster_replicas.cluster_id = mz_catalog.mz_clusters.id
5237        LEFT JOIN
5238            (
5239                SELECT
5240                    replica_id,
5241                    bool_and(hydrated) AS ready
5242                FROM mz_internal.mz_hydration_statuses
5243                WHERE replica_id is not null
5244                GROUP BY replica_id
5245            ) AS statuses
5246            ON mz_catalog.mz_cluster_replicas.id = statuses.replica_id
5247        LEFT JOIN mz_internal.mz_comments comments
5248            ON mz_catalog.mz_cluster_replicas.id = comments.id
5249WHERE (comments.object_type = 'cluster-replica' OR comments.object_type IS NULL)
5250ORDER BY 1, 2"#,
5251    access: vec![PUBLIC_SELECT],
5252    ontology: None,
5253});
5254
5255/// Lightweight data product discovery for MCP (Model Context Protocol).
5256///
5257/// Lists materialized views and indexed views that the current user has
5258/// SELECT privileges on. Non-indexed regular views are excluded because
5259/// querying them would trigger a full recompute. Comments are optional
5260/// enrichment.
5261/// Used by the `get_data_products` and `read_data_product` MCP tools.
5262/// Does not include schema details: use `mz_mcp_data_product_details` for that.
5263pub static MZ_MCP_DATA_PRODUCTS: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
5264    name: "mz_mcp_data_products",
5265    schema: MZ_INTERNAL_SCHEMA,
5266    oid: oid::VIEW_MZ_MCP_DATA_PRODUCTS_OID,
5267    desc: RelationDesc::builder()
5268        .with_column("object_name", SqlScalarType::String.nullable(false))
5269        .with_column("cluster", SqlScalarType::String.nullable(true))
5270        .with_column("description", SqlScalarType::String.nullable(true))
5271        .with_key(vec![0, 1, 2])
5272        .finish(),
5273    column_comments: BTreeMap::from_iter([
5274        (
5275            "object_name",
5276            "Fully qualified object name (database.schema.name).",
5277        ),
5278        (
5279            "cluster",
5280            "Cluster where the object computes or its index is hosted. Reads from any cluster work, but only reads on this cluster benefit from the index.",
5281        ),
5282        (
5283            "description",
5284            "Index comment if available, otherwise object comment. Used as data product description.",
5285        ),
5286    ]),
5287    sql: r#"
5288SELECT DISTINCT
5289    '"' || op.database || '"."' || op.schema || '"."' || op.name || '"' AS object_name,
5290    COALESCE(c_idx.name, c_obj.name) AS cluster,
5291    COALESCE(cts_idx.comment, cts_obj.comment) AS description
5292FROM mz_internal.mz_show_my_object_privileges op
5293JOIN mz_objects o ON op.name = o.name AND op.object_type = o.type
5294JOIN mz_schemas s ON s.name = op.schema AND s.id = o.schema_id
5295JOIN mz_databases d ON d.name = op.database AND d.id = s.database_id
5296LEFT JOIN mz_indexes i ON i.on_id = o.id
5297LEFT JOIN mz_clusters c_idx ON c_idx.id = i.cluster_id
5298LEFT JOIN mz_clusters c_obj ON c_obj.id = o.cluster_id
5299LEFT JOIN mz_internal.mz_comments cts_idx ON cts_idx.id = i.id AND cts_idx.object_sub_id IS NULL
5300LEFT JOIN mz_internal.mz_comments cts_obj ON cts_obj.id = o.id AND cts_obj.object_sub_id IS NULL
5301WHERE op.privilege_type = 'SELECT'
5302  AND (o.type = 'materialized-view' OR (o.type = 'view' AND i.id IS NOT NULL))
5303  AND s.name NOT IN ('mz_catalog', 'mz_internal', 'pg_catalog', 'information_schema', 'mz_introspection')
5304"#,
5305    access: vec![PUBLIC_SELECT],
5306    ontology: None,
5307});
5308
5309/// Full data product details with JSON Schema for MCP agents.
5310///
5311/// Extends `mz_mcp_data_products` with column types, index keys (when
5312/// available), and column comments, formatted as a JSON Schema object.
5313/// Used by the `get_data_product_details` MCP tool. Lists materialized
5314/// views and indexed views; non-indexed regular views are excluded to
5315/// avoid triggering full recompute on query. Comments are optional
5316/// enrichment.
5317pub static MZ_MCP_DATA_PRODUCT_DETAILS: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
5318    name: "mz_mcp_data_product_details",
5319    schema: MZ_INTERNAL_SCHEMA,
5320    oid: oid::VIEW_MZ_MCP_DATA_PRODUCT_DETAILS_OID,
5321    // Note: no `.with_key` here. The view's row identity is semantically
5322    // (object_name, cluster, description) — same as the underlying details
5323    // CTE — but the planner can't prove key propagation through the
5324    // `LEFT JOIN ... ON ... IS NOT DISTINCT FROM` to the hydration CTE,
5325    // so declaring it here would diverge from the inferred RelationDesc
5326    // and fail `verify_builtin_descs`.
5327    desc: RelationDesc::builder()
5328        .with_column("object_name", SqlScalarType::String.nullable(false))
5329        .with_column("cluster", SqlScalarType::String.nullable(true))
5330        .with_column("description", SqlScalarType::String.nullable(true))
5331        .with_column("schema", SqlScalarType::Jsonb.nullable(false))
5332        .with_column("hydration", SqlScalarType::Jsonb.nullable(false))
5333        .finish(),
5334    column_comments: BTreeMap::from_iter([
5335        (
5336            "object_name",
5337            "Fully qualified object name (database.schema.name).",
5338        ),
5339        (
5340            "cluster",
5341            "Cluster where the object computes or its index is hosted. Reads from any cluster work, but only reads on this cluster benefit from the index.",
5342        ),
5343        (
5344            "description",
5345            "Index comment if available, otherwise object comment. Used as data product description.",
5346        ),
5347        (
5348            "schema",
5349            "JSON Schema describing the object's columns and types.",
5350        ),
5351        (
5352            "hydration",
5353            "Readiness summary as a JSON object with `hydrated` (bool), `replica_count` (int), and `hydrated_replica_count` (int). `hydrated` is true only when the cluster has at least one replica and the dataflow is hydrated on every replica. Reads against a non-hydrated data product block until the dataflow catches up (they never return partial data). Check this before reading: if `hydrated` is false and `replica_count > 0`, wait and retry; if `replica_count` is 0, the cluster has no replicas and that needs operator action, not a retry.",
5354        ),
5355    ]),
5356    sql: r#"
5357WITH details_raw AS (
5358    SELECT
5359        '"' || op.database || '"."' || op.schema || '"."' || op.name || '"' AS object_name,
5360        COALESCE(c_idx.name, c_obj.name) AS cluster,
5361        COALESCE(cts_idx.comment, cts_obj.comment) AS description,
5362        COALESCE(jsonb_build_object(
5363        'type', 'object',
5364        'indexedColumns', jsonb_agg(distinct ccol.name) FILTER (WHERE ccol.position = ic.on_position),
5365        'properties', jsonb_strip_nulls(jsonb_object_agg(
5366            ccol.name,
5367            CASE
5368                WHEN ccol.type IN (
5369                    'uint2', 'uint4','uint8', 'int', 'integer', 'smallint',
5370                    'double', 'double precision', 'bigint', 'float',
5371                    'numeric', 'real'
5372                ) THEN jsonb_build_object(
5373                    'type', 'number',
5374                    'description', cts_col.comment
5375                )
5376                WHEN ccol.type = 'boolean' THEN jsonb_build_object(
5377                    'type', 'boolean',
5378                    'description', cts_col.comment
5379                )
5380                WHEN ccol.type = 'bytea' THEN jsonb_build_object(
5381                    'type', 'string',
5382                    'description', cts_col.comment,
5383                    'contentEncoding', 'base64',
5384                    'contentMediaType', 'application/octet-stream'
5385                )
5386                WHEN ccol.type = 'date' THEN jsonb_build_object(
5387                    'type', 'string',
5388                    'format', 'date',
5389                    'description', cts_col.comment
5390                )
5391                WHEN ccol.type = 'time' THEN jsonb_build_object(
5392                    'type', 'string',
5393                    'format', 'time',
5394                    'description', cts_col.comment
5395                )
5396                WHEN ccol.type ilike 'timestamp%%' THEN jsonb_build_object(
5397                    'type', 'string',
5398                    'format', 'date-time',
5399                    'description', cts_col.comment
5400                )
5401                WHEN ccol.type = 'jsonb' THEN jsonb_build_object(
5402                    'type', 'object',
5403                    'description', cts_col.comment
5404                )
5405                WHEN ccol.type = 'uuid' THEN jsonb_build_object(
5406                    'type', 'string',
5407                    'format', 'uuid',
5408                    'description', cts_col.comment
5409                )
5410                ELSE jsonb_build_object(
5411                    'type', 'string',
5412                    'description', cts_col.comment
5413                )
5414            END
5415        ))
5416    ), '{"type": "object", "properties": {}}'::jsonb) AS schema
5417FROM mz_internal.mz_show_my_object_privileges op
5418JOIN mz_objects o ON op.name = o.name AND op.object_type = o.type
5419JOIN mz_schemas s ON s.name = op.schema AND s.id = o.schema_id
5420JOIN mz_databases d ON d.name = op.database AND d.id = s.database_id
5421JOIN mz_columns ccol ON ccol.id = o.id
5422LEFT JOIN mz_indexes i ON i.on_id = o.id
5423LEFT JOIN mz_index_columns ic ON i.id = ic.index_id
5424LEFT JOIN mz_clusters c_idx ON c_idx.id = i.cluster_id
5425LEFT JOIN mz_clusters c_obj ON c_obj.id = o.cluster_id
5426LEFT JOIN mz_internal.mz_comments cts_idx ON cts_idx.id = i.id AND cts_idx.object_sub_id IS NULL
5427LEFT JOIN mz_internal.mz_comments cts_obj ON cts_obj.id = o.id AND cts_obj.object_sub_id IS NULL
5428LEFT JOIN mz_internal.mz_comments cts_col ON cts_col.id = o.id AND cts_col.object_sub_id = ccol.position
5429WHERE op.privilege_type = 'SELECT'
5430  AND (o.type = 'materialized-view' OR (o.type = 'view' AND i.id IS NOT NULL))
5431  AND s.name NOT IN ('mz_catalog', 'mz_internal', 'pg_catalog', 'information_schema', 'mz_introspection')
5432GROUP BY 1, 2, 3
5433),
5434-- Pick the right (object_id, cluster_id) for hydration: the index's id +
5435-- cluster when an index exists (its arrangement is what the data product
5436-- reads from), otherwise the materialized view's own id + cluster.
5437hydration_meta AS (
5438    SELECT DISTINCT
5439        '"' || db.name || '"."' || s.name || '"."' || o.name || '"' AS object_name,
5440        COALESCE(c_idx.name, c_obj.name) AS cluster,
5441        COALESCE(i.id, o.id) AS hydration_object_id,
5442        COALESCE(i.cluster_id, o.cluster_id) AS cluster_id
5443    FROM mz_objects o
5444    JOIN mz_schemas s ON s.id = o.schema_id
5445    JOIN mz_databases db ON db.id = s.database_id
5446    LEFT JOIN mz_indexes i ON i.on_id = o.id
5447    LEFT JOIN mz_clusters c_idx ON c_idx.id = i.cluster_id
5448    LEFT JOIN mz_clusters c_obj ON c_obj.id = o.cluster_id
5449    WHERE (o.type = 'materialized-view' OR (o.type = 'view' AND i.id IS NOT NULL))
5450      AND s.name NOT IN ('mz_catalog', 'mz_internal', 'pg_catalog', 'information_schema', 'mz_introspection')
5451),
5452-- Dedupe by replica before counting: an MV with multiple indexes on the
5453-- same cluster has multiple rows in `hydration_meta`, and joining each
5454-- of them against `mz_cluster_replicas` would otherwise inflate the
5455-- counts by the number of indexes. A replica is "hydrated" only when
5456-- every index dataflow for this data product is hydrated on it.
5457hydration_per_replica AS (
5458    SELECT
5459        m.object_name,
5460        m.cluster,
5461        r.id AS replica_id,
5462        bool_and(COALESCE(h.hydrated, false)) AS replica_hydrated
5463    FROM hydration_meta m
5464    LEFT JOIN mz_catalog.mz_cluster_replicas r ON r.cluster_id = m.cluster_id
5465    LEFT JOIN mz_internal.mz_hydration_statuses h
5466        ON h.replica_id = r.id AND h.object_id = m.hydration_object_id
5467    GROUP BY m.object_name, m.cluster, r.id
5468),
5469hydration AS (
5470    SELECT
5471        object_name,
5472        cluster,
5473        COUNT(replica_id)::int AS replica_count,
5474        COUNT(replica_id) FILTER (WHERE replica_hydrated)::int AS hydrated_replica_count
5475    FROM hydration_per_replica
5476    GROUP BY object_name, cluster
5477)
5478SELECT
5479    d.object_name,
5480    d.cluster,
5481    d.description,
5482    d.schema,
5483    jsonb_build_object(
5484        'hydrated',
5485        COALESCE(h.replica_count > 0 AND h.hydrated_replica_count = h.replica_count, false),
5486        'replica_count', COALESCE(h.replica_count, 0),
5487        'hydrated_replica_count', COALESCE(h.hydrated_replica_count, 0)
5488    ) AS hydration
5489FROM details_raw d
5490LEFT JOIN hydration h
5491    ON h.object_name = d.object_name
5492   AND h.cluster IS NOT DISTINCT FROM d.cluster
5493"#,
5494    access: vec![PUBLIC_SELECT],
5495    ontology: None,
5496});
5497
5498pub static MZ_SHOW_ROLE_MEMBERS: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
5499    name: "mz_show_role_members",
5500    schema: MZ_INTERNAL_SCHEMA,
5501    oid: oid::VIEW_MZ_SHOW_ROLE_MEMBERS_OID,
5502    desc: RelationDesc::builder()
5503        .with_column("role", SqlScalarType::String.nullable(false))
5504        .with_column("member", SqlScalarType::String.nullable(false))
5505        .with_column("grantor", SqlScalarType::String.nullable(false))
5506        .finish(),
5507    column_comments: BTreeMap::from_iter([
5508        ("role", "The role that `member` is a member of."),
5509        ("member", "The role that is a member of `role`."),
5510        (
5511            "grantor",
5512            "The role that granted membership of `member` to `role`.",
5513        ),
5514    ]),
5515    sql: r#"SELECT
5516    r1.name AS role,
5517    r2.name AS member,
5518    r3.name AS grantor
5519FROM mz_catalog.mz_role_members rm
5520JOIN mz_catalog.mz_roles r1 ON r1.id = rm.role_id
5521JOIN mz_catalog.mz_roles r2 ON r2.id = rm.member
5522JOIN mz_catalog.mz_roles r3 ON r3.id = rm.grantor
5523ORDER BY role"#,
5524    access: vec![PUBLIC_SELECT],
5525    ontology: None,
5526});
5527
5528pub static MZ_SHOW_MY_ROLE_MEMBERS: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
5529    name: "mz_show_my_role_members",
5530    schema: MZ_INTERNAL_SCHEMA,
5531    oid: oid::VIEW_MZ_SHOW_MY_ROLE_MEMBERS_OID,
5532    desc: RelationDesc::builder()
5533        .with_column("role", SqlScalarType::String.nullable(false))
5534        .with_column("member", SqlScalarType::String.nullable(false))
5535        .with_column("grantor", SqlScalarType::String.nullable(false))
5536        .finish(),
5537    column_comments: BTreeMap::from_iter([
5538        ("role", "The role that `member` is a member of."),
5539        ("member", "The role that is a member of `role`."),
5540        (
5541            "grantor",
5542            "The role that granted membership of `member` to `role`.",
5543        ),
5544    ]),
5545    sql: r#"SELECT role, member, grantor
5546FROM mz_internal.mz_show_role_members
5547WHERE pg_has_role(member, 'USAGE')"#,
5548    access: vec![PUBLIC_SELECT],
5549    ontology: None,
5550});
5551
5552pub static MZ_SHOW_SYSTEM_PRIVILEGES: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
5553    name: "mz_show_system_privileges",
5554    schema: MZ_INTERNAL_SCHEMA,
5555    oid: oid::VIEW_MZ_SHOW_SYSTEM_PRIVILEGES_OID,
5556    desc: RelationDesc::builder()
5557        .with_column("grantor", SqlScalarType::String.nullable(true))
5558        .with_column("grantee", SqlScalarType::String.nullable(true))
5559        .with_column("privilege_type", SqlScalarType::String.nullable(false))
5560        .finish(),
5561    column_comments: BTreeMap::from_iter([
5562        ("grantor", "The role that granted the privilege."),
5563        ("grantee", "The role that the privilege was granted to."),
5564        ("privilege_type", "They type of privilege granted."),
5565    ]),
5566    sql: r#"SELECT
5567    grantor.name AS grantor,
5568    CASE privileges.grantee
5569        WHEN 'p' THEN 'PUBLIC'
5570        ELSE grantee.name
5571    END AS grantee,
5572    privileges.privilege_type AS privilege_type
5573FROM
5574    (SELECT mz_internal.mz_aclexplode(ARRAY[privileges]).*
5575    FROM mz_catalog.mz_system_privileges) AS privileges
5576LEFT JOIN mz_catalog.mz_roles grantor ON privileges.grantor = grantor.id
5577LEFT JOIN mz_catalog.mz_roles grantee ON privileges.grantee = grantee.id
5578WHERE privileges.grantee NOT LIKE 's%'"#,
5579    access: vec![PUBLIC_SELECT],
5580    ontology: None,
5581});
5582
5583pub static MZ_SHOW_MY_SYSTEM_PRIVILEGES: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
5584    name: "mz_show_my_system_privileges",
5585    schema: MZ_INTERNAL_SCHEMA,
5586    oid: oid::VIEW_MZ_SHOW_MY_SYSTEM_PRIVILEGES_OID,
5587    desc: RelationDesc::builder()
5588        .with_column("grantor", SqlScalarType::String.nullable(true))
5589        .with_column("grantee", SqlScalarType::String.nullable(true))
5590        .with_column("privilege_type", SqlScalarType::String.nullable(false))
5591        .finish(),
5592    column_comments: BTreeMap::from_iter([
5593        ("grantor", "The role that granted the privilege."),
5594        ("grantee", "The role that the privilege was granted to."),
5595        ("privilege_type", "They type of privilege granted."),
5596    ]),
5597    sql: r#"SELECT grantor, grantee, privilege_type
5598FROM mz_internal.mz_show_system_privileges
5599WHERE
5600    CASE
5601        WHEN grantee = 'PUBLIC' THEN true
5602        ELSE pg_has_role(grantee, 'USAGE')
5603    END"#,
5604    access: vec![PUBLIC_SELECT],
5605    ontology: None,
5606});
5607
5608pub static MZ_SHOW_CLUSTER_PRIVILEGES: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
5609    name: "mz_show_cluster_privileges",
5610    schema: MZ_INTERNAL_SCHEMA,
5611    oid: oid::VIEW_MZ_SHOW_CLUSTER_PRIVILEGES_OID,
5612    desc: RelationDesc::builder()
5613        .with_column("grantor", SqlScalarType::String.nullable(true))
5614        .with_column("grantee", SqlScalarType::String.nullable(true))
5615        .with_column("name", SqlScalarType::String.nullable(false))
5616        .with_column("privilege_type", SqlScalarType::String.nullable(false))
5617        .finish(),
5618    column_comments: BTreeMap::from_iter([
5619        ("grantor", "The role that granted the privilege."),
5620        ("grantee", "The role that the privilege was granted to."),
5621        ("name", "The name of the cluster."),
5622        ("privilege_type", "They type of privilege granted."),
5623    ]),
5624    sql: r#"SELECT
5625    grantor.name AS grantor,
5626    CASE privileges.grantee
5627        WHEN 'p' THEN 'PUBLIC'
5628        ELSE grantee.name
5629    END AS grantee,
5630    privileges.name AS name,
5631    privileges.privilege_type AS privilege_type
5632FROM
5633    (SELECT mz_internal.mz_aclexplode(privileges).*, name
5634    FROM mz_catalog.mz_clusters
5635    WHERE id NOT LIKE 's%') AS privileges
5636LEFT JOIN mz_catalog.mz_roles grantor ON privileges.grantor = grantor.id
5637LEFT JOIN mz_catalog.mz_roles grantee ON privileges.grantee = grantee.id
5638WHERE privileges.grantee NOT LIKE 's%'"#,
5639    access: vec![PUBLIC_SELECT],
5640    ontology: None,
5641});
5642
5643pub static MZ_SHOW_MY_CLUSTER_PRIVILEGES: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
5644    name: "mz_show_my_cluster_privileges",
5645    schema: MZ_INTERNAL_SCHEMA,
5646    oid: oid::VIEW_MZ_SHOW_MY_CLUSTER_PRIVILEGES_OID,
5647    desc: RelationDesc::builder()
5648        .with_column("grantor", SqlScalarType::String.nullable(true))
5649        .with_column("grantee", SqlScalarType::String.nullable(true))
5650        .with_column("name", SqlScalarType::String.nullable(false))
5651        .with_column("privilege_type", SqlScalarType::String.nullable(false))
5652        .finish(),
5653    column_comments: BTreeMap::from_iter([
5654        ("grantor", "The role that granted the privilege."),
5655        ("grantee", "The role that the privilege was granted to."),
5656        ("name", "The name of the cluster."),
5657        ("privilege_type", "They type of privilege granted."),
5658    ]),
5659    sql: r#"SELECT grantor, grantee, name, privilege_type
5660FROM mz_internal.mz_show_cluster_privileges
5661WHERE
5662    CASE
5663        WHEN grantee = 'PUBLIC' THEN true
5664        ELSE pg_has_role(grantee, 'USAGE')
5665    END"#,
5666    access: vec![PUBLIC_SELECT],
5667    ontology: None,
5668});
5669
5670pub static MZ_SHOW_DATABASE_PRIVILEGES: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
5671    name: "mz_show_database_privileges",
5672    schema: MZ_INTERNAL_SCHEMA,
5673    oid: oid::VIEW_MZ_SHOW_DATABASE_PRIVILEGES_OID,
5674    desc: RelationDesc::builder()
5675        .with_column("grantor", SqlScalarType::String.nullable(true))
5676        .with_column("grantee", SqlScalarType::String.nullable(true))
5677        .with_column("name", SqlScalarType::String.nullable(false))
5678        .with_column("privilege_type", SqlScalarType::String.nullable(false))
5679        .finish(),
5680    column_comments: BTreeMap::from_iter([
5681        ("grantor", "The role that granted the privilege."),
5682        ("grantee", "The role that the privilege was granted to."),
5683        ("name", "The name of the database."),
5684        ("privilege_type", "They type of privilege granted."),
5685    ]),
5686    sql: r#"SELECT
5687    grantor.name AS grantor,
5688    CASE privileges.grantee
5689        WHEN 'p' THEN 'PUBLIC'
5690        ELSE grantee.name
5691    END AS grantee,
5692    privileges.name AS name,
5693    privileges.privilege_type AS privilege_type
5694FROM
5695    (SELECT mz_internal.mz_aclexplode(privileges).*, name
5696    FROM mz_catalog.mz_databases
5697    WHERE id NOT LIKE 's%') AS privileges
5698LEFT JOIN mz_catalog.mz_roles grantor ON privileges.grantor = grantor.id
5699LEFT JOIN mz_catalog.mz_roles grantee ON privileges.grantee = grantee.id
5700WHERE privileges.grantee NOT LIKE 's%'"#,
5701    access: vec![PUBLIC_SELECT],
5702    ontology: None,
5703});
5704
5705pub static MZ_SHOW_MY_DATABASE_PRIVILEGES: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
5706    name: "mz_show_my_database_privileges",
5707    schema: MZ_INTERNAL_SCHEMA,
5708    oid: oid::VIEW_MZ_SHOW_MY_DATABASE_PRIVILEGES_OID,
5709    desc: RelationDesc::builder()
5710        .with_column("grantor", SqlScalarType::String.nullable(true))
5711        .with_column("grantee", SqlScalarType::String.nullable(true))
5712        .with_column("name", SqlScalarType::String.nullable(false))
5713        .with_column("privilege_type", SqlScalarType::String.nullable(false))
5714        .finish(),
5715    column_comments: BTreeMap::from_iter([
5716        ("grantor", "The role that granted the privilege."),
5717        ("grantee", "The role that the privilege was granted to."),
5718        ("name", "The name of the cluster."),
5719        ("privilege_type", "They type of privilege granted."),
5720    ]),
5721    sql: r#"SELECT grantor, grantee, name, privilege_type
5722FROM mz_internal.mz_show_database_privileges
5723WHERE
5724    CASE
5725        WHEN grantee = 'PUBLIC' THEN true
5726        ELSE pg_has_role(grantee, 'USAGE')
5727    END"#,
5728    access: vec![PUBLIC_SELECT],
5729    ontology: None,
5730});
5731
5732pub static MZ_SHOW_SCHEMA_PRIVILEGES: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
5733    name: "mz_show_schema_privileges",
5734    schema: MZ_INTERNAL_SCHEMA,
5735    oid: oid::VIEW_MZ_SHOW_SCHEMA_PRIVILEGES_OID,
5736    desc: RelationDesc::builder()
5737        .with_column("grantor", SqlScalarType::String.nullable(true))
5738        .with_column("grantee", SqlScalarType::String.nullable(true))
5739        .with_column("database", SqlScalarType::String.nullable(true))
5740        .with_column("name", SqlScalarType::String.nullable(false))
5741        .with_column("privilege_type", SqlScalarType::String.nullable(false))
5742        .finish(),
5743    column_comments: BTreeMap::from_iter([
5744        ("grantor", "The role that granted the privilege."),
5745        ("grantee", "The role that the privilege was granted to."),
5746        (
5747            "database",
5748            "The name of the database containing the schema.",
5749        ),
5750        ("name", "The name of the schema."),
5751        ("privilege_type", "They type of privilege granted."),
5752    ]),
5753    sql: r#"SELECT
5754    grantor.name AS grantor,
5755    CASE privileges.grantee
5756        WHEN 'p' THEN 'PUBLIC'
5757        ELSE grantee.name
5758    END AS grantee,
5759    databases.name AS database,
5760    privileges.name AS name,
5761    privileges.privilege_type AS privilege_type
5762FROM
5763    (SELECT mz_internal.mz_aclexplode(privileges).*, database_id, name
5764    FROM mz_catalog.mz_schemas
5765    WHERE id NOT LIKE 's%') AS privileges
5766LEFT JOIN mz_catalog.mz_roles grantor ON privileges.grantor = grantor.id
5767LEFT JOIN mz_catalog.mz_roles grantee ON privileges.grantee = grantee.id
5768LEFT JOIN mz_catalog.mz_databases databases ON privileges.database_id = databases.id
5769WHERE privileges.grantee NOT LIKE 's%'"#,
5770    access: vec![PUBLIC_SELECT],
5771    ontology: None,
5772});
5773
5774pub static MZ_SHOW_MY_SCHEMA_PRIVILEGES: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
5775    name: "mz_show_my_schema_privileges",
5776    schema: MZ_INTERNAL_SCHEMA,
5777    oid: oid::VIEW_MZ_SHOW_MY_SCHEMA_PRIVILEGES_OID,
5778    desc: RelationDesc::builder()
5779        .with_column("grantor", SqlScalarType::String.nullable(true))
5780        .with_column("grantee", SqlScalarType::String.nullable(true))
5781        .with_column("database", SqlScalarType::String.nullable(true))
5782        .with_column("name", SqlScalarType::String.nullable(false))
5783        .with_column("privilege_type", SqlScalarType::String.nullable(false))
5784        .finish(),
5785    column_comments: BTreeMap::from_iter([
5786        ("grantor", "The role that granted the privilege."),
5787        ("grantee", "The role that the privilege was granted to."),
5788        (
5789            "database",
5790            "The name of the database containing the schema.",
5791        ),
5792        ("name", "The name of the schema."),
5793        ("privilege_type", "They type of privilege granted."),
5794    ]),
5795    sql: r#"SELECT grantor, grantee, database, name, privilege_type
5796FROM mz_internal.mz_show_schema_privileges
5797WHERE
5798    CASE
5799        WHEN grantee = 'PUBLIC' THEN true
5800        ELSE pg_has_role(grantee, 'USAGE')
5801    END"#,
5802    access: vec![PUBLIC_SELECT],
5803    ontology: None,
5804});
5805
5806pub static MZ_SHOW_OBJECT_PRIVILEGES: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
5807    name: "mz_show_object_privileges",
5808    schema: MZ_INTERNAL_SCHEMA,
5809    oid: oid::VIEW_MZ_SHOW_OBJECT_PRIVILEGES_OID,
5810    desc: RelationDesc::builder()
5811        .with_column("grantor", SqlScalarType::String.nullable(true))
5812        .with_column("grantee", SqlScalarType::String.nullable(true))
5813        .with_column("database", SqlScalarType::String.nullable(true))
5814        .with_column("schema", SqlScalarType::String.nullable(true))
5815        .with_column("name", SqlScalarType::String.nullable(false))
5816        .with_column("object_type", SqlScalarType::String.nullable(false))
5817        .with_column("privilege_type", SqlScalarType::String.nullable(false))
5818        .finish(),
5819    column_comments: BTreeMap::from_iter([
5820        ("grantor", "The role that granted the privilege."),
5821        ("grantee", "The role that the privilege was granted to."),
5822        (
5823            "database",
5824            "The name of the database containing the object.",
5825        ),
5826        ("schema", "The name of the schema containing the object."),
5827        ("name", "The name of the object."),
5828        (
5829            "object_type",
5830            "The type of object the privilege is granted on.",
5831        ),
5832        ("privilege_type", "They type of privilege granted."),
5833    ]),
5834    sql: r#"SELECT
5835    grantor.name AS grantor,
5836    CASE privileges.grantee
5837            WHEN 'p' THEN 'PUBLIC'
5838            ELSE grantee.name
5839        END AS grantee,
5840    databases.name AS database,
5841    schemas.name AS schema,
5842    privileges.name AS name,
5843    privileges.type AS object_type,
5844    privileges.privilege_type AS privilege_type
5845FROM
5846    (SELECT mz_internal.mz_aclexplode(privileges).*, schema_id, name, type
5847    FROM mz_catalog.mz_objects
5848    WHERE id NOT LIKE 's%') AS privileges
5849LEFT JOIN mz_catalog.mz_roles grantor ON privileges.grantor = grantor.id
5850LEFT JOIN mz_catalog.mz_roles grantee ON privileges.grantee = grantee.id
5851LEFT JOIN mz_catalog.mz_schemas schemas ON privileges.schema_id = schemas.id
5852LEFT JOIN mz_catalog.mz_databases databases ON schemas.database_id = databases.id
5853WHERE privileges.grantee NOT LIKE 's%'"#,
5854    access: vec![PUBLIC_SELECT],
5855    ontology: None,
5856});
5857
5858pub static MZ_SHOW_MY_OBJECT_PRIVILEGES: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
5859    name: "mz_show_my_object_privileges",
5860    schema: MZ_INTERNAL_SCHEMA,
5861    oid: oid::VIEW_MZ_SHOW_MY_OBJECT_PRIVILEGES_OID,
5862    desc: RelationDesc::builder()
5863        .with_column("grantor", SqlScalarType::String.nullable(true))
5864        .with_column("grantee", SqlScalarType::String.nullable(true))
5865        .with_column("database", SqlScalarType::String.nullable(true))
5866        .with_column("schema", SqlScalarType::String.nullable(true))
5867        .with_column("name", SqlScalarType::String.nullable(false))
5868        .with_column("object_type", SqlScalarType::String.nullable(false))
5869        .with_column("privilege_type", SqlScalarType::String.nullable(false))
5870        .finish(),
5871    column_comments: BTreeMap::from_iter([
5872        ("grantor", "The role that granted the privilege."),
5873        ("grantee", "The role that the privilege was granted to."),
5874        (
5875            "database",
5876            "The name of the database containing the object.",
5877        ),
5878        ("schema", "The name of the schema containing the object."),
5879        ("name", "The name of the object."),
5880        (
5881            "object_type",
5882            "The type of object the privilege is granted on.",
5883        ),
5884        ("privilege_type", "They type of privilege granted."),
5885    ]),
5886    sql: r#"SELECT grantor, grantee, database, schema, name, object_type, privilege_type
5887FROM mz_internal.mz_show_object_privileges
5888WHERE
5889    CASE
5890        WHEN grantee = 'PUBLIC' THEN true
5891        -- Semantically equivalent to pg_has_role(grantee, 'USAGE'), which checks
5892        -- whether the current user holds role `grantee`. For a nonexistent grantee
5893        -- name, both return false. We use mz_session_role_memberships() instead
5894        -- because pg_has_role internally calls mz_role_oid_memberships(), which
5895        -- loads the full system role graph and is blocked in restricted sessions.
5896        ELSE grantee = ANY(mz_internal.mz_session_role_memberships())
5897    END"#,
5898    access: vec![PUBLIC_SELECT],
5899    ontology: None,
5900});
5901
5902pub static MZ_SHOW_ALL_PRIVILEGES: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
5903    name: "mz_show_all_privileges",
5904    schema: MZ_INTERNAL_SCHEMA,
5905    oid: oid::VIEW_MZ_SHOW_ALL_PRIVILEGES_OID,
5906    desc: RelationDesc::builder()
5907        .with_column("grantor", SqlScalarType::String.nullable(true))
5908        .with_column("grantee", SqlScalarType::String.nullable(true))
5909        .with_column("database", SqlScalarType::String.nullable(true))
5910        .with_column("schema", SqlScalarType::String.nullable(true))
5911        .with_column("name", SqlScalarType::String.nullable(true))
5912        .with_column("object_type", SqlScalarType::String.nullable(false))
5913        .with_column("privilege_type", SqlScalarType::String.nullable(false))
5914        .finish(),
5915    column_comments: BTreeMap::from_iter([
5916        ("grantor", "The role that granted the privilege."),
5917        ("grantee", "The role that the privilege was granted to."),
5918        (
5919            "database",
5920            "The name of the database containing the object.",
5921        ),
5922        ("schema", "The name of the schema containing the object."),
5923        ("name", "The name of the privilege target."),
5924        (
5925            "object_type",
5926            "The type of object the privilege is granted on.",
5927        ),
5928        ("privilege_type", "They type of privilege granted."),
5929    ]),
5930    sql: r#"SELECT grantor, grantee, NULL AS database, NULL AS schema, NULL AS name, 'system' AS object_type, privilege_type
5931FROM mz_internal.mz_show_system_privileges
5932UNION ALL
5933SELECT grantor, grantee, NULL AS database, NULL AS schema, name, 'cluster' AS object_type, privilege_type
5934FROM mz_internal.mz_show_cluster_privileges
5935UNION ALL
5936SELECT grantor, grantee, NULL AS database, NULL AS schema, name, 'database' AS object_type, privilege_type
5937FROM mz_internal.mz_show_database_privileges
5938UNION ALL
5939SELECT grantor, grantee, database, NULL AS schema, name, 'schema' AS object_type, privilege_type
5940FROM mz_internal.mz_show_schema_privileges
5941UNION ALL
5942SELECT grantor, grantee, database, schema, name, object_type, privilege_type
5943FROM mz_internal.mz_show_object_privileges"#,
5944    access: vec![PUBLIC_SELECT],
5945    ontology: None,
5946});
5947
5948pub static MZ_SHOW_ALL_MY_PRIVILEGES: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
5949    name: "mz_show_all_my_privileges",
5950    schema: MZ_INTERNAL_SCHEMA,
5951    oid: oid::VIEW_MZ_SHOW_ALL_MY_PRIVILEGES_OID,
5952    desc: RelationDesc::builder()
5953        .with_column("grantor", SqlScalarType::String.nullable(true))
5954        .with_column("grantee", SqlScalarType::String.nullable(true))
5955        .with_column("database", SqlScalarType::String.nullable(true))
5956        .with_column("schema", SqlScalarType::String.nullable(true))
5957        .with_column("name", SqlScalarType::String.nullable(true))
5958        .with_column("object_type", SqlScalarType::String.nullable(false))
5959        .with_column("privilege_type", SqlScalarType::String.nullable(false))
5960        .finish(),
5961    column_comments: BTreeMap::from_iter([
5962        ("grantor", "The role that granted the privilege."),
5963        ("grantee", "The role that the privilege was granted to."),
5964        (
5965            "database",
5966            "The name of the database containing the object.",
5967        ),
5968        ("schema", "The name of the schema containing the object."),
5969        ("name", "The name of the privilege target."),
5970        (
5971            "object_type",
5972            "The type of object the privilege is granted on.",
5973        ),
5974        ("privilege_type", "They type of privilege granted."),
5975    ]),
5976    sql: r#"SELECT grantor, grantee, database, schema, name, object_type, privilege_type
5977FROM mz_internal.mz_show_all_privileges
5978WHERE
5979    CASE
5980        WHEN grantee = 'PUBLIC' THEN true
5981        ELSE pg_has_role(grantee, 'USAGE')
5982    END"#,
5983    access: vec![PUBLIC_SELECT],
5984    ontology: None,
5985});
5986
5987pub static MZ_SHOW_DEFAULT_PRIVILEGES: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
5988    name: "mz_show_default_privileges",
5989    schema: MZ_INTERNAL_SCHEMA,
5990    oid: oid::VIEW_MZ_SHOW_DEFAULT_PRIVILEGES_OID,
5991    desc: RelationDesc::builder()
5992        .with_column("object_owner", SqlScalarType::String.nullable(true))
5993        .with_column("database", SqlScalarType::String.nullable(true))
5994        .with_column("schema", SqlScalarType::String.nullable(true))
5995        .with_column("object_type", SqlScalarType::String.nullable(false))
5996        .with_column("grantee", SqlScalarType::String.nullable(true))
5997        .with_column("privilege_type", SqlScalarType::String.nullable(true))
5998        .finish(),
5999    column_comments: BTreeMap::from_iter([
6000        (
6001            "object_owner",
6002            "Privileges described in this row will be granted on objects created by `object_owner`.",
6003        ),
6004        (
6005            "database",
6006            "Privileges described in this row will be granted only on objects created in `database` if non-null.",
6007        ),
6008        (
6009            "schema",
6010            "Privileges described in this row will be granted only on objects created in `schema` if non-null.",
6011        ),
6012        (
6013            "object_type",
6014            "Privileges described in this row will be granted only on objects of type `object_type`.",
6015        ),
6016        (
6017            "grantee",
6018            "Privileges described in this row will be granted to `grantee`.",
6019        ),
6020        ("privilege_type", "They type of privilege to be granted."),
6021    ]),
6022    sql: r#"SELECT
6023    CASE defaults.role_id
6024        WHEN 'p' THEN 'PUBLIC'
6025        ELSE object_owner.name
6026    END AS object_owner,
6027    databases.name AS database,
6028    schemas.name AS schema,
6029    object_type,
6030    CASE defaults.grantee
6031        WHEN 'p' THEN 'PUBLIC'
6032        ELSE grantee.name
6033    END AS grantee,
6034    unnest(mz_internal.mz_format_privileges(defaults.privileges)) AS privilege_type
6035FROM mz_catalog.mz_default_privileges defaults
6036LEFT JOIN mz_catalog.mz_roles AS object_owner ON defaults.role_id = object_owner.id
6037LEFT JOIN mz_catalog.mz_roles AS grantee ON defaults.grantee = grantee.id
6038LEFT JOIN mz_catalog.mz_databases AS databases ON defaults.database_id = databases.id
6039LEFT JOIN mz_catalog.mz_schemas AS schemas ON defaults.schema_id = schemas.id
6040WHERE defaults.grantee NOT LIKE 's%'
6041    AND defaults.database_id IS NULL OR defaults.database_id NOT LIKE 's%'
6042    AND defaults.schema_id IS NULL OR defaults.schema_id NOT LIKE 's%'"#,
6043    access: vec![PUBLIC_SELECT],
6044    ontology: None,
6045});
6046
6047pub static MZ_SHOW_MY_DEFAULT_PRIVILEGES: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
6048    name: "mz_show_my_default_privileges",
6049    schema: MZ_INTERNAL_SCHEMA,
6050    oid: oid::VIEW_MZ_SHOW_MY_DEFAULT_PRIVILEGES_OID,
6051    desc: RelationDesc::builder()
6052        .with_column("object_owner", SqlScalarType::String.nullable(true))
6053        .with_column("database", SqlScalarType::String.nullable(true))
6054        .with_column("schema", SqlScalarType::String.nullable(true))
6055        .with_column("object_type", SqlScalarType::String.nullable(false))
6056        .with_column("grantee", SqlScalarType::String.nullable(true))
6057        .with_column("privilege_type", SqlScalarType::String.nullable(true))
6058        .finish(),
6059    column_comments: BTreeMap::from_iter([
6060        (
6061            "object_owner",
6062            "Privileges described in this row will be granted on objects created by `object_owner`.",
6063        ),
6064        (
6065            "database",
6066            "Privileges described in this row will be granted only on objects created in `database` if non-null.",
6067        ),
6068        (
6069            "schema",
6070            "Privileges described in this row will be granted only on objects created in `schema` if non-null.",
6071        ),
6072        (
6073            "object_type",
6074            "Privileges described in this row will be granted only on objects of type `object_type`.",
6075        ),
6076        (
6077            "grantee",
6078            "Privileges described in this row will be granted to `grantee`.",
6079        ),
6080        ("privilege_type", "They type of privilege to be granted."),
6081    ]),
6082    sql: r#"SELECT object_owner, database, schema, object_type, grantee, privilege_type
6083FROM mz_internal.mz_show_default_privileges
6084WHERE
6085    CASE
6086        WHEN grantee = 'PUBLIC' THEN true
6087        ELSE pg_has_role(grantee, 'USAGE')
6088    END"#,
6089    access: vec![PUBLIC_SELECT],
6090    ontology: None,
6091});
6092
6093pub static MZ_SHOW_NETWORK_POLICIES: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
6094    name: "mz_show_network_policies",
6095    schema: MZ_INTERNAL_SCHEMA,
6096    oid: oid::VIEW_MZ_SHOW_NETWORK_POLICIES_OID,
6097    desc: RelationDesc::builder()
6098        .with_column("name", SqlScalarType::String.nullable(false))
6099        .with_column("rules", SqlScalarType::String.nullable(true))
6100        .with_column("comment", SqlScalarType::String.nullable(false))
6101        .finish(),
6102    column_comments: BTreeMap::new(),
6103    sql: "
6104WITH comments AS (
6105    SELECT id, comment
6106    FROM mz_internal.mz_comments
6107    WHERE object_type = 'network-policy' AND object_sub_id IS NULL
6108)
6109SELECT
6110    policy.name,
6111    pg_catalog.string_agg(rule.name,',' ORDER BY rule.name) as rules,
6112    COALESCE(comment, '') as comment
6113FROM
6114    mz_internal.mz_network_policies as policy
6115LEFT JOIN
6116    mz_internal.mz_network_policy_rules as rule ON policy.id = rule.policy_id
6117LEFT JOIN
6118    comments ON policy.id = comments.id
6119WHERE
6120    policy.id NOT LIKE 's%'
6121AND
6122    policy.id NOT LIKE 'g%'
6123GROUP BY policy.name, comments.comment;",
6124    access: vec![PUBLIC_SELECT],
6125    ontology: None,
6126});
6127
6128pub static MZ_CLUSTER_REPLICA_HISTORY: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
6129    name: "mz_cluster_replica_history",
6130    schema: MZ_INTERNAL_SCHEMA,
6131    oid: oid::VIEW_MZ_CLUSTER_REPLICA_HISTORY_OID,
6132    desc: RelationDesc::builder()
6133        .with_column("replica_id", SqlScalarType::String.nullable(true))
6134        .with_column("size", SqlScalarType::String.nullable(true))
6135        .with_column("cluster_id", SqlScalarType::String.nullable(true))
6136        .with_column("cluster_name", SqlScalarType::String.nullable(true))
6137        .with_column("replica_name", SqlScalarType::String.nullable(true))
6138        .with_column(
6139            "created_at",
6140            SqlScalarType::TimestampTz { precision: None }.nullable(false),
6141        )
6142        .with_column(
6143            "dropped_at",
6144            SqlScalarType::TimestampTz { precision: None }.nullable(true),
6145        )
6146        .with_column(
6147            "credits_per_hour",
6148            SqlScalarType::Numeric { max_scale: None }.nullable(true),
6149        )
6150        .finish(),
6151    column_comments: BTreeMap::from_iter([
6152        ("replica_id", "The ID of a cluster replica."),
6153        (
6154            "size",
6155            "The size of the cluster replica. Corresponds to `mz_cluster_replica_sizes.size`.",
6156        ),
6157        (
6158            "cluster_id",
6159            "The ID of the cluster associated with the replica.",
6160        ),
6161        (
6162            "cluster_name",
6163            "The name of the cluster associated with the replica.",
6164        ),
6165        ("replica_name", "The name of the replica."),
6166        ("created_at", "The time at which the replica was created."),
6167        (
6168            "dropped_at",
6169            "The time at which the replica was dropped, or `NULL` if it still exists.",
6170        ),
6171        (
6172            "credits_per_hour",
6173            "The number of compute credits consumed per hour. Corresponds to `mz_cluster_replica_sizes.credits_per_hour`.",
6174        ),
6175    ]),
6176    sql: r#"
6177        WITH
6178            creates AS
6179            (
6180                SELECT
6181                    details ->> 'logical_size' AS size,
6182                    details ->> 'replica_id' AS replica_id,
6183                    details ->> 'replica_name' AS replica_name,
6184                    details ->> 'cluster_name' AS cluster_name,
6185                    details ->> 'cluster_id' AS cluster_id,
6186                    occurred_at
6187                FROM mz_catalog.mz_audit_events
6188                WHERE
6189                    object_type = 'cluster-replica' AND event_type = 'create'
6190                        AND
6191                    details ->> 'replica_id' IS NOT NULL
6192                        AND
6193                    details ->> 'cluster_id' !~~ 's%'
6194            ),
6195            drops AS
6196            (
6197                SELECT details ->> 'replica_id' AS replica_id, occurred_at
6198                FROM mz_catalog.mz_audit_events
6199                WHERE object_type = 'cluster-replica' AND event_type = 'drop'
6200            )
6201        SELECT
6202            creates.replica_id,
6203            creates.size,
6204            creates.cluster_id,
6205            creates.cluster_name,
6206            creates.replica_name,
6207            creates.occurred_at AS created_at,
6208            drops.occurred_at AS dropped_at,
6209            mz_cluster_replica_sizes.credits_per_hour as credits_per_hour
6210        FROM
6211            creates
6212                LEFT JOIN drops ON creates.replica_id = drops.replica_id
6213                LEFT JOIN
6214                    mz_catalog.mz_cluster_replica_sizes
6215                    ON mz_cluster_replica_sizes.size = creates.size"#,
6216    access: vec![PUBLIC_SELECT],
6217    ontology: Some(Ontology {
6218        entity_name: "replica_history",
6219        description: "Historical record of replica creation/drops",
6220        links: &const { [] },
6221        column_semantic_types: &[],
6222    }),
6223});
6224
6225pub static MZ_CLUSTER_REPLICA_NAME_HISTORY: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
6226    name: "mz_cluster_replica_name_history",
6227    schema: MZ_INTERNAL_SCHEMA,
6228    oid: oid::VIEW_MZ_CLUSTER_REPLICA_NAME_HISTORY_OID,
6229    desc: RelationDesc::builder()
6230        .with_column(
6231            "occurred_at",
6232            SqlScalarType::TimestampTz { precision: None }.nullable(true),
6233        )
6234        .with_column("id", SqlScalarType::String.nullable(true))
6235        .with_column("previous_name", SqlScalarType::String.nullable(true))
6236        .with_column("new_name", SqlScalarType::String.nullable(true))
6237        .finish(),
6238    column_comments: BTreeMap::from_iter([
6239        (
6240            "occurred_at",
6241            "The time at which the cluster replica was created or renamed. `NULL` if it's a built in system cluster replica.",
6242        ),
6243        ("id", "The ID of the cluster replica."),
6244        (
6245            "previous_name",
6246            "The previous name of the cluster replica. `NULL` if there was no previous name.",
6247        ),
6248        ("new_name", "The new name of the cluster replica."),
6249    ]),
6250    sql: r#"WITH user_replica_alter_history AS (
6251  SELECT occurred_at,
6252    audit_events.details->>'replica_id' AS id,
6253    audit_events.details->>'old_name' AS previous_name,
6254    audit_events.details->>'new_name' AS new_name
6255  FROM mz_catalog.mz_audit_events AS audit_events
6256  WHERE object_type = 'cluster-replica'
6257    AND audit_events.event_type = 'alter'
6258    AND audit_events.details->>'replica_id' like 'u%'
6259),
6260user_replica_create_history AS (
6261  SELECT occurred_at,
6262    audit_events.details->>'replica_id' AS id,
6263    NULL AS previous_name,
6264    audit_events.details->>'replica_name' AS new_name
6265  FROM mz_catalog.mz_audit_events AS audit_events
6266  WHERE object_type = 'cluster-replica'
6267    AND audit_events.event_type = 'create'
6268    AND audit_events.details->>'replica_id' like 'u%'
6269),
6270-- Because built in system cluster replicas don't have audit events, we need to manually add them
6271system_replicas AS (
6272  -- We assume that the system cluster replicas were created at the beginning of time
6273  SELECT NULL::timestamptz AS occurred_at,
6274    id,
6275    NULL AS previous_name,
6276    name AS new_name
6277  FROM mz_catalog.mz_cluster_replicas
6278  WHERE id LIKE 's%'
6279)
6280SELECT *
6281FROM user_replica_alter_history
6282UNION ALL
6283SELECT *
6284FROM user_replica_create_history
6285UNION ALL
6286SELECT *
6287FROM system_replicas"#,
6288    access: vec![PUBLIC_SELECT],
6289    ontology: Some(Ontology {
6290        entity_name: "replica_name_history",
6291        description: "Historical replica names",
6292        links: &const { [] },
6293        column_semantic_types: &[("id", SemanticType::CatalogItemId)],
6294    }),
6295});
6296
6297pub static MZ_HYDRATION_STATUSES: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
6298    name: "mz_hydration_statuses",
6299    schema: MZ_INTERNAL_SCHEMA,
6300    oid: oid::VIEW_MZ_HYDRATION_STATUSES_OID,
6301    desc: RelationDesc::builder()
6302        .with_column("object_id", SqlScalarType::String.nullable(false))
6303        .with_column("replica_id", SqlScalarType::String.nullable(true))
6304        .with_column("hydrated", SqlScalarType::Bool.nullable(true))
6305        .finish(),
6306    column_comments: BTreeMap::from_iter([
6307        (
6308            "object_id",
6309            "The ID of a dataflow-powered object. Corresponds to `mz_catalog.mz_indexes.id`, `mz_catalog.mz_materialized_views.id`, `mz_internal.mz_subscriptions`, `mz_catalog.mz_sources.id`, or `mz_catalog.mz_sinks.id`.",
6310        ),
6311        ("replica_id", "The ID of a cluster replica."),
6312        ("hydrated", "Whether the object is hydrated on the replica."),
6313    ]),
6314    sql: r#"WITH
6315-- Joining against the linearizable catalog tables ensures that this view
6316-- always contains the set of installed objects, even when it depends
6317-- on introspection relations that may received delayed updates.
6318--
6319-- Note that this view only includes objects that are maintained by dataflows.
6320-- In particular, some source types (webhook, introspection, ...) are not and
6321-- are therefore omitted.
6322indexes AS (
6323    SELECT
6324        i.id AS object_id,
6325        h.replica_id,
6326        COALESCE(h.hydrated, false) AS hydrated
6327    FROM mz_catalog.mz_indexes i
6328    LEFT JOIN mz_internal.mz_compute_hydration_statuses h
6329        ON (h.object_id = i.id)
6330),
6331materialized_views AS (
6332    SELECT
6333        i.id AS object_id,
6334        h.replica_id,
6335        COALESCE(h.hydrated, false) AS hydrated
6336    FROM mz_catalog.mz_materialized_views i
6337    LEFT JOIN mz_internal.mz_compute_hydration_statuses h
6338        ON (h.object_id = i.id)
6339),
6340-- Hydration is a dataflow concept and not all sources are maintained by
6341-- dataflows, so we need to find the ones that are. Generally, sources that
6342-- have a cluster ID are maintained by a dataflow running on that cluster.
6343-- Webhook sources are an exception to this rule.
6344sources_with_clusters AS (
6345    SELECT id, cluster_id
6346    FROM mz_catalog.mz_sources
6347    WHERE cluster_id IS NOT NULL AND type != 'webhook'
6348),
6349sources AS (
6350    SELECT
6351        s.id AS object_id,
6352        ss.replica_id AS replica_id,
6353        ss.rehydration_latency IS NOT NULL AS hydrated
6354    FROM sources_with_clusters s
6355    LEFT JOIN mz_internal.mz_source_statistics ss USING (id)
6356),
6357-- We don't yet report sink hydration status (database-issues#8331), so we do a best effort attempt here and
6358-- define a sink as hydrated when it's both "running" and has a frontier greater than the minimum.
6359-- There is likely still a possibility of FPs.
6360sinks AS (
6361    SELECT
6362        s.id AS object_id,
6363        r.id AS replica_id,
6364        ss.status = 'running' AND COALESCE(f.write_frontier, 0) > 0 AS hydrated
6365    FROM mz_catalog.mz_sinks s
6366    LEFT JOIN mz_internal.mz_sink_statuses ss USING (id)
6367    JOIN mz_catalog.mz_cluster_replicas r
6368        ON (r.cluster_id = s.cluster_id)
6369    LEFT JOIN mz_catalog.mz_cluster_replica_frontiers f
6370        ON (f.object_id = s.id AND f.replica_id = r.id)
6371)
6372SELECT * FROM indexes
6373UNION ALL
6374SELECT * FROM materialized_views
6375UNION ALL
6376SELECT * FROM sources
6377UNION ALL
6378SELECT * FROM sinks"#,
6379    access: vec![PUBLIC_SELECT],
6380    ontology: Some(Ontology {
6381        entity_name: "hydration_status",
6382        description: "Overall hydration status per object",
6383        links: &const {
6384            [
6385                OntologyLink {
6386                    name: "hydration_of",
6387                    target: "object",
6388                    properties: LinkProperties::fk_typed(
6389                        "object_id",
6390                        "id",
6391                        Cardinality::OneToOne,
6392                        mz_repr::SemanticType::CatalogItemId,
6393                    ),
6394                },
6395                OntologyLink {
6396                    name: "hydration_on_replica",
6397                    target: "replica",
6398                    properties: LinkProperties::fk("replica_id", "id", Cardinality::ManyToOne),
6399                },
6400            ]
6401        },
6402        column_semantic_types: &const {
6403            [
6404                ("object_id", SemanticType::CatalogItemId),
6405                ("replica_id", SemanticType::ReplicaId),
6406            ]
6407        },
6408    }),
6409});
6410
6411pub const MZ_HYDRATION_STATUSES_IND: BuiltinIndex = BuiltinIndex {
6412    name: "mz_hydration_statuses_ind",
6413    schema: MZ_INTERNAL_SCHEMA,
6414    oid: oid::INDEX_MZ_HYDRATION_STATUSES_IND_OID,
6415    sql: "IN CLUSTER mz_catalog_server
6416ON mz_internal.mz_hydration_statuses (object_id, replica_id)",
6417    is_retained_metrics_object: false,
6418};
6419
6420pub static MZ_MATERIALIZATION_DEPENDENCIES: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
6421    name: "mz_materialization_dependencies",
6422    schema: MZ_INTERNAL_SCHEMA,
6423    oid: oid::VIEW_MZ_MATERIALIZATION_DEPENDENCIES_OID,
6424    desc: RelationDesc::builder()
6425        .with_column("object_id", SqlScalarType::String.nullable(false))
6426        .with_column("dependency_id", SqlScalarType::String.nullable(false))
6427        .finish(),
6428    column_comments: BTreeMap::from_iter([
6429        (
6430            "object_id",
6431            "The ID of a materialization. Corresponds to `mz_catalog.mz_indexes.id`, `mz_catalog.mz_materialized_views.id`, or `mz_catalog.mz_sinks.id`.",
6432        ),
6433        (
6434            "dependency_id",
6435            "The ID of a dataflow dependency. Corresponds to `mz_catalog.mz_indexes.id`, `mz_catalog.mz_materialized_views.id`, `mz_catalog.mz_sources.id`, or `mz_catalog.mz_tables.id`.",
6436        ),
6437    ]),
6438    sql: "
6439SELECT object_id, dependency_id
6440FROM mz_internal.mz_compute_dependencies
6441UNION ALL
6442SELECT s.id, d.referenced_object_id AS dependency_id
6443FROM mz_internal.mz_object_dependencies d
6444JOIN mz_catalog.mz_sinks s ON (s.id = d.object_id)
6445JOIN mz_catalog.mz_relations r ON (r.id = d.referenced_object_id)",
6446    access: vec![PUBLIC_SELECT],
6447    ontology: Some(Ontology {
6448        entity_name: "materialization_dep",
6449        description: "Dependencies between materializations",
6450        links: &const {
6451            [
6452                OntologyLink {
6453                    name: "depends_on",
6454                    target: "object",
6455                    properties: LinkProperties::DependsOn {
6456                        source_column: "object_id",
6457                        target_column: "id",
6458                        source_id_type: Some(mz_repr::SemanticType::CatalogItemId),
6459                        requires_mapping: None,
6460                    },
6461                },
6462                OntologyLink {
6463                    name: "dependency_is",
6464                    target: "object",
6465                    properties: LinkProperties::fk("dependency_id", "id", Cardinality::ManyToOne),
6466                },
6467            ]
6468        },
6469        column_semantic_types: &const {
6470            [
6471                ("object_id", SemanticType::CatalogItemId),
6472                ("dependency_id", SemanticType::CatalogItemId),
6473            ]
6474        },
6475    }),
6476});
6477
6478pub static MZ_MATERIALIZATION_LAG: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
6479    name: "mz_materialization_lag",
6480    schema: MZ_INTERNAL_SCHEMA,
6481    oid: oid::VIEW_MZ_MATERIALIZATION_LAG_OID,
6482    desc: RelationDesc::builder()
6483        .with_column("object_id", SqlScalarType::String.nullable(false))
6484        .with_column("local_lag", SqlScalarType::Interval.nullable(true))
6485        .with_column("global_lag", SqlScalarType::Interval.nullable(true))
6486        .with_column(
6487            "slowest_local_input_id",
6488            SqlScalarType::String.nullable(false),
6489        )
6490        .with_column(
6491            "slowest_global_input_id",
6492            SqlScalarType::String.nullable(false),
6493        )
6494        .finish(),
6495    column_comments: BTreeMap::from_iter([
6496        (
6497            "object_id",
6498            "The ID of the materialized view, index, or sink.",
6499        ),
6500        (
6501            "local_lag",
6502            "The amount of time the materialization lags behind its direct inputs.",
6503        ),
6504        (
6505            "global_lag",
6506            "The amount of time the materialization lags behind its root inputs (sources and tables).",
6507        ),
6508        (
6509            "slowest_local_input_id",
6510            "The ID of the slowest direct input.",
6511        ),
6512        (
6513            "slowest_global_input_id",
6514            "The ID of the slowest root input.",
6515        ),
6516    ]),
6517    sql: "
6518WITH MUTUALLY RECURSIVE
6519    -- IDs of objects for which we want to know the lag.
6520    materializations (id text) AS (
6521        SELECT id FROM mz_catalog.mz_indexes
6522        UNION ALL
6523        SELECT id FROM mz_catalog.mz_materialized_views
6524        UNION ALL
6525        SELECT id FROM mz_catalog.mz_sinks
6526    ),
6527    -- Direct dependencies of materializations.
6528    direct_dependencies (id text, dep_id text) AS (
6529        SELECT m.id, d.dependency_id
6530        FROM materializations m
6531        JOIN mz_internal.mz_materialization_dependencies d ON (m.id = d.object_id)
6532    ),
6533    -- All transitive dependencies of materializations.
6534    transitive_dependencies (id text, dep_id text) AS (
6535        SELECT id, dep_id FROM direct_dependencies
6536        UNION
6537        SELECT td.id, dd.dep_id
6538        FROM transitive_dependencies td
6539        JOIN direct_dependencies dd ON (dd.id = td.dep_id)
6540    ),
6541    -- Root dependencies of materializations (sources and tables).
6542    root_dependencies (id text, dep_id text) AS (
6543        SELECT *
6544        FROM transitive_dependencies td
6545        WHERE NOT EXISTS (
6546            SELECT 1
6547            FROM direct_dependencies dd
6548            WHERE dd.id = td.dep_id
6549        )
6550    ),
6551    -- Write progress times of materializations.
6552    materialization_times (id text, time timestamptz) AS (
6553        SELECT m.id, to_timestamp(f.write_frontier::text::double / 1000)
6554        FROM materializations m
6555        JOIN mz_internal.mz_frontiers f ON (m.id = f.object_id)
6556    ),
6557    -- Write progress times of direct dependencies of materializations.
6558    input_times (id text, slowest_dep text, time timestamptz) AS (
6559        SELECT DISTINCT ON (d.id)
6560            d.id,
6561            d.dep_id,
6562            to_timestamp(f.write_frontier::text::double / 1000)
6563        FROM direct_dependencies d
6564        JOIN mz_internal.mz_frontiers f ON (d.dep_id = f.object_id)
6565        ORDER BY d.id, f.write_frontier ASC
6566    ),
6567    -- Write progress times of root dependencies of materializations.
6568    root_times (id text, slowest_dep text, time timestamptz) AS (
6569        SELECT DISTINCT ON (d.id)
6570            d.id,
6571            d.dep_id,
6572            to_timestamp(f.write_frontier::text::double / 1000)
6573        FROM root_dependencies d
6574        JOIN mz_internal.mz_frontiers f ON (d.dep_id = f.object_id)
6575        ORDER BY d.id, f.write_frontier ASC
6576    )
6577SELECT
6578    id AS object_id,
6579    -- Ensure that lag values are always NULL for materializations that have reached the empty
6580    -- frontier, as those have processed all their input data.
6581    -- Also make sure that lag values are never negative, even when input frontiers are before
6582    -- output frontiers (as can happen during hydration).
6583    CASE
6584        WHEN m.time IS NULL THEN INTERVAL '0'
6585        WHEN i.time IS NULL THEN NULL
6586        ELSE greatest(i.time - m.time, INTERVAL '0')
6587    END AS local_lag,
6588    CASE
6589        WHEN m.time IS NULL THEN INTERVAL '0'
6590        WHEN r.time IS NULL THEN NULL
6591        ELSE greatest(r.time - m.time, INTERVAL '0')
6592    END AS global_lag,
6593    i.slowest_dep AS slowest_local_input_id,
6594    r.slowest_dep AS slowest_global_input_id
6595FROM materialization_times m
6596JOIN input_times i USING (id)
6597JOIN root_times r USING (id)",
6598    access: vec![PUBLIC_SELECT],
6599    ontology: Some(Ontology {
6600        entity_name: "materialization_lag",
6601        description: "Lag between a materialization and its inputs",
6602        links: &const {
6603            [
6604                OntologyLink {
6605                    name: "measures_materialization_lag",
6606                    target: "object",
6607                    properties: LinkProperties::measures("object_id", "id", "materialization_lag"),
6608                },
6609                OntologyLink {
6610                    name: "slowest_local_input",
6611                    target: "object",
6612                    properties: LinkProperties::fk(
6613                        "slowest_local_input_id",
6614                        "id",
6615                        Cardinality::ManyToOne,
6616                    ),
6617                },
6618                OntologyLink {
6619                    name: "slowest_global_input",
6620                    target: "object",
6621                    properties: LinkProperties::fk(
6622                        "slowest_global_input_id",
6623                        "id",
6624                        Cardinality::ManyToOne,
6625                    ),
6626                },
6627            ]
6628        },
6629        column_semantic_types: &const {
6630            [
6631                ("object_id", SemanticType::CatalogItemId),
6632                ("slowest_local_input_id", SemanticType::CatalogItemId),
6633                ("slowest_global_input_id", SemanticType::CatalogItemId),
6634            ]
6635        },
6636    }),
6637});
6638/**
6639 * This view is used to display the cluster utilization over 14 days bucketed by 8 hours.
6640 * It's specifically for the Console's environment overview page to speed up load times.
6641 * This query should be kept in sync with MaterializeInc/console/src/api/materialize/cluster/replicaUtilizationHistory.ts
6642 */
6643pub static MZ_CONSOLE_CLUSTER_UTILIZATION_OVERVIEW: LazyLock<BuiltinView> = LazyLock::new(|| {
6644    BuiltinView {
6645        name: "mz_console_cluster_utilization_overview",
6646        schema: MZ_INTERNAL_SCHEMA,
6647        oid: oid::VIEW_MZ_CONSOLE_CLUSTER_UTILIZATION_OVERVIEW_OID,
6648        desc: RelationDesc::builder()
6649            .with_column(
6650                "bucket_start",
6651                SqlScalarType::TimestampTz { precision: None }.nullable(false),
6652            )
6653            .with_column("replica_id", SqlScalarType::String.nullable(false))
6654            .with_column("memory_percent", SqlScalarType::Float64.nullable(true))
6655            .with_column(
6656                "max_memory_at",
6657                SqlScalarType::TimestampTz { precision: None }.nullable(false),
6658            )
6659            .with_column("disk_percent", SqlScalarType::Float64.nullable(true))
6660            .with_column(
6661                "max_disk_at",
6662                SqlScalarType::TimestampTz { precision: None }.nullable(false),
6663            )
6664            .with_column(
6665                "memory_and_disk_percent",
6666                SqlScalarType::Float64.nullable(true),
6667            )
6668            .with_column(
6669                "max_memory_and_disk_memory_percent",
6670                SqlScalarType::Float64.nullable(true),
6671            )
6672            .with_column(
6673                "max_memory_and_disk_disk_percent",
6674                SqlScalarType::Float64.nullable(true),
6675            )
6676            .with_column(
6677                "max_memory_and_disk_at",
6678                SqlScalarType::TimestampTz { precision: None }.nullable(false),
6679            )
6680            .with_column("heap_percent", SqlScalarType::Float64.nullable(true))
6681            .with_column(
6682                "max_heap_at",
6683                SqlScalarType::TimestampTz { precision: None }.nullable(false),
6684            )
6685            .with_column("max_cpu_percent", SqlScalarType::Float64.nullable(true))
6686            .with_column(
6687                "max_cpu_at",
6688                SqlScalarType::TimestampTz { precision: None }.nullable(false),
6689            )
6690            .with_column("offline_events", SqlScalarType::Jsonb.nullable(true))
6691            .with_column(
6692                "bucket_end",
6693                SqlScalarType::TimestampTz { precision: None }.nullable(false),
6694            )
6695            .with_column("name", SqlScalarType::String.nullable(true))
6696            .with_column("cluster_id", SqlScalarType::String.nullable(true))
6697            .with_column("size", SqlScalarType::String.nullable(true))
6698            .finish(),
6699        column_comments: BTreeMap::new(),
6700        sql: r#"WITH replica_history AS (
6701  SELECT replica_id,
6702    size,
6703    cluster_id
6704  FROM mz_internal.mz_cluster_replica_history
6705  UNION
6706  -- We need to union the current set of cluster replicas since mz_cluster_replica_history doesn't include system clusters
6707  SELECT id AS replica_id,
6708    size,
6709    cluster_id
6710  FROM mz_catalog.mz_cluster_replicas
6711),
6712replica_metrics_history AS (
6713  SELECT
6714    m.occurred_at,
6715    m.replica_id,
6716    r.size,
6717    (SUM(m.cpu_nano_cores::float8) / NULLIF(s.cpu_nano_cores, 0)) / NULLIF(s.processes, 0) AS cpu_percent,
6718    (SUM(m.memory_bytes::float8) / NULLIF(s.memory_bytes, 0)) / NULLIF(s.processes, 0) AS memory_percent,
6719    (SUM(m.disk_bytes::float8) / NULLIF(s.disk_bytes, 0)) / NULLIF(s.processes, 0) AS disk_percent,
6720    (SUM(m.heap_bytes::float8) / NULLIF(m.heap_limit, 0)) / NULLIF(s.processes, 0) AS heap_percent,
6721    SUM(m.disk_bytes::float8) AS disk_bytes,
6722    SUM(m.memory_bytes::float8) AS memory_bytes,
6723    s.disk_bytes::numeric * s.processes AS total_disk_bytes,
6724    s.memory_bytes::numeric * s.processes AS total_memory_bytes
6725  FROM
6726    replica_history AS r
6727    INNER JOIN mz_catalog.mz_cluster_replica_sizes AS s ON r.size = s.size
6728    INNER JOIN mz_internal.mz_cluster_replica_metrics_history AS m ON m.replica_id = r.replica_id
6729  GROUP BY
6730    m.occurred_at,
6731    m.replica_id,
6732    r.size,
6733    s.cpu_nano_cores,
6734    s.memory_bytes,
6735    s.disk_bytes,
6736    m.heap_limit,
6737    s.processes
6738),
6739replica_utilization_history_binned AS (
6740  SELECT m.occurred_at,
6741    m.replica_id,
6742    m.cpu_percent,
6743    m.memory_percent,
6744    m.memory_bytes,
6745    m.disk_percent,
6746    m.disk_bytes,
6747    m.heap_percent,
6748    m.total_disk_bytes,
6749    m.total_memory_bytes,
6750    m.size,
6751    date_bin(
6752      '8 HOURS',
6753      occurred_at,
6754      '1970-01-01'::timestamp
6755    ) AS bucket_start
6756  FROM replica_history AS r
6757    JOIN replica_metrics_history AS m ON m.replica_id = r.replica_id
6758  WHERE mz_now() <= date_bin(
6759      '8 HOURS',
6760      occurred_at,
6761      '1970-01-01'::timestamp
6762    ) + INTERVAL '14 DAYS'
6763),
6764-- For each (replica, bucket), take the (replica, bucket) with the highest memory
6765max_memory AS (
6766  SELECT DISTINCT ON (bucket_start, replica_id) bucket_start,
6767    replica_id,
6768    memory_percent,
6769    occurred_at
6770  FROM replica_utilization_history_binned
6771  OPTIONS (DISTINCT ON INPUT GROUP SIZE = 480)
6772  ORDER BY bucket_start,
6773    replica_id,
6774    COALESCE(memory_bytes, 0) DESC
6775),
6776max_disk AS (
6777  SELECT DISTINCT ON (bucket_start, replica_id) bucket_start,
6778    replica_id,
6779    disk_percent,
6780    occurred_at
6781  FROM replica_utilization_history_binned
6782  OPTIONS (DISTINCT ON INPUT GROUP SIZE = 480)
6783  ORDER BY bucket_start,
6784    replica_id,
6785    COALESCE(disk_bytes, 0) DESC
6786),
6787max_cpu AS (
6788  SELECT DISTINCT ON (bucket_start, replica_id) bucket_start,
6789    replica_id,
6790    cpu_percent,
6791    occurred_at
6792  FROM replica_utilization_history_binned
6793  OPTIONS (DISTINCT ON INPUT GROUP SIZE = 480)
6794  ORDER BY bucket_start,
6795    replica_id,
6796    COALESCE(cpu_percent, 0) DESC
6797),
6798/*
6799 This is different
6800 from adding max_memory
6801 and max_disk per bucket because both
6802 values may not occur at the same time if the bucket interval is large.
6803 */
6804max_memory_and_disk AS (
6805  SELECT DISTINCT ON (bucket_start, replica_id) bucket_start,
6806    replica_id,
6807    memory_percent,
6808    disk_percent,
6809    memory_and_disk_percent,
6810    occurred_at
6811  FROM (
6812      SELECT *,
6813        CASE
6814          WHEN disk_bytes IS NULL
6815          AND memory_bytes IS NULL THEN NULL
6816          ELSE (COALESCE(disk_bytes, 0) + COALESCE(memory_bytes, 0))
6817               / (total_disk_bytes::numeric + total_memory_bytes::numeric)
6818        END AS memory_and_disk_percent
6819      FROM replica_utilization_history_binned
6820    ) AS max_memory_and_disk_inner
6821  OPTIONS (DISTINCT ON INPUT GROUP SIZE = 480)
6822  ORDER BY bucket_start,
6823    replica_id,
6824    COALESCE(memory_and_disk_percent, 0) DESC
6825),
6826max_heap AS (
6827  SELECT DISTINCT ON (bucket_start, replica_id)
6828    bucket_start,
6829    replica_id,
6830    heap_percent,
6831    occurred_at
6832  FROM replica_utilization_history_binned
6833  OPTIONS (DISTINCT ON INPUT GROUP SIZE = 480)
6834  ORDER BY bucket_start, replica_id, COALESCE(heap_percent, 0) DESC
6835),
6836-- For each (replica, bucket), get its offline events at that time
6837replica_offline_event_history AS (
6838  SELECT date_bin(
6839      '8 HOURS',
6840      occurred_at,
6841      '1970-01-01'::timestamp
6842    ) AS bucket_start,
6843    replica_id,
6844    jsonb_agg(
6845      jsonb_build_object(
6846        'replicaId',
6847        rsh.replica_id,
6848        'occurredAt',
6849        rsh.occurred_at,
6850        'status',
6851        rsh.status,
6852        'reason',
6853        rsh.reason
6854      )
6855    ) AS offline_events
6856  FROM mz_internal.mz_cluster_replica_status_history AS rsh -- We assume the statuses for process 0 are the same as all processes
6857  WHERE process_id = '0'
6858    AND status = 'offline'
6859    AND mz_now() <= date_bin(
6860      '8 HOURS',
6861      occurred_at,
6862      '1970-01-01'::timestamp
6863    ) + INTERVAL '14 DAYS'
6864  GROUP BY bucket_start,
6865    replica_id
6866)
6867SELECT
6868  bucket_start,
6869  replica_id,
6870  max_memory.memory_percent,
6871  max_memory.occurred_at as max_memory_at,
6872  max_disk.disk_percent,
6873  max_disk.occurred_at as max_disk_at,
6874  max_memory_and_disk.memory_and_disk_percent as memory_and_disk_percent,
6875  max_memory_and_disk.memory_percent as max_memory_and_disk_memory_percent,
6876  max_memory_and_disk.disk_percent as max_memory_and_disk_disk_percent,
6877  max_memory_and_disk.occurred_at as max_memory_and_disk_at,
6878  max_heap.heap_percent,
6879  max_heap.occurred_at as max_heap_at,
6880  max_cpu.cpu_percent as max_cpu_percent,
6881  max_cpu.occurred_at as max_cpu_at,
6882  replica_offline_event_history.offline_events,
6883  bucket_start + INTERVAL '8 HOURS' as bucket_end,
6884  replica_name_history.new_name AS name,
6885  replica_history.cluster_id,
6886  replica_history.size
6887FROM max_memory
6888JOIN max_disk USING (bucket_start, replica_id)
6889JOIN max_cpu USING (bucket_start, replica_id)
6890JOIN max_memory_and_disk USING (bucket_start, replica_id)
6891JOIN max_heap USING (bucket_start, replica_id)
6892JOIN replica_history USING (replica_id)
6893CROSS JOIN LATERAL (
6894  SELECT new_name
6895  FROM mz_internal.mz_cluster_replica_name_history as replica_name_history
6896  WHERE replica_id = replica_name_history.id -- We treat NULLs as the beginning of time
6897    AND bucket_start + INTERVAL '8 HOURS' >= COALESCE(
6898      replica_name_history.occurred_at,
6899      '1970-01-01'::timestamp
6900    )
6901  ORDER BY replica_name_history.occurred_at DESC
6902  LIMIT '1'
6903) AS replica_name_history
6904LEFT JOIN replica_offline_event_history USING (bucket_start, replica_id)"#,
6905        access: vec![PUBLIC_SELECT],
6906        ontology: None,
6907    }
6908});
6909/**
6910 * Traces the blue/green deployment lineage in the audit log to determine all cluster
6911 * IDs that are logically the same cluster.
6912 * cluster_id: The ID of a cluster.
6913 * current_deployment_cluster_id: The cluster ID of the last cluster in
6914 *   cluster_id's blue/green lineage.
6915 * cluster_name: The name of the cluster.
6916 * The approach taken is as follows. First, find all extant clusters and add them
6917 * to the result set. Per cluster, we do the following:
6918 * 1. Find the most recent create or rename event. This moment represents when the
6919 *    cluster took on its final logical identity.
6920 * 2. Look for a cluster that had the same name (or the same name with `_dbt_deploy`
6921 *    appended) that was dropped within one minute of that moment. That cluster is
6922 *    almost certainly the logical predecessor of the current cluster. Add the cluster
6923 *    to the result set.
6924 * 3. Repeat the procedure until a cluster with no logical predecessor is discovered.
6925 * Limiting the search for a dropped cluster to a window of one minute is a heuristic,
6926 * but one that's likely to be pretty good one. If a name is reused after more
6927 * than one minute, that's a good sign that it wasn't an automatic blue/green
6928 * process, but someone turning on a new use case that happens to have the same
6929 * name as a previous but logically distinct use case.
6930 */
6931pub static MZ_CLUSTER_DEPLOYMENT_LINEAGE: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
6932    name: "mz_cluster_deployment_lineage",
6933    schema: MZ_INTERNAL_SCHEMA,
6934    oid: oid::VIEW_MZ_CLUSTER_DEPLOYMENT_LINEAGE_OID,
6935    desc: RelationDesc::builder()
6936        .with_column("cluster_id", SqlScalarType::String.nullable(true))
6937        .with_column(
6938            "current_deployment_cluster_id",
6939            SqlScalarType::String.nullable(false),
6940        )
6941        .with_column("cluster_name", SqlScalarType::String.nullable(false))
6942        .with_key(vec![0, 1, 2])
6943        .finish(),
6944    column_comments: BTreeMap::from_iter([
6945        (
6946            "cluster_id",
6947            "The ID of the cluster. Corresponds to `mz_clusters.id` (though the cluster may no longer exist).",
6948        ),
6949        (
6950            "current_deployment_cluster_id",
6951            "The cluster ID of the last cluster in `cluster_id`'s blue/green lineage (the cluster is guaranteed to exist).",
6952        ),
6953        ("cluster_name", "The name of the cluster"),
6954    ]),
6955    sql: r#"WITH MUTUALLY RECURSIVE cluster_events (
6956  cluster_id text,
6957  cluster_name text,
6958  event_type text,
6959  occurred_at timestamptz
6960) AS (
6961  SELECT coalesce(details->>'id', details->>'cluster_id') AS cluster_id,
6962    coalesce(details->>'name', details->>'new_name') AS cluster_name,
6963    event_type,
6964    occurred_at
6965  FROM mz_audit_events
6966  WHERE (
6967      event_type IN ('create', 'drop')
6968      OR (
6969        event_type = 'alter'
6970        AND details ? 'new_name'
6971      )
6972    )
6973    AND object_type = 'cluster'
6974    AND mz_now() < occurred_at + INTERVAL '30 days'
6975),
6976mz_cluster_deployment_lineage (
6977  cluster_id text,
6978  current_deployment_cluster_id text,
6979  cluster_name text
6980) AS (
6981  SELECT c.id,
6982    c.id,
6983    c.name
6984  FROM mz_clusters c
6985  WHERE c.id LIKE 'u%'
6986  UNION
6987  SELECT *
6988  FROM dropped_clusters
6989),
6990-- Closest create or rename event based on the current clusters in the result set
6991most_recent_create_or_rename (
6992  cluster_id text,
6993  current_deployment_cluster_id text,
6994  cluster_name text,
6995  occurred_at timestamptz
6996) AS (
6997  SELECT DISTINCT ON (e.cluster_id) e.cluster_id,
6998    c.current_deployment_cluster_id,
6999    e.cluster_name,
7000    e.occurred_at
7001  FROM mz_cluster_deployment_lineage c
7002    JOIN cluster_events e ON c.cluster_id = e.cluster_id
7003    AND c.cluster_name = e.cluster_name
7004  WHERE e.event_type <> 'drop'
7005  ORDER BY e.cluster_id,
7006    e.occurred_at DESC
7007),
7008-- Clusters that were dropped most recently within 1 minute of most_recent_create_or_rename
7009dropped_clusters (
7010  cluster_id text,
7011  current_deployment_cluster_id text,
7012  cluster_name text
7013) AS (
7014  SELECT DISTINCT ON (cr.cluster_id) e.cluster_id,
7015    cr.current_deployment_cluster_id,
7016    cr.cluster_name
7017  FROM most_recent_create_or_rename cr
7018    JOIN cluster_events e ON e.occurred_at BETWEEN cr.occurred_at - interval '1 minute'
7019    AND cr.occurred_at + interval '1 minute'
7020    AND (
7021      e.cluster_name = cr.cluster_name
7022      OR e.cluster_name = cr.cluster_name || '_dbt_deploy'
7023    )
7024  WHERE e.event_type = 'drop'
7025  ORDER BY cr.cluster_id,
7026    abs(
7027      extract(
7028        epoch
7029        FROM cr.occurred_at - e.occurred_at
7030      )
7031    )
7032)
7033SELECT *
7034FROM mz_cluster_deployment_lineage"#,
7035    access: vec![PUBLIC_SELECT],
7036    ontology: Some(Ontology {
7037        entity_name: "cluster_deployment",
7038        description: "Cluster deployment lineage information",
7039        links: &const {
7040            [
7041                OntologyLink {
7042                    name: "deployment_of",
7043                    target: "cluster",
7044                    properties: LinkProperties::fk("cluster_id", "id", Cardinality::ManyToOne),
7045                },
7046                OntologyLink {
7047                    name: "current_deployment",
7048                    target: "cluster",
7049                    properties: LinkProperties::fk(
7050                        "current_deployment_cluster_id",
7051                        "id",
7052                        Cardinality::ManyToOne,
7053                    ),
7054                },
7055            ]
7056        },
7057        column_semantic_types: &[],
7058    }),
7059});
7060
7061pub const MZ_SHOW_DATABASES_IND: BuiltinIndex = BuiltinIndex {
7062    name: "mz_show_databases_ind",
7063    schema: MZ_INTERNAL_SCHEMA,
7064    oid: oid::INDEX_MZ_SHOW_DATABASES_IND_OID,
7065    sql: "IN CLUSTER mz_catalog_server
7066ON mz_internal.mz_show_databases (name)",
7067    is_retained_metrics_object: false,
7068};
7069
7070pub const MZ_SHOW_SCHEMAS_IND: BuiltinIndex = BuiltinIndex {
7071    name: "mz_show_schemas_ind",
7072    schema: MZ_INTERNAL_SCHEMA,
7073    oid: oid::INDEX_MZ_SHOW_SCHEMAS_IND_OID,
7074    sql: "IN CLUSTER mz_catalog_server
7075ON mz_internal.mz_show_schemas (database_id)",
7076    is_retained_metrics_object: false,
7077};
7078
7079pub const MZ_SHOW_CONNECTIONS_IND: BuiltinIndex = BuiltinIndex {
7080    name: "mz_show_connections_ind",
7081    schema: MZ_INTERNAL_SCHEMA,
7082    oid: oid::INDEX_MZ_SHOW_CONNECTIONS_IND_OID,
7083    sql: "IN CLUSTER mz_catalog_server
7084ON mz_internal.mz_show_connections (schema_id)",
7085    is_retained_metrics_object: false,
7086};
7087
7088pub const MZ_SHOW_TABLES_IND: BuiltinIndex = BuiltinIndex {
7089    name: "mz_show_tables_ind",
7090    schema: MZ_INTERNAL_SCHEMA,
7091    oid: oid::INDEX_MZ_SHOW_TABLES_IND_OID,
7092    sql: "IN CLUSTER mz_catalog_server
7093ON mz_internal.mz_show_tables (schema_id)",
7094    is_retained_metrics_object: false,
7095};
7096
7097pub const MZ_SHOW_SOURCES_IND: BuiltinIndex = BuiltinIndex {
7098    name: "mz_show_sources_ind",
7099    schema: MZ_INTERNAL_SCHEMA,
7100    oid: oid::INDEX_MZ_SHOW_SOURCES_IND_OID,
7101    sql: "IN CLUSTER mz_catalog_server
7102ON mz_internal.mz_show_sources (schema_id)",
7103    is_retained_metrics_object: false,
7104};
7105
7106pub const MZ_SHOW_VIEWS_IND: BuiltinIndex = BuiltinIndex {
7107    name: "mz_show_views_ind",
7108    schema: MZ_INTERNAL_SCHEMA,
7109    oid: oid::INDEX_MZ_SHOW_VIEWS_IND_OID,
7110    sql: "IN CLUSTER mz_catalog_server
7111ON mz_internal.mz_show_views (schema_id)",
7112    is_retained_metrics_object: false,
7113};
7114
7115pub const MZ_SHOW_MATERIALIZED_VIEWS_IND: BuiltinIndex = BuiltinIndex {
7116    name: "mz_show_materialized_views_ind",
7117    schema: MZ_INTERNAL_SCHEMA,
7118    oid: oid::INDEX_MZ_SHOW_MATERIALIZED_VIEWS_IND_OID,
7119    sql: "IN CLUSTER mz_catalog_server
7120ON mz_internal.mz_show_materialized_views (schema_id)",
7121    is_retained_metrics_object: false,
7122};
7123
7124pub const MZ_SHOW_SINKS_IND: BuiltinIndex = BuiltinIndex {
7125    name: "mz_show_sinks_ind",
7126    schema: MZ_INTERNAL_SCHEMA,
7127    oid: oid::INDEX_MZ_SHOW_SINKS_IND_OID,
7128    sql: "IN CLUSTER mz_catalog_server
7129ON mz_internal.mz_show_sinks (schema_id)",
7130    is_retained_metrics_object: false,
7131};
7132
7133pub const MZ_SHOW_TYPES_IND: BuiltinIndex = BuiltinIndex {
7134    name: "mz_show_types_ind",
7135    schema: MZ_INTERNAL_SCHEMA,
7136    oid: oid::INDEX_MZ_SHOW_TYPES_IND_OID,
7137    sql: "IN CLUSTER mz_catalog_server
7138ON mz_internal.mz_show_types (schema_id)",
7139    is_retained_metrics_object: false,
7140};
7141
7142pub const MZ_SHOW_ROLES_IND: BuiltinIndex = BuiltinIndex {
7143    name: "mz_show_roles_ind",
7144    schema: MZ_INTERNAL_SCHEMA,
7145    oid: oid::INDEX_MZ_SHOW_ROLES_IND_OID,
7146    sql: "IN CLUSTER mz_catalog_server
7147ON mz_internal.mz_show_roles (name)",
7148    is_retained_metrics_object: false,
7149};
7150
7151pub const MZ_SHOW_ALL_OBJECTS_IND: BuiltinIndex = BuiltinIndex {
7152    name: "mz_show_all_objects_ind",
7153    schema: MZ_INTERNAL_SCHEMA,
7154    oid: oid::INDEX_MZ_SHOW_ALL_OBJECTS_IND_OID,
7155    sql: "IN CLUSTER mz_catalog_server
7156ON mz_internal.mz_show_all_objects (schema_id)",
7157    is_retained_metrics_object: false,
7158};
7159
7160pub const MZ_SHOW_INDEXES_IND: BuiltinIndex = BuiltinIndex {
7161    name: "mz_show_indexes_ind",
7162    schema: MZ_INTERNAL_SCHEMA,
7163    oid: oid::INDEX_MZ_SHOW_INDEXES_IND_OID,
7164    sql: "IN CLUSTER mz_catalog_server
7165ON mz_internal.mz_show_indexes (schema_id)",
7166    is_retained_metrics_object: false,
7167};
7168
7169pub const MZ_SHOW_COLUMNS_IND: BuiltinIndex = BuiltinIndex {
7170    name: "mz_show_columns_ind",
7171    schema: MZ_INTERNAL_SCHEMA,
7172    oid: oid::INDEX_MZ_SHOW_COLUMNS_IND_OID,
7173    sql: "IN CLUSTER mz_catalog_server
7174ON mz_internal.mz_show_columns (id)",
7175    is_retained_metrics_object: false,
7176};
7177
7178pub const MZ_SHOW_CLUSTERS_IND: BuiltinIndex = BuiltinIndex {
7179    name: "mz_show_clusters_ind",
7180    schema: MZ_INTERNAL_SCHEMA,
7181    oid: oid::INDEX_MZ_SHOW_CLUSTERS_IND_OID,
7182    sql: "IN CLUSTER mz_catalog_server
7183ON mz_internal.mz_show_clusters (name)",
7184    is_retained_metrics_object: false,
7185};
7186
7187pub const MZ_SHOW_CLUSTER_REPLICAS_IND: BuiltinIndex = BuiltinIndex {
7188    name: "mz_show_cluster_replicas_ind",
7189    schema: MZ_INTERNAL_SCHEMA,
7190    oid: oid::INDEX_MZ_SHOW_CLUSTER_REPLICAS_IND_OID,
7191    sql: "IN CLUSTER mz_catalog_server
7192ON mz_internal.mz_show_cluster_replicas (cluster)",
7193    is_retained_metrics_object: false,
7194};
7195
7196pub const MZ_SHOW_SECRETS_IND: BuiltinIndex = BuiltinIndex {
7197    name: "mz_show_secrets_ind",
7198    schema: MZ_INTERNAL_SCHEMA,
7199    oid: oid::INDEX_MZ_SHOW_SECRETS_IND_OID,
7200    sql: "IN CLUSTER mz_catalog_server
7201ON mz_internal.mz_show_secrets (schema_id)",
7202    is_retained_metrics_object: false,
7203};
7204
7205pub const MZ_CONSOLE_CLUSTER_UTILIZATION_OVERVIEW_IND: BuiltinIndex = BuiltinIndex {
7206    name: "mz_console_cluster_utilization_overview_ind",
7207    schema: MZ_INTERNAL_SCHEMA,
7208    oid: oid::INDEX_MZ_CONSOLE_CLUSTER_UTILIZATION_OVERVIEW_IND_OID,
7209    sql: "IN CLUSTER mz_catalog_server
7210ON mz_internal.mz_console_cluster_utilization_overview (cluster_id)",
7211    is_retained_metrics_object: false,
7212};
7213
7214pub const MZ_CLUSTER_DEPLOYMENT_LINEAGE_IND: BuiltinIndex = BuiltinIndex {
7215    name: "mz_cluster_deployment_lineage_ind",
7216    schema: MZ_INTERNAL_SCHEMA,
7217    oid: oid::INDEX_MZ_CLUSTER_DEPLOYMENT_LINEAGE_IND_OID,
7218    sql: "IN CLUSTER mz_catalog_server
7219ON mz_internal.mz_cluster_deployment_lineage (cluster_id)",
7220    is_retained_metrics_object: false,
7221};
7222
7223pub const MZ_SOURCE_STATUSES_IND: BuiltinIndex = BuiltinIndex {
7224    name: "mz_source_statuses_ind",
7225    schema: MZ_INTERNAL_SCHEMA,
7226    oid: oid::INDEX_MZ_SOURCE_STATUSES_IND_OID,
7227    sql: "IN CLUSTER mz_catalog_server
7228ON mz_internal.mz_source_statuses (id)",
7229    is_retained_metrics_object: false,
7230};
7231
7232pub const MZ_SINK_STATUSES_IND: BuiltinIndex = BuiltinIndex {
7233    name: "mz_sink_statuses_ind",
7234    schema: MZ_INTERNAL_SCHEMA,
7235    oid: oid::INDEX_MZ_SINK_STATUSES_IND_OID,
7236    sql: "IN CLUSTER mz_catalog_server
7237ON mz_internal.mz_sink_statuses (id)",
7238    is_retained_metrics_object: false,
7239};
7240
7241pub const MZ_SOURCE_STATUS_HISTORY_IND: BuiltinIndex = BuiltinIndex {
7242    name: "mz_source_status_history_ind",
7243    schema: MZ_INTERNAL_SCHEMA,
7244    oid: oid::INDEX_MZ_SOURCE_STATUS_HISTORY_IND_OID,
7245    sql: "IN CLUSTER mz_catalog_server
7246ON mz_internal.mz_source_status_history (source_id)",
7247    is_retained_metrics_object: false,
7248};
7249
7250pub const MZ_SINK_STATUS_HISTORY_IND: BuiltinIndex = BuiltinIndex {
7251    name: "mz_sink_status_history_ind",
7252    schema: MZ_INTERNAL_SCHEMA,
7253    oid: oid::INDEX_MZ_SINK_STATUS_HISTORY_IND_OID,
7254    sql: "IN CLUSTER mz_catalog_server
7255ON mz_internal.mz_sink_status_history (sink_id)",
7256    is_retained_metrics_object: false,
7257};
7258
7259// In both `mz_source_statistics` and `mz_sink_statistics` we cast the `SUM` of
7260// uint8's to `uint8` instead of leaving them as `numeric`. This is because we want to
7261// save index space, and we don't expect the sum to be > 2^63
7262// (even if a source with 2000 workers, that each produce 400 terabytes in a month ~ 2^61).
7263//
7264//
7265// These aggregations are just to make `GROUP BY` happy. Each id has a single row in the
7266// underlying relation.
7267//
7268// We append WITH_HISTORY because we want to build a separate view + index that doesn't
7269// retain history. This is because retaining its history causes MZ_SOURCE_STATISTICS_WITH_HISTORY_IND
7270// to hold all records/updates, which causes CPU and latency of querying it to spike.
7271pub static MZ_SOURCE_STATISTICS_WITH_HISTORY: LazyLock<BuiltinView> =
7272    LazyLock::new(|| BuiltinView {
7273        name: "mz_source_statistics_with_history",
7274        schema: MZ_INTERNAL_SCHEMA,
7275        oid: oid::VIEW_MZ_SOURCE_STATISTICS_WITH_HISTORY_OID,
7276        desc: RelationDesc::builder()
7277            .with_column("id", SqlScalarType::String.nullable(false))
7278            .with_column("replica_id", SqlScalarType::String.nullable(true))
7279            .with_column("messages_received", SqlScalarType::UInt64.nullable(false))
7280            .with_column("bytes_received", SqlScalarType::UInt64.nullable(false))
7281            .with_column("updates_staged", SqlScalarType::UInt64.nullable(false))
7282            .with_column("updates_committed", SqlScalarType::UInt64.nullable(false))
7283            .with_column("records_indexed", SqlScalarType::UInt64.nullable(false))
7284            .with_column("bytes_indexed", SqlScalarType::UInt64.nullable(false))
7285            .with_column(
7286                "rehydration_latency",
7287                SqlScalarType::Interval.nullable(true),
7288            )
7289            .with_column(
7290                "snapshot_records_known",
7291                SqlScalarType::UInt64.nullable(true),
7292            )
7293            .with_column(
7294                "snapshot_records_staged",
7295                SqlScalarType::UInt64.nullable(true),
7296            )
7297            .with_column("snapshot_committed", SqlScalarType::Bool.nullable(false))
7298            .with_column("offset_known", SqlScalarType::UInt64.nullable(true))
7299            .with_column("offset_committed", SqlScalarType::UInt64.nullable(true))
7300            .with_key(vec![0, 1])
7301            .finish(),
7302        column_comments: BTreeMap::new(),
7303        sql: "
7304WITH
7305    -- For each subsource, statistics are reported as its parent source
7306    subsource_to_parent AS
7307    (
7308        SELECT subsource.id AS id, parent.id AS report_id
7309        FROM mz_catalog.mz_sources AS subsource
7310            JOIN mz_internal.mz_object_dependencies AS dep ON subsource.id = dep.object_id
7311            JOIN mz_catalog.mz_sources AS parent ON parent.id = dep.referenced_object_id
7312        WHERE subsource.type = 'subsource'
7313    ),
7314    -- For each table from source, statistics are reported as its parent source
7315    table_to_parent AS
7316    (
7317        SELECT id, source_id AS report_id
7318        FROM mz_catalog.mz_tables
7319        WHERE source_id IS NOT NULL
7320    ),
7321    -- For each source and subsource, statistics are reported as itself
7322    source_refl AS
7323    (
7324        SELECT id, id AS report_id
7325        FROM mz_catalog.mz_sources
7326        WHERE type NOT IN ('progress', 'log')
7327    ),
7328    -- For each table from source, statistics are reported as itself
7329    table_refl AS
7330    (
7331        SELECT id, id AS report_id
7332        FROM mz_catalog.mz_tables
7333        WHERE source_id IS NOT NULL
7334    ),
7335    report_paths AS
7336    (
7337        SELECT id, report_id FROM subsource_to_parent
7338        UNION ALL SELECT id, report_id FROM table_to_parent
7339        UNION ALL SELECT id, report_id FROM source_refl
7340        UNION ALL SELECT id, report_id FROM table_refl
7341    )
7342SELECT
7343    report_paths.report_id AS id,
7344    replica_id,
7345    -- Counters
7346    SUM(messages_received)::uint8 AS messages_received,
7347    SUM(bytes_received)::uint8 AS bytes_received,
7348    SUM(updates_staged)::uint8 AS updates_staged,
7349    SUM(updates_committed)::uint8 AS updates_committed,
7350    -- Resetting Gauges
7351    SUM(records_indexed)::uint8 AS records_indexed,
7352    SUM(bytes_indexed)::uint8 AS bytes_indexed,
7353    -- Ensure we aggregate to NULL when not all workers are done rehydrating.
7354    CASE
7355        WHEN bool_or(rehydration_latency IS NULL) THEN NULL
7356        ELSE MAX(rehydration_latency)::interval
7357    END AS rehydration_latency,
7358    SUM(snapshot_records_known)::uint8 AS snapshot_records_known,
7359    SUM(snapshot_records_staged)::uint8 AS snapshot_records_staged,
7360    bool_and(snapshot_committed) as snapshot_committed,
7361    -- Gauges
7362    MAX(offset_known)::uint8 AS offset_known,
7363    MIN(offset_committed)::uint8 AS offset_committed
7364FROM mz_internal.mz_source_statistics_raw
7365    JOIN report_paths USING (id)
7366GROUP BY report_paths.report_id, replica_id",
7367        access: vec![PUBLIC_SELECT],
7368        ontology: None,
7369    });
7370
7371pub const MZ_SOURCE_STATISTICS_WITH_HISTORY_IND: BuiltinIndex = BuiltinIndex {
7372    name: "mz_source_statistics_with_history_ind",
7373    schema: MZ_INTERNAL_SCHEMA,
7374    oid: oid::INDEX_MZ_SOURCE_STATISTICS_WITH_HISTORY_IND_OID,
7375    sql: "IN CLUSTER mz_catalog_server
7376ON mz_internal.mz_source_statistics_with_history (id, replica_id)",
7377    is_retained_metrics_object: true,
7378};
7379
7380// The non historical version of MZ_SOURCE_STATISTICS_WITH_HISTORY.
7381// Used to query MZ_SOURCE_STATISTICS at the current time.
7382pub static MZ_SOURCE_STATISTICS: LazyLock<BuiltinView> = LazyLock::new(|| {
7383    BuiltinView {
7384        name: "mz_source_statistics",
7385        schema: MZ_INTERNAL_SCHEMA,
7386        oid: oid::VIEW_MZ_SOURCE_STATISTICS_OID,
7387        // We need to add a redundant where clause for a new dataflow to be created.
7388        desc: RelationDesc::builder()
7389            .with_column("id", SqlScalarType::String.nullable(false))
7390            .with_column("replica_id", SqlScalarType::String.nullable(true))
7391            .with_column("messages_received", SqlScalarType::UInt64.nullable(false))
7392            .with_column("bytes_received", SqlScalarType::UInt64.nullable(false))
7393            .with_column("updates_staged", SqlScalarType::UInt64.nullable(false))
7394            .with_column("updates_committed", SqlScalarType::UInt64.nullable(false))
7395            .with_column("records_indexed", SqlScalarType::UInt64.nullable(false))
7396            .with_column("bytes_indexed", SqlScalarType::UInt64.nullable(false))
7397            .with_column(
7398                "rehydration_latency",
7399                SqlScalarType::Interval.nullable(true),
7400            )
7401            .with_column(
7402                "snapshot_records_known",
7403                SqlScalarType::UInt64.nullable(true),
7404            )
7405            .with_column(
7406                "snapshot_records_staged",
7407                SqlScalarType::UInt64.nullable(true),
7408            )
7409            .with_column("snapshot_committed", SqlScalarType::Bool.nullable(false))
7410            .with_column("offset_known", SqlScalarType::UInt64.nullable(true))
7411            .with_column("offset_committed", SqlScalarType::UInt64.nullable(true))
7412            .with_key(vec![0, 1])
7413            .finish(),
7414        column_comments: BTreeMap::from_iter([
7415            (
7416                "id",
7417                "The ID of the source. Corresponds to `mz_catalog.mz_sources.id`.",
7418            ),
7419            (
7420                "replica_id",
7421                "The ID of a replica running the source. Corresponds to `mz_catalog.mz_cluster_replicas.id`.",
7422            ),
7423            (
7424                "messages_received",
7425                "The number of messages the source has received from the external system. Messages are counted in a source type-specific manner. Messages do not correspond directly to updates: some messages produce multiple updates, while other messages may be coalesced into a single update.",
7426            ),
7427            (
7428                "bytes_received",
7429                "The number of bytes the source has read from the external system. Bytes are counted in a source type-specific manner and may or may not include protocol overhead.",
7430            ),
7431            (
7432                "updates_staged",
7433                "The number of updates (insertions plus deletions) the source has written but not yet committed to the storage layer.",
7434            ),
7435            (
7436                "updates_committed",
7437                "The number of updates (insertions plus deletions) the source has committed to the storage layer.",
7438            ),
7439            (
7440                "records_indexed",
7441                "The number of individual records indexed in the source envelope state.",
7442            ),
7443            (
7444                "bytes_indexed",
7445                "The number of bytes stored in the source's internal index, if any.",
7446            ),
7447            (
7448                "rehydration_latency",
7449                "The amount of time it took for the source to rehydrate its internal index, if any, after the source last restarted.",
7450            ),
7451            (
7452                "snapshot_records_known",
7453                "The size of the source's snapshot, measured in number of records. See below to learn what constitutes a record.",
7454            ),
7455            (
7456                "snapshot_records_staged",
7457                "The number of records in the source's snapshot that Materialize has read. See below to learn what constitutes a record.",
7458            ),
7459            (
7460                "snapshot_committed",
7461                "Whether the source has committed the initial snapshot for a source.",
7462            ),
7463            (
7464                "offset_known",
7465                "The offset of the most recent data in the source's upstream service that Materialize knows about. See below to learn what constitutes an offset.",
7466            ),
7467            (
7468                "offset_committed",
7469                "The offset of the the data that Materialize has durably ingested. See below to learn what constitutes an offset.",
7470            ),
7471        ]),
7472        sql: "SELECT * FROM mz_internal.mz_source_statistics_with_history WHERE length(id) > 0",
7473        access: vec![PUBLIC_SELECT],
7474        ontology: Some(Ontology {
7475            entity_name: "source_statistics",
7476            description: "Aggregated source ingestion statistics",
7477            links: &const {
7478                [OntologyLink {
7479                    name: "statistics_of_source",
7480                    target: "source",
7481                    properties: LinkProperties::measures("id", "id", "ingestion_statistics"),
7482                }]
7483            },
7484            column_semantic_types: &const {
7485                [
7486                    ("id", SemanticType::CatalogItemId),
7487                    ("replica_id", SemanticType::ReplicaId),
7488                    ("messages_received", SemanticType::RecordCount),
7489                    ("bytes_received", SemanticType::ByteCount),
7490                    ("updates_staged", SemanticType::RecordCount),
7491                    ("updates_committed", SemanticType::RecordCount),
7492                    ("records_indexed", SemanticType::RecordCount),
7493                    ("bytes_indexed", SemanticType::ByteCount),
7494                    ("snapshot_records_known", SemanticType::RecordCount),
7495                    ("snapshot_records_staged", SemanticType::RecordCount),
7496                ]
7497            },
7498        }),
7499    }
7500});
7501
7502pub const MZ_SOURCE_STATISTICS_IND: BuiltinIndex = BuiltinIndex {
7503    name: "mz_source_statistics_ind",
7504    schema: MZ_INTERNAL_SCHEMA,
7505    oid: oid::INDEX_MZ_SOURCE_STATISTICS_IND_OID,
7506    sql: "IN CLUSTER mz_catalog_server
7507ON mz_internal.mz_source_statistics (id, replica_id)",
7508    is_retained_metrics_object: false,
7509};
7510
7511pub static MZ_SINK_STATISTICS: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
7512    name: "mz_sink_statistics",
7513    schema: MZ_INTERNAL_SCHEMA,
7514    oid: oid::VIEW_MZ_SINK_STATISTICS_OID,
7515    desc: RelationDesc::builder()
7516        .with_column("id", SqlScalarType::String.nullable(false))
7517        .with_column("replica_id", SqlScalarType::String.nullable(true))
7518        .with_column("messages_staged", SqlScalarType::UInt64.nullable(false))
7519        .with_column("messages_committed", SqlScalarType::UInt64.nullable(false))
7520        .with_column("bytes_staged", SqlScalarType::UInt64.nullable(false))
7521        .with_column("bytes_committed", SqlScalarType::UInt64.nullable(false))
7522        .with_key(vec![0, 1])
7523        .finish(),
7524    column_comments: BTreeMap::from_iter([
7525        (
7526            "id",
7527            "The ID of the sink. Corresponds to `mz_catalog.mz_sinks.id`.",
7528        ),
7529        (
7530            "replica_id",
7531            "The ID of a replica running the sink. Corresponds to `mz_catalog.mz_cluster_replicas.id`.",
7532        ),
7533        (
7534            "messages_staged",
7535            "The number of messages staged but possibly not committed to the sink.",
7536        ),
7537        (
7538            "messages_committed",
7539            "The number of messages committed to the sink.",
7540        ),
7541        (
7542            "bytes_staged",
7543            "The number of bytes staged but possibly not committed to the sink. This counts both keys and values, if applicable.",
7544        ),
7545        (
7546            "bytes_committed",
7547            "The number of bytes committed to the sink. This counts both keys and values, if applicable.",
7548        ),
7549    ]),
7550    sql: "
7551SELECT
7552    id,
7553    replica_id,
7554    SUM(messages_staged)::uint8 AS messages_staged,
7555    SUM(messages_committed)::uint8 AS messages_committed,
7556    SUM(bytes_staged)::uint8 AS bytes_staged,
7557    SUM(bytes_committed)::uint8 AS bytes_committed
7558FROM mz_internal.mz_sink_statistics_raw
7559GROUP BY id, replica_id",
7560    access: vec![PUBLIC_SELECT],
7561    ontology: Some(Ontology {
7562        entity_name: "sink_statistics",
7563        description: "Aggregated sink export statistics",
7564        links: &const {
7565            [OntologyLink {
7566                name: "statistics_of_sink",
7567                target: "sink",
7568                properties: LinkProperties::measures("id", "id", "export_statistics"),
7569            }]
7570        },
7571        column_semantic_types: &const {
7572            [
7573                ("id", SemanticType::CatalogItemId),
7574                ("replica_id", SemanticType::ReplicaId),
7575                ("messages_staged", SemanticType::RecordCount),
7576                ("messages_committed", SemanticType::RecordCount),
7577                ("bytes_staged", SemanticType::ByteCount),
7578                ("bytes_committed", SemanticType::ByteCount),
7579            ]
7580        },
7581    }),
7582});
7583
7584pub const MZ_SINK_STATISTICS_IND: BuiltinIndex = BuiltinIndex {
7585    name: "mz_sink_statistics_ind",
7586    schema: MZ_INTERNAL_SCHEMA,
7587    oid: oid::INDEX_MZ_SINK_STATISTICS_IND_OID,
7588    sql: "IN CLUSTER mz_catalog_server
7589ON mz_internal.mz_sink_statistics (id, replica_id)",
7590    is_retained_metrics_object: true,
7591};
7592
7593pub const MZ_CLUSTER_REPLICA_STATUSES_IND: BuiltinIndex = BuiltinIndex {
7594    name: "mz_cluster_replica_statuses_ind",
7595    schema: MZ_INTERNAL_SCHEMA,
7596    oid: oid::INDEX_MZ_CLUSTER_REPLICA_STATUSES_IND_OID,
7597    sql: "IN CLUSTER mz_catalog_server
7598ON mz_internal.mz_cluster_replica_statuses (replica_id)",
7599    is_retained_metrics_object: false,
7600};
7601
7602pub const MZ_CLUSTER_REPLICA_STATUS_HISTORY_IND: BuiltinIndex = BuiltinIndex {
7603    name: "mz_cluster_replica_status_history_ind",
7604    schema: MZ_INTERNAL_SCHEMA,
7605    oid: oid::INDEX_MZ_CLUSTER_REPLICA_STATUS_HISTORY_IND_OID,
7606    sql: "IN CLUSTER mz_catalog_server
7607ON mz_internal.mz_cluster_replica_status_history (replica_id)",
7608    is_retained_metrics_object: false,
7609};
7610
7611pub const MZ_CLUSTER_REPLICA_METRICS_IND: BuiltinIndex = BuiltinIndex {
7612    name: "mz_cluster_replica_metrics_ind",
7613    schema: MZ_INTERNAL_SCHEMA,
7614    oid: oid::INDEX_MZ_CLUSTER_REPLICA_METRICS_IND_OID,
7615    sql: "IN CLUSTER mz_catalog_server
7616ON mz_internal.mz_cluster_replica_metrics (replica_id)",
7617    is_retained_metrics_object: false,
7618};
7619
7620pub const MZ_CLUSTER_REPLICA_METRICS_HISTORY_IND: BuiltinIndex = BuiltinIndex {
7621    name: "mz_cluster_replica_metrics_history_ind",
7622    schema: MZ_INTERNAL_SCHEMA,
7623    oid: oid::INDEX_MZ_CLUSTER_REPLICA_METRICS_HISTORY_IND_OID,
7624    sql: "IN CLUSTER mz_catalog_server
7625ON mz_internal.mz_cluster_replica_metrics_history (replica_id)",
7626    is_retained_metrics_object: false,
7627};
7628
7629pub const MZ_CLUSTER_REPLICA_HISTORY_IND: BuiltinIndex = BuiltinIndex {
7630    name: "mz_cluster_replica_history_ind",
7631    schema: MZ_INTERNAL_SCHEMA,
7632    oid: oid::INDEX_MZ_CLUSTER_REPLICA_HISTORY_IND_OID,
7633    sql: "IN CLUSTER mz_catalog_server
7634ON mz_internal.mz_cluster_replica_history (dropped_at)",
7635    is_retained_metrics_object: true,
7636};
7637
7638pub const MZ_CLUSTER_REPLICA_NAME_HISTORY_IND: BuiltinIndex = BuiltinIndex {
7639    name: "mz_cluster_replica_name_history_ind",
7640    schema: MZ_INTERNAL_SCHEMA,
7641    oid: oid::INDEX_MZ_CLUSTER_REPLICA_NAME_HISTORY_IND_OID,
7642    sql: "IN CLUSTER mz_catalog_server
7643ON mz_internal.mz_cluster_replica_name_history (id)",
7644    is_retained_metrics_object: false,
7645};
7646
7647pub const MZ_OBJECT_LIFETIMES_IND: BuiltinIndex = BuiltinIndex {
7648    name: "mz_object_lifetimes_ind",
7649    schema: MZ_INTERNAL_SCHEMA,
7650    oid: oid::INDEX_MZ_OBJECT_LIFETIMES_IND_OID,
7651    sql: "IN CLUSTER mz_catalog_server
7652ON mz_internal.mz_object_lifetimes (id)",
7653    is_retained_metrics_object: false,
7654};
7655
7656pub const MZ_OBJECT_HISTORY_IND: BuiltinIndex = BuiltinIndex {
7657    name: "mz_object_history_ind",
7658    schema: MZ_INTERNAL_SCHEMA,
7659    oid: oid::INDEX_MZ_OBJECT_HISTORY_IND_OID,
7660    sql: "IN CLUSTER mz_catalog_server
7661ON mz_internal.mz_object_history (id)",
7662    is_retained_metrics_object: false,
7663};
7664
7665pub const MZ_OBJECT_DEPENDENCIES_IND: BuiltinIndex = BuiltinIndex {
7666    name: "mz_object_dependencies_ind",
7667    schema: MZ_INTERNAL_SCHEMA,
7668    oid: oid::INDEX_MZ_OBJECT_DEPENDENCIES_IND_OID,
7669    sql: "IN CLUSTER mz_catalog_server
7670ON mz_internal.mz_object_dependencies (object_id)",
7671    is_retained_metrics_object: true,
7672};
7673
7674pub const MZ_COMPUTE_DEPENDENCIES_IND: BuiltinIndex = BuiltinIndex {
7675    name: "mz_compute_dependencies_ind",
7676    schema: MZ_INTERNAL_SCHEMA,
7677    oid: oid::INDEX_MZ_COMPUTE_DEPENDENCIES_IND_OID,
7678    sql: "IN CLUSTER mz_catalog_server
7679ON mz_internal.mz_compute_dependencies (dependency_id)",
7680    is_retained_metrics_object: false,
7681};
7682
7683pub const MZ_OBJECT_TRANSITIVE_DEPENDENCIES_IND: BuiltinIndex = BuiltinIndex {
7684    name: "mz_object_transitive_dependencies_ind",
7685    schema: MZ_INTERNAL_SCHEMA,
7686    oid: oid::INDEX_MZ_OBJECT_TRANSITIVE_DEPENDENCIES_IND_OID,
7687    sql: "IN CLUSTER mz_catalog_server
7688ON mz_internal.mz_object_transitive_dependencies (object_id)",
7689    is_retained_metrics_object: false,
7690};
7691
7692pub const MZ_FRONTIERS_IND: BuiltinIndex = BuiltinIndex {
7693    name: "mz_frontiers_ind",
7694    schema: MZ_INTERNAL_SCHEMA,
7695    oid: oid::INDEX_MZ_FRONTIERS_IND_OID,
7696    sql: "IN CLUSTER mz_catalog_server
7697ON mz_internal.mz_frontiers (object_id)",
7698    is_retained_metrics_object: false,
7699};
7700
7701pub const MZ_WALLCLOCK_GLOBAL_LAG_RECENT_HISTORY_IND: BuiltinIndex = BuiltinIndex {
7702    name: "mz_wallclock_global_lag_recent_history_ind",
7703    schema: MZ_INTERNAL_SCHEMA,
7704    oid: oid::INDEX_MZ_WALLCLOCK_GLOBAL_LAG_RECENT_HISTORY_IND_OID,
7705    sql: "IN CLUSTER mz_catalog_server
7706ON mz_internal.mz_wallclock_global_lag_recent_history (object_id)",
7707    is_retained_metrics_object: false,
7708};
7709
7710pub const MZ_RECENT_ACTIVITY_LOG_THINNED_IND: BuiltinIndex = BuiltinIndex {
7711    name: "mz_recent_activity_log_thinned_ind",
7712    schema: MZ_INTERNAL_SCHEMA,
7713    oid: oid::INDEX_MZ_RECENT_ACTIVITY_LOG_THINNED_IND_OID,
7714    sql: "IN CLUSTER mz_catalog_server
7715-- sql_hash because we plan to join
7716-- this against mz_internal.mz_sql_text
7717ON mz_internal.mz_recent_activity_log_thinned (sql_hash)",
7718    is_retained_metrics_object: false,
7719};
7720
7721pub const MZ_WEBHOOK_SOURCES_IND: BuiltinIndex = BuiltinIndex {
7722    name: "mz_webhook_sources_ind",
7723    schema: MZ_INTERNAL_SCHEMA,
7724    oid: oid::INDEX_MZ_WEBHOOK_SOURCES_IND_OID,
7725    sql: "IN CLUSTER mz_catalog_server
7726ON mz_internal.mz_webhook_sources (id)",
7727    is_retained_metrics_object: true,
7728};
7729
7730pub const MZ_COMMENTS_IND: BuiltinIndex = BuiltinIndex {
7731    name: "mz_comments_ind",
7732    schema: MZ_INTERNAL_SCHEMA,
7733    oid: oid::INDEX_MZ_COMMENTS_IND_OID,
7734    sql: "IN CLUSTER mz_catalog_server
7735ON mz_internal.mz_comments (id)",
7736    is_retained_metrics_object: true,
7737};
7738
7739pub static MZ_ANALYTICS: BuiltinConnection = BuiltinConnection {
7740    name: "mz_analytics",
7741    schema: MZ_INTERNAL_SCHEMA,
7742    oid: oid::CONNECTION_MZ_ANALYTICS_OID,
7743    sql: "CREATE CONNECTION mz_internal.mz_analytics TO AWS (ASSUME ROLE ARN = '')",
7744    access: &[MzAclItem {
7745        grantee: MZ_SYSTEM_ROLE_ID,
7746        grantor: MZ_ANALYTICS_ROLE_ID,
7747        acl_mode: rbac::all_object_privileges(SystemObjectType::Object(ObjectType::Connection)),
7748    }],
7749    owner_id: &MZ_ANALYTICS_ROLE_ID,
7750    runtime_alterable: true,
7751};