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