From 4a32615e90c5d5bf0b5c9fd7ea58f6d1222cdc1a Mon Sep 17 00:00:00 2001 From: Sang Jun Bak Date: Mon, 19 Oct 2026 12:55:19 -0400 Subject: [PATCH 1/4] catalog: generate builtin type, function and operator views Adds three generated constant views that report builtin objects: mz_internal.mz_builtin_types, mz_internal.mz_builtin_functions and mz_internal.mz_builtin_operators. They join the other mz_builtin_* views in mz_builtin_views and mz_builtin_columns. builtin_types_ctes and builtin_signature_ctes resolve builtin type names to catalog ids through GidMapping records in mz_catalog_raw. catalog-decode now decodes CREATE TYPE statements: the type kind and category, plus the element, key and value type ids and modifiers of list and map types, so the type relations can report user-defined types from mz_catalog_raw. Co-Authored-By: Claude Fable 5.1 Co-Authored-By: Claude Opus 5.5 --- src/catalog-decode/src/create_sql.rs | 155 ++++++++- src/catalog/src/builtin.rs | 6 +- src/catalog/src/builtin/builtin.rs | 464 ++++++++++++++++++++++++++- src/pgrepr-consts/src/oid.rs | 3 + 4 files changed, 613 insertions(+), 15 deletions(-) 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..cdd62ce9ef97d 100644 --- a/src/catalog/src/builtin.rs +++ b/src/catalog/src/builtin.rs @@ -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/pgrepr-consts/src/oid.rs b/src/pgrepr-consts/src/oid.rs index 3f26b5ecaf697..1c91fdeb74482 100644 --- a/src/pgrepr-consts/src/oid.rs +++ b/src/pgrepr-consts/src/oid.rs @@ -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; From 0fb0dcfe353f349bbbf80386a34f7f33b25cfdbc Mon Sep 17 00:00:00 2001 From: Sang Jun Bak Date: Mon, 19 Oct 2026 12:55:19 -0400 Subject: [PATCH 2/4] catalog: define type, function and operator relations over mz_catalog_raw Converts the builtin tables mz_types, mz_array_types, mz_base_types, mz_list_types, mz_map_types, mz_pseudo_types, mz_type_pg_metadata, mz_functions and mz_operators to materialized views over mz_catalog_raw, and mz_aggregates to a view over mz_builtin_functions. Builtin rows come from the generated mz_builtin_types, mz_builtin_functions and mz_builtin_operators views, user-defined types from their decoded CREATE TYPE statements. pg_aggregate declares the oid key it now derives through mz_aggregates. Co-Authored-By: Claude Fable 5.1 Co-Authored-By: Claude Opus 5.5 --- src/catalog/src/builtin.rs | 20 +- src/catalog/src/builtin/mz_catalog.rs | 439 +++++++++++++++++++------ src/catalog/src/builtin/mz_internal.rs | 77 +++-- src/catalog/src/builtin/pg_catalog.rs | 1 + src/pgrepr-consts/src/oid.rs | 20 +- 5 files changed, 408 insertions(+), 149 deletions(-) diff --git a/src/catalog/src/builtin.rs b/src/catalog/src/builtin.rs index cdd62ce9ef97d..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), 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 1c91fdeb74482..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; From 362856cf75bd2624d6c656dcc117a4b5bfc2038b Mon Sep 17 00:00:00 2001 From: Sang Jun Bak Date: Mon, 19 Oct 2026 12:55:19 -0400 Subject: [PATCH 3/4] adapter: stop packing type, function and operator rows The type, function and operator relations are derived from mz_catalog_raw, so pack_item_update no longer packs rows for types and functions, and catalog open no longer packs a row per operator. Co-Authored-By: Claude Fable 5.1 Co-Authored-By: Claude Opus 5.5 --- .../src/catalog/builtin_table_updates.rs | 300 +----------------- src/adapter/src/catalog/open.rs | 16 - 2 files changed, 10 insertions(+), 306 deletions(-) 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 From 187e43c0004bbf3c133a5a6eb50b845cfa7bc012 Mon Sep 17 00:00:00 2001 From: Sang Jun Bak Date: Mon, 19 Oct 2026 12:55:19 -0400 Subject: [PATCH 4/4] catalog: migrations and test updates for the type, function and operator relations Adds replacement migration steps for the converted relations, records their conversion version for the builtin version pin platform check, and updates the generated docs and the sqllogictest and testdrive expectations. Co-Authored-By: Claude Fable 5.1 Co-Authored-By: Claude Opus 5.5 --- .../content/sql/system-catalog/mz_internal.md | 3 + .../checks/all_checks/builtin_version_pin.py | 16 +- .../catalog/open/builtin_schema_migration.rs | 81 ++- .../autogenerated/mz_internal.slt | 3 + test/sqllogictest/catalog_server_explain.slt | 463 +++++++++++++++++- test/sqllogictest/github-2514.slt | 1 - .../information_schema_tables.slt | 32 +- .../mz_catalog_server_index_accounting.slt | 184 +++---- test/sqllogictest/mz_functions.slt | 256 ++++++++++ test/sqllogictest/mz_types.slt | 403 +++++++++++++++ test/sqllogictest/mz_views.slt | 3 + test/sqllogictest/oid.slt | 3 + test/sqllogictest/transactions.slt | 1 - test/testdrive/catalog.td | 25 +- 14 files changed, 1325 insertions(+), 149 deletions(-) create mode 100644 test/sqllogictest/mz_functions.slt create mode 100644 test/sqllogictest/mz_types.slt 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/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/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%'