diff --git a/doc/user/content/sql/system-catalog/mz_internal.md b/doc/user/content/sql/system-catalog/mz_internal.md index e3c0e09a3f29c..13556d5265290 100644 --- a/doc/user/content/sql/system-catalog/mz_internal.md +++ b/doc/user/content/sql/system-catalog/mz_internal.md @@ -1633,12 +1633,15 @@ The `mz_webhook_sources` table contains a row for each webhook source in the sys + + + diff --git a/misc/python/materialize/checks/all_checks/builtin_version_pin.py b/misc/python/materialize/checks/all_checks/builtin_version_pin.py index cee0fa71346f7..8ddabdae0f963 100644 --- a/misc/python/materialize/checks/all_checks/builtin_version_pin.py +++ b/misc/python/materialize/checks/all_checks/builtin_version_pin.py @@ -34,31 +34,31 @@ # dependencies, so conversions there cannot poison customer catalogs. # mz_role_auth is excluded because only mz_system can read it. _STABLE_BUILTINS: dict[str, MzVersion | None] = { - "mz_array_types": None, + "mz_array_types": MzVersion.parse_mz("v26.50.0"), "mz_audit_events": MzVersion.parse_mz("v26.33.0"), "mz_aws_privatelink_connections": MzVersion.parse_mz("v26.37.0"), - "mz_base_types": None, + "mz_base_types": MzVersion.parse_mz("v26.50.0"), "mz_cluster_replica_sizes": None, "mz_cluster_replicas": MzVersion.parse_mz("v26.30.0"), "mz_clusters": MzVersion.parse_mz("v26.30.0"), "mz_columns": MzVersion.parse_mz("v26.49.0"), "mz_default_privileges": MzVersion.parse_mz("v26.30.0"), "mz_egress_ips": None, - "mz_functions": None, + "mz_functions": MzVersion.parse_mz("v26.50.0"), "mz_iceberg_sinks": MzVersion.parse_mz("v26.38.0"), "mz_index_columns": MzVersion.parse_mz("v26.49.0"), "mz_kafka_connections": MzVersion.parse_mz("v26.37.0"), "mz_kafka_sinks": MzVersion.parse_mz("v26.38.0"), "mz_kafka_sources": MzVersion.parse_mz("v26.34.0"), - "mz_list_types": None, - "mz_map_types": None, - "mz_operators": None, - "mz_pseudo_types": None, + "mz_list_types": MzVersion.parse_mz("v26.50.0"), + "mz_map_types": MzVersion.parse_mz("v26.50.0"), + "mz_operators": MzVersion.parse_mz("v26.50.0"), + "mz_pseudo_types": MzVersion.parse_mz("v26.50.0"), "mz_sinks": MzVersion.parse_mz("v26.38.0"), "mz_ssh_tunnel_connections": MzVersion.parse_mz("v26.37.0"), "mz_system_privileges": MzVersion.parse_mz("v26.30.0"), "mz_tables": MzVersion.parse_mz("v26.39.0"), - "mz_types": None, + "mz_types": MzVersion.parse_mz("v26.50.0"), "mz_views": MzVersion.parse_mz("v26.39.0"), } diff --git a/src/adapter/src/catalog/builtin_table_updates.rs b/src/adapter/src/catalog/builtin_table_updates.rs index eb5091b4d84d8..9078aa7e9edb2 100644 --- a/src/adapter/src/catalog/builtin_table_updates.rs +++ b/src/adapter/src/catalog/builtin_table_updates.rs @@ -12,29 +12,19 @@ mod notice; use bytesize::ByteSize; use ipnet::IpNet; use mz_audit_log::VersionedStorageUsage; -use mz_catalog::SYSTEM_CONN_ID; use mz_catalog::builtin::{ - BuiltinTable, MZ_AGGREGATES, MZ_ARRAY_TYPES, MZ_BASE_TYPES, MZ_CLUSTER_REPLICA_SIZE_INTERNAL, - MZ_CLUSTER_REPLICA_SIZES, MZ_EGRESS_IPS, MZ_FUNCTIONS, MZ_LICENSE_KEYS, MZ_LIST_TYPES, - MZ_MAP_TYPES, MZ_OPERATORS, MZ_PSEUDO_TYPES, MZ_ROLE_AUTH, MZ_SESSIONS, - MZ_STORAGE_USAGE_BY_SHARD, MZ_SUBSCRIPTIONS, MZ_TYPE_PG_METADATA, MZ_TYPES, + BuiltinTable, MZ_CLUSTER_REPLICA_SIZE_INTERNAL, MZ_CLUSTER_REPLICA_SIZES, MZ_EGRESS_IPS, + MZ_LICENSE_KEYS, MZ_ROLE_AUTH, MZ_SESSIONS, MZ_STORAGE_USAGE_BY_SHARD, MZ_SUBSCRIPTIONS, MZ_WEBHOOKS_SOURCES, }; use mz_catalog::memory::error::Error; -use mz_catalog::memory::objects::{CatalogItem, DataSourceDesc, Func, Type}; +use mz_catalog::memory::objects::{CatalogItem, DataSourceDesc}; use mz_license_keys::ValidatedLicenseKey; use mz_orchestrator::{CpuLimit, DiskLimit, MemoryLimit}; use mz_ore::cast::CastFrom; -use mz_ore::collections::CollectionExt; use mz_persist_client::batch::ProtoBatch; -use mz_repr::adt::array::ArrayDimension; -use mz_repr::adt::mz_acl_item::PrivilegeMap; use mz_repr::role_id::RoleId; -use mz_repr::{CatalogItemId, Datum, Diff, GlobalId, Row, RowPacker}; -use mz_sql::catalog::{CatalogType, TypeCategory}; -use mz_sql::func::FuncImplCatalogDetails; -use mz_sql::names::SchemaSpecifier; -use mz_sql_parser::ast::display::AstDisplay; +use mz_repr::{CatalogItemId, Datum, Diff, GlobalId, Row}; use mz_storage_client::client::TableData; use smallvec::smallvec; use uuid::Uuid; @@ -121,19 +111,6 @@ impl CatalogState { diff: Diff, ) -> Vec> { let entry = self.get_entry(&id); - let oid = entry.oid(); - let conn_id = entry.item().conn_id().unwrap_or(&SYSTEM_CONN_ID); - let schema_id = &self - .get_schema( - &entry.name().qualifiers.database_spec, - &entry.name().qualifiers.schema_spec, - conn_id, - ) - .id; - let name = &entry.name().item; - let owner_id = entry.owner_id(); - let privileges_row = self.pack_privilege_array_row(entry.privileges()); - let privileges = privileges_row.unpack_first(); let updates = match entry.item() { CatalogItem::Source(source) => { match &source.data_source { @@ -154,20 +131,16 @@ impl CatalogState { // mz_sinks, mz_kafka_sinks and mz_iceberg_sinks read create_sql // out of mz_catalog_raw, so there is nothing to pack here. CatalogItem::Sink(_) => vec![], - CatalogItem::Type(ty) => { - self.pack_type_update(id, oid, schema_id, name, owner_id, privileges, ty, diff) - } - CatalogItem::Func(func) => { - self.pack_func_update(id, schema_id, name, owner_id, func, diff) - } - // Tables, views, materialized views, indexes, and metric sinks - // are exposed through materialized views derived from - // `mz_catalog_raw`, and logs and secrets never had builtin-table - // rows, so none pack a row here. + // Tables, views, materialized views, indexes, types, functions + // and metric sinks are exposed through materialized views derived + // from `mz_catalog_raw`, and logs and secrets never had + // builtin-table rows, so none pack a row here. CatalogItem::Table(_) | CatalogItem::View(_) | CatalogItem::MaterializedView(_) | CatalogItem::Index(_) + | CatalogItem::Type(_) + | CatalogItem::Func(_) | CatalogItem::Log(_) | CatalogItem::Secret(_) | CatalogItem::MetricSink(_) => vec![], @@ -181,242 +154,6 @@ impl CatalogState { updates } - fn pack_type_update( - &self, - id: CatalogItemId, - oid: u32, - schema_id: &SchemaSpecifier, - name: &str, - owner_id: &RoleId, - privileges: Datum, - typ: &Type, - diff: Diff, - ) -> Vec> { - let mut out = vec![]; - - let redacted = typ.create_sql.as_ref().map(|create_sql| { - mz_sql::parse::parse(create_sql) - .unwrap_or_else(|_| panic!("create_sql cannot be invalid: {}", create_sql)) - .into_element() - .ast - .to_ast_string_redacted() - }); - - out.push(BuiltinTableUpdate::row( - &*MZ_TYPES, - Row::pack_slice(&[ - Datum::String(&id.to_string()), - Datum::UInt32(oid), - Datum::String(&schema_id.to_string()), - Datum::String(name), - Datum::String(&TypeCategory::from_catalog_type(&typ.details.typ).to_string()), - Datum::String(&owner_id.to_string()), - privileges, - if let Some(create_sql) = &typ.create_sql { - Datum::String(create_sql) - } else { - Datum::Null - }, - if let Some(redacted) = &redacted { - Datum::String(redacted) - } else { - Datum::Null - }, - ]), - diff, - )); - - let mut row = Row::default(); - let mut packer = row.packer(); - - fn append_modifier(packer: &mut RowPacker<'_>, mods: &[i64]) { - if mods.is_empty() { - packer.push(Datum::Null); - } else { - packer.push_list(mods.iter().map(|m| Datum::Int64(*m))); - } - } - - let index_id = match &typ.details.typ { - CatalogType::Array { - element_reference: element_id, - } => { - packer.push(Datum::String(&id.to_string())); - packer.push(Datum::String(&element_id.to_string())); - &MZ_ARRAY_TYPES - } - CatalogType::List { - element_reference: element_id, - element_modifiers, - } => { - packer.push(Datum::String(&id.to_string())); - packer.push(Datum::String(&element_id.to_string())); - append_modifier(&mut packer, element_modifiers); - &MZ_LIST_TYPES - } - CatalogType::Map { - key_reference: key_id, - value_reference: value_id, - key_modifiers, - value_modifiers, - } => { - packer.push(Datum::String(&id.to_string())); - packer.push(Datum::String(&key_id.to_string())); - packer.push(Datum::String(&value_id.to_string())); - append_modifier(&mut packer, key_modifiers); - append_modifier(&mut packer, value_modifiers); - &MZ_MAP_TYPES - } - CatalogType::Pseudo => { - packer.push(Datum::String(&id.to_string())); - &MZ_PSEUDO_TYPES - } - _ => { - packer.push(Datum::String(&id.to_string())); - &MZ_BASE_TYPES - } - }; - out.push(BuiltinTableUpdate::row(index_id, row, diff)); - - if let Some(pg_metadata) = &typ.details.pg_metadata { - // Resolved the same way as a column's wire type, so this matches the - // `type_len` pgwire sends in `RowDescription`. Pseudo-types and arrays - // of them (`_record`) have no scalar type, so their length is unknown. - let typlen = - match mz_sql::plan::scalar_type_from_catalog(&self.for_system_session(), id, &[]) { - Ok(scalar_type) => Datum::Int16(mz_pgrepr::Type::from(&scalar_type).typlen()), - Err(_) => Datum::Null, - }; - out.push(BuiltinTableUpdate::row( - &*MZ_TYPE_PG_METADATA, - Row::pack_slice(&[ - Datum::String(&id.to_string()), - Datum::UInt32(pg_metadata.typinput_oid), - Datum::UInt32(pg_metadata.typreceive_oid), - Datum::UInt32(pg_metadata.typsend_oid), - typlen, - ]), - diff, - )); - } - - out - } - - fn pack_func_update( - &self, - id: CatalogItemId, - schema_id: &SchemaSpecifier, - name: &str, - owner_id: &RoleId, - func: &Func, - diff: Diff, - ) -> Vec> { - let mut updates = vec![]; - for func_impl_details in func.inner.func_impls() { - let arg_type_ids = func_impl_details - .arg_typs - .iter() - .map(|typ| self.get_system_type(typ).id().to_string()) - .collect::>(); - - let mut row = Row::default(); - row.packer() - .try_push_array( - &[ArrayDimension { - lower_bound: 1, - length: arg_type_ids.len(), - }], - arg_type_ids.iter().map(|id| Datum::String(id)), - ) - .expect( - "arg_type_ids is 1 dimensional, and its length is used for the array length", - ); - let arg_type_ids = row.unpack_first(); - - updates.push(BuiltinTableUpdate::row( - &*MZ_FUNCTIONS, - Row::pack_slice(&[ - Datum::String(&id.to_string()), - Datum::UInt32(func_impl_details.oid), - Datum::String(&schema_id.to_string()), - Datum::String(name), - arg_type_ids, - Datum::from( - func_impl_details - .variadic_typ - .map(|typ| self.get_system_type(typ).id().to_string()) - .as_deref(), - ), - Datum::from( - func_impl_details - .return_typ - .map(|typ| self.get_system_type(typ).id().to_string()) - .as_deref(), - ), - func_impl_details.return_is_set.into(), - Datum::String(&owner_id.to_string()), - ]), - diff, - )); - - if let mz_sql::func::Func::Aggregate(_) = func.inner { - updates.push(BuiltinTableUpdate::row( - &*MZ_AGGREGATES, - Row::pack_slice(&[ - Datum::UInt32(func_impl_details.oid), - // TODO(database-issues#1064): Support ordered-set aggregate functions. - Datum::String("n"), - Datum::Int16(0), - ]), - diff, - )); - } - } - updates - } - - pub fn pack_op_update( - &self, - operator: &str, - func_impl_details: FuncImplCatalogDetails, - diff: Diff, - ) -> BuiltinTableUpdate<&'static BuiltinTable> { - let arg_type_ids = func_impl_details - .arg_typs - .iter() - .map(|typ| self.get_system_type(typ).id().to_string()) - .collect::>(); - - let mut row = Row::default(); - row.packer() - .try_push_array( - &[ArrayDimension { - lower_bound: 1, - length: arg_type_ids.len(), - }], - arg_type_ids.iter().map(|id| Datum::String(id)), - ) - .expect("arg_type_ids is 1 dimensional, and its length is used for the array length"); - let arg_type_ids = row.unpack_first(); - - BuiltinTableUpdate::row( - &*MZ_OPERATORS, - Row::pack_slice(&[ - Datum::UInt32(func_impl_details.oid), - Datum::String(operator), - arg_type_ids, - Datum::from( - func_impl_details - .return_typ - .map(|typ| self.get_system_type(typ).id().to_string()) - .as_deref(), - ), - ]), - diff, - ) - } - pub fn pack_storage_usage_update( &self, VersionedStorageUsage::V1(event): VersionedStorageUsage, @@ -573,23 +310,6 @@ impl CatalogState { ) } - fn pack_privilege_array_row(&self, privileges: &PrivilegeMap) -> Row { - let mut row = Row::default(); - let flat_privileges: Vec<_> = privileges.all_values_owned().collect(); - row.packer() - .try_push_array( - &[ArrayDimension { - lower_bound: 1, - length: flat_privileges.len(), - }], - flat_privileges - .into_iter() - .map(|mz_acl_item| Datum::MzAclItem(mz_acl_item.clone())), - ) - .expect("privileges is 1 dimensional, and its length is used for the array length"); - row - } - pub fn pack_webhook_source_update( &self, item_id: CatalogItemId, diff --git a/src/adapter/src/catalog/open.rs b/src/adapter/src/catalog/open.rs index 7fdaa1e96c483..2081669585a54 100644 --- a/src/adapter/src/catalog/open.rs +++ b/src/adapter/src/catalog/open.rs @@ -55,7 +55,6 @@ use mz_repr::adt::mz_acl_item::PrivilegeMap; use mz_repr::namespaces::is_unstable_schema; use mz_repr::{CatalogItemId, Diff, GlobalId, RelationVersion, Timestamp}; use mz_sql::catalog::{CatalogError as SqlCatalogError, CatalogItemType, RoleMembership, RoleVars}; -use mz_sql::func::OP_IMPLS; use mz_sql::names::CommentObjectId; use mz_sql::rbac; use mz_sql::session::user::{MZ_SYSTEM_ROLE_ID, SYSTEM_USER}; @@ -613,21 +612,6 @@ impl Catalog { storage: Arc::new(tokio::sync::Mutex::new(storage)), }; - // Operators aren't stored in the catalog, but we would like them in - // introspection views. - for (op, func) in OP_IMPLS.iter() { - match func { - mz_sql::func::Func::Scalar(impls) => { - for imp in impls { - builtin_table_updates.push(catalog.state.resolve_builtin_table_update( - catalog.state.pack_op_update(op, imp.details(), Diff::ONE), - )); - } - } - _ => unreachable!("all operators must be scalar functions"), - } - } - for ip in &catalog.state.egress_addresses { builtin_table_updates.push( catalog diff --git a/src/adapter/src/catalog/open/builtin_schema_migration.rs b/src/adapter/src/catalog/open/builtin_schema_migration.rs index db1c32a97daec..fdf87f5d8add3 100644 --- a/src/adapter/src/catalog/open/builtin_schema_migration.rs +++ b/src/adapter/src/catalog/open/builtin_schema_migration.rs @@ -325,24 +325,6 @@ static MIGRATIONS: LazyLock> = LazyLock::new(|| { MZ_INTERNAL_SCHEMA, "mz_kafka_source_tables", ), - // `mz_type_pg_metadata` gained a trailing `typsend` column. See the NOTE - // above: this version must stay at the workspace's current dev version - // until the change ships. - MigrationStep::replacement( - "26.40.0-dev.0", - CatalogItemType::Table, - MZ_INTERNAL_SCHEMA, - "mz_type_pg_metadata", - ), - // `mz_type_pg_metadata` gained a trailing `typlen` column. See the NOTE - // above: this version must stay at the workspace's current dev version - // until the change ships. - MigrationStep::replacement( - "26.47.0-dev.0", - CatalogItemType::Table, - MZ_INTERNAL_SCHEMA, - "mz_type_pg_metadata", - ), // Converting the connection-detail builtin tables to materialized views // changes their catalog fingerprint, so each needs an explicit // replacement step. @@ -570,6 +552,69 @@ static MIGRATIONS: LazyLock> = LazyLock::new(|| { MZ_CATALOG_SCHEMA, "mz_index_columns", ), + // Converting the type relations from builtin tables to materialized + // views over mz_catalog_raw changes their catalog fingerprint, so each + // needs an explicit replacement step. See the NOTE above: this version + // must stay at the workspace's current dev version until the change + // ships. + MigrationStep::replacement( + "26.50.0-dev.0", + CatalogItemType::MaterializedView, + MZ_CATALOG_SCHEMA, + "mz_types", + ), + MigrationStep::replacement( + "26.50.0-dev.0", + CatalogItemType::MaterializedView, + MZ_CATALOG_SCHEMA, + "mz_array_types", + ), + MigrationStep::replacement( + "26.50.0-dev.0", + CatalogItemType::MaterializedView, + MZ_CATALOG_SCHEMA, + "mz_base_types", + ), + MigrationStep::replacement( + "26.50.0-dev.0", + CatalogItemType::MaterializedView, + MZ_CATALOG_SCHEMA, + "mz_list_types", + ), + MigrationStep::replacement( + "26.50.0-dev.0", + CatalogItemType::MaterializedView, + MZ_CATALOG_SCHEMA, + "mz_map_types", + ), + MigrationStep::replacement( + "26.50.0-dev.0", + CatalogItemType::MaterializedView, + MZ_CATALOG_SCHEMA, + "mz_pseudo_types", + ), + MigrationStep::replacement( + "26.50.0-dev.0", + CatalogItemType::MaterializedView, + MZ_INTERNAL_SCHEMA, + "mz_type_pg_metadata", + ), + // Converting mz_functions and mz_operators from builtin tables to + // materialized views changes their catalog fingerprint, so each needs + // an explicit replacement step. See the NOTE above: this version must + // stay at the workspace's current dev version until the change ships. + MigrationStep::replacement( + "26.50.0-dev.0", + CatalogItemType::MaterializedView, + MZ_CATALOG_SCHEMA, + "mz_functions", + ), + MigrationStep::replacement( + "26.50.0-dev.0", + CatalogItemType::MaterializedView, + MZ_CATALOG_SCHEMA, + "mz_operators", + ), ] }); diff --git a/src/catalog-decode/src/create_sql.rs b/src/catalog-decode/src/create_sql.rs index f62a96aade209..209e4baf9c194 100644 --- a/src/catalog-decode/src/create_sql.rs +++ b/src/catalog-decode/src/create_sql.rs @@ -22,12 +22,12 @@ use mz_sql_parser::ast::item_refs::collect_item_references; use mz_sql_parser::ast::{ AstInfo, AvroSchema, ColumnOption, ConnectionOption, ConnectionOptionName, CreateConnectionType, CreateSinkConnection, CreateSourceOptionName, CreateSubsourceOptionName, - Expr, Format, FormatSpecifier, IcebergSinkConfigOptionName, IcebergSinkMode, IndexOptionName, - KafkaSinkConfigOptionName, KafkaSourceConfigOptionName, MaterializedViewOptionName, - PgConfigOptionName, ProtobufSchema, Raw, RawClusterName, RawItemName, RefreshAtOptionValue, - RefreshEveryOptionValue, RefreshOptionValue, SinkEnvelope, SourceEnvelope, SourceErrorPolicy, - Statement, TableFromSourceOptionName, TableOptionName, UnresolvedItemName, Value, - WithOptionValue, + CreateTypeAs, CreateTypeListOptionName, CreateTypeMapOptionName, Expr, Format, FormatSpecifier, + IcebergSinkConfigOptionName, IcebergSinkMode, IndexOptionName, KafkaSinkConfigOptionName, + KafkaSourceConfigOptionName, MaterializedViewOptionName, PgConfigOptionName, ProtobufSchema, + Raw, RawClusterName, RawDataType, RawItemName, RefreshAtOptionValue, RefreshEveryOptionValue, + RefreshOptionValue, SinkEnvelope, SourceEnvelope, SourceErrorPolicy, Statement, + TableFromSourceOptionName, TableOptionName, UnresolvedItemName, Value, WithOptionValue, }; use prost::Message as _; use serde_json::json; @@ -152,6 +152,44 @@ fn is_null_literal(expr: &Expr) -> bool { } } +/// The item id and type modifiers of the data type a `CREATE TYPE` option names. +/// +/// `plan_create_type` only accepts named types for list elements, map keys and +/// values, and record fields, so a persisted statement always carries a +/// `RawDataType::Other` whose name is an item id. +fn type_option( + value: Option>, + option: &str, +) -> Result<(String, Vec), String> { + match value { + Some(WithOptionValue::DataType(RawDataType::Other { name, typ_mod })) => { + Ok((item_id(name)?, typ_mod)) + } + _ => Err(format!("{option} is not a named data type")), + } +} + +/// Records a type reference as `id_key`, plus `modifiers_key` when the reference +/// carries type modifiers. Modifiers are rendered as a `bigint list` literal +/// (`{38,2}`) for the views to cast, and an absent key is how `mz_list_types` +/// and `mz_map_types` report a reference without modifiers as NULL. +fn insert_type_reference( + info: &mut BTreeMap<&str, serde_json::Value>, + id_key: &'static str, + modifiers_key: &'static str, + (id, modifiers): (String, Vec), +) { + info.insert(id_key, json!(id)); + if !modifiers.is_empty() { + let modifiers = modifiers + .iter() + .map(|m| m.to_string()) + .collect::>() + .join(","); + info.insert(modifiers_key, json!(format!("{{{modifiers}}}"))); + } +} + /// Records the `REFRESH` options among `options` as `refresh` in `info`, one entry per option in /// statement order. fn insert_refresh_strategies<'a, T: AstInfo + 'a>( @@ -563,7 +601,41 @@ pub fn item_details(a: &str) -> Result { info.insert("key_parts", json!(key_parts)); "index" } - CreateType(_) => "type", + // Everything mz_types, mz_base_types, mz_list_types and mz_map_types read. + CreateType(stmt) => { + let (type_kind, category) = match stmt.as_type { + CreateTypeAs::List { options } => { + let element = options + .into_iter() + .find(|o| o.name == CreateTypeListOptionName::ElementType) + .and_then(|o| o.value); + let element = type_option(element, "ELEMENT TYPE")?; + insert_type_reference(&mut info, "element_id", "element_modifiers", element); + ("list", "list") + } + CreateTypeAs::Map { options } => { + let mut key = None; + let mut value = None; + for option in options { + match option.name { + CreateTypeMapOptionName::KeyType => key = option.value, + CreateTypeMapOptionName::ValueType => value = option.value, + } + } + let key = type_option(key, "KEY TYPE")?; + let value = type_option(value, "VALUE TYPE")?; + insert_type_reference(&mut info, "key_id", "key_modifiers", key); + insert_type_reference(&mut info, "value_id", "value_modifiers", value); + ("map", "pseudo") + } + CreateTypeAs::Record { .. } => ("record", "composite"), + }; + info.insert("type_kind", json!(type_kind)); + // Mirrors `TypeCategory::from_catalog_type` in `mz_sql` for the three + // kinds `CREATE TYPE` can produce. + info.insert("category", json!(category)); + "type" + } // NOTE: every statement that creates a catalog item needs an arm above. These // catalog views run this over every item row before their type filter drops the // unwanted rows, so one unclassified `create_sql` takes out `mz_objects`, @@ -2347,4 +2419,73 @@ mod tests { let out = super::item_details(mv_sql_with_replacement).expect("ok"); assert_eq!(out["replacement_target"], json!("u7")); } + + // --- parse_catalog_create_sql, CreateType arm ---------------------------- + + #[mz_ore::test] + fn catalog_type_list() { + let sql = "CREATE TYPE \"materialize\".\"public\".\"int4_list\" \ + AS LIST (ELEMENT TYPE = [s20 AS \"pg_catalog\".\"int4\"])"; + let out = super::item_details(sql).expect("ok"); + assert_eq!( + out, + json!({ + "type": "type", + "type_kind": "list", + "category": "list", + "element_id": "s20", + }) + ); + } + + #[mz_ore::test] + fn catalog_type_list_with_modifiers() { + let sql = "CREATE TYPE \"materialize\".\"public\".\"nums\" \ + AS LIST (ELEMENT TYPE = [s27 AS \"pg_catalog\".\"numeric\"](38, 2))"; + let out = super::item_details(sql).expect("ok"); + assert_eq!(out["element_id"], json!("s27")); + assert_eq!(out["element_modifiers"], json!("{38,2}")); + } + + #[mz_ore::test] + fn catalog_type_map() { + let sql = "CREATE TYPE \"materialize\".\"public\".\"m\" \ + AS MAP (KEY TYPE = [s46 AS \"pg_catalog\".\"text\"], \ + VALUE TYPE = [s27 AS \"pg_catalog\".\"numeric\"](5, 2))"; + let out = super::item_details(sql).expect("ok"); + assert_eq!( + out, + json!({ + "type": "type", + "type_kind": "map", + "category": "pseudo", + "key_id": "s46", + "value_id": "s27", + "value_modifiers": "{5,2}", + }) + ); + } + + #[mz_ore::test] + fn catalog_type_record() { + let sql = "CREATE TYPE \"materialize\".\"public\".\"y1\" \ + AS (\"id\" [s20 AS \"pg_catalog\".\"int4\"], \ + \"name\" [s46 AS \"pg_catalog\".\"text\"])"; + let out = super::item_details(sql).expect("ok"); + assert_eq!( + out, + json!({ + "type": "type", + "type_kind": "record", + "category": "composite", + }) + ); + } + + #[mz_ore::test] + fn catalog_type_unresolved_element_is_an_error() { + let sql = "CREATE TYPE \"materialize\".\"public\".\"l\" AS LIST (ELEMENT TYPE = int4)"; + let err = super::item_details(sql).unwrap_err(); + assert!(err.contains("unresolved item name"), "{err}"); + } } diff --git a/src/catalog/src/builtin.rs b/src/catalog/src/builtin.rs index aabc335507e34..6881638cb76a0 100644 --- a/src/catalog/src/builtin.rs +++ b/src/catalog/src/builtin.rs @@ -1205,20 +1205,20 @@ pub static BUILTINS_STATIC: LazyLock>> = LazyLock::ne Builtin::MaterializedView(&MZ_KAFKA_SOURCE_TABLES), Builtin::MaterializedView(&MZ_SINKS), Builtin::MaterializedView(&MZ_VIEWS), - Builtin::Table(&MZ_TYPES), - Builtin::Table(&MZ_TYPE_PG_METADATA), - Builtin::Table(&MZ_ARRAY_TYPES), - Builtin::Table(&MZ_BASE_TYPES), - Builtin::Table(&MZ_LIST_TYPES), - Builtin::Table(&MZ_MAP_TYPES), + Builtin::MaterializedView(&MZ_TYPES), + Builtin::MaterializedView(&MZ_TYPE_PG_METADATA), + Builtin::MaterializedView(&MZ_ARRAY_TYPES), + Builtin::MaterializedView(&MZ_BASE_TYPES), + Builtin::MaterializedView(&MZ_LIST_TYPES), + Builtin::MaterializedView(&MZ_MAP_TYPES), Builtin::MaterializedView(&MZ_ROLES), Builtin::Table(&MZ_ROLE_AUTH), Builtin::MaterializedView(&MZ_ROLE_MEMBERS), Builtin::MaterializedView(&MZ_ROLE_PARAMETERS), - Builtin::Table(&MZ_PSEUDO_TYPES), - Builtin::Table(&MZ_FUNCTIONS), - Builtin::Table(&MZ_OPERATORS), - Builtin::Table(&MZ_AGGREGATES), + Builtin::MaterializedView(&MZ_PSEUDO_TYPES), + Builtin::MaterializedView(&MZ_FUNCTIONS), + Builtin::MaterializedView(&MZ_OPERATORS), + Builtin::View(&MZ_AGGREGATES), Builtin::Table(&MZ_CLUSTER_REPLICA_SIZES), Builtin::Table(&MZ_CLUSTER_REPLICA_SIZE_INTERNAL), Builtin::MaterializedView(&MZ_CLUSTERS), @@ -1561,7 +1561,8 @@ pub static BUILTINS_STATIC: LazyLock>> = LazyLock::ne // themselves. The real ones are built below. { let ontology_preview = ontology::generate_views(&builtin_items); - let builtin_reporter_preview: Vec<_> = builtin::builtins(&builtin_items).collect(); + let builtin_reporter_preview: Vec<_> = + builtin::builtins(&builtin_types, &builtin_funcs, &builtin_items).collect(); let generator_input: Vec<_> = builtin_types .iter() .chain(builtin_funcs.iter()) @@ -1588,7 +1589,8 @@ pub static BUILTINS_STATIC: LazyLock>> = LazyLock::ne // Generate builtin relations reporting builtin objects last, since they need a complete view // of all other builtins. - let mut builtin_builtins = builtin::builtins(&builtin_items).collect(); + let mut builtin_builtins = + builtin::builtins(&builtin_types, &builtin_funcs, &builtin_items).collect(); // Construct the full list of builtins, retaining dependency order. let mut builtins = Vec::new(); diff --git a/src/catalog/src/builtin/builtin.rs b/src/catalog/src/builtin/builtin.rs index 7590ed90d9009..4c59ba92925ae 100644 --- a/src/catalog/src/builtin/builtin.rs +++ b/src/catalog/src/builtin/builtin.rs @@ -10,28 +10,33 @@ //! Constant builtin views exposing information about builtin objects. use std::borrow::Cow; -use std::collections::BTreeMap; +use std::collections::{BTreeMap, BTreeSet}; use itertools::Itertools; use mz_catalog_protos::objects::CatalogItemType; use mz_ore::collections::CollectionExt; use mz_ore::iter::IteratorExt; use mz_pgrepr::oid; +use mz_repr::adt::char::CharLength; use mz_repr::adt::mz_acl_item::MzAclItem; use mz_repr::namespaces::MZ_INTERNAL_SCHEMA; use mz_repr::{RelationDesc, SqlScalarType}; use mz_sql::ast::Statement; use mz_sql::ast::display::{AstDisplay, escaped_string_literal}; -use mz_sql::catalog::{NameReference, ObjectType}; +use mz_sql::catalog::{CatalogType, NameReference, ObjectType, TypeCategory}; use mz_sql::rbac; use mz_sql::session::user::MZ_SYSTEM_ROLE_ID; -use crate::builtin::{Builtin, BuiltinView, PUBLIC_SELECT, assert_safe_builtin_name}; +use crate::builtin::{Builtin, BuiltinType, BuiltinView, PUBLIC_SELECT, assert_safe_builtin_name}; /// Generate builtin views reporting the given builtins. /// -/// Used in the [`super::BUILTINS_STATIC`] initializer. +/// Used in the [`super::BUILTINS_STATIC`] initializer, which keeps the +/// `Builtin::Type`s in `builtin_types` and the `Builtin::Func`s in +/// `builtin_funcs` apart from the other `builtin_items`. pub(super) fn builtins( + builtin_types: &[Builtin], + builtin_funcs: &[Builtin], builtin_items: &[Builtin], ) -> impl Iterator> { let sources: &'static BuiltinView = Box::leak(Box::new(make_builtin_sources(builtin_items))); @@ -43,6 +48,13 @@ pub(super) fn builtins( Box::leak(Box::new(make_builtin_log_indexes(builtin_items))); let index_columns: &'static BuiltinView = Box::leak(Box::new(make_builtin_index_columns(builtin_items))); + let types: &'static BuiltinView = Box::leak(Box::new(make_builtin_types(builtin_types))); + let functions: &'static BuiltinView = Box::leak(Box::new(make_builtin_functions( + builtin_types, + builtin_funcs, + ))); + let operators: &'static BuiltinView = + Box::leak(Box::new(make_builtin_operators(builtin_types))); // The generated views above, and `mz_builtin_views` itself, are listed in // `mz_builtin_views` with placeholder SQL rather than their real @@ -63,6 +75,9 @@ pub(super) fn builtins( indexes, index_columns, &columns, + types, + functions, + operators, ], ))); make_builtin_columns_sql( @@ -74,6 +89,9 @@ pub(super) fn builtins( tables, indexes, index_columns, + types, + functions, + operators, views, ], &mut columns, @@ -90,6 +108,9 @@ pub(super) fn builtins( indexes, index_columns, columns, + types, + functions, + operators, views, ] .into_iter() @@ -440,6 +461,437 @@ FROM (VALUES {values}) AS v(oid, schema_name, name, col_list, privileges)" } } +/// Generates `mz_internal.mz_builtin_types`, which `mz_catalog.mz_types`, the +/// per-kind `mz_catalog.mz_*_types` views and `mz_internal.mz_type_pg_metadata` +/// read to report builtin types. [`builtin_types_ctes`] is how they join it to +/// catalog ids. +/// +/// `type_kind` names the per-kind view a type belongs to: `array`, `pseudo`, +/// or `base` for everything else, range types included. `element_schema_name` +/// and `element_name` name an array type's element type. `typlen` is NULL for +/// a type with no scalar type, see [`builtin_scalar_type`]. +fn make_builtin_types(builtin_types: &[Builtin]) -> BuiltinView { + let types: Vec<&BuiltinType> = builtin_types + .iter() + .filter_map(|b| match b { + Builtin::Type(t) => Some(*t), + _ => None, + }) + .collect(); + let by_name: BTreeMap<&str, &BuiltinType> = + types.iter().map(|t| (t.name, *t)).collect(); + // The privileges `apply_system_object_mapping_update` grants every builtin + // type. + let privileges = make_privileges_sql( + &[rbac::default_builtin_object_privilege(ObjectType::Type)], + &rbac::owner_privilege(ObjectType::Type, MZ_SYSTEM_ROLE_ID), + ); + let values = types + .iter() + .map(|t| { + assert_safe_builtin_name(t.name, "type"); + let (type_kind, element) = match &t.details.typ { + CatalogType::Array { element_reference } => ("array", Some(*element_reference)), + CatalogType::Pseudo => ("pseudo", None), + // `mz_list_types` and `mz_map_types` read only user-defined + // types, so a builtin list or map would go unreported. + CatalogType::List { .. } | CatalogType::Map { .. } => panic!( + "builtin type {} is a list or map, which mz_builtin_types cannot report", + t.name + ), + _ => ("base", None), + }; + let (element_schema_name, element_name) = match element { + Some(name) => { + let element = by_name.get(name).unwrap_or_else(|| { + panic!( + "builtin type {} references unknown builtin type {name}", + t.name + ) + }); + ( + escaped_string_literal(element.schema).to_string(), + escaped_string_literal(name).to_string(), + ) + } + None => ("NULL::text".to_string(), "NULL::text".to_string()), + }; + let category = TypeCategory::from_catalog_type(&t.details.typ).to_string(); + let (typinput, typreceive, typsend) = match &t.details.pg_metadata { + Some(pg) => ( + format!("{}::oid", pg.typinput_oid), + format!("{}::oid", pg.typreceive_oid), + format!("{}::oid", pg.typsend_oid), + ), + None => ( + "NULL::oid".to_string(), + "NULL::oid".to_string(), + "NULL::oid".to_string(), + ), + }; + let typlen = match builtin_scalar_type(&t.details.typ, &by_name) { + Some(scalar_type) => { + format!("{}::int2", mz_pgrepr::Type::from(&scalar_type).typlen()) + } + None => "NULL::int2".to_string(), + }; + format!( + "({}::oid, {}, {}, {}, '{type_kind}', {privileges}, {element_schema_name}, {element_name}, {typinput}, {typreceive}, {typsend}, {typlen})", + t.oid, + escaped_string_literal(t.schema), + escaped_string_literal(t.name), + escaped_string_literal(&category), + ) + }) + .join(","); + let sql = format!( + " +SELECT oid, schema_name, name, category, type_kind, privileges, element_schema_name, element_name, typinput, typreceive, typsend, typlen +FROM (VALUES {values}) AS v(oid, schema_name, name, category, type_kind, privileges, element_schema_name, element_name, typinput, typreceive, typsend, typlen)" + ); + + BuiltinView { + name: "mz_builtin_types", + schema: MZ_INTERNAL_SCHEMA, + oid: oid::VIEW_MZ_BUILTIN_TYPES_OID, + desc: RelationDesc::builder() + .with_column("oid", SqlScalarType::Oid.nullable(false)) + .with_column("schema_name", SqlScalarType::String.nullable(false)) + .with_column("name", SqlScalarType::String.nullable(false)) + .with_column("category", SqlScalarType::String.nullable(false)) + .with_column("type_kind", SqlScalarType::String.nullable(false)) + .with_column( + "privileges", + SqlScalarType::Array(Box::new(SqlScalarType::MzAclItem)).nullable(false), + ) + .with_column("element_schema_name", SqlScalarType::String.nullable(true)) + .with_column("element_name", SqlScalarType::String.nullable(true)) + .with_column("typinput", SqlScalarType::Oid.nullable(true)) + .with_column("typreceive", SqlScalarType::Oid.nullable(true)) + .with_column("typsend", SqlScalarType::Oid.nullable(true)) + .with_column("typlen", SqlScalarType::Int16.nullable(true)) + // NOTE: The declared keys must exactly match the keys the + // optimizer derives from the generated VALUES list + // (`verify_builtin_descs` enforces this). Builtin type names are + // unique across schemas, which `test_builtins_static_dependency_order` + // asserts, so `name` is a key. + .with_key(vec![0]) + .with_key(vec![2]) + .finish(), + column_comments: Default::default(), + sql: Box::leak(sql.into_boxed_str()), + access: vec![PUBLIC_SELECT], + ontology: None, + } +} + +/// The CTEs through which the type views reach builtin types: `builtin_mappings` +/// maps a builtin type's schema and name to its catalog id via its `GidMapping` +/// record, and `builtin_types` is `mz_builtin_types` extended with that id. +pub(super) fn builtin_types_ctes() -> String { + format!( + "{builtin_mappings}, + builtin_types AS ( + SELECT + m.id, + t.oid, + t.schema_name, + t.name, + t.category, + t.type_kind, + t.privileges, + t.element_schema_name, + t.element_name, + t.typinput, + t.typreceive, + t.typsend, + t.typlen + FROM mz_internal.mz_builtin_types t + JOIN builtin_mappings m USING (schema_name, name) + )", + builtin_mappings = builtin_mappings_cte("builtin_mappings", CatalogItemType::Type) + ) +} + +/// A CTE named `name` that maps the builtins of `item_type` to their catalog +/// ids through their `GidMapping` records, as `(schema_name, name, id)`. +pub(super) fn builtin_mappings_cte(name: &str, item_type: CatalogItemType) -> String { + let object_type = gid_mapping_object_type(item_type); + format!( + "{name} AS ( + SELECT + data->'key'->>'schema_name' AS schema_name, + data->'key'->>'object_name' AS name, + 's' || (data->'value'->>'catalog_id') AS id + FROM mz_internal.mz_catalog_raw + WHERE + data->>'kind' = 'GidMapping' AND + data->'key'->>'object_type' = {object_type} + )" + ) +} + +/// The CTEs through which `mz_functions` and `mz_operators` resolve the type +/// names of `relation`, `mz_internal.mz_builtin_functions` or +/// `mz_internal.mz_builtin_operators`, to catalog ids. `type_mappings` maps a +/// builtin type's name to its id, which is exact because builtin type names +/// are unique across schemas, see [`make_builtin_types`]. `argument_type_ids` +/// maps each row's `oid` to its `argument_type_names` resolved in argument +/// order, with no row for a nullary signature. +pub(super) fn builtin_signature_ctes(relation: &str) -> String { + format!( + "{type_mappings}, + argument_type_ids AS ( + SELECT r.oid, array_agg(t.id ORDER BY a.ordinality) AS argument_type_ids + FROM + {relation} r, + unnest(r.argument_type_names) WITH ORDINALITY AS a (name, ordinality), + type_mappings t + WHERE t.name = a.name + GROUP BY r.oid + )", + type_mappings = builtin_mappings_cte("type_mappings", CatalogItemType::Type) + ) +} + +/// The `SqlScalarType` of a column of the builtin type `typ`, with element +/// references resolved through `by_name`. Mirrors `scalar_type_from_catalog` +/// for the modifier-free builtin types, so that `mz_pgrepr::Type::from` on the +/// result yields the `typlen` pgwire sends for the type. `None` for +/// pseudo-types and containers of them, which have no scalar type. +fn builtin_scalar_type( + typ: &CatalogType, + by_name: &BTreeMap<&str, &BuiltinType>, +) -> Option { + let resolve = |name: &str| { + let element = by_name + .get(name) + .unwrap_or_else(|| panic!("builtin type references unknown builtin type {name}")); + builtin_scalar_type(&element.details.typ, by_name) + }; + Some(match typ { + CatalogType::Pseudo => return None, + CatalogType::Array { element_reference } => { + SqlScalarType::Array(Box::new(resolve(element_reference)?)) + } + CatalogType::Range { element_reference } => SqlScalarType::Range { + element_type: Box::new(resolve(element_reference)?), + }, + // These scalar types carry the catalog id of their defining type, which + // a builtin type does not have statically. + CatalogType::List { .. } | CatalogType::Map { .. } | CatalogType::Record { .. } => { + panic!("builtin types cannot be lists, maps or records") + } + CatalogType::AclItem => SqlScalarType::AclItem, + CatalogType::Bool => SqlScalarType::Bool, + CatalogType::Bytes => SqlScalarType::Bytes, + CatalogType::Char => SqlScalarType::Char { + length: Some(CharLength::ONE), + }, + CatalogType::Date => SqlScalarType::Date, + CatalogType::Float32 => SqlScalarType::Float32, + CatalogType::Float64 => SqlScalarType::Float64, + CatalogType::Int16 => SqlScalarType::Int16, + CatalogType::Int32 => SqlScalarType::Int32, + CatalogType::Int64 => SqlScalarType::Int64, + CatalogType::UInt16 => SqlScalarType::UInt16, + CatalogType::UInt32 => SqlScalarType::UInt32, + CatalogType::UInt64 => SqlScalarType::UInt64, + CatalogType::MzTimestamp => SqlScalarType::MzTimestamp, + CatalogType::Interval => SqlScalarType::Interval, + CatalogType::Jsonb => SqlScalarType::Jsonb, + CatalogType::Numeric => SqlScalarType::Numeric { max_scale: None }, + CatalogType::Oid => SqlScalarType::Oid, + CatalogType::PgLegacyChar => SqlScalarType::PgLegacyChar, + CatalogType::PgLegacyName => SqlScalarType::PgLegacyName, + CatalogType::RegClass => SqlScalarType::RegClass, + CatalogType::RegProc => SqlScalarType::RegProc, + CatalogType::RegType => SqlScalarType::RegType, + CatalogType::String => SqlScalarType::String, + CatalogType::Time => SqlScalarType::Time, + CatalogType::Timestamp => SqlScalarType::Timestamp { precision: None }, + CatalogType::TimestampTz => SqlScalarType::TimestampTz { precision: None }, + CatalogType::Uuid => SqlScalarType::Uuid, + CatalogType::VarChar => SqlScalarType::VarChar { max_length: None }, + CatalogType::Int2Vector => SqlScalarType::Int2Vector, + CatalogType::MzAclItem => SqlScalarType::MzAclItem, + }) +} + +/// Generates `mz_internal.mz_builtin_functions`, one row per implementation of +/// each builtin function, which `mz_catalog.mz_functions` and +/// `mz_internal.mz_aggregates` read. [`builtin_signature_ctes`] is how +/// `mz_functions` resolves the type names it reports to catalog ids. +/// +/// `kind` is the function's [`mz_sql::func::Func::class`]: `scalar`, +/// `aggregate`, `table` or `window`. The argument, variadic and return types +/// are named as the function registry names them, by the builtin type's name +/// without its schema. +fn make_builtin_functions( + builtin_types: &[Builtin], + builtin_funcs: &[Builtin], +) -> BuiltinView { + let type_names = builtin_type_names(builtin_types); + let type_names = &type_names; + let values = builtin_funcs + .iter() + .filter_map(|b| match b { + Builtin::Func(f) => Some(f), + _ => None, + }) + .flat_map(|func| { + assert_safe_builtin_name(func.name, "function"); + let kind = func.inner.class(); + func.inner.func_impls().into_iter().map(move |imp| { + format!( + "({}::oid, {}, {}, '{kind}', {}, {}, {}, {})", + imp.oid, + escaped_string_literal(func.schema), + escaped_string_literal(func.name), + type_names_sql(&imp.arg_typs, type_names), + type_name_sql(imp.variadic_typ, type_names), + type_name_sql(imp.return_typ, type_names), + imp.return_is_set, + ) + }) + }) + .join(","); + let sql = format!( + " +SELECT oid, schema_name, name, kind, argument_type_names, variadic_argument_type_name, return_type_name, returns_set +FROM (VALUES {values}) AS v(oid, schema_name, name, kind, argument_type_names, variadic_argument_type_name, return_type_name, returns_set)" + ); + + BuiltinView { + name: "mz_builtin_functions", + schema: MZ_INTERNAL_SCHEMA, + oid: oid::VIEW_MZ_BUILTIN_FUNCTIONS_OID, + desc: RelationDesc::builder() + .with_column("oid", SqlScalarType::Oid.nullable(false)) + .with_column("schema_name", SqlScalarType::String.nullable(false)) + .with_column("name", SqlScalarType::String.nullable(false)) + .with_column("kind", SqlScalarType::String.nullable(false)) + .with_column( + "argument_type_names", + SqlScalarType::Array(Box::new(SqlScalarType::String)).nullable(false), + ) + .with_column( + "variadic_argument_type_name", + SqlScalarType::String.nullable(true), + ) + .with_column("return_type_name", SqlScalarType::String.nullable(true)) + .with_column("returns_set", SqlScalarType::Bool.nullable(false)) + // NOTE: The declared keys must exactly match the keys the + // optimizer derives from the generated VALUES list + // (`verify_builtin_descs` enforces this). Every implementation has + // its own oid, which `test_compare_builtins_postgres` asserts, so + // `oid` is a key. + .with_key(vec![0]) + .finish(), + column_comments: Default::default(), + sql: Box::leak(sql.into_boxed_str()), + access: vec![PUBLIC_SELECT], + ontology: None, + } +} + +/// Generates `mz_internal.mz_builtin_operators`, one row per implementation of +/// each operator in [`mz_sql::func::OP_IMPLS`], which `mz_catalog.mz_operators` +/// reads. Operators are not catalog items, so they have no `GidMapping` record +/// and no catalog id, and this view is the only place that lists them. +fn make_builtin_operators(builtin_types: &[Builtin]) -> BuiltinView { + let type_names = builtin_type_names(builtin_types); + let type_names = &type_names; + let values = mz_sql::func::OP_IMPLS + .iter() + .flat_map(|(op, func)| { + assert!( + matches!(func, mz_sql::func::Func::Scalar(_)), + "operator {op} is not a scalar function" + ); + func.func_impls().into_iter().map(move |imp| { + format!( + "({}::oid, {}, {}, {})", + imp.oid, + escaped_string_literal(op), + type_names_sql(&imp.arg_typs, type_names), + type_name_sql(imp.return_typ, type_names), + ) + }) + }) + .join(","); + let sql = format!( + " +SELECT oid, name, argument_type_names, return_type_name +FROM (VALUES {values}) AS v(oid, name, argument_type_names, return_type_name)" + ); + + BuiltinView { + name: "mz_builtin_operators", + schema: MZ_INTERNAL_SCHEMA, + oid: oid::VIEW_MZ_BUILTIN_OPERATORS_OID, + desc: RelationDesc::builder() + .with_column("oid", SqlScalarType::Oid.nullable(false)) + .with_column("name", SqlScalarType::String.nullable(false)) + .with_column( + "argument_type_names", + SqlScalarType::Array(Box::new(SqlScalarType::String)).nullable(false), + ) + .with_column("return_type_name", SqlScalarType::String.nullable(false)) + // NOTE: The declared keys must exactly match the keys the + // optimizer derives from the generated VALUES list + // (`verify_builtin_descs` enforces this). Every implementation has + // its own oid, which `test_compare_builtins_postgres` asserts, so + // `oid` is a key. + .with_key(vec![0]) + .finish(), + column_comments: Default::default(), + sql: Box::leak(sql.into_boxed_str()), + access: vec![PUBLIC_SELECT], + ontology: None, + } +} + +/// The names of the builtin types, which the function registry references +/// without a schema. They are unique across schemas, see [`make_builtin_types`]. +fn builtin_type_names(builtin_types: &[Builtin]) -> BTreeSet<&str> { + builtin_types + .iter() + .filter_map(|b| match b { + Builtin::Type(t) => Some(t.name), + _ => None, + }) + .collect() +} + +/// `name` as a SQL string literal, or NULL for no type. A name that is not a +/// builtin type's panics here, since the join in [`builtin_signature_ctes`] +/// would otherwise drop the signature silently. +fn type_name_sql(name: Option<&str>, type_names: &BTreeSet<&str>) -> String { + match name { + Some(name) => { + assert!( + type_names.contains(name), + "function signature references unknown builtin type {name}" + ); + escaped_string_literal(name).to_string() + } + None => "NULL::text".to_string(), + } +} + +/// `names` as a SQL `text[]` literal, see [`type_name_sql`]. +fn type_names_sql(names: &[&str], type_names: &BTreeSet<&str>) -> String { + if names.is_empty() { + return "ARRAY[]::text[]".to_string(); + } + let names = names + .iter() + .map(|name| type_name_sql(Some(name), type_names)) + .join(", "); + format!("ARRAY[{names}]") +} + /// Generates `mz_internal.mz_builtin_views`, listing every builtin view, /// including itself and the `generated` views. /// @@ -460,7 +912,7 @@ FROM (VALUES {values}) AS v(oid, schema_name, name, col_list, privileges)" /// declared keys rely on. fn make_builtin_views( builtin_items: &[Builtin], - generated: [&BuiltinView; 7], + generated: [&BuiltinView; 10], ) -> BuiltinView { let iter = builtin_items.iter().filter_map(|b| match b { Builtin::View(x) => Some(*x), @@ -572,7 +1024,7 @@ fn builtin_columns_view() -> BuiltinView { /// itself. fn make_builtin_columns_sql( builtin_items: &[Builtin], - generated: [&BuiltinView; 7], + generated: [&BuiltinView; 10], columns: &mut BuiltinView, ) { // Map to (schema, relation, desc, is_table) diff --git a/src/catalog/src/builtin/mz_catalog.rs b/src/catalog/src/builtin/mz_catalog.rs index dee649871914b..d2dc7bacbfbe9 100644 --- a/src/catalog/src/builtin/mz_catalog.rs +++ b/src/catalog/src/builtin/mz_catalog.rs @@ -2109,10 +2109,11 @@ SELECT * FROM builtin_mvs").into_boxed_str()), }), } }); -pub static MZ_TYPES: LazyLock = LazyLock::new(|| BuiltinTable { +pub static MZ_TYPES: LazyLock = LazyLock::new(|| { + BuiltinMaterializedView { name: "mz_types", schema: MZ_CATALOG_SCHEMA, - oid: oid::TABLE_MZ_TYPES_OID, + oid: oid::MV_MZ_TYPES_OID, desc: RelationDesc::builder() .with_column("id", SqlScalarType::String.nullable(false)) .with_column("oid", SqlScalarType::Oid.nullable(false)) @@ -2149,6 +2150,56 @@ pub static MZ_TYPES: LazyLock = LazyLock::new(|| BuiltinTable { "The redacted `CREATE` SQL statement for the type.", ), ]), + // Builtin types are reported through `mz_internal.mz_builtin_types`, a + // generated constant view, and take their ids from their `GidMapping` + // records. See `make_builtin_types`. + sql: Box::leak(format!(" +IN CLUSTER mz_catalog_server +WITH ( + ASSERT NOT NULL id, + ASSERT NOT NULL oid, + ASSERT NOT NULL schema_id, + ASSERT NOT NULL name, + ASSERT NOT NULL category, + ASSERT NOT NULL owner_id, + ASSERT NOT NULL privileges +) AS +WITH + user_types AS ( + SELECT + mz_internal.parse_catalog_id(data->'key'->'gid') AS id, + (data->'value'->>'oid')::oid AS oid, + mz_internal.parse_catalog_id(data->'value'->'schema_id') AS schema_id, + data->'value'->>'name' AS name, + mz_internal.parse_catalog_create_sql(data->'value'->'definition'->'V1'->>'create_sql')->>'category' AS category, + mz_internal.parse_catalog_id(data->'value'->'owner_id') AS owner_id, + mz_internal.parse_catalog_privileges(data->'value'->'privileges') AS privileges, + data->'value'->'definition'->'V1'->>'create_sql' AS create_sql, + mz_internal.redact_sql(data->'value'->'definition'->'V1'->>'create_sql') AS redacted_create_sql + FROM mz_internal.mz_catalog_raw + WHERE + data->>'kind' = 'Item' AND + mz_internal.parse_catalog_create_sql(data->'value'->'definition'->'V1'->>'create_sql')->>'type' = 'type' + ), + {builtin_ctes}, + builtin_rows AS ( + SELECT + t.id, + t.oid, + s.id AS schema_id, + t.name, + t.category, + '{MZ_SYSTEM_ROLE_ID}' AS owner_id, + t.privileges, + NULL::text AS create_sql, + NULL::text AS redacted_create_sql + FROM builtin_types t + JOIN mz_schemas s ON s.name = t.schema_name + WHERE s.database_id IS NULL + ) +SELECT * FROM user_types +UNION ALL +SELECT * FROM builtin_rows", builtin_ctes = super::builtin::builtin_types_ctes()).into_boxed_str()), is_retained_metrics_object: false, access: vec![PUBLIC_SELECT], ontology: Some(Ontology { @@ -2179,54 +2230,94 @@ pub static MZ_TYPES: LazyLock = LazyLock::new(|| BuiltinTable { ] }, }), +} }); -pub static MZ_ARRAY_TYPES: LazyLock = LazyLock::new(|| BuiltinTable { - name: "mz_array_types", - schema: MZ_CATALOG_SCHEMA, - oid: oid::TABLE_MZ_ARRAY_TYPES_OID, - desc: RelationDesc::builder() - .with_column("id", SqlScalarType::String.nullable(false)) - .with_column("element_id", SqlScalarType::String.nullable(false)) - .finish(), - column_comments: BTreeMap::from_iter([ - ("id", "The ID of the array type."), - ("element_id", "The ID of the array's element type."), - ]), - is_retained_metrics_object: false, - access: vec![PUBLIC_SELECT], - ontology: Some(Ontology { - entity_name: "array_type", - description: "An array type with its element type", - links: &const { - [ - OntologyLink { - name: "detail_of", - target: "type", - properties: LinkProperties::fk("id", "id", Cardinality::OneToOne), - }, - OntologyLink { - name: "has_element_type", - target: "type", - properties: LinkProperties::fk("element_id", "id", Cardinality::ManyToOne), - }, - ] - }, - column_semantic_types: &const { - [ - ("id", SemanticType::CatalogItemId), - ("element_id", SemanticType::CatalogItemId), - ] - }, - }), -}); -pub static MZ_BASE_TYPES: LazyLock = LazyLock::new(|| BuiltinTable { +pub static MZ_ARRAY_TYPES: LazyLock = + LazyLock::new(|| BuiltinMaterializedView { + name: "mz_array_types", + schema: MZ_CATALOG_SCHEMA, + oid: oid::MV_MZ_ARRAY_TYPES_OID, + desc: RelationDesc::builder() + .with_column("id", SqlScalarType::String.nullable(false)) + .with_column("element_id", SqlScalarType::String.nullable(false)) + .finish(), + column_comments: BTreeMap::from_iter([ + ("id", "The ID of the array type."), + ("element_id", "The ID of the array's element type."), + ]), + // `CREATE TYPE` creates list, map and record types (`plan_create_type`), + // so every array type is builtin. + sql: Box::leak( + format!( + " +IN CLUSTER mz_catalog_server +WITH ( + ASSERT NOT NULL id, + ASSERT NOT NULL element_id +) AS +WITH + {builtin_ctes} +SELECT t.id, e.id AS element_id +FROM builtin_types t +JOIN builtin_mappings e ON e.schema_name = t.element_schema_name AND e.name = t.element_name +WHERE t.type_kind = 'array'", + builtin_ctes = super::builtin::builtin_types_ctes() + ) + .into_boxed_str(), + ), + is_retained_metrics_object: false, + access: vec![PUBLIC_SELECT], + ontology: Some(Ontology { + entity_name: "array_type", + description: "An array type with its element type", + links: &const { + [ + OntologyLink { + name: "detail_of", + target: "type", + properties: LinkProperties::fk("id", "id", Cardinality::OneToOne), + }, + OntologyLink { + name: "has_element_type", + target: "type", + properties: LinkProperties::fk("element_id", "id", Cardinality::ManyToOne), + }, + ] + }, + column_semantic_types: &const { + [ + ("id", SemanticType::CatalogItemId), + ("element_id", SemanticType::CatalogItemId), + ] + }, + }), + }); +pub static MZ_BASE_TYPES: LazyLock = LazyLock::new(|| { + BuiltinMaterializedView { name: "mz_base_types", schema: MZ_CATALOG_SCHEMA, - oid: oid::TABLE_MZ_BASE_TYPES_OID, + oid: oid::MV_MZ_BASE_TYPES_OID, desc: RelationDesc::builder() .with_column("id", SqlScalarType::String.nullable(false)) .finish(), column_comments: BTreeMap::from_iter([("id", "The ID of the type.")]), + // A user-defined record type has no per-kind relation of its own and is + // reported as a base type. + sql: Box::leak(format!(" +IN CLUSTER mz_catalog_server +WITH (ASSERT NOT NULL id) AS +WITH + {builtin_ctes}, + user_items AS ( + SELECT + mz_internal.parse_catalog_id(data->'key'->'gid') AS id, + mz_internal.parse_catalog_create_sql(data->'value'->'definition'->'V1'->>'create_sql') AS parsed + FROM mz_internal.mz_catalog_raw + WHERE data->>'kind' = 'Item' + ) +SELECT id FROM builtin_types WHERE type_kind = 'base' +UNION ALL +SELECT id FROM user_items WHERE parsed->>'type' = 'type' AND parsed->>'type_kind' = 'record'", builtin_ctes = super::builtin::builtin_types_ctes()).into_boxed_str()), is_retained_metrics_object: false, access: vec![PUBLIC_SELECT], ontology: Some(Ontology { @@ -2235,11 +2326,13 @@ pub static MZ_BASE_TYPES: LazyLock = LazyLock::new(|| BuiltinTable links: &const { [] }, column_semantic_types: &[("id", SemanticType::CatalogItemId)], }), +} }); -pub static MZ_LIST_TYPES: LazyLock = LazyLock::new(|| BuiltinTable { +pub static MZ_LIST_TYPES: LazyLock = LazyLock::new(|| { + BuiltinMaterializedView { name: "mz_list_types", schema: MZ_CATALOG_SCHEMA, - oid: oid::TABLE_MZ_LIST_TYPES_OID, + oid: oid::MV_MZ_LIST_TYPES_OID, desc: RelationDesc::builder() .with_column("id", SqlScalarType::String.nullable(false)) .with_column("element_id", SqlScalarType::String.nullable(false)) @@ -2260,6 +2353,28 @@ pub static MZ_LIST_TYPES: LazyLock = LazyLock::new(|| BuiltinTable "The element type modifiers, or `NULL` if none.", ), ]), + // Every list type is user-defined: `make_builtin_types` asserts that no + // builtin type is a list or a map. + sql: " +IN CLUSTER mz_catalog_server +WITH ( + ASSERT NOT NULL id, + ASSERT NOT NULL element_id +) AS +WITH + user_items AS ( + SELECT + mz_internal.parse_catalog_id(data->'key'->'gid') AS id, + mz_internal.parse_catalog_create_sql(data->'value'->'definition'->'V1'->>'create_sql') AS parsed + FROM mz_internal.mz_catalog_raw + WHERE data->>'kind' = 'Item' + ) +SELECT + id, + parsed->>'element_id' AS element_id, + (parsed->>'element_modifiers')::bigint list AS element_modifiers +FROM user_items +WHERE parsed->>'type' = 'type' AND parsed->>'type_kind' = 'list'", is_retained_metrics_object: false, access: vec![PUBLIC_SELECT], ontology: Some(Ontology { @@ -2286,11 +2401,13 @@ pub static MZ_LIST_TYPES: LazyLock = LazyLock::new(|| BuiltinTable ] }, }), +} }); -pub static MZ_MAP_TYPES: LazyLock = LazyLock::new(|| BuiltinTable { +pub static MZ_MAP_TYPES: LazyLock = LazyLock::new(|| { + BuiltinMaterializedView { name: "mz_map_types", schema: MZ_CATALOG_SCHEMA, - oid: oid::TABLE_MZ_MAP_TYPES_OID, + oid: oid::MV_MZ_MAP_TYPES_OID, desc: RelationDesc::builder() .with_column("id", SqlScalarType::String.nullable(false)) .with_column("key_id", SqlScalarType::String.nullable(false)) @@ -2325,6 +2442,31 @@ pub static MZ_MAP_TYPES: LazyLock = LazyLock::new(|| BuiltinTable "The value type modifiers, or `NULL` if none.", ), ]), + // Every map type is user-defined: `make_builtin_types` asserts that no + // builtin type is a list or a map. + sql: " +IN CLUSTER mz_catalog_server +WITH ( + ASSERT NOT NULL id, + ASSERT NOT NULL key_id, + ASSERT NOT NULL value_id +) AS +WITH + user_items AS ( + SELECT + mz_internal.parse_catalog_id(data->'key'->'gid') AS id, + mz_internal.parse_catalog_create_sql(data->'value'->'definition'->'V1'->>'create_sql') AS parsed + FROM mz_internal.mz_catalog_raw + WHERE data->>'kind' = 'Item' + ) +SELECT + id, + parsed->>'key_id' AS key_id, + parsed->>'value_id' AS value_id, + (parsed->>'key_modifiers')::bigint list AS key_modifiers, + (parsed->>'value_modifiers')::bigint list AS value_modifiers +FROM user_items +WHERE parsed->>'type' = 'type' AND parsed->>'type_kind' = 'map'", is_retained_metrics_object: false, access: vec![PUBLIC_SELECT], ontology: Some(Ontology { @@ -2357,6 +2499,7 @@ pub static MZ_MAP_TYPES: LazyLock = LazyLock::new(|| BuiltinTable ] }, }), +} }); pub static MZ_ROLES: LazyLock = LazyLock::new(|| { // The two built-in super-roles are identified by name; their names live as @@ -2595,28 +2738,43 @@ pub static MZ_ROLE_AUTH: LazyLock = LazyLock::new(|| BuiltinTable access: vec![rbac::owner_privilege(ObjectType::Table, MZ_SYSTEM_ROLE_ID)], ontology: None, }); -pub static MZ_PSEUDO_TYPES: LazyLock = LazyLock::new(|| BuiltinTable { - name: "mz_pseudo_types", - schema: MZ_CATALOG_SCHEMA, - oid: oid::TABLE_MZ_PSEUDO_TYPES_OID, - desc: RelationDesc::builder() - .with_column("id", SqlScalarType::String.nullable(false)) - .finish(), - column_comments: BTreeMap::from_iter([("id", "The ID of the type.")]), - is_retained_metrics_object: false, - access: vec![PUBLIC_SELECT], - ontology: Some(Ontology { - entity_name: "pseudo_type", - description: "A pseudo-type used in function signatures", - links: &const { [] }, - column_semantic_types: &[("id", SemanticType::CatalogItemId)], - }), -}); -pub static MZ_FUNCTIONS: LazyLock = LazyLock::new(|| { - BuiltinTable { +pub static MZ_PSEUDO_TYPES: LazyLock = + LazyLock::new(|| BuiltinMaterializedView { + name: "mz_pseudo_types", + schema: MZ_CATALOG_SCHEMA, + oid: oid::MV_MZ_PSEUDO_TYPES_OID, + desc: RelationDesc::builder() + .with_column("id", SqlScalarType::String.nullable(false)) + .finish(), + column_comments: BTreeMap::from_iter([("id", "The ID of the type.")]), + // `CREATE TYPE` cannot create a pseudo-type, so every pseudo-type is + // builtin. + sql: Box::leak( + format!( + " +IN CLUSTER mz_catalog_server +WITH (ASSERT NOT NULL id) AS +WITH + {builtin_ctes} +SELECT id FROM builtin_types WHERE type_kind = 'pseudo'", + builtin_ctes = super::builtin::builtin_types_ctes() + ) + .into_boxed_str(), + ), + is_retained_metrics_object: false, + access: vec![PUBLIC_SELECT], + ontology: Some(Ontology { + entity_name: "pseudo_type", + description: "A pseudo-type used in function signatures", + links: &const { [] }, + column_semantic_types: &[("id", SemanticType::CatalogItemId)], + }), + }); +pub static MZ_FUNCTIONS: LazyLock = LazyLock::new(|| { + BuiltinMaterializedView { name: "mz_functions", schema: MZ_CATALOG_SCHEMA, - oid: oid::TABLE_MZ_FUNCTIONS_OID, + oid: oid::MV_MZ_FUNCTIONS_OID, desc: RelationDesc::builder() .with_column("id", SqlScalarType::String.nullable(false)) // not a key! .with_column("oid", SqlScalarType::Oid.nullable(false)) @@ -2663,6 +2821,49 @@ pub static MZ_FUNCTIONS: LazyLock = LazyLock::new(|| { "The role ID of the owner of the function. Corresponds to `mz_roles.id`.", ), ]), + // Every function is builtin, there is no `CREATE FUNCTION`. The rows + // come from `mz_internal.mz_builtin_functions`, a generated constant + // view, with ids from each function's `GidMapping` record and type + // ids from the types' records. See `make_builtin_functions`. + sql: Box::leak( + format!( + " +IN CLUSTER mz_catalog_server +WITH ( + ASSERT NOT NULL id, + ASSERT NOT NULL oid, + ASSERT NOT NULL schema_id, + ASSERT NOT NULL name, + ASSERT NOT NULL argument_type_ids, + ASSERT NOT NULL returns_set, + ASSERT NOT NULL owner_id +) AS +WITH + {signature_ctes}, + {func_mappings} +SELECT + m.id, + f.oid, + s.id AS schema_id, + f.name, + COALESCE(a.argument_type_ids, ARRAY[]::text[]) AS argument_type_ids, + v.id AS variadic_argument_type_id, + r.id AS return_type_id, + f.returns_set, + '{MZ_SYSTEM_ROLE_ID}' AS owner_id +FROM mz_internal.mz_builtin_functions f +JOIN func_mappings m ON m.schema_name = f.schema_name AND m.name = f.name +JOIN mz_catalog.mz_schemas s ON s.name = f.schema_name AND s.database_id IS NULL +LEFT JOIN argument_type_ids a ON a.oid = f.oid +LEFT JOIN type_mappings v ON v.name = f.variadic_argument_type_name +LEFT JOIN type_mappings r ON r.name = f.return_type_name", + signature_ctes = + super::builtin::builtin_signature_ctes("mz_internal.mz_builtin_functions"), + func_mappings = + super::builtin::builtin_mappings_cte("func_mappings", CatalogItemType::Func), + ) + .into_boxed_str(), + ), is_retained_metrics_object: false, access: vec![PUBLIC_SELECT], ontology: Some(Ontology { @@ -2713,44 +2914,72 @@ pub static MZ_FUNCTIONS: LazyLock = LazyLock::new(|| { }), } }); -pub static MZ_OPERATORS: LazyLock = LazyLock::new(|| BuiltinTable { - name: "mz_operators", - schema: MZ_CATALOG_SCHEMA, - oid: oid::TABLE_MZ_OPERATORS_OID, - desc: RelationDesc::builder() - .with_column("oid", SqlScalarType::Oid.nullable(false)) - .with_column("name", SqlScalarType::String.nullable(false)) - .with_column( - "argument_type_ids", - SqlScalarType::Array(Box::new(SqlScalarType::String)).nullable(false), - ) - .with_column("return_type_id", SqlScalarType::String.nullable(true)) - .finish(), - column_comments: BTreeMap::new(), - is_retained_metrics_object: false, - access: vec![PUBLIC_SELECT], - ontology: Some(Ontology { - entity_name: "operator", - description: "A built-in SQL operator", - links: &const { - [OntologyLink { - name: "returns_type", - target: "type", - properties: LinkProperties::fk_nullable( - "return_type_id", - "id", - Cardinality::ManyToOne, - ), - }] - }, - column_semantic_types: &const { - [ - ("oid", SemanticType::OID), - ("return_type_id", SemanticType::CatalogItemId), - ] - }, - }), -}); +pub static MZ_OPERATORS: LazyLock = + LazyLock::new(|| BuiltinMaterializedView { + name: "mz_operators", + schema: MZ_CATALOG_SCHEMA, + oid: oid::MV_MZ_OPERATORS_OID, + desc: RelationDesc::builder() + .with_column("oid", SqlScalarType::Oid.nullable(false)) + .with_column("name", SqlScalarType::String.nullable(false)) + .with_column( + "argument_type_ids", + SqlScalarType::Array(Box::new(SqlScalarType::String)).nullable(false), + ) + .with_column("return_type_id", SqlScalarType::String.nullable(true)) + .finish(), + column_comments: BTreeMap::new(), + // Operators come from `mz_internal.mz_builtin_operators`, a generated + // constant view, with type ids from the types' `GidMapping` records. See + // `make_builtin_operators`. + sql: Box::leak( + format!( + " +IN CLUSTER mz_catalog_server +WITH ( + ASSERT NOT NULL oid, + ASSERT NOT NULL name, + ASSERT NOT NULL argument_type_ids +) AS +WITH + {signature_ctes} +SELECT + o.oid, + o.name, + a.argument_type_ids, + r.id AS return_type_id +FROM mz_internal.mz_builtin_operators o +JOIN argument_type_ids a ON a.oid = o.oid +LEFT JOIN type_mappings r ON r.name = o.return_type_name", + signature_ctes = + super::builtin::builtin_signature_ctes("mz_internal.mz_builtin_operators"), + ) + .into_boxed_str(), + ), + is_retained_metrics_object: false, + access: vec![PUBLIC_SELECT], + ontology: Some(Ontology { + entity_name: "operator", + description: "A built-in SQL operator", + links: &const { + [OntologyLink { + name: "returns_type", + target: "type", + properties: LinkProperties::fk_nullable( + "return_type_id", + "id", + Cardinality::ManyToOne, + ), + }] + }, + column_semantic_types: &const { + [ + ("oid", SemanticType::OID), + ("return_type_id", SemanticType::CatalogItemId), + ] + }, + }), + }); pub static MZ_CLUSTERS: LazyLock = LazyLock::new(|| { BuiltinMaterializedView { diff --git a/src/catalog/src/builtin/mz_internal.rs b/src/catalog/src/builtin/mz_internal.rs index 51b8c5718ce65..0a2bbbdb563c1 100644 --- a/src/catalog/src/builtin/mz_internal.rs +++ b/src/catalog/src/builtin/mz_internal.rs @@ -682,38 +682,67 @@ WHERE data->>'kind' = 'NetworkPolicy'", }); /// PostgreSQL-specific metadata about types that doesn't make sense to expose -/// in the `mz_types` table as part of our public, stable API. -pub static MZ_TYPE_PG_METADATA: LazyLock = LazyLock::new(|| BuiltinTable { - name: "mz_type_pg_metadata", - schema: MZ_INTERNAL_SCHEMA, - oid: oid::TABLE_MZ_TYPE_PG_METADATA_OID, - desc: RelationDesc::builder() - .with_column("id", SqlScalarType::String.nullable(false)) - .with_column("typinput", SqlScalarType::Oid.nullable(false)) - .with_column("typreceive", SqlScalarType::Oid.nullable(false)) - // NOTE: `pg_type_all_databases` still needs `COALESCE` on this column, - // because its `LEFT JOIN` against this table yields NULLs for types with - // no PostgreSQL metadata. - .with_column("typsend", SqlScalarType::Oid.nullable(false)) - // NULL for pseudo-types and arrays of them. - .with_column("typlen", SqlScalarType::Int16.nullable(true)) - .finish(), - column_comments: BTreeMap::new(), - is_retained_metrics_object: false, - access: vec![PUBLIC_SELECT], - ontology: None, -}); -pub static MZ_AGGREGATES: LazyLock = LazyLock::new(|| BuiltinTable { +/// in `mz_types` as part of our public, stable API. +pub static MZ_TYPE_PG_METADATA: LazyLock = + LazyLock::new(|| BuiltinMaterializedView { + name: "mz_type_pg_metadata", + schema: MZ_INTERNAL_SCHEMA, + oid: oid::MV_MZ_TYPE_PG_METADATA_OID, + desc: RelationDesc::builder() + .with_column("id", SqlScalarType::String.nullable(false)) + .with_column("typinput", SqlScalarType::Oid.nullable(false)) + .with_column("typreceive", SqlScalarType::Oid.nullable(false)) + // NOTE: `pg_type_all_databases` still needs `COALESCE` on this column, + // because its `LEFT JOIN` against this table yields NULLs for types with + // no PostgreSQL metadata. + .with_column("typsend", SqlScalarType::Oid.nullable(false)) + // NULL for pseudo-types and arrays of them. + .with_column("typlen", SqlScalarType::Int16.nullable(true)) + .finish(), + column_comments: BTreeMap::new(), + // User-defined types carry no PostgreSQL metadata. A builtin type has + // either all three function oids or none (`CatalogTypePgMetadata`), so + // `typinput` stands in for the whole record. + sql: Box::leak( + format!( + " +IN CLUSTER mz_catalog_server +WITH ( + ASSERT NOT NULL id, + ASSERT NOT NULL typinput, + ASSERT NOT NULL typreceive, + ASSERT NOT NULL typsend +) AS +WITH + {builtin_ctes} +SELECT id, typinput, typreceive, typsend, typlen +FROM builtin_types +WHERE typinput IS NOT NULL", + builtin_ctes = super::builtin::builtin_types_ctes() + ) + .into_boxed_str(), + ), + is_retained_metrics_object: false, + access: vec![PUBLIC_SELECT], + ontology: None, + }); +pub static MZ_AGGREGATES: LazyLock = LazyLock::new(|| BuiltinView { name: "mz_aggregates", schema: MZ_INTERNAL_SCHEMA, - oid: oid::TABLE_MZ_AGGREGATES_OID, + oid: oid::VIEW_MZ_AGGREGATES_OID, desc: RelationDesc::builder() .with_column("oid", SqlScalarType::Oid.nullable(false)) .with_column("agg_kind", SqlScalarType::String.nullable(false)) .with_column("agg_num_direct_args", SqlScalarType::Int16.nullable(false)) + .with_key(vec![0]) .finish(), column_comments: BTreeMap::new(), - is_retained_metrics_object: false, + // TODO(database-issues#1064): Support ordered-set aggregate functions, + // which have an agg_kind of 'o' and direct arguments. + sql: " +SELECT oid, 'n' AS agg_kind, 0::int2 AS agg_num_direct_args +FROM mz_internal.mz_builtin_functions +WHERE kind = 'aggregate'", access: vec![PUBLIC_SELECT], ontology: Some(Ontology { entity_name: "aggregate", diff --git a/src/catalog/src/builtin/pg_catalog.rs b/src/catalog/src/builtin/pg_catalog.rs index 72f2a52511484..2fd0d495940b4 100644 --- a/src/catalog/src/builtin/pg_catalog.rs +++ b/src/catalog/src/builtin/pg_catalog.rs @@ -2493,6 +2493,7 @@ pub static PG_AGGREGATE: LazyLock = LazyLock::new(|| BuiltinView { .with_column("aggmtransspace", SqlScalarType::Int32.nullable(true)) .with_column("agginitval", SqlScalarType::String.nullable(true)) .with_column("aggminitval", SqlScalarType::String.nullable(true)) + .with_key(vec![0]) .finish(), column_comments: BTreeMap::new(), sql: "SELECT diff --git a/src/pgrepr-consts/src/oid.rs b/src/pgrepr-consts/src/oid.rs index 3f26b5ecaf697..8f5cf93ee2caa 100644 --- a/src/pgrepr-consts/src/oid.rs +++ b/src/pgrepr-consts/src/oid.rs @@ -436,18 +436,18 @@ pub const MV_MZ_SOURCES_OID: u32 = 16710; pub const MV_MZ_SINKS_OID: u32 = 16711; pub const MV_MZ_VIEWS_OID: u32 = 16712; pub const MV_MZ_MATERIALIZED_VIEWS_OID: u32 = 16713; -pub const TABLE_MZ_TYPES_OID: u32 = 16714; -pub const TABLE_MZ_TYPE_PG_METADATA_OID: u32 = 16715; -pub const TABLE_MZ_ARRAY_TYPES_OID: u32 = 16716; -pub const TABLE_MZ_BASE_TYPES_OID: u32 = 16717; -pub const TABLE_MZ_LIST_TYPES_OID: u32 = 16718; -pub const TABLE_MZ_MAP_TYPES_OID: u32 = 16719; +pub const MV_MZ_TYPES_OID: u32 = 16714; +pub const MV_MZ_TYPE_PG_METADATA_OID: u32 = 16715; +pub const MV_MZ_ARRAY_TYPES_OID: u32 = 16716; +pub const MV_MZ_BASE_TYPES_OID: u32 = 16717; +pub const MV_MZ_LIST_TYPES_OID: u32 = 16718; +pub const MV_MZ_MAP_TYPES_OID: u32 = 16719; pub const MV_MZ_ROLES_OID: u32 = 16720; pub const MV_MZ_ROLE_MEMBERS_OID: u32 = 16721; -pub const TABLE_MZ_PSEUDO_TYPES_OID: u32 = 16722; -pub const TABLE_MZ_FUNCTIONS_OID: u32 = 16723; -pub const TABLE_MZ_OPERATORS_OID: u32 = 16724; -pub const TABLE_MZ_AGGREGATES_OID: u32 = 16725; +pub const MV_MZ_PSEUDO_TYPES_OID: u32 = 16722; +pub const MV_MZ_FUNCTIONS_OID: u32 = 16723; +pub const MV_MZ_OPERATORS_OID: u32 = 16724; +pub const VIEW_MZ_AGGREGATES_OID: u32 = 16725; pub const MV_MZ_CLUSTERS_OID: u32 = 16726; pub const MV_MZ_SECRETS_OID: u32 = 16727; pub const MV_MZ_CLUSTER_REPLICAS_OID: u32 = 16728; @@ -847,3 +847,6 @@ pub const FUNC_LIST_GTE_OID: u32 = 17137; pub const FUNC_JQ_OID: u32 = 17138; pub const VIEW_MZ_BUILTIN_COLUMNS_OID: u32 = 17139; pub const VIEW_MZ_BUILTIN_INDEX_COLUMNS_OID: u32 = 17140; +pub const VIEW_MZ_BUILTIN_TYPES_OID: u32 = 17141; +pub const VIEW_MZ_BUILTIN_FUNCTIONS_OID: u32 = 17142; +pub const VIEW_MZ_BUILTIN_OPERATORS_OID: u32 = 17143; diff --git a/test/sqllogictest/autogenerated/mz_internal.slt b/test/sqllogictest/autogenerated/mz_internal.slt index 2f63ad056c1eb..0fbdf8090efaa 100644 --- a/test/sqllogictest/autogenerated/mz_internal.slt +++ b/test/sqllogictest/autogenerated/mz_internal.slt @@ -813,12 +813,15 @@ mz_aws_connections mz_aws_privatelink_connection_status_history mz_aws_privatelink_connection_statuses mz_builtin_columns +mz_builtin_functions mz_builtin_index_columns mz_builtin_indexes mz_builtin_log_indexes mz_builtin_materialized_views +mz_builtin_operators mz_builtin_sources mz_builtin_tables +mz_builtin_types mz_builtin_views mz_catalog_raw mz_cluster_auto_scaling_strategies diff --git a/test/sqllogictest/catalog_server_explain.slt b/test/sqllogictest/catalog_server_explain.slt index 9a50baffe0401..74337be9cfb0b 100644 --- a/test/sqllogictest/catalog_server_explain.slt +++ b/test/sqllogictest/catalog_server_explain.slt @@ -4596,6 +4596,30 @@ Target cluster: mz_catalog_server EOF +query T multiline +EXPLAIN MATERIALIZED VIEW "mz_catalog"."mz_array_types"; +---- +mz_catalog.mz_array_types: + →With + cte l0 = + →Arrange (#0{schema_name}, #1{name}) + →Read mz_internal.mz_catalog_raw + →Return + →Delta Join [%0[#0{schema_name}, #1{name}] » %1:l0[#0{schema_name}, #1{name}] » %2:l0[#0{schema_name}, #1{name}]] [%1:l0[#0{schema_name}, #1{name}] » %0[#0{schema_name}, #1{name}] » %2:l0[#0{schema_name}, #1{name}]] [%2:l0[#0{schema_name}, #1{name}] » %0[#2{element_schema_name}, #3{element_name}] » %1:l0[#0{schema_name}, #1{name}]] + →Arrange (#0{schema_name}, #1{name}) (#2{element_schema_name}, #3{element_name}) + →Constant (38 rows) + →Arranged l0 + →Arranged l0 + +Source mz_internal.mz_catalog_raw + project=(#3, #2, #4) + filter=(("GidMapping" = (#0{data} ->> "kind")) AND ("7" = (#1 ->> "object_type")) AND (#2) IS NOT NULL AND (#3) IS NOT NULL) + map=((#0{data} -> "key"), (#1 ->> "object_name"), (#1 ->> "schema_name"), ("s" || ((#0{data} -> "value") ->> "catalog_id"))) + +Target cluster: mz_catalog_server + +EOF + query T multiline EXPLAIN MATERIALIZED VIEW "mz_catalog"."mz_audit_events"; ---- @@ -4621,6 +4645,34 @@ Target cluster: mz_catalog_server EOF +query T multiline +EXPLAIN MATERIALIZED VIEW "mz_catalog"."mz_base_types"; +---- +mz_catalog.mz_base_types: + →Union + →Differential Join %0[#0{schema_name}, #1{name}] » %1:mz_catalog_raw[#0{schema_name}, #1{name}] + →Arrange (#0{schema_name}, #1{name}) + →Constant (37 rows) + →Arrange (#0{schema_name}, #1{name}) + →Fused with Child Map/Filter/Project + Project: #4, #3, #5 + Filter: ("7" = (#0 ->> "object_type")) AND ("GidMapping" = #2) AND (#3) IS NOT NULL AND (#4) IS NOT NULL + Map: (#0 ->> "object_name"), (#0 ->> "schema_name"), ("s" || (#1 ->> "catalog_id")) + →Read mz_internal.mz_catalog_raw + →Fused with Child Map/Filter/Project + Project: #4 + Filter: ("Item" = #2) AND ("type" = (#3 ->> "type")) AND ("record" = (#3 ->> "type_kind")) + Map: parse_catalog_create_sql((((#1 -> "definition") -> "V1") ->> "create_sql")), parse_catalog_id((#0 -> "gid")) + →Read mz_internal.mz_catalog_raw + +Source mz_internal.mz_catalog_raw + project=(#1..=#3) + map=((#0{data} -> "key"), (#0{data} -> "value"), (#0{data} ->> "kind")) + +Target cluster: mz_catalog_server + +EOF + query T multiline EXPLAIN MATERIALIZED VIEW "mz_catalog"."mz_cluster_replicas"; ---- @@ -4930,7 +4982,7 @@ mz_catalog.mz_columns: →Read l1 →Differential Join %1:mz_catalog_raw[#1{schema_name}, #2{name}] » %0[#0{schema_name}, #1{relation_name}] →Arrange (#0{schema_name}, #1{relation_name}) - →Constant (1937 rows) + →Constant (1961 rows) →Arrange (#1{schema_name}, #2{name}) →Fused with Child Map/Filter/Project Project: #6, #4, #3 @@ -4991,6 +5043,172 @@ Target cluster: mz_catalog_server EOF +query T multiline +EXPLAIN MATERIALIZED VIEW "mz_catalog"."mz_functions"; +---- +mz_catalog.mz_functions: + →With + cte l0 = + →Delta Join [%0[#1{schema_name}, #2{name}] » %1:mz_catalog_raw[#0{schema_name}, #1{name}] » %2:mz_schemas[#1{name}]] [%1:mz_catalog_raw[#0{schema_name}] » %0[#1{schema_name}, #2{name}] » %2:mz_schemas[#1{name}]] [%2:mz_schemas[#1{name}] » %1:mz_catalog_raw[#0{schema_name}] » %0[#1{schema_name}, #2{name}]] + →Arrange (#1{schema_name}, #2{name}) + →Constant (639 rows) + →Arrange (#0{schema_name}) (#0{schema_name}, #1{name}) + →Fused with Child Map/Filter/Project + Project: #4, #3, #5 + Filter: ("8" = #2) AND (#4) IS NOT NULL + Map: (#1 ->> "schema_name"), ("s" || ((#0{data} -> "value") ->> "catalog_id")) + →Read mz_internal.mz_catalog_raw + →Arrange (#1{name}) + →Fused with Child Map/Filter/Project + Project: #1, #3 + Filter: (#0{database_id}) IS NULL + →Arranged mz_catalog.mz_schemas + Key: (#2{database_id}) + cte l1 = + →Non-incremental GroupAggregate + Aggregation: array_agg[order_by=[#0 asc nulls_last]](row(array[#2{id}], #1{ordinality})) + Key: + Project: #0 + →Differential Join %1:mz_catalog_raw[#0{name}] » %0[#1{name}] + →Arrange (#1{name}) + →Constant (937 rows) + →Arrange (#0{name}) + →Fused with Child Map/Filter/Project + Project: #3, #4 + Filter: ("7" = #2) + Map: ("s" || ((#0{data} -> "value") ->> "catalog_id")) + →Read mz_internal.mz_catalog_raw + cte l2 = + →Union + →Fused with Child Map/Filter/Project + Project: #2, #3 + →Read l0 + →Constant (1 row) + cte l3 = + →Negate Diffs + →Fused with Child Map/Filter/Project + Project: #3 + Filter: ("7" = #2) + →Read mz_internal.mz_catalog_raw + cte l4 = + →Fused with Child Map/Filter/Project + Project: #3..=#5 + Filter: ("7" = #2) + Map: ("s" || ((#0{data} -> "value") ->> "catalog_id")), true + →Read mz_internal.mz_catalog_raw + →Return + →Delta Join [%0:l0[#0] » %1[#0] » %2[#0] » %3[#0]] [%1[#0] » %0:l0[#0] » %2[#0] » %3[#0]] [%2[#0] » %0:l0[#2] » %1[#0] » %3[#0]] [%3[#0] » %0:l0[#3] » %1[#0] » %2[#0]] + path %0: + after %1: + Project: #0..=#6, #9 + Map: case when (#8) IS NULL then {} else coalesce(#7, {}) end + after %2: + Project: #1..=#7, #10 + Map: case when (#9) IS NULL then null else #8 end + after %3: + Project: #1..=#7, #10 + Map: case when (#9) IS NULL then null else #8 end + Final closure: + Project: #3, #0, #4, #1, #5..=#7, #2, #8 + Map: "s1" + path %1: + after %2: + Project: #1..=#7, #10 + Map: case when (#9) IS NULL then null else #8 end + after %3: + Project: #1..=#7, #10 + Map: case when (#9) IS NULL then null else #8 end + Final closure: + Project: #3, #0, #4, #1, #5..=#7, #2, #8 + Map: "s1" + path %2: + after %1: + Project: #0..=#6, #9 + Map: case when (#8) IS NULL then {} else coalesce(#7, {}) end + after %3: + Project: #1..=#7, #10 + Map: case when (#9) IS NULL then null else #8 end + Final closure: + Project: #3, #0, #4, #1, #6, #5, #7, #2, #8 + Map: "s1" + path %3: + after %1: + Project: #0..=#6, #9 + Map: case when (#8) IS NULL then {} else coalesce(#7, {}) end + after %2: + Project: #1..=#7, #10 + Map: case when (#9) IS NULL then null else #8 end + Final closure: + Project: #3, #0, #4, #1, #6, #7, #5, #2, #8 + Map: "s1" + →Arrange (#0) (#2) (#3) + →Stream l0 + →Arrange (#0) + →Union + →Fused with Child Map/Filter/Project + Project: #0..=#2 + Map: true + →Arranged l1 + Key: (#0) + →Map/Filter/Project + Project: #0..=#2 + Map: null, null + →Threshold Diffs #0 + →Arrange (#0) + →Consolidating Union + →Negate Diffs + →Fused with Child Map/Filter/Project + Project: #0 + →Arranged l1 + Key: (#0) + →Unarranged Raw Stream + →Distinct GroupAggregate + →Fused with Child Map/Filter/Project + Project: #0 + →Read l0 + →Arrange (#0) + →Union + →Stream l4 + →Map/Filter/Project + Project: #0..=#2 + Map: null, null + →Threshold Diffs #0 + →Arrange (#0) + →Union + →Stream l3 + →Unarranged Raw Stream + →Distinct GroupAggregate + →Fused with Child Map/Filter/Project + Project: #0 + →Read l2 + →Arrange (#0) + →Union + →Stream l4 + →Map/Filter/Project + Project: #0..=#2 + Map: null, null + →Threshold Diffs #0 + →Arrange (#0) + →Union + →Stream l3 + →Unarranged Raw Stream + →Distinct GroupAggregate + →Fused with Child Map/Filter/Project + Project: #1 + →Read l2 + +Source mz_internal.mz_catalog_raw + project=(#0, #1, #3, #2) + filter=(("GidMapping" = (#0{data} ->> "kind")) AND (#2) IS NOT NULL) + map=((#0{data} -> "key"), (#1 ->> "object_name"), (#1 ->> "object_type")) + +Used Indexes: + - mz_catalog.mz_schemas_ind (*** full scan ***) + +Target cluster: mz_catalog_server + +EOF + query T multiline EXPLAIN MATERIALIZED VIEW "mz_catalog"."mz_iceberg_sinks"; ---- @@ -5306,6 +5524,36 @@ Target cluster: mz_catalog_server EOF +query T multiline +EXPLAIN MATERIALIZED VIEW "mz_catalog"."mz_list_types"; +---- +mz_catalog.mz_list_types: + →Read mz_internal.mz_catalog_raw + +Source mz_internal.mz_catalog_raw + project=(#2..=#4) + filter=(("Item" = (#0{data} ->> "kind")) AND ("list" = (#1 ->> "type_kind")) AND ("type" = (#1 ->> "type"))) + map=(parse_catalog_create_sql(((((#0{data} -> "value") -> "definition") -> "V1") ->> "create_sql")), parse_catalog_id(((#0{data} -> "key") -> "gid")), (#1{parsed} ->> "element_id"), strtolist((#1{parsed} ->> "element_modifiers"))) + +Target cluster: mz_catalog_server + +EOF + +query T multiline +EXPLAIN MATERIALIZED VIEW "mz_catalog"."mz_map_types"; +---- +mz_catalog.mz_map_types: + →Read mz_internal.mz_catalog_raw + +Source mz_internal.mz_catalog_raw + project=(#2..=#6) + filter=(("Item" = (#0{data} ->> "kind")) AND ("map" = (#1 ->> "type_kind")) AND ("type" = (#1 ->> "type"))) + map=(parse_catalog_create_sql(((((#0{data} -> "value") -> "definition") -> "V1") ->> "create_sql")), parse_catalog_id(((#0{data} -> "key") -> "gid")), (#1{parsed} ->> "key_id"), (#1{parsed} ->> "value_id"), strtolist((#1{parsed} ->> "key_modifiers")), strtolist((#1{parsed} ->> "value_modifiers"))) + +Target cluster: mz_catalog_server + +EOF + query T multiline EXPLAIN MATERIALIZED VIEW "mz_catalog"."mz_materialized_views"; ---- @@ -5343,7 +5591,7 @@ mz_catalog.mz_materialized_views: Project: #4, #0, #5, #1, #6, #2, #9, #8, #3, #7 Map: {=r/s1, s1=r/s1}, "s1" →Arrange (#1{schema_name}, #2{name}) - →Constant (51 rows) + →Constant (60 rows) →Arrange (empty key) (#0{schema_name}) (#0{schema_name}, #1{name}) →Fused with Child Map/Filter/Project Project: #4, #3, #5 @@ -5375,6 +5623,81 @@ Target cluster: mz_catalog_server EOF +query T multiline +EXPLAIN MATERIALIZED VIEW "mz_catalog"."mz_operators"; +---- +mz_catalog.mz_operators: + →With + cte l0 = + →Arrange (#0{name}) + →Read mz_internal.mz_catalog_raw + cte l1 = + →Differential Join %1[#0] » %0[#0{oid}] + →Arrange (#0{oid}) + →Constant (344 rows) + →Non-incremental GroupAggregate + Aggregation: array_agg[order_by=[#0 asc nulls_last]](row(array[#2{id}], #1{ordinality})) + Key: + Project: #0 + →Differential Join %1:l0[#0{name}] » %0[#1{name}] + →Arrange (#1{name}) + →Constant (674 rows) + →Arranged l0 + cte l2 = + →Arrange (#2{return_type_name}) + →Stream l1 + cte l3 = + →Differential Join %1:l0[#0{name}] » %0:l2[#2{return_type_name}] + →Arranged l2 + →Arranged l0 + →Return + →Union + →Map/Filter/Project + Project: #0..=#3 + Map: null + →Consolidating Union + →Negate Diffs + →Differential Join %1[#0] » %0:l2[#2{return_type_name}] + →Arranged l2 + →Distinct GroupAggregate + →Fused with Child Map/Filter/Project + Project: #2 + →Read l3 + →Fused with Child Map/Filter/Project + Project: #0, #1, #3 + →Read l1 + →Fused with Child Map/Filter/Project + Project: #0, #1, #3, #4 + →Read l3 + +Source mz_internal.mz_catalog_raw + project=(#2, #3) + filter=(("GidMapping" = (#0{data} ->> "kind")) AND ("7" = (#1 ->> "object_type")) AND (#2) IS NOT NULL) + map=((#0{data} -> "key"), (#1 ->> "object_name"), ("s" || ((#0{data} -> "value") ->> "catalog_id"))) + +Target cluster: mz_catalog_server + +EOF + +query T multiline +EXPLAIN MATERIALIZED VIEW "mz_catalog"."mz_pseudo_types"; +---- +mz_catalog.mz_pseudo_types: + →Differential Join %0[#0{schema_name}, #1{name}] » %1:mz_catalog_raw[#0{schema_name}, #1{name}] + →Arrange (#0{schema_name}, #1{name}) + →Constant (15 rows) + →Arrange (#0{schema_name}, #1{name}) + →Read mz_internal.mz_catalog_raw + +Source mz_internal.mz_catalog_raw + project=(#3, #2, #4) + filter=(("GidMapping" = (#0{data} ->> "kind")) AND ("7" = (#1 ->> "object_type")) AND (#2) IS NOT NULL AND (#3) IS NOT NULL) + map=((#0{data} -> "key"), (#1 ->> "object_name"), (#1 ->> "schema_name"), ("s" || ((#0{data} -> "value") ->> "catalog_id"))) + +Target cluster: mz_catalog_server + +EOF + query T multiline EXPLAIN MATERIALIZED VIEW "mz_catalog"."mz_role_members"; ---- @@ -5688,7 +6011,7 @@ mz_catalog.mz_tables: Project: #3, #0, #4, #1, #5, #2, #6, #6, #6 Map: "s1", null →Arrange (#1{schema_name}, #2{name}) - →Constant (23 rows) + →Constant (13 rows) →Arrange (#0{schema_name}) (#0{schema_name}, #1{name}) →Fused with Child Map/Filter/Project Project: #5, #4, #6 @@ -5713,6 +6036,55 @@ Target cluster: mz_catalog_server EOF +query T multiline +EXPLAIN MATERIALIZED VIEW "mz_catalog"."mz_types"; +---- +mz_catalog.mz_types: + →Union + →Fused with Child Map/Filter/Project + Project: #5..=#11, #3, #12 + Filter: ("Item" = #2) AND ("type" = (#4 ->> "type")) + Map: (((#1 -> "definition") -> "V1") ->> "create_sql"), parse_catalog_create_sql(#3), parse_catalog_id((#0 -> "gid")), text_to_oid((#1 ->> "oid")), parse_catalog_id((#1 -> "schema_id")), (#1 ->> "name"), (#4 ->> "category"), parse_catalog_id((#1 -> "owner_id")), parse_catalog_privileges((#1 -> "privileges")), redact_sql(#3) + →Read mz_internal.mz_catalog_raw + →Delta Join [%0[#1{schema_name}, #2{name}] » %1:mz_catalog_raw[#0{schema_name}, #1{name}] » %2:mz_schemas[#1{name}]] [%1:mz_catalog_raw[#0{schema_name}] » %0[#1{schema_name}, #2{name}] » %2:mz_schemas[#1{name}]] [%2:mz_schemas[#1{name}] » %1:mz_catalog_raw[#0{schema_name}] » %0[#1{schema_name}, #2{name}]] + path %0: + Final closure: + Project: #3, #0, #4, #1, #2, #6, #5, #7, #7 + Map: {=U/s1, s1=U/s1}, "s1", null + path %1: + Final closure: + Project: #3, #0, #4, #1, #2, #6, #5, #7, #7 + Map: {=U/s1, s1=U/s1}, "s1", null + path %2: + Final closure: + Project: #3, #0, #4, #1, #2, #6, #5, #7, #7 + Map: {=U/s1, s1=U/s1}, "s1", null + →Arrange (#1{schema_name}, #2{name}) + →Constant (90 rows) + →Arrange (#0{schema_name}) (#0{schema_name}, #1{name}) + →Fused with Child Map/Filter/Project + Project: #4, #3, #5 + Filter: ("7" = (#0 ->> "object_type")) AND ("GidMapping" = #2) AND (#3) IS NOT NULL AND (#4) IS NOT NULL + Map: (#0 ->> "object_name"), (#0 ->> "schema_name"), ("s" || (#1 ->> "catalog_id")) + →Read mz_internal.mz_catalog_raw + →Arrange (#1{name}) + →Fused with Child Map/Filter/Project + Project: #1, #3 + Filter: (#0{database_id}) IS NULL + →Arranged mz_catalog.mz_schemas + Key: (#2{database_id}) + +Source mz_internal.mz_catalog_raw + project=(#1..=#3) + map=((#0{data} -> "key"), (#0{data} -> "value"), (#0{data} ->> "kind")) + +Used Indexes: + - mz_catalog.mz_schemas_ind (*** full scan ***) + +Target cluster: mz_catalog_server + +EOF + query T multiline EXPLAIN MATERIALIZED VIEW "mz_catalog"."mz_views"; ---- @@ -5743,7 +6115,7 @@ mz_catalog.mz_views: Project: #5, #0, #6, #1, #2, #8, #3, #4, #7 Map: "s1" →Arrange (#1{schema_name}, #2{name}) - →Constant (198 rows) + →Constant (202 rows) →Arrange (#0{schema_name}) (#0{schema_name}, #1{name}) →Fused with Child Map/Filter/Project Project: #5, #4, #6 @@ -5884,7 +6256,7 @@ mz_internal.mz_history_retention_strategies: Project: #3, #5 Map: ("s" || ((#4{data} -> "value") ->> "catalog_id")) →Arrange (#2{name}, #0{object_type}, #1{schema_name}) - →Constant (180 rows) + →Constant (179 rows) →Arrange (((#0{data} -> "key") ->> "object_name"), ((#0{data} -> "key") ->> "object_type"), ((#0{data} -> "key") ->> "schema_name")) →Fused with Child Map/Filter/Project Project: #0 @@ -6046,7 +6418,7 @@ mz_internal.mz_materialized_view_refresh_strategies: Project: #0..=#3, #3 Map: "on-commit", null, null →Arrange (#1{name}, #0{schema_name}) - →Constant (51 rows) + →Constant (60 rows) →Arrange (((#0{data} -> "key") ->> "object_name"), ((#0{data} -> "key") ->> "schema_name")) →Fused with Child Map/Filter/Project Project: #0 @@ -6230,7 +6602,7 @@ mz_internal.mz_object_dependencies: Project: #4..=#6, #2 Filter: case when (#7{ref_kind} = "func") then (#3{object_type} = "8") else case when (#7{ref_kind} = "type") then (#3{object_type} = "7") else ((#3{object_type} != "7") AND (#3{object_type} != "8")) end end →Arrange (#0{object_schema}..=#2{object_type}) (#3{ref_schema}, #4{ref_name}) - →Constant (1088 rows) + →Constant (1135 rows) →Arrange (#1{schema_name}..=#3{object_type}) →Fused with Child Map/Filter/Project Project: #5, #4, #2, #3 @@ -6541,6 +6913,25 @@ Target cluster: mz_catalog_server EOF +query T multiline +EXPLAIN MATERIALIZED VIEW "mz_internal"."mz_type_pg_metadata"; +---- +mz_internal.mz_type_pg_metadata: + →Differential Join %0[#0{schema_name}, #1{name}] » %1:mz_catalog_raw[#0{schema_name}, #1{name}] + →Arrange (#0{schema_name}, #1{name}) + →Constant (77 rows) + →Arrange (#0{schema_name}, #1{name}) + →Read mz_internal.mz_catalog_raw + +Source mz_internal.mz_catalog_raw + project=(#3, #2, #4) + filter=(("GidMapping" = (#0{data} ->> "kind")) AND ("7" = (#1 ->> "object_type")) AND (#2) IS NOT NULL AND (#3) IS NOT NULL) + map=((#0{data} -> "key"), (#1 ->> "object_name"), (#1 ->> "schema_name"), ("s" || ((#0{data} -> "value") ->> "catalog_id"))) + +Target cluster: mz_catalog_server + +EOF + query T multiline EXPLAIN SELECT * FROM "information_schema"."applicable_roles"; ---- @@ -8757,6 +9148,16 @@ Target cluster: mz_catalog_server EOF +query T multiline +EXPLAIN SELECT * FROM "mz_internal"."mz_aggregates"; +---- +Explained Query (fast path): + →Constant (65 rows) + +Target cluster: mz_catalog_server + +EOF + query T multiline EXPLAIN SELECT * FROM "mz_internal"."mz_aws_privatelink_connection_statuses"; ---- @@ -8796,7 +9197,17 @@ query T multiline EXPLAIN SELECT * FROM "mz_internal"."mz_builtin_columns"; ---- Explained Query (fast path): - →Constant (1937 rows) + →Constant (1961 rows) + +Target cluster: mz_catalog_server + +EOF + +query T multiline +EXPLAIN SELECT * FROM "mz_internal"."mz_builtin_functions"; +---- +Explained Query (fast path): + →Constant (639 rows) Target cluster: mz_catalog_server @@ -8836,7 +9247,17 @@ query T multiline EXPLAIN SELECT * FROM "mz_internal"."mz_builtin_materialized_views"; ---- Explained Query (fast path): - →Constant (51 rows) + →Constant (60 rows) + +Target cluster: mz_catalog_server + +EOF + +query T multiline +EXPLAIN SELECT * FROM "mz_internal"."mz_builtin_operators"; +---- +Explained Query (fast path): + →Constant (344 rows) Target cluster: mz_catalog_server @@ -8856,7 +9277,17 @@ query T multiline EXPLAIN SELECT * FROM "mz_internal"."mz_builtin_tables"; ---- Explained Query (fast path): - →Constant (23 rows) + →Constant (13 rows) + +Target cluster: mz_catalog_server + +EOF + +query T multiline +EXPLAIN SELECT * FROM "mz_internal"."mz_builtin_types"; +---- +Explained Query (fast path): + →Constant (90 rows) Target cluster: mz_catalog_server @@ -8866,7 +9297,7 @@ query T multiline EXPLAIN SELECT * FROM "mz_internal"."mz_builtin_views"; ---- Explained Query (fast path): - →Constant (198 rows) + →Constant (202 rows) Target cluster: mz_catalog_server @@ -10784,7 +11215,7 @@ Explained Query: Project: #3, #4 Filter: case when (#2{ref_kind} = "func") then (#5{object_type} = "8") else case when (#2{ref_kind} = "type") then (#5{object_type} = "7") else ((#5{object_type} != "7") AND (#5{object_type} != "8")) end end →Unarranged Raw Stream - →Constant (1088 rows) + →Constant (1135 rows) →Arrange (#1{schema_name}..=#3{object_type}) →Fused with Child Map/Filter/Project Project: #5, #4, #2, #3 @@ -17733,12 +18164,8 @@ EOF query T multiline EXPLAIN SELECT * FROM "pg_catalog"."pg_aggregate"; ---- -Explained Query: - →Read mz_internal.mz_aggregates - -Source mz_internal.mz_aggregates - project=(#0..=#2, #4, #3, #3, #3, #3, #3, #3, #3, #5..=#7, #7..=#10, #8, #10, #11, #11) - map=(0, null, false, false, null, 0, null, null, null) +Explained Query (fast path): + →Constant (65 rows) Target cluster: mz_catalog_server diff --git a/test/sqllogictest/github-2514.slt b/test/sqllogictest/github-2514.slt index 7180d6172a2fa..a9f286ddab30c 100644 --- a/test/sqllogictest/github-2514.slt +++ b/test/sqllogictest/github-2514.slt @@ -64,7 +64,6 @@ Only the following relations are available: "mz_catalog.mz_tables" "mz_catalog.mz_types" "mz_catalog.mz_views" -"mz_internal.mz_aggregates" "mz_internal.mz_comments" "mz_internal.mz_metric_sinks" "mz_internal.mz_object_dependencies" diff --git a/test/sqllogictest/information_schema_tables.slt b/test/sqllogictest/information_schema_tables.slt index 00fc60ceb506d..3b2b767bece8d 100644 --- a/test/sqllogictest/information_schema_tables.slt +++ b/test/sqllogictest/information_schema_tables.slt @@ -94,7 +94,7 @@ VIEW materialize mz_catalog mz_array_types -BASE TABLE +MATERIALIZED VIEW materialize mz_catalog mz_audit_events @@ -106,7 +106,7 @@ MATERIALIZED VIEW materialize mz_catalog mz_base_types -BASE TABLE +MATERIALIZED VIEW materialize mz_catalog mz_cluster_replica_frontiers @@ -146,7 +146,7 @@ BASE TABLE materialize mz_catalog mz_functions -BASE TABLE +MATERIALIZED VIEW materialize mz_catalog mz_iceberg_sinks @@ -174,11 +174,11 @@ MATERIALIZED VIEW materialize mz_catalog mz_list_types -BASE TABLE +MATERIALIZED VIEW materialize mz_catalog mz_map_types -BASE TABLE +MATERIALIZED VIEW materialize mz_catalog mz_materialized_views @@ -190,11 +190,11 @@ VIEW materialize mz_catalog mz_operators -BASE TABLE +MATERIALIZED VIEW materialize mz_catalog mz_pseudo_types -BASE TABLE +MATERIALIZED VIEW materialize mz_catalog mz_recent_storage_usage @@ -262,7 +262,7 @@ VIEW materialize mz_catalog mz_types -BASE TABLE +MATERIALIZED VIEW materialize mz_catalog mz_views @@ -274,7 +274,7 @@ VIEW materialize mz_internal mz_aggregates -BASE TABLE +VIEW materialize mz_internal mz_aws_connections @@ -293,6 +293,10 @@ mz_builtin_columns VIEW materialize mz_internal +mz_builtin_functions +VIEW +materialize +mz_internal mz_builtin_index_columns VIEW materialize @@ -309,6 +313,10 @@ mz_builtin_materialized_views VIEW materialize mz_internal +mz_builtin_operators +VIEW +materialize +mz_internal mz_builtin_sources VIEW materialize @@ -317,6 +325,10 @@ mz_builtin_tables VIEW materialize mz_internal +mz_builtin_types +VIEW +materialize +mz_internal mz_builtin_views VIEW materialize @@ -842,7 +854,7 @@ BASE TABLE materialize mz_internal mz_type_pg_metadata -BASE TABLE +MATERIALIZED VIEW materialize mz_internal mz_wallclock_global_lag diff --git a/test/sqllogictest/mz_catalog_server_index_accounting.slt b/test/sqllogictest/mz_catalog_server_index_accounting.slt index 7493afec8e68d..13a93db861632 100644 --- a/test/sqllogictest/mz_catalog_server_index_accounting.slt +++ b/test/sqllogictest/mz_catalog_server_index_accounting.slt @@ -37,110 +37,110 @@ mz_arrangement_heap_capacity_raw_s2_primary_idx CREATE␠INDEX␠"mz_arrangemen mz_arrangement_heap_size_raw_s2_primary_idx CREATE␠INDEX␠"mz_arrangement_heap_size_raw_s2_primary_idx"␠IN␠CLUSTER␠[s2]␠ON␠"mz_introspection"."mz_arrangement_heap_size_raw"␠("operator_id",␠"worker_id") mz_arrangement_records_raw_s2_primary_idx CREATE␠INDEX␠"mz_arrangement_records_raw_s2_primary_idx"␠IN␠CLUSTER␠[s2]␠ON␠"mz_introspection"."mz_arrangement_records_raw"␠("operator_id",␠"worker_id") mz_arrangement_sharing_raw_s2_primary_idx CREATE␠INDEX␠"mz_arrangement_sharing_raw_s2_primary_idx"␠IN␠CLUSTER␠[s2]␠ON␠"mz_introspection"."mz_arrangement_sharing_raw"␠("operator_id",␠"worker_id") -mz_cluster_auto_scaling_strategies_ind CREATE␠INDEX␠"mz_cluster_auto_scaling_strategies_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s528␠AS␠"mz_internal"."mz_cluster_auto_scaling_strategies"]␠("cluster_id") -mz_cluster_deployment_lineage_ind CREATE␠INDEX␠"mz_cluster_deployment_lineage_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s777␠AS␠"mz_internal"."mz_cluster_deployment_lineage"]␠("cluster_id") +mz_cluster_auto_scaling_strategies_ind CREATE␠INDEX␠"mz_cluster_auto_scaling_strategies_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s531␠AS␠"mz_internal"."mz_cluster_auto_scaling_strategies"]␠("cluster_id") +mz_cluster_deployment_lineage_ind CREATE␠INDEX␠"mz_cluster_deployment_lineage_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s780␠AS␠"mz_internal"."mz_cluster_deployment_lineage"]␠("cluster_id") mz_cluster_prometheus_metrics_s2_primary_idx CREATE␠INDEX␠"mz_cluster_prometheus_metrics_s2_primary_idx"␠IN␠CLUSTER␠[s2]␠ON␠"mz_introspection"."mz_cluster_prometheus_metrics"␠("process_id",␠"metric_name",␠"labels") -mz_cluster_reconfigurations_ind CREATE␠INDEX␠"mz_cluster_reconfigurations_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s527␠AS␠"mz_internal"."mz_cluster_reconfigurations"]␠("cluster_id") -mz_cluster_replica_frontiers_ind CREATE␠INDEX␠"mz_cluster_replica_frontiers_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s771␠AS␠"mz_catalog"."mz_cluster_replica_frontiers"]␠("object_id") -mz_cluster_replica_history_ind CREATE␠INDEX␠"mz_cluster_replica_history_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s626␠AS␠"mz_internal"."mz_cluster_replica_history"]␠("dropped_at") -mz_cluster_replica_metrics_history_ind CREATE␠INDEX␠"mz_cluster_replica_metrics_history_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s533␠AS␠"mz_internal"."mz_cluster_replica_metrics_history"]␠("replica_id") -mz_cluster_replica_metrics_ind CREATE␠INDEX␠"mz_cluster_replica_metrics_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s534␠AS␠"mz_internal"."mz_cluster_replica_metrics"]␠("replica_id") -mz_cluster_replica_name_history_ind CREATE␠INDEX␠"mz_cluster_replica_name_history_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s627␠AS␠"mz_internal"."mz_cluster_replica_name_history"]␠("id") +mz_cluster_reconfigurations_ind CREATE␠INDEX␠"mz_cluster_reconfigurations_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s530␠AS␠"mz_internal"."mz_cluster_reconfigurations"]␠("cluster_id") +mz_cluster_replica_frontiers_ind CREATE␠INDEX␠"mz_cluster_replica_frontiers_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s774␠AS␠"mz_catalog"."mz_cluster_replica_frontiers"]␠("object_id") +mz_cluster_replica_history_ind CREATE␠INDEX␠"mz_cluster_replica_history_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s629␠AS␠"mz_internal"."mz_cluster_replica_history"]␠("dropped_at") +mz_cluster_replica_metrics_history_ind CREATE␠INDEX␠"mz_cluster_replica_metrics_history_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s536␠AS␠"mz_internal"."mz_cluster_replica_metrics_history"]␠("replica_id") +mz_cluster_replica_metrics_ind CREATE␠INDEX␠"mz_cluster_replica_metrics_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s537␠AS␠"mz_internal"."mz_cluster_replica_metrics"]␠("replica_id") +mz_cluster_replica_name_history_ind CREATE␠INDEX␠"mz_cluster_replica_name_history_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s630␠AS␠"mz_internal"."mz_cluster_replica_name_history"]␠("id") mz_cluster_replica_resource_usage_s2_primary_idx CREATE␠INDEX␠"mz_cluster_replica_resource_usage_s2_primary_idx"␠IN␠CLUSTER␠[s2]␠ON␠"mz_introspection"."mz_cluster_replica_resource_usage"␠("process_id",␠"source",␠"metric") -mz_cluster_replica_size_internal_ind CREATE␠INDEX␠"mz_cluster_replica_size_internal_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s523␠AS␠"mz_internal"."mz_cluster_replica_size_internal"]␠("size") -mz_cluster_replica_sizes_ind CREATE␠INDEX␠"mz_cluster_replica_sizes_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s522␠AS␠"mz_catalog"."mz_cluster_replica_sizes"]␠("size") -mz_cluster_replica_status_history_ind CREATE␠INDEX␠"mz_cluster_replica_status_history_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s535␠AS␠"mz_internal"."mz_cluster_replica_status_history"]␠("replica_id") -mz_cluster_replica_statuses_ind CREATE␠INDEX␠"mz_cluster_replica_statuses_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s536␠AS␠"mz_internal"."mz_cluster_replica_statuses"]␠("replica_id") -mz_cluster_replicas_ind CREATE␠INDEX␠"mz_cluster_replicas_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s532␠AS␠"mz_catalog"."mz_cluster_replicas"]␠("id") -mz_clusters_ind CREATE␠INDEX␠"mz_clusters_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s524␠AS␠"mz_catalog"."mz_clusters"]␠("id") -mz_columns_ind CREATE␠INDEX␠"mz_columns_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s495␠AS␠"mz_catalog"."mz_columns"]␠("name") -mz_comments_ind CREATE␠INDEX␠"mz_comments_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s551␠AS␠"mz_internal"."mz_comments"]␠("id") +mz_cluster_replica_size_internal_ind CREATE␠INDEX␠"mz_cluster_replica_size_internal_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s526␠AS␠"mz_internal"."mz_cluster_replica_size_internal"]␠("size") +mz_cluster_replica_sizes_ind CREATE␠INDEX␠"mz_cluster_replica_sizes_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s525␠AS␠"mz_catalog"."mz_cluster_replica_sizes"]␠("size") +mz_cluster_replica_status_history_ind CREATE␠INDEX␠"mz_cluster_replica_status_history_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s538␠AS␠"mz_internal"."mz_cluster_replica_status_history"]␠("replica_id") +mz_cluster_replica_statuses_ind CREATE␠INDEX␠"mz_cluster_replica_statuses_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s539␠AS␠"mz_internal"."mz_cluster_replica_statuses"]␠("replica_id") +mz_cluster_replicas_ind CREATE␠INDEX␠"mz_cluster_replicas_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s535␠AS␠"mz_catalog"."mz_cluster_replicas"]␠("id") +mz_clusters_ind CREATE␠INDEX␠"mz_clusters_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s527␠AS␠"mz_catalog"."mz_clusters"]␠("id") +mz_columns_ind CREATE␠INDEX␠"mz_columns_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s498␠AS␠"mz_catalog"."mz_columns"]␠("name") +mz_comments_ind CREATE␠INDEX␠"mz_comments_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s554␠AS␠"mz_internal"."mz_comments"]␠("id") mz_compute_dataflow_global_ids_per_worker_s2_primary_idx CREATE␠INDEX␠"mz_compute_dataflow_global_ids_per_worker_s2_primary_idx"␠IN␠CLUSTER␠[s2]␠ON␠"mz_introspection"."mz_compute_dataflow_global_ids_per_worker"␠("id",␠"worker_id",␠"global_id") -mz_compute_dependencies_ind CREATE␠INDEX␠"mz_compute_dependencies_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s752␠AS␠"mz_internal"."mz_compute_dependencies"]␠("dependency_id") +mz_compute_dependencies_ind CREATE␠INDEX␠"mz_compute_dependencies_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s755␠AS␠"mz_internal"."mz_compute_dependencies"]␠("dependency_id") mz_compute_error_counts_raw_s2_primary_idx CREATE␠INDEX␠"mz_compute_error_counts_raw_s2_primary_idx"␠IN␠CLUSTER␠[s2]␠ON␠"mz_introspection"."mz_compute_error_counts_raw"␠("export_id",␠"worker_id") mz_compute_exports_per_worker_s2_primary_idx CREATE␠INDEX␠"mz_compute_exports_per_worker_s2_primary_idx"␠IN␠CLUSTER␠[s2]␠ON␠"mz_introspection"."mz_compute_exports_per_worker"␠("export_id",␠"worker_id") mz_compute_frontiers_per_worker_s2_primary_idx CREATE␠INDEX␠"mz_compute_frontiers_per_worker_s2_primary_idx"␠IN␠CLUSTER␠[s2]␠ON␠"mz_introspection"."mz_compute_frontiers_per_worker"␠("export_id",␠"worker_id") -mz_compute_hydration_times_ind CREATE␠INDEX␠"mz_compute_hydration_times_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s762␠AS␠"mz_internal"."mz_compute_hydration_times"]␠("replica_id") +mz_compute_hydration_times_ind CREATE␠INDEX␠"mz_compute_hydration_times_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s765␠AS␠"mz_internal"."mz_compute_hydration_times"]␠("replica_id") mz_compute_hydration_times_per_worker_s2_primary_idx CREATE␠INDEX␠"mz_compute_hydration_times_per_worker_s2_primary_idx"␠IN␠CLUSTER␠[s2]␠ON␠"mz_introspection"."mz_compute_hydration_times_per_worker"␠("export_id",␠"worker_id") mz_compute_import_frontiers_per_worker_s2_primary_idx CREATE␠INDEX␠"mz_compute_import_frontiers_per_worker_s2_primary_idx"␠IN␠CLUSTER␠[s2]␠ON␠"mz_introspection"."mz_compute_import_frontiers_per_worker"␠("export_id",␠"import_id",␠"worker_id") mz_compute_lir_mapping_per_worker_s2_primary_idx CREATE␠INDEX␠"mz_compute_lir_mapping_per_worker_s2_primary_idx"␠IN␠CLUSTER␠[s2]␠ON␠"mz_introspection"."mz_compute_lir_mapping_per_worker"␠("global_id",␠"lir_id",␠"worker_id") mz_compute_operator_durations_histogram_raw_s2_primary_idx CREATE␠INDEX␠"mz_compute_operator_durations_histogram_raw_s2_primary_idx"␠IN␠CLUSTER␠[s2]␠ON␠"mz_introspection"."mz_compute_operator_durations_histogram_raw"␠("id",␠"worker_id",␠"duration_ns") mz_compute_operator_hydration_statuses_per_worker_s2_primary_idx CREATE␠INDEX␠"mz_compute_operator_hydration_statuses_per_worker_s2_primary_idx"␠IN␠CLUSTER␠[s2]␠ON␠"mz_introspection"."mz_compute_operator_hydration_statuses_per_worker"␠("export_id",␠"lir_id",␠"worker_id") -mz_connections_ind CREATE␠INDEX␠"mz_connections_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s530␠AS␠"mz_catalog"."mz_connections"]␠("schema_id") -mz_console_cluster_utilization_overview_24h_ind CREATE␠INDEX␠"mz_console_cluster_utilization_overview_24h_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s758␠AS␠"mz_internal"."mz_console_cluster_utilization_overview_24h"]␠("cluster_id") -mz_console_cluster_utilization_overview_3h_ind CREATE␠INDEX␠"mz_console_cluster_utilization_overview_3h_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s757␠AS␠"mz_internal"."mz_console_cluster_utilization_overview_3h"]␠("cluster_id") -mz_console_cluster_utilization_overview_ind CREATE␠INDEX␠"mz_console_cluster_utilization_overview_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s756␠AS␠"mz_internal"."mz_console_cluster_utilization_overview"]␠("cluster_id") -mz_databases_ind CREATE␠INDEX␠"mz_databases_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s493␠AS␠"mz_catalog"."mz_databases"]␠("name") +mz_connections_ind CREATE␠INDEX␠"mz_connections_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s533␠AS␠"mz_catalog"."mz_connections"]␠("schema_id") +mz_console_cluster_utilization_overview_24h_ind CREATE␠INDEX␠"mz_console_cluster_utilization_overview_24h_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s761␠AS␠"mz_internal"."mz_console_cluster_utilization_overview_24h"]␠("cluster_id") +mz_console_cluster_utilization_overview_3h_ind CREATE␠INDEX␠"mz_console_cluster_utilization_overview_3h_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s760␠AS␠"mz_internal"."mz_console_cluster_utilization_overview_3h"]␠("cluster_id") +mz_console_cluster_utilization_overview_ind CREATE␠INDEX␠"mz_console_cluster_utilization_overview_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s759␠AS␠"mz_internal"."mz_console_cluster_utilization_overview"]␠("cluster_id") +mz_databases_ind CREATE␠INDEX␠"mz_databases_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s496␠AS␠"mz_catalog"."mz_databases"]␠("name") mz_dataflow_addresses_per_worker_s2_primary_idx CREATE␠INDEX␠"mz_dataflow_addresses_per_worker_s2_primary_idx"␠IN␠CLUSTER␠[s2]␠ON␠"mz_introspection"."mz_dataflow_addresses_per_worker"␠("id",␠"worker_id") mz_dataflow_channels_per_worker_s2_primary_idx CREATE␠INDEX␠"mz_dataflow_channels_per_worker_s2_primary_idx"␠IN␠CLUSTER␠[s2]␠ON␠"mz_introspection"."mz_dataflow_channels_per_worker"␠("id",␠"worker_id") mz_dataflow_operator_reachability_raw_s2_primary_idx CREATE␠INDEX␠"mz_dataflow_operator_reachability_raw_s2_primary_idx"␠IN␠CLUSTER␠[s2]␠ON␠"mz_introspection"."mz_dataflow_operator_reachability_raw"␠("id",␠"worker_id",␠"source",␠"port",␠"update_type",␠"time") mz_dataflow_operators_per_worker_s2_primary_idx CREATE␠INDEX␠"mz_dataflow_operators_per_worker_s2_primary_idx"␠IN␠CLUSTER␠[s2]␠ON␠"mz_introspection"."mz_dataflow_operators_per_worker"␠("id",␠"worker_id") -mz_frontiers_ind CREATE␠INDEX␠"mz_frontiers_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s743␠AS␠"mz_internal"."mz_frontiers"]␠("object_id") -mz_hydration_statuses_ind CREATE␠INDEX␠"mz_hydration_statuses_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s773␠AS␠"mz_internal"."mz_hydration_statuses"]␠("object_id",␠"replica_id") -mz_indexes_ind CREATE␠INDEX␠"mz_indexes_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s496␠AS␠"mz_catalog"."mz_indexes"]␠("id") -mz_kafka_sources_ind CREATE␠INDEX␠"mz_kafka_sources_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s489␠AS␠"mz_catalog"."mz_kafka_sources"]␠("id") -mz_materialized_views_ind CREATE␠INDEX␠"mz_materialized_views_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s555␠AS␠"mz_catalog"."mz_materialized_views"]␠("id") +mz_frontiers_ind CREATE␠INDEX␠"mz_frontiers_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s746␠AS␠"mz_internal"."mz_frontiers"]␠("object_id") +mz_hydration_statuses_ind CREATE␠INDEX␠"mz_hydration_statuses_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s776␠AS␠"mz_internal"."mz_hydration_statuses"]␠("object_id",␠"replica_id") +mz_indexes_ind CREATE␠INDEX␠"mz_indexes_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s499␠AS␠"mz_catalog"."mz_indexes"]␠("id") +mz_kafka_sources_ind CREATE␠INDEX␠"mz_kafka_sources_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s492␠AS␠"mz_catalog"."mz_kafka_sources"]␠("id") +mz_materialized_views_ind CREATE␠INDEX␠"mz_materialized_views_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s558␠AS␠"mz_catalog"."mz_materialized_views"]␠("id") mz_message_batch_counts_received_raw_s2_primary_idx CREATE␠INDEX␠"mz_message_batch_counts_received_raw_s2_primary_idx"␠IN␠CLUSTER␠[s2]␠ON␠"mz_introspection"."mz_message_batch_counts_received_raw"␠("channel_id",␠"from_worker_id",␠"to_worker_id") mz_message_batch_counts_sent_raw_s2_primary_idx CREATE␠INDEX␠"mz_message_batch_counts_sent_raw_s2_primary_idx"␠IN␠CLUSTER␠[s2]␠ON␠"mz_introspection"."mz_message_batch_counts_sent_raw"␠("channel_id",␠"from_worker_id",␠"to_worker_id") mz_message_counts_received_raw_s2_primary_idx CREATE␠INDEX␠"mz_message_counts_received_raw_s2_primary_idx"␠IN␠CLUSTER␠[s2]␠ON␠"mz_introspection"."mz_message_counts_received_raw"␠("channel_id",␠"from_worker_id",␠"to_worker_id") mz_message_counts_sent_raw_s2_primary_idx CREATE␠INDEX␠"mz_message_counts_sent_raw_s2_primary_idx"␠IN␠CLUSTER␠[s2]␠ON␠"mz_introspection"."mz_message_counts_sent_raw"␠("channel_id",␠"from_worker_id",␠"to_worker_id") -mz_metric_sinks_ind CREATE␠INDEX␠"mz_metric_sinks_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s553␠AS␠"mz_internal"."mz_metric_sinks"]␠("id") -mz_notices_ind CREATE␠INDEX␠"mz_notices_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s851␠AS␠"mz_internal"."mz_notices"]␠("id") -mz_object_arrangement_size_history_object_ind CREATE␠INDEX␠"mz_object_arrangement_size_history_object_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s765␠AS␠"mz_internal"."mz_object_arrangement_size_history"]␠("object_id") -mz_object_arrangement_size_history_ts_ind CREATE␠INDEX␠"mz_object_arrangement_size_history_ts_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s765␠AS␠"mz_internal"."mz_object_arrangement_size_history"]␠("collection_timestamp") -mz_object_arrangement_sizes_ind CREATE␠INDEX␠"mz_object_arrangement_sizes_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s763␠AS␠"mz_internal"."mz_object_arrangement_sizes"]␠("replica_id") -mz_object_dependencies_ind CREATE␠INDEX␠"mz_object_dependencies_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s491␠AS␠"mz_internal"."mz_object_dependencies"]␠("object_id") -mz_object_graph_edges_ind CREATE␠INDEX␠"mz_object_graph_edges_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s754␠AS␠"mz_internal"."mz_object_graph_edges"]␠("object_id") -mz_object_history_ind CREATE␠INDEX␠"mz_object_history_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s566␠AS␠"mz_internal"."mz_object_history"]␠("id") -mz_object_lifetimes_ind CREATE␠INDEX␠"mz_object_lifetimes_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s567␠AS␠"mz_internal"."mz_object_lifetimes"]␠("id") -mz_object_transitive_dependencies_ind CREATE␠INDEX␠"mz_object_transitive_dependencies_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s583␠AS␠"mz_internal"."mz_object_transitive_dependencies"]␠("object_id") -mz_objects_ind CREATE␠INDEX␠"mz_objects_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s563␠AS␠"mz_catalog"."mz_objects"]␠("schema_id") +mz_metric_sinks_ind CREATE␠INDEX␠"mz_metric_sinks_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s556␠AS␠"mz_internal"."mz_metric_sinks"]␠("id") +mz_notices_ind CREATE␠INDEX␠"mz_notices_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s854␠AS␠"mz_internal"."mz_notices"]␠("id") +mz_object_arrangement_size_history_object_ind CREATE␠INDEX␠"mz_object_arrangement_size_history_object_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s768␠AS␠"mz_internal"."mz_object_arrangement_size_history"]␠("object_id") +mz_object_arrangement_size_history_ts_ind CREATE␠INDEX␠"mz_object_arrangement_size_history_ts_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s768␠AS␠"mz_internal"."mz_object_arrangement_size_history"]␠("collection_timestamp") +mz_object_arrangement_sizes_ind CREATE␠INDEX␠"mz_object_arrangement_sizes_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s766␠AS␠"mz_internal"."mz_object_arrangement_sizes"]␠("replica_id") +mz_object_dependencies_ind CREATE␠INDEX␠"mz_object_dependencies_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s494␠AS␠"mz_internal"."mz_object_dependencies"]␠("object_id") +mz_object_graph_edges_ind CREATE␠INDEX␠"mz_object_graph_edges_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s757␠AS␠"mz_internal"."mz_object_graph_edges"]␠("object_id") +mz_object_history_ind CREATE␠INDEX␠"mz_object_history_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s569␠AS␠"mz_internal"."mz_object_history"]␠("id") +mz_object_lifetimes_ind CREATE␠INDEX␠"mz_object_lifetimes_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s570␠AS␠"mz_internal"."mz_object_lifetimes"]␠("id") +mz_object_transitive_dependencies_ind CREATE␠INDEX␠"mz_object_transitive_dependencies_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s586␠AS␠"mz_internal"."mz_object_transitive_dependencies"]␠("object_id") +mz_objects_ind CREATE␠INDEX␠"mz_objects_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s566␠AS␠"mz_catalog"."mz_objects"]␠("schema_id") mz_peek_durations_histogram_raw_s2_primary_idx CREATE␠INDEX␠"mz_peek_durations_histogram_raw_s2_primary_idx"␠IN␠CLUSTER␠[s2]␠ON␠"mz_introspection"."mz_peek_durations_histogram_raw"␠("worker_id",␠"type",␠"duration_ns") -mz_recent_activity_log_thinned_ind CREATE␠INDEX␠"mz_recent_activity_log_thinned_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s727␠AS␠"mz_internal"."mz_recent_activity_log_thinned"]␠("sql_hash") -mz_recent_sql_text_ind CREATE␠INDEX␠"mz_recent_sql_text_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s723␠AS␠"mz_internal"."mz_recent_sql_text"]␠("sql_hash") -mz_recent_storage_usage_ind CREATE␠INDEX␠"mz_recent_storage_usage_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s842␠AS␠"mz_catalog"."mz_recent_storage_usage"]␠("object_id") -mz_roles_ind CREATE␠INDEX␠"mz_roles_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s514␠AS␠"mz_catalog"."mz_roles"]␠("id") +mz_recent_activity_log_thinned_ind CREATE␠INDEX␠"mz_recent_activity_log_thinned_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s730␠AS␠"mz_internal"."mz_recent_activity_log_thinned"]␠("sql_hash") +mz_recent_sql_text_ind CREATE␠INDEX␠"mz_recent_sql_text_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s726␠AS␠"mz_internal"."mz_recent_sql_text"]␠("sql_hash") +mz_recent_storage_usage_ind CREATE␠INDEX␠"mz_recent_storage_usage_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s845␠AS␠"mz_catalog"."mz_recent_storage_usage"]␠("object_id") +mz_roles_ind CREATE␠INDEX␠"mz_roles_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s517␠AS␠"mz_catalog"."mz_roles"]␠("id") mz_scheduling_elapsed_raw_s2_primary_idx CREATE␠INDEX␠"mz_scheduling_elapsed_raw_s2_primary_idx"␠IN␠CLUSTER␠[s2]␠ON␠"mz_introspection"."mz_scheduling_elapsed_raw"␠("id",␠"worker_id") mz_scheduling_parks_histogram_raw_s2_primary_idx CREATE␠INDEX␠"mz_scheduling_parks_histogram_raw_s2_primary_idx"␠IN␠CLUSTER␠[s2]␠ON␠"mz_introspection"."mz_scheduling_parks_histogram_raw"␠("worker_id",␠"slept_for_ns",␠"requested_ns") -mz_schemas_ind CREATE␠INDEX␠"mz_schemas_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s494␠AS␠"mz_catalog"."mz_schemas"]␠("database_id") -mz_secrets_ind CREATE␠INDEX␠"mz_secrets_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s529␠AS␠"mz_catalog"."mz_secrets"]␠("name") -mz_show_all_objects_ind CREATE␠INDEX␠"mz_show_all_objects_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s611␠AS␠"mz_internal"."mz_show_all_objects"]␠("schema_id") -mz_show_cluster_replicas_ind CREATE␠INDEX␠"mz_show_cluster_replicas_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s775␠AS␠"mz_internal"."mz_show_cluster_replicas"]␠("cluster") -mz_show_clusters_ind CREATE␠INDEX␠"mz_show_clusters_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s613␠AS␠"mz_internal"."mz_show_clusters"]␠("name") -mz_show_columns_ind CREATE␠INDEX␠"mz_show_columns_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s612␠AS␠"mz_internal"."mz_show_columns"]␠("id") -mz_show_connections_ind CREATE␠INDEX␠"mz_show_connections_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s621␠AS␠"mz_internal"."mz_show_connections"]␠("schema_id") -mz_show_databases_ind CREATE␠INDEX␠"mz_show_databases_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s615␠AS␠"mz_internal"."mz_show_databases"]␠("name") -mz_show_indexes_ind CREATE␠INDEX␠"mz_show_indexes_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s625␠AS␠"mz_internal"."mz_show_indexes"]␠("schema_id") -mz_show_materialized_views_ind CREATE␠INDEX␠"mz_show_materialized_views_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s624␠AS␠"mz_internal"."mz_show_materialized_views"]␠("schema_id") -mz_show_roles_ind CREATE␠INDEX␠"mz_show_roles_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s620␠AS␠"mz_internal"."mz_show_roles"]␠("name") -mz_show_schemas_ind CREATE␠INDEX␠"mz_show_schemas_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s616␠AS␠"mz_internal"."mz_show_schemas"]␠("database_id") -mz_show_secrets_ind CREATE␠INDEX␠"mz_show_secrets_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s614␠AS␠"mz_internal"."mz_show_secrets"]␠("schema_id") -mz_show_sinks_ind CREATE␠INDEX␠"mz_show_sinks_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s623␠AS␠"mz_internal"."mz_show_sinks"]␠("schema_id") -mz_show_sources_ind CREATE␠INDEX␠"mz_show_sources_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s622␠AS␠"mz_internal"."mz_show_sources"]␠("schema_id") -mz_show_tables_ind CREATE␠INDEX␠"mz_show_tables_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s617␠AS␠"mz_internal"."mz_show_tables"]␠("schema_id") -mz_show_types_ind CREATE␠INDEX␠"mz_show_types_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s619␠AS␠"mz_internal"."mz_show_types"]␠("schema_id") -mz_show_views_ind CREATE␠INDEX␠"mz_show_views_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s618␠AS␠"mz_internal"."mz_show_views"]␠("schema_id") -mz_sink_statistics_ind CREATE␠INDEX␠"mz_sink_statistics_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s740␠AS␠"mz_internal"."mz_sink_statistics"]␠("id",␠"replica_id") -mz_sink_status_history_ind CREATE␠INDEX␠"mz_sink_status_history_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s712␠AS␠"mz_internal"."mz_sink_status_history"]␠("sink_id") -mz_sink_statuses_ind CREATE␠INDEX␠"mz_sink_statuses_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s713␠AS␠"mz_internal"."mz_sink_statuses"]␠("id") -mz_sinks_ind CREATE␠INDEX␠"mz_sinks_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s506␠AS␠"mz_catalog"."mz_sinks"]␠("id") -mz_source_statistics_ind CREATE␠INDEX␠"mz_source_statistics_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s738␠AS␠"mz_internal"."mz_source_statistics"]␠("id",␠"replica_id") -mz_source_statistics_with_history_ind CREATE␠INDEX␠"mz_source_statistics_with_history_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s736␠AS␠"mz_internal"."mz_source_statistics_with_history"]␠("id",␠"replica_id") -mz_source_status_history_ind CREATE␠INDEX␠"mz_source_status_history_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s714␠AS␠"mz_internal"."mz_source_status_history"]␠("source_id") -mz_source_statuses_ind CREATE␠INDEX␠"mz_source_statuses_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s731␠AS␠"mz_internal"."mz_source_statuses"]␠("id") -mz_sources_ind CREATE␠INDEX␠"mz_sources_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s499␠AS␠"mz_catalog"."mz_sources"]␠("id") -mz_tables_ind CREATE␠INDEX␠"mz_tables_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s498␠AS␠"mz_catalog"."mz_tables"]␠("schema_id") -mz_types_ind CREATE␠INDEX␠"mz_types_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s508␠AS␠"mz_catalog"."mz_types"]␠("schema_id") -mz_views_ind CREATE␠INDEX␠"mz_views_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s507␠AS␠"mz_catalog"."mz_views"]␠("schema_id") -mz_wallclock_global_lag_recent_history_ind CREATE␠INDEX␠"mz_wallclock_global_lag_recent_history_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s747␠AS␠"mz_internal"."mz_wallclock_global_lag_recent_history"]␠("object_id") -mz_webhook_sources_ind CREATE␠INDEX␠"mz_webhook_sources_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s552␠AS␠"mz_internal"."mz_webhook_sources"]␠("id") -pg_attrdef_all_databases_ind CREATE␠INDEX␠"pg_attrdef_all_databases_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s652␠AS␠"mz_internal"."pg_attrdef_all_databases"]␠("oid",␠"adrelid",␠"adnum",␠"adbin",␠"adsrc") -pg_attribute_all_databases_ind CREATE␠INDEX␠"pg_attribute_all_databases_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s645␠AS␠"mz_internal"."pg_attribute_all_databases"]␠("attrelid",␠"attname",␠"atttypid",␠"attlen",␠"attnum",␠"atttypmod",␠"attnotnull",␠"atthasdef",␠"attidentity",␠"attgenerated",␠"attisdropped",␠"attcollation",␠"database_name",␠"pg_type_database_name") -pg_authid_core_ind CREATE␠INDEX␠"pg_authid_core_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s662␠AS␠"mz_internal"."pg_authid_core"]␠("rolname") -pg_class_all_databases_ind CREATE␠INDEX␠"pg_class_all_databases_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s633␠AS␠"mz_internal"."pg_class_all_databases"]␠("relname") -pg_description_all_databases_ind CREATE␠INDEX␠"pg_description_all_databases_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s642␠AS␠"mz_internal"."pg_description_all_databases"]␠("objoid",␠"classoid",␠"objsubid",␠"description",␠"oid_database_name",␠"class_database_name") -pg_namespace_all_databases_ind CREATE␠INDEX␠"pg_namespace_all_databases_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s630␠AS␠"mz_internal"."pg_namespace_all_databases"]␠("nspname") -pg_type_all_databases_ind CREATE␠INDEX␠"pg_type_all_databases_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s639␠AS␠"mz_internal"."pg_type_all_databases"]␠("oid") +mz_schemas_ind CREATE␠INDEX␠"mz_schemas_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s497␠AS␠"mz_catalog"."mz_schemas"]␠("database_id") +mz_secrets_ind CREATE␠INDEX␠"mz_secrets_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s532␠AS␠"mz_catalog"."mz_secrets"]␠("name") +mz_show_all_objects_ind CREATE␠INDEX␠"mz_show_all_objects_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s614␠AS␠"mz_internal"."mz_show_all_objects"]␠("schema_id") +mz_show_cluster_replicas_ind CREATE␠INDEX␠"mz_show_cluster_replicas_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s778␠AS␠"mz_internal"."mz_show_cluster_replicas"]␠("cluster") +mz_show_clusters_ind CREATE␠INDEX␠"mz_show_clusters_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s616␠AS␠"mz_internal"."mz_show_clusters"]␠("name") +mz_show_columns_ind CREATE␠INDEX␠"mz_show_columns_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s615␠AS␠"mz_internal"."mz_show_columns"]␠("id") +mz_show_connections_ind CREATE␠INDEX␠"mz_show_connections_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s624␠AS␠"mz_internal"."mz_show_connections"]␠("schema_id") +mz_show_databases_ind CREATE␠INDEX␠"mz_show_databases_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s618␠AS␠"mz_internal"."mz_show_databases"]␠("name") +mz_show_indexes_ind CREATE␠INDEX␠"mz_show_indexes_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s628␠AS␠"mz_internal"."mz_show_indexes"]␠("schema_id") +mz_show_materialized_views_ind CREATE␠INDEX␠"mz_show_materialized_views_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s627␠AS␠"mz_internal"."mz_show_materialized_views"]␠("schema_id") +mz_show_roles_ind CREATE␠INDEX␠"mz_show_roles_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s623␠AS␠"mz_internal"."mz_show_roles"]␠("name") +mz_show_schemas_ind CREATE␠INDEX␠"mz_show_schemas_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s619␠AS␠"mz_internal"."mz_show_schemas"]␠("database_id") +mz_show_secrets_ind CREATE␠INDEX␠"mz_show_secrets_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s617␠AS␠"mz_internal"."mz_show_secrets"]␠("schema_id") +mz_show_sinks_ind CREATE␠INDEX␠"mz_show_sinks_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s626␠AS␠"mz_internal"."mz_show_sinks"]␠("schema_id") +mz_show_sources_ind CREATE␠INDEX␠"mz_show_sources_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s625␠AS␠"mz_internal"."mz_show_sources"]␠("schema_id") +mz_show_tables_ind CREATE␠INDEX␠"mz_show_tables_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s620␠AS␠"mz_internal"."mz_show_tables"]␠("schema_id") +mz_show_types_ind CREATE␠INDEX␠"mz_show_types_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s622␠AS␠"mz_internal"."mz_show_types"]␠("schema_id") +mz_show_views_ind CREATE␠INDEX␠"mz_show_views_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s621␠AS␠"mz_internal"."mz_show_views"]␠("schema_id") +mz_sink_statistics_ind CREATE␠INDEX␠"mz_sink_statistics_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s743␠AS␠"mz_internal"."mz_sink_statistics"]␠("id",␠"replica_id") +mz_sink_status_history_ind CREATE␠INDEX␠"mz_sink_status_history_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s715␠AS␠"mz_internal"."mz_sink_status_history"]␠("sink_id") +mz_sink_statuses_ind CREATE␠INDEX␠"mz_sink_statuses_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s716␠AS␠"mz_internal"."mz_sink_statuses"]␠("id") +mz_sinks_ind CREATE␠INDEX␠"mz_sinks_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s509␠AS␠"mz_catalog"."mz_sinks"]␠("id") +mz_source_statistics_ind CREATE␠INDEX␠"mz_source_statistics_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s741␠AS␠"mz_internal"."mz_source_statistics"]␠("id",␠"replica_id") +mz_source_statistics_with_history_ind CREATE␠INDEX␠"mz_source_statistics_with_history_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s739␠AS␠"mz_internal"."mz_source_statistics_with_history"]␠("id",␠"replica_id") +mz_source_status_history_ind CREATE␠INDEX␠"mz_source_status_history_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s717␠AS␠"mz_internal"."mz_source_status_history"]␠("source_id") +mz_source_statuses_ind CREATE␠INDEX␠"mz_source_statuses_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s734␠AS␠"mz_internal"."mz_source_statuses"]␠("id") +mz_sources_ind CREATE␠INDEX␠"mz_sources_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s502␠AS␠"mz_catalog"."mz_sources"]␠("id") +mz_tables_ind CREATE␠INDEX␠"mz_tables_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s501␠AS␠"mz_catalog"."mz_tables"]␠("schema_id") +mz_types_ind CREATE␠INDEX␠"mz_types_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s511␠AS␠"mz_catalog"."mz_types"]␠("schema_id") +mz_views_ind CREATE␠INDEX␠"mz_views_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s510␠AS␠"mz_catalog"."mz_views"]␠("schema_id") +mz_wallclock_global_lag_recent_history_ind CREATE␠INDEX␠"mz_wallclock_global_lag_recent_history_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s750␠AS␠"mz_internal"."mz_wallclock_global_lag_recent_history"]␠("object_id") +mz_webhook_sources_ind CREATE␠INDEX␠"mz_webhook_sources_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s555␠AS␠"mz_internal"."mz_webhook_sources"]␠("id") +pg_attrdef_all_databases_ind CREATE␠INDEX␠"pg_attrdef_all_databases_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s655␠AS␠"mz_internal"."pg_attrdef_all_databases"]␠("oid",␠"adrelid",␠"adnum",␠"adbin",␠"adsrc") +pg_attribute_all_databases_ind CREATE␠INDEX␠"pg_attribute_all_databases_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s648␠AS␠"mz_internal"."pg_attribute_all_databases"]␠("attrelid",␠"attname",␠"atttypid",␠"attlen",␠"attnum",␠"atttypmod",␠"attnotnull",␠"atthasdef",␠"attidentity",␠"attgenerated",␠"attisdropped",␠"attcollation",␠"database_name",␠"pg_type_database_name") +pg_authid_core_ind CREATE␠INDEX␠"pg_authid_core_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s665␠AS␠"mz_internal"."pg_authid_core"]␠("rolname") +pg_class_all_databases_ind CREATE␠INDEX␠"pg_class_all_databases_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s636␠AS␠"mz_internal"."pg_class_all_databases"]␠("relname") +pg_description_all_databases_ind CREATE␠INDEX␠"pg_description_all_databases_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s645␠AS␠"mz_internal"."pg_description_all_databases"]␠("objoid",␠"classoid",␠"objsubid",␠"description",␠"oid_database_name",␠"class_database_name") +pg_namespace_all_databases_ind CREATE␠INDEX␠"pg_namespace_all_databases_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s633␠AS␠"mz_internal"."pg_namespace_all_databases"]␠("nspname") +pg_type_all_databases_ind CREATE␠INDEX␠"pg_type_all_databases_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s642␠AS␠"mz_internal"."pg_type_all_databases"]␠("oid") # Record all transitive dependencies (tables, sources, views, mvs) of indexes on # the mz_catalog_server cluster. @@ -229,6 +229,14 @@ mz_builtin_columns schema_name mz_builtin_columns type mz_builtin_columns type_mod mz_builtin_columns type_oid +mz_builtin_functions argument_type_names +mz_builtin_functions kind +mz_builtin_functions name +mz_builtin_functions oid +mz_builtin_functions return_type_name +mz_builtin_functions returns_set +mz_builtin_functions schema_name +mz_builtin_functions variadic_argument_type_name mz_builtin_index_columns index_position mz_builtin_index_columns name mz_builtin_index_columns nullable @@ -269,6 +277,18 @@ mz_builtin_tables object_type mz_builtin_tables oid mz_builtin_tables privileges mz_builtin_tables schema_name +mz_builtin_types category +mz_builtin_types element_name +mz_builtin_types element_schema_name +mz_builtin_types name +mz_builtin_types oid +mz_builtin_types privileges +mz_builtin_types schema_name +mz_builtin_types type_kind +mz_builtin_types typinput +mz_builtin_types typlen +mz_builtin_types typreceive +mz_builtin_types typsend mz_builtin_views create_sql mz_builtin_views definition mz_builtin_views name diff --git a/test/sqllogictest/mz_functions.slt b/test/sqllogictest/mz_functions.slt new file mode 100644 index 0000000000000..b5077b15bff9d --- /dev/null +++ b/test/sqllogictest/mz_functions.slt @@ -0,0 +1,256 @@ +# Copyright Materialize, Inc. and contributors. All rights reserved. +# +# Use of this software is governed by the Business Source License +# included in the LICENSE file at the root of this repository. +# +# As of the Change Date specified in that file, in accordance with +# the Business Source License, use of this software will be governed +# by the Apache License, Version 2.0. + +# Behavioural tests for the function relations: mz_catalog.mz_functions, +# mz_catalog.mz_operators and mz_internal.mz_aggregates. Every function and +# operator is builtin. mz_functions and mz_operators are +# BuiltinMaterializedViews over mz_internal.mz_catalog_raw (see MZ_FUNCTIONS +# in src/catalog/src/builtin/mz_catalog.rs) that read each signature from the +# generated constant views mz_internal.mz_builtin_functions and +# mz_internal.mz_builtin_operators (make_builtin_functions in +# src/catalog/src/builtin/builtin.rs) and resolve the function and type names +# to ids through GidMapping records. mz_aggregates is a view over +# mz_builtin_functions. +# +# pg_proc, pg_operator and pg_aggregate read through these relations, so the +# values pinned here are a compatibility surface. + +mode cockroach + +# --- mz_builtin_functions ------------------------------------------------------ + +# A signature as the function registry reports it: type names, not ids. +query TTTTTTT +SELECT schema_name, name, kind, argument_type_names::text, variadic_argument_type_name, return_type_name, returns_set +FROM mz_internal.mz_builtin_functions WHERE name = 'concat' +---- +pg_catalog concat scalar {any} any text false + +# --- mz_functions ------------------------------------------------------------ + +# Every implementation of an overloaded function shares the function's id. +query I +SELECT count(DISTINCT id) FROM mz_functions WHERE name = 'abs' +---- +1 + +query T +SELECT count(*) > 1 FROM mz_functions WHERE name = 'abs' +---- +true + +# The id comes from the function's GidMapping record, the schema from +# mz_schemas, and the owner is mz_system. +query TTT +SELECT + id LIKE 's%', + schema_id = (SELECT id FROM mz_schemas WHERE name = 'pg_catalog' AND database_id IS NULL), + owner_id +FROM mz_functions WHERE name = 'now' +---- +true true s1 + +# The oid is the compiled-in PostgreSQL oid, read out of the generated view, +# while a regproc cast resolves the name through the in-memory catalog. Two +# independent paths that must agree. +query IT +SELECT oid, oid = 'now'::regproc::oid FROM mz_functions WHERE name = 'now' +---- +1299 true + +# Argument types resolve to mz_types ids in argument order. +query TT rowsort +SELECT a1.name, a2.name +FROM mz_functions f +JOIN mz_types a1 ON a1.id = f.argument_type_ids[1] +JOIN mz_types a2 ON a2.id = f.argument_type_ids[2] +WHERE f.name = 'date_trunc' AND array_length(f.argument_type_ids, 1) = 2 +---- +text interval +text timestamp +text timestamptz + +# A nullary function has an empty argument array. +query T +SELECT argument_type_ids::text FROM mz_functions WHERE name = 'now' +---- +{} + +# A variadic function names its variadic argument's type, which is also its +# last argument; every other function reports NULL. +query TTT +SELECT a.name, v.name, r.name +FROM mz_functions f +JOIN mz_types a ON a.id = f.argument_type_ids[1] +JOIN mz_types v ON v.id = f.variadic_argument_type_id +JOIN mz_types r ON r.id = f.return_type_id +WHERE f.name = 'concat' +---- +any any text + +query I +SELECT count(*) FROM mz_functions WHERE name = 'now' AND variadic_argument_type_id IS NOT NULL +---- +0 + +# Table functions return a set. +query TT +SELECT returns_set, r.name +FROM mz_functions f JOIN mz_types r ON r.id = f.return_type_id +WHERE f.name = 'jsonb_array_elements' +---- +true jsonb + +# Only a function that returns no value has no return type. +query TT +SELECT name, returns_set FROM mz_functions WHERE return_type_id IS NULL ORDER BY name +---- +repeat_row true +repeat_row_non_negative true + +# Functions live in the system schemas. +query T +SELECT s.name +FROM mz_functions f JOIN mz_schemas s ON s.id = f.schema_id +GROUP BY s.name ORDER BY s.name +---- +information_schema +mz_catalog +mz_internal +mz_unsafe +pg_catalog + +# --- mz_operators ------------------------------------------------------------ + +# Binary operators list their arguments in order, and the oid is PostgreSQL's. +query ITTT +SELECT o.oid, l.name, r.name, ret.name +FROM mz_operators o +JOIN mz_types l ON l.id = o.argument_type_ids[1] +JOIN mz_types r ON r.id = o.argument_type_ids[2] +JOIN mz_types ret ON ret.id = o.return_type_id +WHERE o.name = '->' AND l.name = 'jsonb' AND r.name = 'text' +---- +3211 jsonb text jsonb + +# Unary operators have one argument. +query T +SELECT ret.name +FROM mz_operators o +JOIN mz_types l ON l.id = o.argument_type_ids[1] +JOIN mz_types ret ON ret.id = o.return_type_id +WHERE o.name = '-' AND array_length(o.argument_type_ids, 1) = 1 AND l.name = 'int4' +---- +int4 + +# --- mz_aggregates ----------------------------------------------------------- + +# Every implementation of an aggregate function has a row, and no other +# function does. +query TI rowsort +SELECT a.agg_kind, a.agg_num_direct_args +FROM mz_internal.mz_aggregates a JOIN mz_functions f USING (oid) +WHERE f.name = 'count' +---- +n 0 +n 0 + +query I +SELECT count(*) +FROM mz_internal.mz_builtin_functions b +LEFT JOIN mz_internal.mz_aggregates a USING (oid) +WHERE (b.kind = 'aggregate') <> (a.oid IS NOT NULL) +---- +0 + +# --- Cross-relation invariants ----------------------------------------------- + +# Every type a signature names resolves to a type. +query I +SELECT count(*) +FROM ( + SELECT unnest(argument_type_ids) AS id FROM mz_functions + UNION ALL SELECT variadic_argument_type_id FROM mz_functions WHERE variadic_argument_type_id IS NOT NULL + UNION ALL SELECT return_type_id FROM mz_functions WHERE return_type_id IS NOT NULL + UNION ALL SELECT unnest(argument_type_ids) FROM mz_operators + UNION ALL SELECT return_type_id FROM mz_operators +) refs +LEFT JOIN mz_types t USING (id) +WHERE t.id IS NULL +---- +0 + +# Every builtin signature is reported exactly once, by oid. +query I +SELECT count(*) FROM ( + SELECT oid FROM mz_internal.mz_builtin_functions + EXCEPT ALL + SELECT oid FROM mz_functions +) +---- +0 + +query I +SELECT count(*) FROM ( + SELECT oid FROM mz_functions + EXCEPT ALL + SELECT oid FROM mz_internal.mz_builtin_functions +) +---- +0 + +query I +SELECT count(*) FROM ( + SELECT oid FROM mz_internal.mz_builtin_operators + EXCEPT ALL + SELECT oid FROM mz_operators +) +---- +0 + +query I +SELECT count(*) FROM ( + SELECT oid FROM mz_operators + EXCEPT ALL + SELECT oid FROM mz_internal.mz_builtin_operators +) +---- +0 + +# mz_objects reports each implementation, as it always has. +query T +SELECT count(*) = (SELECT count(*) FROM mz_functions) +FROM mz_objects WHERE type = 'function' +---- +true + +# --- pg_catalog --------------------------------------------------------------- + +query TI +SELECT proname, prorettype FROM pg_proc WHERE oid = 1299 +---- +now 1184 + +query T +SELECT pg_function_is_visible(1299) +---- +true + +query TII +SELECT oprname, oprleft, oprright FROM pg_operator WHERE oid = 3211 +---- +-> 3802 25 + +query TI rowsort +SELECT aggkind, aggnumdirectargs +FROM pg_aggregate +WHERE aggfnoid IN (SELECT oid FROM mz_functions WHERE name = 'count') +---- +n 0 +n 0 diff --git a/test/sqllogictest/mz_types.slt b/test/sqllogictest/mz_types.slt new file mode 100644 index 0000000000000..441d47dd67888 --- /dev/null +++ b/test/sqllogictest/mz_types.slt @@ -0,0 +1,403 @@ +# Copyright Materialize, Inc. and contributors. All rights reserved. +# +# Use of this software is governed by the Business Source License +# included in the LICENSE file at the root of this repository. +# +# As of the Change Date specified in that file, in accordance with +# the Business Source License, use of this software will be governed +# by the Apache License, Version 2.0. + +# Behavioural tests for the type relations: mz_catalog.mz_types, the per-kind +# mz_catalog.mz_array_types, mz_base_types, mz_list_types, mz_map_types and +# mz_pseudo_types, and mz_internal.mz_type_pg_metadata. Each is a +# BuiltinMaterializedView over mz_internal.mz_catalog_raw (see MZ_TYPES in +# src/catalog/src/builtin/mz_catalog.rs). User-defined types come from each +# item's persisted create_sql through parse_catalog_create_sql +# (src/catalog-decode/src/create_sql.rs). Builtin types come from +# mz_internal.mz_builtin_types, a generated constant view +# (make_builtin_types in src/catalog/src/builtin/builtin.rs), joined to their +# GidMapping records for ids. +# +# pg_type reads through all seven relations, so the values pinned here are a +# compatibility surface. + +mode cockroach + +# Stable object ids, so create_sql can name dependencies by id. +reset-server + +# --- user types --------------------------------------------------------------- + +# `int4_list` is the first object created after the reset, so it is u1. +statement ok +CREATE TYPE int4_list AS LIST (ELEMENT TYPE = int4) + +query TT +SELECT id, category FROM mz_types WHERE name = 'int4_list' +---- +u1 list + +query T +SELECT schema_id = (SELECT id FROM mz_schemas WHERE name = 'public' AND database_id IS NOT NULL) +FROM mz_types WHERE name = 'int4_list' +---- +true + +query T +SELECT owner_id = (SELECT id FROM mz_roles WHERE name = 'materialize') +FROM mz_types WHERE name = 'int4_list' +---- +true + +query T rowsort +SELECT unnest(privileges)::text FROM mz_types WHERE name = 'int4_list' +---- +=U/materialize +materialize=U/materialize + +query T multiline +SELECT create_sql FROM mz_types WHERE name = 'int4_list' +---- +CREATE TYPE "materialize"."public"."int4_list" AS LIST (ELEMENT TYPE = [s20 AS "pg_catalog"."int4"]) +EOF + +query T multiline +SELECT redacted_create_sql FROM mz_types WHERE name = 'int4_list' +---- +CREATE TYPE materialize.public.int4_list AS LIST (ELEMENT TYPE = [s20 AS pg_catalog.int4]) +EOF + +# The oid column is read out of the durable JSON, while a regtype cast resolves +# the name through the in-memory catalog. Two independent paths that must agree. +query T +SELECT oid = 'int4_list'::regtype::oid FROM mz_types WHERE name = 'int4_list' +---- +true + +# --- mz_list_types ------------------------------------------------------------ + +query TT +SELECT element_id = (SELECT id FROM mz_types WHERE name = 'int4'), element_modifiers IS NULL +FROM mz_list_types WHERE id = 'u1' +---- +true true + +# Element type modifiers come back as a bigint list. +statement ok +CREATE TYPE numeric_list AS LIST (ELEMENT TYPE = numeric(38, 2)) + +query TT +SELECT element_modifiers::text, pg_typeof(element_modifiers)::text = 'bigint list' +FROM mz_list_types l JOIN mz_types t USING (id) WHERE t.name = 'numeric_list' +---- +{38,2} true + +# --- mz_map_types ------------------------------------------------------------- + +statement ok +CREATE TYPE text_numeric_map AS MAP (KEY TYPE = text, VALUE TYPE = numeric(5, 2)) + +# A map's category is pseudo, as TypeCategory::from_catalog_type reports it. +query T +SELECT category FROM mz_types WHERE name = 'text_numeric_map' +---- +pseudo + +query TTTT +SELECT + key_id = (SELECT id FROM mz_types WHERE name = 'text'), + value_id = (SELECT id FROM mz_types WHERE name = 'numeric'), + key_modifiers IS NULL, + value_modifiers::text +FROM mz_map_types m JOIN mz_types t USING (id) WHERE t.name = 'text_numeric_map' +---- +true true true {5,2} + +# --- record types ------------------------------------------------------------- + +# A record type has no per-kind relation of its own and is reported as a base +# type. +statement ok +CREATE TYPE rec AS (a int4, b text) + +query T +SELECT category FROM mz_types WHERE name = 'rec' +---- +composite + +query I +SELECT count(*) FROM mz_base_types b JOIN mz_types t USING (id) WHERE t.name = 'rec' +---- +1 + +# User-defined types never carry PostgreSQL metadata. +query I +SELECT count(*) +FROM mz_internal.mz_type_pg_metadata m JOIN mz_types t USING (id) +WHERE t.id LIKE 'u%' +---- +0 + +# --- builtin types ------------------------------------------------------------ + +query TTTTT +SELECT id LIKE 's%', owner_id, create_sql IS NULL, redacted_create_sql IS NULL, category +FROM mz_types WHERE name = 'int4' +---- +true s1 true true numeric + +query T +SELECT schema_id = (SELECT id FROM mz_schemas WHERE name = 'pg_catalog' AND database_id IS NULL) +FROM mz_types WHERE name = 'int4' +---- +true + +query T +SELECT schema_id = (SELECT id FROM mz_schemas WHERE name = 'mz_catalog' AND database_id IS NULL) +FROM mz_types WHERE name = 'uint2' +---- +true + +# The oid is the compiled-in PostgreSQL oid, and the regtype cast agrees. +query IT +SELECT oid, oid = 'int4'::regtype::oid FROM mz_types WHERE name = 'int4' +---- +23 true + +query T rowsort +SELECT unnest(privileges)::text FROM mz_types WHERE name = 'int4' +---- +=U/mz_system +mz_system=U/mz_system + +# Exactly once: the user and builtin branches must not both claim a row. +query I +SELECT count(*) FROM mz_types WHERE name = 'int4' +---- +1 + +# --- mz_array_types ----------------------------------------------------------- + +# Array types are all builtin; element references resolve to the element's id. +query T +SELECT t.name +FROM mz_array_types a +JOIN mz_types arr ON a.id = arr.id +JOIN mz_types t ON a.element_id = t.id +WHERE arr.name = '_int4' +---- +int4 + +query I +SELECT count(*) FROM mz_array_types WHERE id LIKE 'u%' +---- +0 + +# --- mz_pseudo_types and mz_base_types ---------------------------------------- + +query T rowsort +SELECT t.name +FROM mz_pseudo_types p JOIN mz_types t USING (id) +WHERE t.name IN ('anyelement', 'record', 'list', 'map', 'int4') +---- +anyelement +list +map +record + +# Range types have no per-kind relation of their own and are base types. +query T rowsort +SELECT t.name +FROM mz_base_types b JOIN mz_types t USING (id) +WHERE t.name IN ('int4', 'int4range', '_int4', 'anyelement') +---- +int4 +int4range + +# --- mz_type_pg_metadata ------------------------------------------------------ + +query IIII +SELECT typinput, typreceive, typsend, typlen +FROM mz_internal.mz_type_pg_metadata m JOIN mz_types t USING (id) +WHERE t.name = 'int4' +---- +42 2406 2407 4 + +# typlen is the length pgwire reports for a column of the type: -1 for +# variable-length types, NULL for pseudo-types and arrays of them, which have +# no scalar type. +query TT rowsort +SELECT t.name, m.typlen::text +FROM mz_internal.mz_type_pg_metadata m JOIN mz_types t USING (id) +WHERE t.name IN ('_int4', 'text', 'record', '_record', 'anyelement', 'int4range') +---- +_int4 -1 +_record NULL +anyelement NULL +int4range -1 +record NULL +text -1 + +# A type without PostgreSQL metadata has no row. +query I +SELECT count(*) +FROM mz_internal.mz_type_pg_metadata m JOIN mz_types t USING (id) +WHERE t.name = 'uint2' +---- +0 + +# --- Cross-relation invariants ------------------------------------------------ + +# Every type is in exactly one per-kind relation, and every per-kind row is a +# type. +query I +SELECT count(*) FROM ( + SELECT id FROM mz_types + EXCEPT ALL + SELECT id FROM ( + SELECT id FROM mz_array_types + UNION ALL SELECT id FROM mz_base_types + UNION ALL SELECT id FROM mz_list_types + UNION ALL SELECT id FROM mz_map_types + UNION ALL SELECT id FROM mz_pseudo_types + ) +) +---- +0 + +query I +SELECT count(*) FROM ( + SELECT id FROM ( + SELECT id FROM mz_array_types + UNION ALL SELECT id FROM mz_base_types + UNION ALL SELECT id FROM mz_list_types + UNION ALL SELECT id FROM mz_map_types + UNION ALL SELECT id FROM mz_pseudo_types + ) + EXCEPT ALL + SELECT id FROM mz_types +) +---- +0 + +query I +SELECT count(*) FROM ( + SELECT id FROM mz_internal.mz_type_pg_metadata + EXCEPT ALL + SELECT id FROM mz_types +) +---- +0 + +# Every builtin type the catalog compiles in must be reported... +query T +SELECT array_agg(name ORDER BY name) FROM ( + SELECT name FROM mz_internal.mz_builtin_types + EXCEPT + SELECT name FROM mz_types WHERE id LIKE 's%' +) +---- +NULL + +# ...and nothing else: every builtin row traces back to the reporter. +query T +SELECT array_agg(name ORDER BY name) FROM ( + SELECT name FROM mz_types WHERE id LIKE 's%' + EXCEPT + SELECT name FROM mz_internal.mz_builtin_types +) +---- +NULL + +# The reporter view backing these MVs is itself a builtin view, reported +# through mz_views with placeholder SQL. See mz_views.slt for the full contract. +query I +SELECT count(*) FROM mz_views WHERE name = 'mz_builtin_types' +---- +1 + +# --- pg_type reads through all seven relations -------------------------------- + +query TTTII rowsort +SELECT typname, typtype::text, typcategory::text, typlen, typelem +FROM pg_type +WHERE typname IN ('int4', '_int4', 'anyelement', 'int4_list', 'text_numeric_map', 'rec') +---- +_int4 b A -1 23 +anyelement p P NULL 0 +int4 b N 4 0 +int4_list l U NULL 23 +rec b C NULL 0 +text_numeric_map m P NULL 0 + +# --- Lifecycle ---------------------------------------------------------------- + +statement ok +DROP TYPE rec + +query I +SELECT count(*) FROM mz_types WHERE name = 'rec' +---- +0 + +query I +SELECT count(*) FROM mz_base_types WHERE id LIKE 'u%' +---- +0 + +# --- Robustness over the whole catalog ---------------------------------------- + +# The MVs run parse_catalog_create_sql over every Item row in the catalog, so a +# single item whose create_sql the parser rejects makes every type relation +# unreadable rather than dropping one row. Create one item of every kind +# reachable here and confirm the relations still resolve. + +statement ok +CREATE TABLE t (a int4_list) + +statement ok +CREATE VIEW v AS SELECT a FROM t + +statement ok +CREATE MATERIALIZED VIEW mv AS SELECT count(*) FROM t + +statement ok +CREATE INDEX t_idx ON t (a) + +statement ok +CREATE SECRET sec AS 'hunter2' + +query T +SELECT count(*) > 0 FROM mz_types +---- +true + +query I +SELECT count(*) FROM mz_list_types WHERE id LIKE 'u%' +---- +2 + +# --- NOT NULL invariants ------------------------------------------------------ + +# The MVs declare ASSERT NOT NULL for these columns. +query I +SELECT count(*) +FROM mz_types +WHERE id IS NULL + OR oid IS NULL + OR schema_id IS NULL + OR name IS NULL + OR category IS NULL + OR owner_id IS NULL + OR privileges IS NULL +---- +0 + +query I +SELECT count(*) FROM mz_internal.mz_type_pg_metadata +WHERE id IS NULL OR typinput IS NULL OR typreceive IS NULL OR typsend IS NULL +---- +0 + +statement ok +DROP TABLE t CASCADE diff --git a/test/sqllogictest/mz_views.slt b/test/sqllogictest/mz_views.slt index 35f6d61fad51b..16fd67609c09e 100644 --- a/test/sqllogictest/mz_views.slt +++ b/test/sqllogictest/mz_views.slt @@ -190,12 +190,15 @@ query T SELECT name FROM mz_views WHERE definition LIKE '%definition elided%' AND id LIKE 's%' ORDER BY name ---- mz_builtin_columns +mz_builtin_functions mz_builtin_index_columns mz_builtin_indexes mz_builtin_log_indexes mz_builtin_materialized_views +mz_builtin_operators mz_builtin_sources mz_builtin_tables +mz_builtin_types mz_builtin_views query T multiline diff --git a/test/sqllogictest/oid.slt b/test/sqllogictest/oid.slt index 68a72efe3a2b6..7b2b9d7e922a8 100644 --- a/test/sqllogictest/oid.slt +++ b/test/sqllogictest/oid.slt @@ -1267,3 +1267,6 @@ SELECT oid, name FROM mz_objects WHERE id LIKE 's%' AND oid < 20000 ORDER BY oid 17138 jq 17139 mz_builtin_columns 17140 mz_builtin_index_columns +17141 mz_builtin_types +17142 mz_builtin_functions +17143 mz_builtin_operators diff --git a/test/sqllogictest/transactions.slt b/test/sqllogictest/transactions.slt index 2b4ccef4576ad..066c816c10bd8 100644 --- a/test/sqllogictest/transactions.slt +++ b/test/sqllogictest/transactions.slt @@ -321,7 +321,6 @@ Only the following relations are available: "mz_catalog.mz_tables" "mz_catalog.mz_types" "mz_catalog.mz_views" -"mz_internal.mz_aggregates" "mz_internal.mz_comments" "mz_internal.mz_metric_sinks" "mz_internal.mz_object_dependencies" diff --git a/test/testdrive/catalog.td b/test/testdrive/catalog.td index e389b93c6635c..4a1ab08c1eb8b 100644 --- a/test/testdrive/catalog.td +++ b/test/testdrive/catalog.td @@ -510,17 +510,9 @@ mz_cluster_replica_frontiers source "" > SHOW TABLES FROM mz_catalog name comment -------------------------------------- -mz_array_types "" -mz_base_types "" mz_cluster_replica_sizes "" mz_egress_ips "" -mz_functions "" -mz_list_types "" -mz_map_types "" -mz_operators "" -mz_pseudo_types "" mz_role_auth "" -mz_types "" > SHOW VIEWS FROM mz_catalog name comment @@ -561,6 +553,14 @@ mz_system_privileges mz_catalog_server "" mz_materialized_views mz_catalog_server "" mz_tables mz_catalog_server "" mz_views mz_catalog_server "" +mz_types mz_catalog_server "" +mz_array_types mz_catalog_server "" +mz_base_types mz_catalog_server "" +mz_list_types mz_catalog_server "" +mz_map_types mz_catalog_server "" +mz_pseudo_types mz_catalog_server "" +mz_functions mz_catalog_server "" +mz_operators mz_catalog_server "" # Check default sources, tables, and views in mz_catalog_unstable. @@ -602,7 +602,6 @@ mz_wallclock_lag_history source "" > SHOW TABLES FROM mz_internal name comment ------------------------------------------------ -mz_aggregates "" mz_cluster_replica_size_internal "" mz_license_keys "" mz_object_arrangement_size_history "" @@ -612,20 +611,23 @@ mz_replica_hydration_history "" mz_sessions "" mz_storage_usage_by_shard "" mz_subscriptions "" -mz_type_pg_metadata "" mz_webhook_sources "" > SHOW VIEWS FROM mz_internal name comment ------------------------------------------------ mz_activity_log_thinned "" +mz_aggregates "" mz_builtin_columns "" +mz_builtin_functions "" mz_builtin_index_columns "" mz_builtin_indexes "" mz_builtin_log_indexes "" mz_builtin_materialized_views "" +mz_builtin_operators "" mz_builtin_sources "" mz_builtin_tables "" +mz_builtin_types "" mz_builtin_views "" mz_cluster_deployment_lineage "" mz_cluster_replica_history "" @@ -745,6 +747,7 @@ mz_replacements mz_catalog_server "" mz_replica_system_parameters mz_catalog_server "" mz_source_references mz_catalog_server "" mz_sql_server_source_tables mz_catalog_server "" +mz_type_pg_metadata mz_catalog_server "" # Check default sources, tables, and views in mz_introspection. @@ -842,7 +845,7 @@ test_table "" # `SHOW TABLES` and `mz_tables` should agree. > SELECT COUNT(*) FROM mz_tables WHERE id LIKE 's%' -23 +13 # There is one entry in mz_indexes for each field_number/expression of the index. > SELECT COUNT(id) FROM mz_indexes WHERE id LIKE 's%'