From cf5a0a9edebfd7e1b21653f9f6e631edb1083c3b Mon Sep 17 00:00:00 2001 From: Shine Love Jean Date: Thu, 3 Sep 2026 13:53:41 -0500 Subject: [PATCH 1/3] Add gp_matviews, a schema-qualified view over gp_matview_aux gp_matview_aux.mvname is populated from a bare, non-schema-qualified relation name (InsertMatviewAuxEntry(), gp_matview_aux.c), so two materialized views sharing a name in different schemas produce identical, indistinguishable mvname values. Flagged same-day in review on the PR that introduced it (#720) but never actioned. Add gp_matviews, modeled on pg_matviews, which live-joins gp_matview_aux -> pg_class -> pg_namespace for an always-correct schema-qualified name (mvschema/mvname) instead of the stored, non-qualified copy. Because it's resolved live rather than synced, ALTER MATERIALIZED VIEW ... RENAME and SET SCHEMA can never leave it stale - there is no sync code to miss, unlike a second stored column would require (verified: no code anywhere handles gp_matview_aux on ALTER TABLE ... SET SCHEMA today, since mvname never tracked schema in the first place - a new synced column would need to add that from scratch and could reproduce the same staleness bug this fixes). gp_matview_aux.mvname itself is left completely unchanged - still populated, still synced on rename via the existing mvaux_rename() - and marked deprecated via COMMENT ON COLUMN, pointing at gp_matviews. This is additive only: no column removed, no existing behavior changed, nothing breaks for any existing direct consumer of mvname. Fixes https://github.com/apache/cloudberry/issues/726 Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01PJKwGjLr1ee53Uh8aq1v2H --- src/backend/catalog/system_views.sql | 15 ++++++++++++ src/include/catalog/catversion.h | 2 +- src/test/regress/sql/matview_data.sql | 35 +++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index 24b7fc1d33b..2c3246a8069 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -165,6 +165,21 @@ CREATE VIEW pg_matviews AS LEFT JOIN pg_tablespace T ON (T.oid = C.reltablespace) WHERE C.relkind = 'm'; +CREATE VIEW gp_matviews AS + SELECT + A.mvoid, + N.nspname AS mvschema, + C.relname AS mvname, + A.has_foreign, + A.datastatus + FROM gp_matview_aux A + JOIN pg_class C ON (C.oid = A.mvoid) + LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace); + +COMMENT ON VIEW gp_matviews IS 'Schema-qualified view of gp_matview_aux, resolving mvname live from pg_class/pg_namespace instead of a stored copy. Prefer this over gp_matview_aux.mvname, which is not schema-qualified (see https://github.com/apache/cloudberry/issues/726).'; + +COMMENT ON COLUMN gp_matview_aux.mvname IS 'Deprecated: bare, non-schema-qualified materialized view name, retained for backward compatibility only. Two materialized views with the same name in different schemas are indistinguishable via this column. Use gp_matviews.mvname (with gp_matviews.mvschema) instead. See https://github.com/apache/cloudberry/issues/726.'; + CREATE VIEW pg_dynamic_tables AS SELECT N.nspname AS schemaname, diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 851e58debc3..483a3a02f18 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -60,6 +60,6 @@ */ /* 3yyymmddN */ -#define CATALOG_VERSION_NO 302606111 +#define CATALOG_VERSION_NO 302609031 #endif diff --git a/src/test/regress/sql/matview_data.sql b/src/test/regress/sql/matview_data.sql index 65de9dd5c9b..0356d042116 100644 --- a/src/test/regress/sql/matview_data.sql +++ b/src/test/regress/sql/matview_data.sql @@ -1177,6 +1177,41 @@ select mvname, datastatus from gp_matview_aux where mvname = 'mv_par_normal_oid' insert into par_normal_oid values(1, 2); select mvname, datastatus from gp_matview_aux where mvname = 'mv_par_normal_oid'; +-- +-- Test https://github.com/apache/cloudberry/issues/726: gp_matview_aux.mvname +-- is not schema-qualified, so two materialized views with the same bare name +-- in different schemas are indistinguishable through it. gp_matviews (added +-- above) resolves the name live from pg_class/pg_namespace instead, so it +-- distinguishes them correctly; mvname itself is unchanged (kept, deprecated, +-- for backward compatibility -- see the COMMENT ON in system_views.sql). +-- +create schema mv_schema_test_s1; +create schema mv_schema_test_s2; +create table mv_schema_test_s1.t0(a int); +create table mv_schema_test_s2.t0(a int); +insert into mv_schema_test_s1.t0 values (1), (2); +insert into mv_schema_test_s2.t0 values (10), (20), (30); +create materialized view mv_schema_test_s1.mv0 as select * from mv_schema_test_s1.t0; +create materialized view mv_schema_test_s2.mv0 as select * from mv_schema_test_s2.t0; +-- gp_matview_aux.mvname alone cannot tell these two mv0's apart (both rows +-- show mvname = 'mv0' with no schema information) -- this is the deprecated, +-- pre-existing behavior, kept for backward compatibility, not the fix. +select mvname, datastatus from gp_matview_aux where mvname = 'mv0' order by mvoid; +-- gp_matviews distinguishes them via mvschema. +select mvschema, mvname, has_foreign, datastatus from gp_matviews + where mvschema in ('mv_schema_test_s1', 'mv_schema_test_s2') and mvname = 'mv0' + order by mvschema; +-- rename in one schema; the other schema's mv0 must be unaffected and +-- gp_matviews must reflect the new name immediately (it's resolved live, +-- not synced). +alter materialized view mv_schema_test_s1.mv0 rename to mv0_renamed; +select mvschema, mvname, has_foreign, datastatus from gp_matviews + where mvschema in ('mv_schema_test_s1', 'mv_schema_test_s2') + and mvname in ('mv0', 'mv0_renamed') + order by mvschema; +drop schema mv_schema_test_s1 cascade; +drop schema mv_schema_test_s2 cascade; + --start_ignore drop schema matview_data_schema cascade; --end_ignore From 1fae8eb5a756d2464a5c0b9c1b8127ff8040b7ee Mon Sep 17 00:00:00 2001 From: Shine Love Jean Date: Thu, 3 Sep 2026 14:02:20 -0500 Subject: [PATCH 2/3] Add expected output for the new gp_matviews schema-collision test Captured against a real live 6-segment gpdemo cluster (1 coordinator + 1 standby + 2 primaries + 2 mirrors), built from this branch, via psql -X -a -q -d regression < matview_data.sql (pg_regress's own harness isn't wired up for this ad hoc Docker-built cluster). Pure addition at the exact insertion point in matview_data.sql - confirmed via diff against the pristine upstream expected file that nothing else changed (0 deletions, 66 insertions). Also confirmed live: misc_sanity.sql diffs byte-identical against its checked-in expected output (the new view/comments don't trip any existing sanity check), and aqumv.sql's diff against its checked-in expected output is 100% pre-existing drift unrelated to this patch (GUC-ordering in EXPLAIN VERBOSE, new DISTRIBUTED BY notices, topology-based Motion labels) - grepped for gp_matview/mvname/mvschema in that diff and found zero hits, so aqumv.out is intentionally left untouched here. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01PJKwGjLr1ee53Uh8aq1v2H --- src/test/regress/expected/matview_data.out | 66 ++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/src/test/regress/expected/matview_data.out b/src/test/regress/expected/matview_data.out index 9a9074cd2d5..87acc981a7c 100644 --- a/src/test/regress/expected/matview_data.out +++ b/src/test/regress/expected/matview_data.out @@ -2826,6 +2826,72 @@ select mvname, datastatus from gp_matview_aux where mvname = 'mv_par_normal_oid' mv_par_normal_oid | i (1 row) +-- Test https://github.com/apache/cloudberry/issues/726: gp_matview_aux.mvname +-- is not schema-qualified, so two materialized views with the same bare name +-- in different schemas are indistinguishable through it. gp_matviews (added +-- above) resolves the name live from pg_class/pg_namespace instead, so it +-- distinguishes them correctly; mvname itself is unchanged (kept, deprecated, +-- for backward compatibility -- see the COMMENT ON in system_views.sql). +-- +create schema mv_schema_test_s1; +create schema mv_schema_test_s2; +create table mv_schema_test_s1.t0(a int); +NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'a' as the Apache Cloudberry data distribution key for this table. +HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew. +create table mv_schema_test_s2.t0(a int); +NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'a' as the Apache Cloudberry data distribution key for this table. +HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew. +insert into mv_schema_test_s1.t0 values (1), (2); +insert into mv_schema_test_s2.t0 values (10), (20), (30); +create materialized view mv_schema_test_s1.mv0 as select * from mv_schema_test_s1.t0; +NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column(s) named 'a' as the Apache Cloudberry data distribution key for this table. +HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew. +create materialized view mv_schema_test_s2.mv0 as select * from mv_schema_test_s2.t0; +NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column(s) named 'a' as the Apache Cloudberry data distribution key for this table. +HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew. +-- gp_matview_aux.mvname alone cannot tell these two mv0's apart (both rows +-- show mvname = 'mv0' with no schema information) -- this is the deprecated, +-- pre-existing behavior, kept for backward compatibility, not the fix. +select mvname, datastatus from gp_matview_aux where mvname = 'mv0' order by mvoid; + mvname | datastatus +--------+------------ + mv0 | u + mv0 | u +(2 rows) + +-- gp_matviews distinguishes them via mvschema. +select mvschema, mvname, has_foreign, datastatus from gp_matviews + where mvschema in ('mv_schema_test_s1', 'mv_schema_test_s2') and mvname = 'mv0' + order by mvschema; + mvschema | mvname | has_foreign | datastatus +-------------------+--------+-------------+------------ + mv_schema_test_s1 | mv0 | f | u + mv_schema_test_s2 | mv0 | f | u +(2 rows) + +-- rename in one schema; the other schema's mv0 must be unaffected and +-- gp_matviews must reflect the new name immediately (it's resolved live, +-- not synced). +alter materialized view mv_schema_test_s1.mv0 rename to mv0_renamed; +select mvschema, mvname, has_foreign, datastatus from gp_matviews + where mvschema in ('mv_schema_test_s1', 'mv_schema_test_s2') + and mvname in ('mv0', 'mv0_renamed') + order by mvschema; + mvschema | mvname | has_foreign | datastatus +-------------------+-------------+-------------+------------ + mv_schema_test_s1 | mv0_renamed | f | u + mv_schema_test_s2 | mv0 | f | u +(2 rows) + +drop schema mv_schema_test_s1 cascade; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table mv_schema_test_s1.t0 +drop cascades to materialized view mv_schema_test_s1.mv0_renamed +drop schema mv_schema_test_s2 cascade; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table mv_schema_test_s2.t0 +drop cascades to materialized view mv_schema_test_s2.mv0 + --start_ignore drop schema matview_data_schema cascade; NOTICE: drop cascades to 13 other objects From f4a5556696a70c53f35a9710a9e7edd81f4bea72 Mon Sep 17 00:00:00 2001 From: Shine Love Jean Date: Tue, 8 Sep 2026 07:09:52 -0500 Subject: [PATCH 3/3] Fix matview_data.out formatting mismatch from manual splice CI (apache/cloudberry#1970) failed the matview_data regression test on every platform/config that runs it (ic-good-opt-off/-on, their -deb variants, ic-cbdb-parallel, ic-orca-parallel), all with the identical 2-line diff: a missing leading "--" comment-separator line before the new issue-#726 test block, and a stray extra blank line before --start_ignore that the official pg_regress harness doesn't produce. Root cause: the previous commit's expected-output was hand-spliced from a psql -a capture using an off-by-one line range, dropping the source .sql file's leading "--" and leaving in a blank line pg_regress doesn't echo the same way. Verified by local repro: rebuilt from this exact branch, ran the real `make installcheck-good` (not psql -a) against a live 6-segment gpdemo cluster inside the actual configured build tree (the same target CI runs), diffed the result against this fix - zero remaining difference on the new block. The ~260 other diff lines in this local run are pre-existing, patch-unrelated topology noise (this ad hoc 2-primary demo cluster vs. the original 3-primary capture) already identified and excluded before merging the prior commit; CI's own diff for this test confirms only the 2 lines fixed here were ever actually wrong. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01PJKwGjLr1ee53Uh8aq1v2H --- src/test/regress/expected/matview_data.out | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/regress/expected/matview_data.out b/src/test/regress/expected/matview_data.out index 87acc981a7c..8cafa4192ec 100644 --- a/src/test/regress/expected/matview_data.out +++ b/src/test/regress/expected/matview_data.out @@ -2826,6 +2826,7 @@ select mvname, datastatus from gp_matview_aux where mvname = 'mv_par_normal_oid' mv_par_normal_oid | i (1 row) +-- -- Test https://github.com/apache/cloudberry/issues/726: gp_matview_aux.mvname -- is not schema-qualified, so two materialized views with the same bare name -- in different schemas are indistinguishable through it. gp_matviews (added @@ -2891,7 +2892,6 @@ drop schema mv_schema_test_s2 cascade; NOTICE: drop cascades to 2 other objects DETAIL: drop cascades to table mv_schema_test_s2.t0 drop cascades to materialized view mv_schema_test_s2.mv0 - --start_ignore drop schema matview_data_schema cascade; NOTICE: drop cascades to 13 other objects