diff --git a/doc/user/content/sql/system-catalog/mz_catalog.md b/doc/user/content/sql/system-catalog/mz_catalog.md index cb812992f5a19..3c86453b0bd19 100644 --- a/doc/user/content/sql/system-catalog/mz_catalog.md +++ b/doc/user/content/sql/system-catalog/mz_catalog.md @@ -262,8 +262,8 @@ The `mz_index_columns` table contains a row for each column in each index in the system. For example, an index on `(a, b + 1)` would have two rows in this table, one for each of the two columns in the index. -For a given row, if `field_number` is null then `expression` will be nonnull, or -vice-versa. +For a given row, if `on_position` is null then `on_expression` will be nonnull, +or vice-versa. Field | Type | Meaning diff --git a/doc/user/content/sql/system-catalog/mz_internal.md b/doc/user/content/sql/system-catalog/mz_internal.md index 266e9e0482cb9..e3c0e09a3f29c 100644 --- a/doc/user/content/sql/system-catalog/mz_internal.md +++ b/doc/user/content/sql/system-catalog/mz_internal.md @@ -1633,6 +1633,7 @@ 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 b1dee0bde660c..cee0fa71346f7 100644 --- a/misc/python/materialize/checks/all_checks/builtin_version_pin.py +++ b/misc/python/materialize/checks/all_checks/builtin_version_pin.py @@ -46,7 +46,7 @@ "mz_egress_ips": None, "mz_functions": None, "mz_iceberg_sinks": MzVersion.parse_mz("v26.38.0"), - "mz_index_columns": None, + "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"), diff --git a/src/adapter/src/catalog/builtin_table_updates.rs b/src/adapter/src/catalog/builtin_table_updates.rs index 897b4f56ca83d..eb5091b4d84d8 100644 --- a/src/adapter/src/catalog/builtin_table_updates.rs +++ b/src/adapter/src/catalog/builtin_table_updates.rs @@ -15,14 +15,13 @@ 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_INDEX_COLUMNS, MZ_LICENSE_KEYS, - MZ_LIST_TYPES, MZ_MAP_TYPES, MZ_OPERATORS, MZ_PSEUDO_TYPES, MZ_ROLE_AUTH, MZ_SESSIONS, + 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, MZ_WEBHOOKS_SOURCES, }; use mz_catalog::memory::error::Error; -use mz_catalog::memory::objects::{CatalogItem, DataSourceDesc, Func, Index, Type}; -use mz_expr::MirScalarExpr; +use mz_catalog::memory::objects::{CatalogItem, DataSourceDesc, Func, Type}; use mz_license_keys::ValidatedLicenseKey; use mz_orchestrator::{CpuLimit, DiskLimit, MemoryLimit}; use mz_ore::cast::CastFrom; @@ -31,8 +30,7 @@ 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, ReprColumnType, Row, RowPacker}; -use mz_sql::ast::{CreateIndexStatement, Statement}; +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; @@ -137,7 +135,6 @@ impl CatalogState { let privileges_row = self.pack_privilege_array_row(entry.privileges()); let privileges = privileges_row.unpack_first(); let updates = match entry.item() { - CatalogItem::Index(index) => self.pack_index_update(id, index, diff), CatalogItem::Source(source) => { match &source.data_source { DataSourceDesc::Webhook { .. } => { @@ -163,13 +160,14 @@ impl CatalogState { CatalogItem::Func(func) => { self.pack_func_update(id, schema_id, name, owner_id, func, diff) } - // Tables, views, materialized views, 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, 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::Log(_) | CatalogItem::Secret(_) | CatalogItem::MetricSink(_) => vec![], @@ -183,70 +181,6 @@ impl CatalogState { updates } - fn pack_index_update( - &self, - id: CatalogItemId, - index: &Index, - diff: Diff, - ) -> Vec> { - let mut updates = vec![]; - - let create_stmt = mz_sql::parse::parse(&index.create_sql) - .unwrap_or_else(|e| { - panic!( - "create_sql cannot be invalid: `{}` --- error: `{}`", - index.create_sql, e - ) - }) - .into_element() - .ast; - - let key_sqls = match &create_stmt { - Statement::CreateIndex(CreateIndexStatement { key_parts, .. }) => key_parts - .as_ref() - .expect("key_parts is filled in during planning"), - _ => unreachable!(), - }; - - let on_entry = self.get_entry_by_global_id(&index.on); - let on_desc = on_entry - .relation_desc() - .expect("can only create indexes on items with a valid description"); - let repr_col_types: Vec = on_desc - .typ() - .column_types - .iter() - .map(ReprColumnType::from) - .collect(); - for (i, key) in index.keys.iter().enumerate() { - let nullable = key.typ(&repr_col_types).nullable; - let seq_in_index = u64::cast_from(i + 1); - let key_sql = key_sqls - .get(i) - .expect("missing sql information for index key") - .to_ast_string_simple(); - let (field_number, expression) = match key { - MirScalarExpr::Column(col, _) => { - (Datum::UInt64(u64::cast_from(*col + 1)), Datum::Null) - } - _ => (Datum::Null, Datum::String(&key_sql)), - }; - updates.push(BuiltinTableUpdate::row( - &*MZ_INDEX_COLUMNS, - Row::pack_slice(&[ - Datum::String(&id.to_string()), - Datum::UInt64(seq_in_index), - field_number, - expression, - Datum::from(nullable), - ]), - diff, - )); - } - - updates - } - fn pack_type_update( &self, id: CatalogItemId, diff --git a/src/adapter/src/catalog/open/builtin_schema_migration.rs b/src/adapter/src/catalog/open/builtin_schema_migration.rs index 2d5bf7f458380..db1c32a97daec 100644 --- a/src/adapter/src/catalog/open/builtin_schema_migration.rs +++ b/src/adapter/src/catalog/open/builtin_schema_migration.rs @@ -561,6 +561,15 @@ static MIGRATIONS: LazyLock> = LazyLock::new(|| { MZ_CATALOG_SCHEMA, "mz_columns", ), + // Converting mz_index_columns from a builtin table to a + // materialized view over mz_catalog_raw changes its catalog + // fingerprint. + MigrationStep::replacement( + "26.49.0-dev.0", + CatalogItemType::MaterializedView, + MZ_CATALOG_SCHEMA, + "mz_index_columns", + ), ] }); diff --git a/src/catalog-decode/src/create_sql.rs b/src/catalog-decode/src/create_sql.rs index d91b04b81e709..7b6f924737d13 100644 --- a/src/catalog-decode/src/create_sql.rs +++ b/src/catalog-decode/src/create_sql.rs @@ -552,6 +552,13 @@ pub fn item_details(a: &str) -> Result { stmt.with_options.iter().map(|o| (&o.name, &o.value)), IndexOptionName::RetainHistory, )?; + let key_parts: Vec<_> = stmt + .key_parts + .iter() + .flatten() + .map(|expr| json!(expr.to_ast_string_simple())) + .collect(); + info.insert("key_parts", json!(key_parts)); "index" } CreateType(_) => "type", @@ -2066,6 +2073,16 @@ mod tests { mz_repr::adt::jsonb::Jsonb::from_serde_json(out).expect("packs as jsonb"); } + #[mz_ore::test] + fn item_details_reports_index_key_parts() { + let sql = r#"CREATE INDEX "t_idx" IN CLUSTER [u1] ON [u4 AS "materialize"."public"."t"] ("pg_catalog"."abs"("a"), "a" + 1, COALESCE("a", 0), 2)"#; + let out = super::item_details(sql).expect("ok"); + assert_eq!( + out["key_parts"], + json!(["pg_catalog.abs(a)", "a + 1", "COALESCE(a, 0)", "2"]) + ); + } + /// Every error here is fatal to the whole of `mz_tables`/`mz_views`, not to /// one row: the MVs call this function inside their `WHERE` clause, so an /// item the parser rejects makes the relation unreadable for everyone. diff --git a/src/catalog/src/builtin.rs b/src/catalog/src/builtin.rs index 8956692b37369..aabc335507e34 100644 --- a/src/catalog/src/builtin.rs +++ b/src/catalog/src/builtin.rs @@ -1194,7 +1194,7 @@ pub static BUILTINS_STATIC: LazyLock>> = LazyLock::ne Builtin::MaterializedView(&MZ_SCHEMAS), Builtin::MaterializedView(&MZ_COLUMNS), Builtin::MaterializedView(&MZ_INDEXES), - Builtin::Table(&MZ_INDEX_COLUMNS), + Builtin::MaterializedView(&MZ_INDEX_COLUMNS), Builtin::MaterializedView(&MZ_TABLES), Builtin::MaterializedView(&MZ_SOURCES), Builtin::MaterializedView(&MZ_SOURCE_REFERENCES), diff --git a/src/catalog/src/builtin/builtin.rs b/src/catalog/src/builtin/builtin.rs index 9b5029c369b36..cf132d0ed2c5c 100644 --- a/src/catalog/src/builtin/builtin.rs +++ b/src/catalog/src/builtin/builtin.rs @@ -10,6 +10,7 @@ //! Constant builtin views exposing information about builtin objects. use std::borrow::Cow; +use std::collections::BTreeMap; use itertools::Itertools; use mz_catalog_protos::objects::CatalogItemType; @@ -40,6 +41,8 @@ pub(super) fn builtins( let indexes: &'static BuiltinView = Box::leak(Box::new(make_builtin_indexes(builtin_items))); let log_indexes: &'static BuiltinView = 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))); // The generated views above, and `mz_builtin_views` itself, are listed in // `mz_builtin_views` with placeholder SQL rather than their real @@ -58,6 +61,7 @@ pub(super) fn builtins( materialized_views, tables, indexes, + index_columns, &columns, ], ))); @@ -69,6 +73,7 @@ pub(super) fn builtins( materialized_views, tables, indexes, + index_columns, views, ], &mut columns, @@ -83,6 +88,7 @@ pub(super) fn builtins( materialized_views, tables, indexes, + index_columns, columns, views, ] @@ -454,7 +460,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; 6], + generated: [&BuiltinView; 7], ) -> BuiltinView { let iter = builtin_items.iter().filter_map(|b| match b { Builtin::View(x) => Some(*x), @@ -566,7 +572,7 @@ fn builtin_columns_view() -> BuiltinView { /// itself. fn make_builtin_columns_sql( builtin_items: &[Builtin], - generated: [&BuiltinView; 6], + generated: [&BuiltinView; 7], columns: &mut BuiltinView, ) { // Map to (schema, relation, desc) @@ -623,6 +629,149 @@ FROM (VALUES {values}) AS v(schema_name, relation_name, name, position, nullable columns.sql = Box::leak(sql.into_boxed_str()); } +/// Generates `mz_internal.mz_builtin_index_columns`: one row per key of each +/// builtin index and of the introspection index each cluster maintains on a +/// builtin log. +fn make_builtin_index_columns(builtin_items: &[Builtin]) -> BuiltinView { + let descs: BTreeMap<(&str, &str), Cow> = builtin_items + .iter() + .filter_map(|b| match b { + Builtin::Table(t) => Some(((t.schema, t.name), Cow::Borrowed(&t.desc))), + Builtin::Source(s) => Some(((s.schema, s.name), Cow::Borrowed(&s.desc))), + Builtin::Log(l) => Some(((l.schema, l.name), Cow::Owned(l.variant.desc()))), + Builtin::View(v) => Some(((v.schema, v.name), Cow::Borrowed(&v.desc))), + Builtin::MaterializedView(mv) => Some(((mv.schema, mv.name), Cow::Borrowed(&mv.desc))), + Builtin::Type(_) | Builtin::Func(_) | Builtin::Index(_) | Builtin::Connection(_) => { + None + } + }) + .collect(); + + let index_values = builtin_items + .iter() + .filter_map(|b| match b { + Builtin::Index(index) => Some(*index), + _ => None, + }) + .flat_map(|index| { + // To get information about a builtin index column, we parse the DDL of the + // builtin index to get information about the underlying relation, get the + // underlying relation's desc, then get the `on_position` and nullability from that. + let create_sql = index.create_sql(); + let stmt = mz_sql::parse::parse(&create_sql) + .unwrap_or_else(|e| panic!("invalid sql for builtin index {}: {e}", index.name)) + .into_element() + .ast; + let Statement::CreateIndex(stmt) = stmt else { + panic!("expected CreateIndex for builtin index {}", index.name); + }; + let mz_sql::ast::RawItemName::Name(on_name) = stmt.on_name else { + panic!("expected Name for on_name in builtin index {}", index.name); + }; + let [on_schema, on_relation] = &on_name.0[..] else { + panic!( + "expected schema.name format for on_name in builtin index {}", + index.name + ); + }; + let desc = descs + .get(&(on_schema.as_str(), on_relation.as_str())) + .unwrap_or_else(|| { + panic!( + "builtin index {} is on unknown relation {on_schema}.{on_relation}", + index.name + ) + }); + let key_parts = stmt + .key_parts + .unwrap_or_else(|| panic!("builtin index {} must have explicit key parts", index.name)); + key_parts + .into_iter() + .enumerate() + .map(|(i, expr)| { + // All builtin indexes don't have an expression as a key. If any of them do + // in the future, we panic here since we can only determine their nullability + // from the planner. + let mz_sql::ast::Expr::Identifier(parts) = &expr else { + panic!("builtin index {} has an expression key {expr}", index.name); + }; + let [column] = &parts[..] else { + panic!("builtin index {} has a qualified key {expr}", index.name); + }; + let position = desc + .iter_names() + .position(|name| name.as_str() == column.as_str()) + .unwrap_or_else(|| { + panic!( + "builtin index {} keys on unknown column {column} of {on_schema}.{on_relation}", + index.name + ) + }); + let nullable = desc.typ().column_types[position].nullable; + format!( + "('{}', {}, {}, {}, 'index')", + index.name, + i + 1, + position + 1, + nullable + ) + }) + .collect::>() + }); + + let log_values = builtin_items + .iter() + .filter_map(|b| match b { + Builtin::Log(log) => Some(*log), + _ => None, + }) + .flat_map(|log| { + let desc = log.variant.desc(); + log.variant + .index_by() + .into_iter() + .enumerate() + .map(|(i, column)| { + let nullable = desc.typ().column_types[column].nullable; + format!( + "('{}', {}, {}, {}, 'log')", + log.name, + i + 1, + column + 1, + nullable + ) + }) + .collect::>() + }); + + let values = index_values.chain(log_values).join(","); + let sql = format!( + " +SELECT name, index_position::uint8 AS index_position, on_position::uint8 AS on_position, nullable, type +FROM (VALUES {values}) AS v(name, index_position, on_position, nullable, type)" + ); + + BuiltinView { + name: "mz_builtin_index_columns", + schema: MZ_INTERNAL_SCHEMA, + oid: oid::VIEW_MZ_BUILTIN_INDEX_COLUMNS_OID, + desc: RelationDesc::builder() + .with_column("name", SqlScalarType::String.nullable(false)) + .with_column("index_position", SqlScalarType::UInt64.nullable(false)) + .with_column("on_position", SqlScalarType::UInt64.nullable(false)) + .with_column("nullable", SqlScalarType::Bool.nullable(false)) + .with_column("type", SqlScalarType::String.nullable(false)) + // No single column is unique, so the optimizer derives no key + // from the generated VALUES list (`verify_builtin_descs` + // enforces that the declared keys match). + .finish(), + column_comments: Default::default(), + sql: Box::leak(sql.into_boxed_str()), + access: vec![PUBLIC_SELECT], + ontology: None, + } +} + /// The `object_type` of a builtin's `GidMapping` record in `mz_catalog_raw`, as a /// SQL literal spelled the way `->>` renders it, so that catalog views can join /// the record on it without hardcoding the enum's discriminants. diff --git a/src/catalog/src/builtin/mz_catalog.rs b/src/catalog/src/builtin/mz_catalog.rs index 022903636e56c..43a6bb1236d50 100644 --- a/src/catalog/src/builtin/mz_catalog.rs +++ b/src/catalog/src/builtin/mz_catalog.rs @@ -836,9 +836,9 @@ const CATALOG_SERVER_CLUSTER_CTE: &str = "\ WHERE data->>'kind' = 'Cluster' AND data->'value'->>'name' = 'mz_catalog_server' )"; -/// Helper CTEs over `GidMapping` rows used to look up the system id of a -/// builtin index by name and of the relation it indexes by (schema, name). -const GID_MAPPING_CTES: &str = "\ +/// CTE over `GidMapping` rows that looks up the system id of a builtin index +/// by name. +const BUILTIN_INDEX_GID_MAPPINGS_CTE: &str = "\ builtin_index_gid_mappings AS ( SELECT 's' || (data->'value'->>'catalog_id') AS id, @@ -847,7 +847,11 @@ const GID_MAPPING_CTES: &str = "\ WHERE data->>'kind' = 'GidMapping' AND data->'key'->>'object_type' = '6' - ), + )"; + +/// CTE over `GidMapping` rows that looks up the system id of a builtin +/// relation by (schema, name). +const ON_GID_MAPPINGS_CTE: &str = "\ on_gid_mappings AS ( SELECT 's' || (data->'value'->>'catalog_id') AS id, @@ -857,6 +861,14 @@ const GID_MAPPING_CTES: &str = "\ WHERE data->>'kind' = 'GidMapping' )"; +/// Both `GidMapping` CTEs, as `mz_indexes` lists them. +/// +/// NOTE: the joiner indents `on_gid_mappings` by four spaces so that the +/// rendered SQL keeps the layout `mz_indexes`' catalog fingerprint was computed +/// with. Changing it needs a replacement step in `builtin_schema_migration.rs`. +static GID_MAPPING_CTES: LazyLock = + LazyLock::new(|| format!("{BUILTIN_INDEX_GID_MAPPINGS_CTE},\n {ON_GID_MAPPINGS_CTE}")); + pub static MZ_INDEXES: LazyLock = LazyLock::new(|| { // Reconstructs `CREATE INDEX ... IN CLUSTER [] ON [ AS "schema"."name"] ()` // from `mz_builtin_indexes` joined to `GidMapping` lookups and the @@ -906,6 +918,7 @@ pub static MZ_INDEXES: LazyLock = LazyLock::new(|| { ) AS t )"); + let gid_mapping_ctes: &str = &GID_MAPPING_CTES; let sql = format!( " IN CLUSTER mz_catalog_server @@ -922,7 +935,7 @@ WITH ( WITH {USER_INDEXES_CTE}, {CATALOG_SERVER_CLUSTER_CTE}, -{GID_MAPPING_CTES}, +{gid_mapping_ctes}, {builtin_indexes_cte}, {introspection_source_indexes_cte} SELECT * FROM user_indexes @@ -1010,53 +1023,136 @@ SELECT * FROM introspection_source_indexes }), } }); -pub static MZ_INDEX_COLUMNS: LazyLock = LazyLock::new(|| BuiltinTable { - name: "mz_index_columns", - schema: MZ_CATALOG_SCHEMA, - oid: oid::TABLE_MZ_INDEX_COLUMNS_OID, - desc: RelationDesc::builder() - .with_column("index_id", SqlScalarType::String.nullable(false)) - .with_column("index_position", SqlScalarType::UInt64.nullable(false)) - .with_column("on_position", SqlScalarType::UInt64.nullable(true)) - .with_column("on_expression", SqlScalarType::String.nullable(true)) - .with_column("nullable", SqlScalarType::Bool.nullable(false)) - .finish(), - column_comments: BTreeMap::from_iter([ - ( - "index_id", - "The ID of the index which contains this column. Corresponds to `mz_indexes.id`.", - ), - ( - "index_position", - "The 1-indexed position of this column within the index. (The order of columns in an index does not necessarily match the order of columns in the relation on which the index is built.)", - ), - ( - "on_position", - "If not `NULL`, specifies the 1-indexed position of a column in the relation on which this index is built that determines the value of this index column.", - ), - ( - "on_expression", - "If not `NULL`, specifies a SQL expression that is evaluated to compute the value of this index column. The expression may contain references to any of the columns of the relation.", - ), - ( - "nullable", - "Can this column of the index evaluate to `NULL`?", - ), - ]), - is_retained_metrics_object: false, - access: vec![PUBLIC_SELECT], - ontology: Some(Ontology { - entity_name: "index_column", - description: "A column or expression in an index, with its position", - links: &const { - [OntologyLink { - name: "belongs_to_index", - target: "index", - properties: LinkProperties::fk("index_id", "id", Cardinality::ManyToOne), - }] - }, - column_semantic_types: &[("index_id", SemanticType::CatalogItemId)], - }), +pub static MZ_INDEX_COLUMNS: LazyLock = LazyLock::new(|| { + let sql = format!( + " +IN CLUSTER mz_catalog_server +WITH ( + ASSERT NOT NULL index_id, + ASSERT NOT NULL index_position, + ASSERT NOT NULL nullable +) AS +WITH + -- An index's keys are one row whose value lists them in key order. + index_keys AS ( + SELECT + mz_internal.parse_catalog_id(k.data->'key'->'id') AS index_id, + k.data->'value'->'columns' AS columns, + mz_internal.parse_catalog_create_sql(i.data->'value'->'definition'->'V1'->>'create_sql')->'key_parts' AS key_parts + FROM + mz_internal.mz_catalog_raw AS k + -- Filter to index items so the join arranges only their rows. A + -- persisted index's create_sql always starts with `CREATE INDEX` + JOIN mz_internal.mz_catalog_raw AS i ON + i.data->>'kind' = 'Item' AND + i.data->'value'->'definition'->'V1'->>'create_sql' LIKE 'CREATE INDEX %' AND + i.data->'key'->'gid' = k.data->'key'->'id' + WHERE k.data->>'kind' = 'IndexColumns' + ), + key_parts AS ( + SELECT k.index_id, p.ordinality, p.value AS expression + FROM + index_keys AS k, + jsonb_array_elements_text(k.key_parts) WITH ORDINALITY AS p(value, ordinality) + ), + user_index_columns AS ( + SELECT + k.index_id, + -- WITH ORDINALITY numbers the list from one, which is what index_position reports + ik.ordinality::uint8 AS index_position, + (ik.value->>'column')::uint8 + 1::uint8 AS on_position, + -- Either on_position is null or on_expression is, thus we use a case + CASE + WHEN ik.value->>'column' IS NULL + THEN p.expression + END AS on_expression, + (ik.value->>'nullable')::bool AS nullable + FROM + index_keys AS k + CROSS JOIN LATERAL jsonb_array_elements(k.columns) WITH ORDINALITY AS ik(value, ordinality) + LEFT JOIN key_parts AS p ON p.index_id = k.index_id AND p.ordinality = ik.ordinality + ), +{BUILTIN_INDEX_GID_MAPPINGS_CTE}, + builtin_index_columns AS ( + SELECT + bigm.id AS index_id, + bic.index_position, + bic.on_position, + NULL::text AS on_expression, + bic.nullable + FROM mz_internal.mz_builtin_index_columns AS bic + JOIN builtin_index_gid_mappings AS bigm ON bigm.name = bic.name + WHERE bic.type = 'index' + ), + introspection_source_index_columns AS ( + SELECT + 'si' || (isi.data->'value'->>'catalog_id') AS index_id, + bic.index_position, + bic.on_position, + NULL::text AS on_expression, + bic.nullable + FROM mz_internal.mz_catalog_raw AS isi + JOIN mz_internal.mz_builtin_index_columns AS bic ON bic.name = isi.data->'key'->>'name' + WHERE + isi.data->>'kind' = 'ClusterIntrospectionSourceIndex' AND + bic.type = 'log' + ) +SELECT * FROM user_index_columns +UNION ALL +SELECT * FROM builtin_index_columns +UNION ALL +SELECT * FROM introspection_source_index_columns" + ); + + BuiltinMaterializedView { + name: "mz_index_columns", + schema: MZ_CATALOG_SCHEMA, + oid: oid::MV_MZ_INDEX_COLUMNS_OID, + desc: RelationDesc::builder() + .with_column("index_id", SqlScalarType::String.nullable(false)) + .with_column("index_position", SqlScalarType::UInt64.nullable(false)) + .with_column("on_position", SqlScalarType::UInt64.nullable(true)) + .with_column("on_expression", SqlScalarType::String.nullable(true)) + .with_column("nullable", SqlScalarType::Bool.nullable(false)) + .finish(), + column_comments: BTreeMap::from_iter([ + ( + "index_id", + "The ID of the index which contains this column. Corresponds to `mz_indexes.id`.", + ), + ( + "index_position", + "The 1-indexed position of this column within the index. (The order of columns in an index does not necessarily match the order of columns in the relation on which the index is built.)", + ), + ( + "on_position", + "If not `NULL`, specifies the 1-indexed position of a column in the relation on which this index is built that determines the value of this index column.", + ), + ( + "on_expression", + "If not `NULL`, specifies a SQL expression that is evaluated to compute the value of this index column. The expression may contain references to any of the columns of the relation.", + ), + ( + "nullable", + "Can this column of the index evaluate to `NULL`?", + ), + ]), + sql: Box::leak(sql.into_boxed_str()), + is_retained_metrics_object: false, + access: vec![PUBLIC_SELECT], + ontology: Some(Ontology { + entity_name: "index_column", + description: "A column or expression in an index, with its position", + links: &const { + [OntologyLink { + name: "belongs_to_index", + target: "index", + properties: LinkProperties::fk("index_id", "id", Cardinality::ManyToOne), + }] + }, + column_semantic_types: &[("index_id", SemanticType::CatalogItemId)], + }), + } }); pub static MZ_TABLES: LazyLock = LazyLock::new(|| { BuiltinMaterializedView { diff --git a/src/pgrepr-consts/src/oid.rs b/src/pgrepr-consts/src/oid.rs index 1b28872c954af..3f26b5ecaf697 100644 --- a/src/pgrepr-consts/src/oid.rs +++ b/src/pgrepr-consts/src/oid.rs @@ -428,7 +428,7 @@ pub const MV_MZ_DATABASES_OID: u32 = 16702; pub const MV_MZ_SCHEMAS_OID: u32 = 16703; pub const MV_MZ_COLUMNS_OID: u32 = 16704; pub const MV_MZ_INDEXES_OID: u32 = 16705; -pub const TABLE_MZ_INDEX_COLUMNS_OID: u32 = 16706; +pub const MV_MZ_INDEX_COLUMNS_OID: u32 = 16706; pub const MV_MZ_TABLES_OID: u32 = 16707; pub const MV_MZ_CONNECTIONS_OID: u32 = 16708; pub const MV_MZ_SSH_TUNNEL_CONNECTIONS_OID: u32 = 16709; @@ -846,3 +846,4 @@ pub const FUNC_LIST_GT_OID: u32 = 17136; 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; diff --git a/test/sqllogictest/autogenerated/mz_internal.slt b/test/sqllogictest/autogenerated/mz_internal.slt index 143106d6b91db..2f63ad056c1eb 100644 --- a/test/sqllogictest/autogenerated/mz_internal.slt +++ b/test/sqllogictest/autogenerated/mz_internal.slt @@ -813,6 +813,7 @@ mz_aws_connections mz_aws_privatelink_connection_status_history mz_aws_privatelink_connection_statuses mz_builtin_columns +mz_builtin_index_columns mz_builtin_indexes mz_builtin_log_indexes mz_builtin_materialized_views diff --git a/test/sqllogictest/catalog_server_explain.slt b/test/sqllogictest/catalog_server_explain.slt index 57ed51578e80b..b20ef35d679c2 100644 --- a/test/sqllogictest/catalog_server_explain.slt +++ b/test/sqllogictest/catalog_server_explain.slt @@ -4933,7 +4933,7 @@ mz_catalog.mz_columns: Project: #6, #0..=#3, #7, #4, #5 Map: null →Arrange (#0{schema_name}, #1{relation_name}) - →Constant (1932 rows) + →Constant (1937 rows) →Arrange (#1{schema_name}, #2{name}) →Fused with Child Map/Filter/Project Project: #6, #4, #3 @@ -5009,6 +5009,103 @@ Target cluster: mz_catalog_server EOF +query T multiline +EXPLAIN MATERIALIZED VIEW "mz_catalog"."mz_index_columns"; +---- +mz_catalog.mz_index_columns: + →With + cte l0 = + →Differential Join %1:mz_catalog_raw[((#0{data} -> "key") -> "gid")] » %0:mz_catalog_raw[((#0{data} -> "key") -> "id")] + after %0: + Project: #3..=#5 + Map: parse_catalog_id(((#2{data} -> "key") -> "id")), ((#2{data} -> "value") -> "columns"), (parse_catalog_create_sql(((((#1{data} -> "value") -> "definition") -> "V1") ->> "create_sql")) -> "key_parts") + →Arrange (((#0{data} -> "key") -> "id")) + →Fused with Child Map/Filter/Project + Project: #0 + Filter: ((#1 -> "id")) IS NOT NULL AND ("IndexColumns" = #2) + →Read mz_internal.mz_catalog_raw + →Arrange (((#0{data} -> "key") -> "gid")) + →Fused with Child Map/Filter/Project + Project: #0 + Filter: like["CREATE INDEX %"](((((#0{data} -> "value") -> "definition") -> "V1") ->> "create_sql")) AND ((#1 -> "gid")) IS NOT NULL AND ("Item" = #2) + →Read mz_internal.mz_catalog_raw + cte l1 = + →Fused with Child Map/Filter/Project + Project: #0, #2, #3 + →Table Function jsonb_array_elements[with_ordinality](#1{columns}) + →Fused with Child Map/Filter/Project + Project: #0, #1 + →Read l0 + cte l2 = + →Arrange (#0{index_id}, #2{ordinality}) + →Fused with Child Map/Filter/Project + Filter: (#0{index_id}) IS NOT NULL + →Read l1 + cte l3 = + →Differential Join %0:l2[#0{index_id}, #2{ordinality}] » %1[#0{index_id}, #2{ordinality}] + →Arranged l2 + →Arrange (#0{index_id}, #2{ordinality}) + →Fused with Child Map/Filter/Project + Project: #0, #2, #3 + →Table Function jsonb_array_elements_text[with_ordinality](#1{key_parts}) + →Fused with Child Map/Filter/Project + Project: #0, #2 + Filter: (#0{index_id}) IS NOT NULL + →Read l0 + →Return + →Union + →Map/Filter/Project + Project: #0, #4, #6..=#8 + Map: bigint_to_uint8(#2{ordinality}), (#1{value} ->> "column"), (text_to_uint8(#5) + 1), case when (#5) IS NULL then #3{expression} else null end, text_to_boolean((#1{value} ->> "nullable")) + →Union + →Map/Filter/Project + Project: #0..=#3 + Map: null + →Consolidating Union + →Negate Diffs + →Differential Join %1[#0, #1] » %0:l2[#0{index_id}, #2{ordinality}] + →Arranged l2 + →Distinct GroupAggregate + →Fused with Child Map/Filter/Project + Project: #0, #2 + →Read l3 + →Stream l1 + →Stream l3 + →Differential Join %1:mz_catalog_raw[#1{name}] » %0[#0{name}] + Final closure: + Project: #3, #0, #1, #4, #2 + Map: null + →Arrange (#0{name}) + →Constant (108 rows) + →Arrange (#1{name}) + →Fused with Child Map/Filter/Project + Project: #4, #3 + Filter: ("6" = (#1 ->> "object_type")) AND ("GidMapping" = #2) AND (#3) IS NOT NULL + Map: (#1 ->> "object_name"), ("s" || ((#0{data} -> "value") ->> "catalog_id")) + →Read mz_internal.mz_catalog_raw + →Differential Join %0:mz_catalog_raw[((#0{data} -> "key") ->> "name")] » %1[#0{name}] + after %1: + Project: #2..=#5 + Map: ("si" || ((#1{data} -> "value") ->> "catalog_id")) + Final closure: + Project: #3, #0, #1, #4, #2 + Map: null + →Arrange (((#0{data} -> "key") ->> "name")) + →Fused with Child Map/Filter/Project + Project: #0 + Filter: ((#1 ->> "name")) IS NOT NULL AND ("ClusterIntrospectionSourceIndex" = #2) + →Read mz_internal.mz_catalog_raw + →Arrange (#0{name}) + →Constant (83 rows) + +Source mz_internal.mz_catalog_raw + project=(#0..=#2) + map=((#0{data} -> "key"), (#0{data} ->> "kind")) + +Target cluster: mz_catalog_server + +EOF + query T multiline EXPLAIN MATERIALIZED VIEW "mz_catalog"."mz_indexes"; ---- @@ -5249,7 +5346,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 (50 rows) + →Constant (51 rows) →Arrange (empty key) (#0{schema_name}) (#0{schema_name}, #1{name}) →Fused with Child Map/Filter/Project Project: #4, #3, #5 @@ -5594,7 +5691,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 (24 rows) + →Constant (23 rows) →Arrange (#0{schema_name}) (#0{schema_name}, #1{name}) →Fused with Child Map/Filter/Project Project: #5, #4, #6 @@ -5649,7 +5746,7 @@ mz_catalog.mz_views: Project: #5, #0, #6, #1, #2, #8, #3, #4, #7 Map: "s1" →Arrange (#1{schema_name}, #2{name}) - →Constant (197 rows) + →Constant (198 rows) →Arrange (#0{schema_name}) (#0{schema_name}, #1{name}) →Fused with Child Map/Filter/Project Project: #5, #4, #6 @@ -5952,7 +6049,7 @@ mz_internal.mz_materialized_view_refresh_strategies: Project: #0..=#3, #3 Map: "on-commit", null, null →Arrange (#1{name}, #0{schema_name}) - →Constant (50 rows) + →Constant (51 rows) →Arrange (((#0{data} -> "key") ->> "object_name"), ((#0{data} -> "key") ->> "schema_name")) →Fused with Child Map/Filter/Project Project: #0 @@ -6136,7 +6233,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 (1078 rows) + →Constant (1088 rows) →Arrange (#1{schema_name}..=#3{object_type}) →Fused with Child Map/Filter/Project Project: #5, #4, #2, #3 @@ -8702,7 +8799,17 @@ query T multiline EXPLAIN SELECT * FROM "mz_internal"."mz_builtin_columns"; ---- Explained Query (fast path): - →Constant (1932 rows) + →Constant (1937 rows) + +Target cluster: mz_catalog_server + +EOF + +query T multiline +EXPLAIN SELECT * FROM "mz_internal"."mz_builtin_index_columns"; +---- +Explained Query (fast path): + →Constant (191 rows) Target cluster: mz_catalog_server @@ -8732,7 +8839,7 @@ query T multiline EXPLAIN SELECT * FROM "mz_internal"."mz_builtin_materialized_views"; ---- Explained Query (fast path): - →Constant (50 rows) + →Constant (51 rows) Target cluster: mz_catalog_server @@ -8752,7 +8859,7 @@ query T multiline EXPLAIN SELECT * FROM "mz_internal"."mz_builtin_tables"; ---- Explained Query (fast path): - →Constant (24 rows) + →Constant (23 rows) Target cluster: mz_catalog_server @@ -8762,7 +8869,7 @@ query T multiline EXPLAIN SELECT * FROM "mz_internal"."mz_builtin_views"; ---- Explained Query (fast path): - →Constant (197 rows) + →Constant (198 rows) Target cluster: mz_catalog_server @@ -10680,7 +10787,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 (1078 rows) + →Constant (1088 rows) →Arrange (#1{schema_name}..=#3{object_type}) →Fused with Child Map/Filter/Project Project: #5, #4, #2, #3 diff --git a/test/sqllogictest/information_schema_tables.slt b/test/sqllogictest/information_schema_tables.slt index 27e19a8371e7a..00fc60ceb506d 100644 --- a/test/sqllogictest/information_schema_tables.slt +++ b/test/sqllogictest/information_schema_tables.slt @@ -154,7 +154,7 @@ MATERIALIZED VIEW materialize mz_catalog mz_index_columns -BASE TABLE +MATERIALIZED VIEW materialize mz_catalog mz_indexes @@ -293,6 +293,10 @@ mz_builtin_columns VIEW materialize mz_internal +mz_builtin_index_columns +VIEW +materialize +mz_internal mz_builtin_indexes VIEW materialize diff --git a/test/sqllogictest/mz_catalog_server_index_accounting.slt b/test/sqllogictest/mz_catalog_server_index_accounting.slt index df34987e105cf..7493afec8e68d 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␠[s527␠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␠[s776␠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␠[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_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␠[s526␠AS␠"mz_internal"."mz_cluster_reconfigurations"]␠("cluster_id") -mz_cluster_replica_frontiers_ind CREATE␠INDEX␠"mz_cluster_replica_frontiers_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s770␠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␠[s625␠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␠[s532␠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␠[s533␠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␠[s626␠AS␠"mz_internal"."mz_cluster_replica_name_history"]␠("id") +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_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␠[s522␠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␠[s521␠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␠[s534␠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␠[s535␠AS␠"mz_internal"."mz_cluster_replica_statuses"]␠("replica_id") -mz_cluster_replicas_ind CREATE␠INDEX␠"mz_cluster_replicas_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s531␠AS␠"mz_catalog"."mz_cluster_replicas"]␠("id") -mz_clusters_ind CREATE␠INDEX␠"mz_clusters_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s523␠AS␠"mz_catalog"."mz_clusters"]␠("id") -mz_columns_ind CREATE␠INDEX␠"mz_columns_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s494␠AS␠"mz_catalog"."mz_columns"]␠("name") -mz_comments_ind CREATE␠INDEX␠"mz_comments_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s550␠AS␠"mz_internal"."mz_comments"]␠("id") +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_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␠[s751␠AS␠"mz_internal"."mz_compute_dependencies"]␠("dependency_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_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␠[s761␠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␠[s762␠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␠[s529␠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␠[s757␠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␠[s756␠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␠[s755␠AS␠"mz_internal"."mz_console_cluster_utilization_overview"]␠("cluster_id") -mz_databases_ind CREATE␠INDEX␠"mz_databases_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s492␠AS␠"mz_catalog"."mz_databases"]␠("name") +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_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␠[s742␠AS␠"mz_internal"."mz_frontiers"]␠("object_id") -mz_hydration_statuses_ind CREATE␠INDEX␠"mz_hydration_statuses_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s772␠AS␠"mz_internal"."mz_hydration_statuses"]␠("object_id",␠"replica_id") -mz_indexes_ind CREATE␠INDEX␠"mz_indexes_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s495␠AS␠"mz_catalog"."mz_indexes"]␠("id") -mz_kafka_sources_ind CREATE␠INDEX␠"mz_kafka_sources_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s488␠AS␠"mz_catalog"."mz_kafka_sources"]␠("id") -mz_materialized_views_ind CREATE␠INDEX␠"mz_materialized_views_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s554␠AS␠"mz_catalog"."mz_materialized_views"]␠("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_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␠[s552␠AS␠"mz_internal"."mz_metric_sinks"]␠("id") -mz_notices_ind CREATE␠INDEX␠"mz_notices_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s850␠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␠[s764␠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␠[s764␠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␠[s762␠AS␠"mz_internal"."mz_object_arrangement_sizes"]␠("replica_id") -mz_object_dependencies_ind CREATE␠INDEX␠"mz_object_dependencies_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s490␠AS␠"mz_internal"."mz_object_dependencies"]␠("object_id") -mz_object_graph_edges_ind CREATE␠INDEX␠"mz_object_graph_edges_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s753␠AS␠"mz_internal"."mz_object_graph_edges"]␠("object_id") -mz_object_history_ind CREATE␠INDEX␠"mz_object_history_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s565␠AS␠"mz_internal"."mz_object_history"]␠("id") -mz_object_lifetimes_ind CREATE␠INDEX␠"mz_object_lifetimes_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s566␠AS␠"mz_internal"."mz_object_lifetimes"]␠("id") -mz_object_transitive_dependencies_ind CREATE␠INDEX␠"mz_object_transitive_dependencies_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s582␠AS␠"mz_internal"."mz_object_transitive_dependencies"]␠("object_id") -mz_objects_ind CREATE␠INDEX␠"mz_objects_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s562␠AS␠"mz_catalog"."mz_objects"]␠("schema_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_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␠[s726␠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␠[s722␠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␠[s841␠AS␠"mz_catalog"."mz_recent_storage_usage"]␠("object_id") -mz_roles_ind CREATE␠INDEX␠"mz_roles_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s513␠AS␠"mz_catalog"."mz_roles"]␠("id") +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_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␠[s493␠AS␠"mz_catalog"."mz_schemas"]␠("database_id") -mz_secrets_ind CREATE␠INDEX␠"mz_secrets_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s528␠AS␠"mz_catalog"."mz_secrets"]␠("name") -mz_show_all_objects_ind CREATE␠INDEX␠"mz_show_all_objects_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s610␠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␠[s774␠AS␠"mz_internal"."mz_show_cluster_replicas"]␠("cluster") -mz_show_clusters_ind CREATE␠INDEX␠"mz_show_clusters_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s612␠AS␠"mz_internal"."mz_show_clusters"]␠("name") -mz_show_columns_ind CREATE␠INDEX␠"mz_show_columns_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s611␠AS␠"mz_internal"."mz_show_columns"]␠("id") -mz_show_connections_ind CREATE␠INDEX␠"mz_show_connections_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s620␠AS␠"mz_internal"."mz_show_connections"]␠("schema_id") -mz_show_databases_ind CREATE␠INDEX␠"mz_show_databases_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s614␠AS␠"mz_internal"."mz_show_databases"]␠("name") -mz_show_indexes_ind CREATE␠INDEX␠"mz_show_indexes_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s624␠AS␠"mz_internal"."mz_show_indexes"]␠("schema_id") -mz_show_materialized_views_ind CREATE␠INDEX␠"mz_show_materialized_views_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s623␠AS␠"mz_internal"."mz_show_materialized_views"]␠("schema_id") -mz_show_roles_ind CREATE␠INDEX␠"mz_show_roles_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s619␠AS␠"mz_internal"."mz_show_roles"]␠("name") -mz_show_schemas_ind CREATE␠INDEX␠"mz_show_schemas_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s615␠AS␠"mz_internal"."mz_show_schemas"]␠("database_id") -mz_show_secrets_ind CREATE␠INDEX␠"mz_show_secrets_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s613␠AS␠"mz_internal"."mz_show_secrets"]␠("schema_id") -mz_show_sinks_ind CREATE␠INDEX␠"mz_show_sinks_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s622␠AS␠"mz_internal"."mz_show_sinks"]␠("schema_id") -mz_show_sources_ind CREATE␠INDEX␠"mz_show_sources_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s621␠AS␠"mz_internal"."mz_show_sources"]␠("schema_id") -mz_show_tables_ind CREATE␠INDEX␠"mz_show_tables_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s616␠AS␠"mz_internal"."mz_show_tables"]␠("schema_id") -mz_show_types_ind CREATE␠INDEX␠"mz_show_types_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s618␠AS␠"mz_internal"."mz_show_types"]␠("schema_id") -mz_show_views_ind CREATE␠INDEX␠"mz_show_views_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s617␠AS␠"mz_internal"."mz_show_views"]␠("schema_id") -mz_sink_statistics_ind CREATE␠INDEX␠"mz_sink_statistics_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s739␠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␠[s711␠AS␠"mz_internal"."mz_sink_status_history"]␠("sink_id") -mz_sink_statuses_ind CREATE␠INDEX␠"mz_sink_statuses_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s712␠AS␠"mz_internal"."mz_sink_statuses"]␠("id") -mz_sinks_ind CREATE␠INDEX␠"mz_sinks_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s505␠AS␠"mz_catalog"."mz_sinks"]␠("id") -mz_source_statistics_ind CREATE␠INDEX␠"mz_source_statistics_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s737␠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␠[s735␠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␠[s713␠AS␠"mz_internal"."mz_source_status_history"]␠("source_id") -mz_source_statuses_ind CREATE␠INDEX␠"mz_source_statuses_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s730␠AS␠"mz_internal"."mz_source_statuses"]␠("id") -mz_sources_ind CREATE␠INDEX␠"mz_sources_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s498␠AS␠"mz_catalog"."mz_sources"]␠("id") -mz_tables_ind CREATE␠INDEX␠"mz_tables_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s497␠AS␠"mz_catalog"."mz_tables"]␠("schema_id") -mz_types_ind CREATE␠INDEX␠"mz_types_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s507␠AS␠"mz_catalog"."mz_types"]␠("schema_id") -mz_views_ind CREATE␠INDEX␠"mz_views_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s506␠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␠[s746␠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␠[s551␠AS␠"mz_internal"."mz_webhook_sources"]␠("id") -pg_attrdef_all_databases_ind CREATE␠INDEX␠"pg_attrdef_all_databases_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s651␠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␠[s644␠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␠[s661␠AS␠"mz_internal"."pg_authid_core"]␠("rolname") -pg_class_all_databases_ind CREATE␠INDEX␠"pg_class_all_databases_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s632␠AS␠"mz_internal"."pg_class_all_databases"]␠("relname") -pg_description_all_databases_ind CREATE␠INDEX␠"pg_description_all_databases_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s641␠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␠[s629␠AS␠"mz_internal"."pg_namespace_all_databases"]␠("nspname") -pg_type_all_databases_ind CREATE␠INDEX␠"pg_type_all_databases_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s638␠AS␠"mz_internal"."pg_type_all_databases"]␠("oid") +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") # Record all transitive dependencies (tables, sources, views, mvs) of indexes on # the mz_catalog_server cluster. @@ -229,6 +229,11 @@ mz_builtin_columns schema_name mz_builtin_columns type mz_builtin_columns type_mod mz_builtin_columns type_oid +mz_builtin_index_columns index_position +mz_builtin_index_columns name +mz_builtin_index_columns nullable +mz_builtin_index_columns on_position +mz_builtin_index_columns type mz_builtin_indexes is_retained_metrics_object mz_builtin_indexes key_exprs mz_builtin_indexes name diff --git a/test/sqllogictest/mz_index_columns.slt b/test/sqllogictest/mz_index_columns.slt new file mode 100644 index 0000000000000..85390c64e55d7 --- /dev/null +++ b/test/sqllogictest/mz_index_columns.slt @@ -0,0 +1,267 @@ +# 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. + +mode cockroach + +reset-server + +simple conn=mz_system,user=mz_system +ALTER SYSTEM SET enable_alter_table_add_column = true +---- +COMPLETE 0 + +simple conn=mz_system,user=mz_system +ALTER SYSTEM SET enable_index_options = true +---- +COMPLETE 0 + +# Every index has at least one key. +query I +SELECT count(*) +FROM mz_catalog.mz_indexes i +WHERE NOT EXISTS (SELECT FROM mz_catalog.mz_index_columns c WHERE c.index_id = i.id) +---- +0 + +# Every key belongs to an existing index. +query I +SELECT count(DISTINCT c.index_id) +FROM mz_catalog.mz_index_columns c +WHERE NOT EXISTS (SELECT FROM mz_catalog.mz_indexes i WHERE i.id = c.index_id) +---- +0 + +# Positions are 1-based and contiguous, and a key is either a column or an +# expression. +query I +SELECT count(*) +FROM ( + SELECT + index_id, + count(*) AS n, + min(index_position) AS lo, + max(index_position) AS hi, + count(*) FILTER ( + WHERE (on_position IS NULL AND on_expression IS NULL) + OR (on_position IS NOT NULL AND on_expression IS NOT NULL) + ) AS malformed + FROM mz_catalog.mz_index_columns + GROUP BY index_id +) +WHERE lo <> 1 OR hi <> n OR malformed > 0 +---- +0 + +# A column key is a column of the indexed relation and has its nullability. +query I +SELECT count(*) +FROM mz_catalog.mz_index_columns ic +JOIN mz_catalog.mz_indexes i ON i.id = ic.index_id +LEFT JOIN mz_catalog.mz_columns c ON c.id = i.on_id AND c.position = ic.on_position +WHERE ic.on_position IS NOT NULL AND (c.id IS NULL OR c.nullable <> ic.nullable) +---- +0 + +# --- Builtin indexes and introspection source indexes ------------------------- + +query TITT +SELECT i.name, ic.index_position, c.name, ic.nullable +FROM mz_catalog.mz_index_columns ic +JOIN mz_catalog.mz_indexes i ON i.id = ic.index_id +JOIN mz_catalog.mz_columns c ON c.id = i.on_id AND c.position = ic.on_position +WHERE + i.id LIKE 's%' AND + i.name IN ( + 'mz_tables_ind', + 'mz_columns_ind', + 'mz_cluster_replica_history_ind', + 'mz_object_dependencies_ind', + 'mz_source_statistics_with_history_ind' + ) +ORDER BY i.name, ic.index_position +---- +mz_cluster_replica_history_ind 1 dropped_at true +mz_columns_ind 1 name false +mz_object_dependencies_ind 1 object_id false +mz_source_statistics_with_history_ind 1 id false +mz_source_statistics_with_history_ind 2 replica_id true +mz_tables_ind 1 schema_id false + +query TITT +SELECT i.name, ic.index_position, c.name, ic.nullable +FROM mz_catalog.mz_index_columns ic +JOIN mz_catalog.mz_indexes i ON i.id = ic.index_id +JOIN mz_catalog.mz_columns c ON c.id = i.on_id AND c.position = ic.on_position +WHERE + i.id LIKE 'si%' AND + i.cluster_id = (SELECT id FROM mz_catalog.mz_clusters WHERE name = 'quickstart') AND + i.name IN ( + 'mz_active_peeks_per_worker_u1_primary_idx', + 'mz_arrangement_batches_raw_u1_primary_idx', + 'mz_compute_error_counts_raw_u1_primary_idx' + ) +ORDER BY i.name, ic.index_position +---- +mz_active_peeks_per_worker_u1_primary_idx 1 id false +mz_active_peeks_per_worker_u1_primary_idx 2 worker_id false +mz_arrangement_batches_raw_u1_primary_idx 1 operator_id false +mz_arrangement_batches_raw_u1_primary_idx 2 worker_id false +mz_compute_error_counts_raw_u1_primary_idx 1 export_id false +mz_compute_error_counts_raw_u1_primary_idx 2 worker_id false + +# --- User indexes ------------------------------------------------------------- + +statement ok +CREATE TABLE indexed_table (a int, b text NOT NULL) + +statement ok +CREATE INDEX indexed_table_idx ON indexed_table (a, b) + +# A no-op cast, a parenthesized column and a positional reference are reported as +# columns in the `on` column. Every other key is reported as the expression written, +# with the nullability decided by the planner. +statement ok +CREATE INDEX indexed_table_expr_idx ON indexed_table ( + abs(a), + a + 1, + coalesce(a, 0), + a::int4, + a::text, + upper(b), + b || 'x', + -a, + a IS NULL, + CASE WHEN a > 0 THEN a END, + 2, + (a), + 'x' +) + +statement ok +CREATE DEFAULT INDEX ON indexed_table + +statement ok +CREATE INDEX indexed_table_retain_idx ON indexed_table (b) WITH (RETAIN HISTORY FOR '1h') + +statement ok +CREATE VIEW indexed_view AS SELECT a, b, a + 1 AS a_plus_one FROM indexed_table + +statement ok +CREATE DEFAULT INDEX ON indexed_view + +statement ok +CREATE MATERIALIZED VIEW indexed_materialized_view AS SELECT a, b FROM indexed_table + +statement ok +CREATE INDEX indexed_materialized_view_idx ON indexed_materialized_view (b) + +statement ok +CREATE SOURCE auction_source IN CLUSTER quickstart FROM LOAD GENERATOR AUCTION FOR ALL TABLES + +statement ok +CREATE INDEX bids_idx ON bids (auction_id, amount) + +# An index on a builtin relation +simple conn=mz_system,user=mz_system +CREATE INDEX mz_tables_name_idx IN CLUSTER quickstart ON mz_catalog.mz_tables (name) +---- +COMPLETE 0 + +# An index keeps referring to the version of its table it was created on. +statement ok +ALTER TABLE indexed_table ADD COLUMN c int + +statement ok +CREATE INDEX indexed_table_c_idx ON indexed_table (c, a) + +# For on_expression, mask the IDs since catalog IDs aren't stable +query TIITTT +SELECT + i.name, + ic.index_position, + ic.on_position, + c.name, + regexp_replace(ic.on_expression, '\[[su][0-9]+', '[', 'g'), + ic.nullable +FROM mz_catalog.mz_index_columns ic +JOIN mz_catalog.mz_indexes i ON i.id = ic.index_id +LEFT JOIN mz_catalog.mz_columns c ON c.id = i.on_id AND c.position = ic.on_position +WHERE i.id LIKE 'u%' AND i.name IN ( + 'bids_idx', + 'indexed_materialized_view_idx', + 'indexed_table_c_idx', + 'indexed_table_expr_idx', + 'indexed_table_idx', + 'indexed_table_primary_idx', + 'indexed_table_retain_idx', + 'indexed_view_primary_idx', + 'mz_tables_name_idx' +) +ORDER BY i.name, ic.index_position +---- +bids_idx 1 3 auction_id NULL false +bids_idx 2 4 amount NULL false +indexed_materialized_view_idx 1 2 b NULL false +indexed_table_c_idx 1 3 c NULL true +indexed_table_c_idx 2 1 a NULL true +indexed_table_expr_idx 1 NULL NULL pg_catalog.abs(a) true +indexed_table_expr_idx 2 NULL NULL a␠+␠1 true +indexed_table_expr_idx 3 NULL NULL COALESCE(a,␠0) false +indexed_table_expr_idx 4 1 a NULL true +indexed_table_expr_idx 5 NULL NULL a::[␠AS␠pg_catalog.text] true +indexed_table_expr_idx 6 NULL NULL pg_catalog.upper(b) false +indexed_table_expr_idx 7 NULL NULL b␠||␠'x' false +indexed_table_expr_idx 8 NULL NULL -␠a true +indexed_table_expr_idx 9 NULL NULL a␠IS␠NULL false +indexed_table_expr_idx 10 NULL NULL CASE␠WHEN␠a␠>␠0␠THEN␠a␠END true +indexed_table_expr_idx 11 2 b NULL false +indexed_table_expr_idx 12 1 a NULL true +indexed_table_expr_idx 13 NULL NULL 'x' false +indexed_table_idx 1 1 a NULL true +indexed_table_idx 2 2 b NULL false +indexed_table_primary_idx 1 1 a NULL true +indexed_table_primary_idx 2 2 b NULL false +indexed_table_retain_idx 1 2 b NULL false +indexed_view_primary_idx 1 1 a NULL true +indexed_view_primary_idx 2 2 b NULL false +indexed_view_primary_idx 3 3 a_plus_one NULL true +mz_tables_name_idx 1 4 name NULL false + +# --- Retraction --------------------------------------------------------------- + +statement ok +DROP INDEX indexed_table_expr_idx + +statement ok +DROP TABLE indexed_table CASCADE + +# The DROP cascades to indexed_view and indexed_materialized_view and to the +# indexes on all three. A row that survived would have an index_id that no index +# has anymore. +query I +SELECT count(*) +FROM mz_catalog.mz_index_columns c +WHERE NOT EXISTS (SELECT FROM mz_catalog.mz_indexes i WHERE i.id = c.index_id) +---- +0 + +# The drop itself took effect. +query I +SELECT count(*) FROM mz_catalog.mz_indexes +WHERE name IN ( + 'indexed_materialized_view_idx', + 'indexed_table_c_idx', + 'indexed_table_expr_idx', + 'indexed_table_idx', + 'indexed_table_primary_idx', + 'indexed_table_retain_idx', + 'indexed_view_primary_idx' +) +---- +0 diff --git a/test/sqllogictest/mz_views.slt b/test/sqllogictest/mz_views.slt index 3b1ae3bb233e6..35f6d61fad51b 100644 --- a/test/sqllogictest/mz_views.slt +++ b/test/sqllogictest/mz_views.slt @@ -190,6 +190,7 @@ query T SELECT name FROM mz_views WHERE definition LIKE '%definition elided%' AND id LIKE 's%' ORDER BY name ---- mz_builtin_columns +mz_builtin_index_columns mz_builtin_indexes mz_builtin_log_indexes mz_builtin_materialized_views diff --git a/test/sqllogictest/oid.slt b/test/sqllogictest/oid.slt index 61dbc810801ef..68a72efe3a2b6 100644 --- a/test/sqllogictest/oid.slt +++ b/test/sqllogictest/oid.slt @@ -1266,3 +1266,4 @@ SELECT oid, name FROM mz_objects WHERE id LIKE 's%' AND oid < 20000 ORDER BY oid 17132 min 17138 jq 17139 mz_builtin_columns +17140 mz_builtin_index_columns diff --git a/test/testdrive/catalog.td b/test/testdrive/catalog.td index a8723944042db..e389b93c6635c 100644 --- a/test/testdrive/catalog.td +++ b/test/testdrive/catalog.td @@ -515,7 +515,6 @@ mz_base_types "" mz_cluster_replica_sizes "" mz_egress_ips "" mz_functions "" -mz_index_columns "" mz_list_types "" mz_map_types "" mz_operators "" @@ -545,6 +544,7 @@ mz_connections mz_catalog_server "" mz_databases mz_catalog_server "" mz_default_privileges mz_catalog_server "" mz_iceberg_sinks mz_catalog_server "" +mz_index_columns mz_catalog_server "" mz_indexes mz_catalog_server "" mz_kafka_connections mz_catalog_server "" mz_kafka_sinks mz_catalog_server "" @@ -620,6 +620,7 @@ name comment ------------------------------------------------ mz_activity_log_thinned "" mz_builtin_columns "" +mz_builtin_index_columns "" mz_builtin_indexes "" mz_builtin_log_indexes "" mz_builtin_materialized_views "" @@ -841,7 +842,7 @@ test_table "" # `SHOW TABLES` and `mz_tables` should agree. > SELECT COUNT(*) FROM mz_tables WHERE id LIKE 's%' -24 +23 # 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%'