|
| 1 | +# Copyright Materialize, Inc. and contributors. All rights reserved. |
| 2 | +# |
| 3 | +# Use of this software is governed by the Business Source License |
| 4 | +# included in the LICENSE file at the root of this repository. |
| 5 | +# |
| 6 | +# As of the Change Date specified in that file, in accordance with |
| 7 | +# the Business Source License, use of this software will be governed |
| 8 | +# by the Apache License, Version 2.0. |
| 9 | + |
| 10 | +# Behavioural tests for mz_catalog.mz_tables. It is a BuiltinMaterializedView |
| 11 | +# over mz_internal.mz_catalog_raw (see MZ_TABLES in |
| 12 | +# src/catalog/src/builtin/mz_catalog.rs) with two union branches, user tables |
| 13 | +# and builtin tables, and it derives every column from the durable catalog JSON |
| 14 | +# through parse_catalog_id, parse_catalog_privileges, redact_sql and |
| 15 | +# parse_catalog_create_sql (src/expr/src/scalar/func/impls/jsonb.rs). |
| 16 | +# |
| 17 | +# Before that it was a BuiltinTable populated by pack_table_update in the |
| 18 | +# adapter, so the values pinned here are a compatibility surface: |
| 19 | +# information_schema.tables, pg_tables and pg_class all read through it. |
| 20 | +# |
| 21 | +# Assertions filter by object name rather than counting rows, so the file also |
| 22 | +# holds under --auto-index-selects, which creates extra views. |
| 23 | + |
| 24 | +mode cockroach |
| 25 | + |
| 26 | +# Stable object ids, so create_sql can name dependencies by id. |
| 27 | +reset-server |
| 28 | + |
| 29 | +# --- user_tables branch ------------------------------------------------------- |
| 30 | + |
| 31 | +# `t` is the first object created after the reset, so it is u1 and create_sql |
| 32 | +# below can name it. |
| 33 | +statement ok |
| 34 | +CREATE TABLE t (a int, b text NOT NULL) |
| 35 | + |
| 36 | +query T |
| 37 | +SELECT id FROM mz_tables WHERE name = 't' |
| 38 | +---- |
| 39 | +u1 |
| 40 | + |
| 41 | +query T |
| 42 | +SELECT schema_id = (SELECT id FROM mz_schemas WHERE name = 'public' AND database_id IS NOT NULL) |
| 43 | +FROM mz_tables WHERE name = 't' |
| 44 | +---- |
| 45 | +true |
| 46 | + |
| 47 | +query T |
| 48 | +SELECT owner_id = (SELECT id FROM mz_roles WHERE name = 'materialize') |
| 49 | +FROM mz_tables WHERE name = 't' |
| 50 | +---- |
| 51 | +true |
| 52 | + |
| 53 | +query T multiline |
| 54 | +SELECT create_sql FROM mz_tables WHERE name = 't' |
| 55 | +---- |
| 56 | +CREATE TABLE "materialize"."public"."t" ("a" [s20 AS "pg_catalog"."int4"], "b" [s46 AS "pg_catalog"."text"] NOT NULL) |
| 57 | +EOF |
| 58 | + |
| 59 | +query T multiline |
| 60 | +SELECT redacted_create_sql FROM mz_tables WHERE name = 't' |
| 61 | +---- |
| 62 | +CREATE TABLE materialize.public.t (a [s20 AS pg_catalog.int4], b [s46 AS pg_catalog.text] NOT NULL) |
| 63 | +EOF |
| 64 | + |
| 65 | +# A table with no source omits `source_id` from the parsed create_sql, so the |
| 66 | +# column must be NULL rather than absent or empty. |
| 67 | +query T |
| 68 | +SELECT source_id IS NULL FROM mz_tables WHERE name = 't' |
| 69 | +---- |
| 70 | +true |
| 71 | + |
| 72 | +# --- Cross-check against the in-memory catalog -------------------------------- |
| 73 | + |
| 74 | +# The oid column is read out of the durable JSON, while a regclass cast resolves |
| 75 | +# the name through the in-memory catalog. Two independent paths that must agree. |
| 76 | +# |
| 77 | +# NB create_sql cannot be compared against SHOW CREATE TABLE the same way: SHOW |
| 78 | +# humanizes item ids back to names and pretty-prints, so it is deliberately not |
| 79 | +# the stored string. |
| 80 | +query T |
| 81 | +SELECT oid = 't'::regclass::oid FROM mz_tables WHERE name = 't' |
| 82 | +---- |
| 83 | +true |
| 84 | + |
| 85 | +# --- source_id, for a table created from a source ----------------------------- |
| 86 | + |
| 87 | +statement ok |
| 88 | +CREATE SOURCE lg FROM LOAD GENERATOR COUNTER |
| 89 | + |
| 90 | +statement ok |
| 91 | +CREATE TABLE lg_tbl FROM SOURCE lg (REFERENCE counter) |
| 92 | + |
| 93 | +query T |
| 94 | +SELECT source_id = (SELECT id FROM mz_sources WHERE name = 'lg') |
| 95 | +FROM mz_tables WHERE name = 'lg_tbl' |
| 96 | +---- |
| 97 | +true |
| 98 | + |
| 99 | +# --- Temporary tables --------------------------------------------------------- |
| 100 | + |
| 101 | +# Temporary items are durable catalog items tagged with their owning session, |
| 102 | +# parented to a sentinel schema id shared by every session. The MV maps that |
| 103 | +# sentinel to schema_id '0', which is what the old SchemaSpecifier::Temporary |
| 104 | +# populator printed (src/sql/src/names.rs). |
| 105 | + |
| 106 | +statement ok |
| 107 | +CREATE TEMP TABLE tt (x int) |
| 108 | + |
| 109 | +query TTT |
| 110 | +SELECT id LIKE 'u%', schema_id, create_sql IS NOT NULL FROM mz_tables WHERE name = 'tt' |
| 111 | +---- |
| 112 | +true 0 true |
| 113 | + |
| 114 | +# Two sessions may each hold a temporary table of the same name: name |
| 115 | +# uniqueness is scoped by the owning session. Both rows show up here, since |
| 116 | +# mz_tables reports every item and per-session visibility lives in name |
| 117 | +# resolution, not in this MV. |
| 118 | +simple conn=other |
| 119 | +CREATE TEMP TABLE tt (y text); |
| 120 | +---- |
| 121 | +COMPLETE 0 |
| 122 | + |
| 123 | +query I |
| 124 | +SELECT count(*) FROM mz_tables WHERE name = 'tt' |
| 125 | +---- |
| 126 | +2 |
| 127 | + |
| 128 | +query T |
| 129 | +SELECT array_agg(DISTINCT schema_id) FROM mz_tables WHERE name = 'tt' |
| 130 | +---- |
| 131 | +{0} |
| 132 | + |
| 133 | +# --- builtin_tables branch ---------------------------------------------------- |
| 134 | + |
| 135 | +query TTTT |
| 136 | +SELECT id LIKE 's%', owner_id, create_sql IS NULL, source_id IS NULL |
| 137 | +FROM mz_tables WHERE name = 'mz_kafka_sinks' |
| 138 | +---- |
| 139 | +true s1 true true |
| 140 | + |
| 141 | +query T |
| 142 | +SELECT schema_id = (SELECT id FROM mz_schemas WHERE name = 'mz_catalog' AND database_id IS NULL) |
| 143 | +FROM mz_tables WHERE name = 'mz_kafka_sinks' |
| 144 | +---- |
| 145 | +true |
| 146 | + |
| 147 | +# Exactly once: the user and builtin branches must not both claim a row. |
| 148 | +query I |
| 149 | +SELECT count(*) FROM mz_tables WHERE name = 'mz_kafka_sinks' |
| 150 | +---- |
| 151 | +1 |
| 152 | + |
| 153 | +# Every builtin table the catalog generates must be reported. |
| 154 | +query T |
| 155 | +SELECT array_agg(name ORDER BY name) FROM ( |
| 156 | + SELECT name FROM mz_internal.mz_builtin_tables |
| 157 | + EXCEPT |
| 158 | + SELECT name FROM mz_tables WHERE id LIKE 's%' |
| 159 | +) |
| 160 | +---- |
| 161 | +NULL |
| 162 | + |
| 163 | +# ...and nothing else: every builtin row traces back to the reporter. |
| 164 | +query T |
| 165 | +SELECT array_agg(name ORDER BY name) FROM ( |
| 166 | + SELECT name FROM mz_tables WHERE id LIKE 's%' |
| 167 | + EXCEPT |
| 168 | + SELECT name FROM mz_internal.mz_builtin_tables |
| 169 | +) |
| 170 | +---- |
| 171 | +NULL |
| 172 | + |
| 173 | +# The reporter view backing this MV is itself a builtin view, reported through |
| 174 | +# mz_views with placeholder SQL. See mz_views.slt for the full contract. |
| 175 | +query I |
| 176 | +SELECT count(*) FROM mz_views WHERE name = 'mz_builtin_tables' |
| 177 | +---- |
| 178 | +1 |
| 179 | + |
| 180 | +# --- Robustness over the whole catalog ---------------------------------------- |
| 181 | + |
| 182 | +# The MV runs parse_catalog_create_sql over every Item row in the catalog, in |
| 183 | +# its WHERE clause, so a single item whose create_sql the parser rejects makes |
| 184 | +# the entire relation unreadable rather than dropping one row. Create one item |
| 185 | +# of every kind reachable here and confirm the relation still resolves. |
| 186 | + |
| 187 | +statement ok |
| 188 | +CREATE VIEW v AS SELECT a FROM t |
| 189 | + |
| 190 | +statement ok |
| 191 | +CREATE MATERIALIZED VIEW mv AS SELECT count(*) FROM t |
| 192 | + |
| 193 | +statement ok |
| 194 | +CREATE INDEX t_idx ON t (a) |
| 195 | + |
| 196 | +statement ok |
| 197 | +CREATE TYPE ty AS LIST (ELEMENT TYPE = int4) |
| 198 | + |
| 199 | +statement ok |
| 200 | +CREATE SECRET sec AS 'hunter2' |
| 201 | + |
| 202 | +query T |
| 203 | +SELECT count(*) > 0 FROM mz_tables |
| 204 | +---- |
| 205 | +true |
| 206 | + |
| 207 | +# --- NOT NULL invariants ------------------------------------------------------ |
| 208 | + |
| 209 | +# The MV declares ASSERT NOT NULL for these columns. |
| 210 | +query I |
| 211 | +SELECT count(*) |
| 212 | +FROM mz_tables |
| 213 | +WHERE id IS NULL |
| 214 | + OR oid IS NULL |
| 215 | + OR schema_id IS NULL |
| 216 | + OR name IS NULL |
| 217 | + OR owner_id IS NULL |
| 218 | + OR privileges IS NULL |
| 219 | +---- |
| 220 | +0 |
| 221 | + |
| 222 | +statement ok |
| 223 | +DROP TABLE t CASCADE |
0 commit comments