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