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