From 732758db4c8226b74a6ea7a90bc8c3cd15f5fe86 Mon Sep 17 00:00:00 2001 From: Kevin Grittner Date: Mon, 4 Nov 2013 14:31:07 -0600 Subject: [PATCH] Fix breakage of MV column name list usage. Per bug report from Tomonari Katsumata. Back-patch to 9.3. --- src/backend/rewrite/rewriteDefine.c | 21 ++++++++++++++------- src/test/regress/expected/matview.out | 23 +++++++++++++++++++++++ src/test/regress/sql/matview.sql | 13 +++++++++++++ 3 files changed, 50 insertions(+), 7 deletions(-) diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c index 9c4a5d47e2..2eca531749 100644 --- a/src/backend/rewrite/rewriteDefine.c +++ b/src/backend/rewrite/rewriteDefine.c @@ -44,7 +44,7 @@ static void checkRuleResultList(List *targetList, TupleDesc resultDesc, - bool isSelect); + bool isSelect, bool requireColumnNameMatch); static bool setRuleCheckAsUser_walker(Node *node, Oid *context); static void setRuleCheckAsUser_Query(Query *qry, Oid userid); @@ -355,7 +355,9 @@ DefineQueryRewrite(char *rulename, */ checkRuleResultList(query->targetList, RelationGetDescr(event_relation), - true); + true, + event_relation->rd_rel->relkind != + RELKIND_MATVIEW); /* * ... there must not be another ON SELECT rule already ... @@ -484,7 +486,7 @@ DefineQueryRewrite(char *rulename, errmsg("RETURNING lists are not supported in non-INSTEAD rules"))); checkRuleResultList(query->returningList, RelationGetDescr(event_relation), - false); + false, false); } } @@ -613,15 +615,20 @@ DefineQueryRewrite(char *rulename, * Verify that targetList produces output compatible with a tupledesc * * The targetList might be either a SELECT targetlist, or a RETURNING list; - * isSelect tells which. (This is mostly used for choosing error messages, - * but also we don't enforce column name matching for RETURNING.) + * isSelect tells which. This is used for choosing error messages. + * + * A SELECT targetlist may optionally require that column names match. */ static void -checkRuleResultList(List *targetList, TupleDesc resultDesc, bool isSelect) +checkRuleResultList(List *targetList, TupleDesc resultDesc, bool isSelect, + bool requireColumnNameMatch) { ListCell *tllist; int i; + /* Only a SELECT may require a column name match. */ + Assert(isSelect || !requireColumnNameMatch); + i = 0; foreach(tllist, targetList) { @@ -657,7 +664,7 @@ checkRuleResultList(List *targetList, TupleDesc resultDesc, bool isSelect) (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot convert relation containing dropped columns to view"))); - if (isSelect && strcmp(tle->resname, attname) != 0) + if (requireColumnNameMatch && strcmp(tle->resname, attname) != 0) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("SELECT rule's target entry %d has different column name from \"%s\"", i, attname))); diff --git a/src/test/regress/expected/matview.out b/src/test/regress/expected/matview.out index 24f8b796df..edbc6f6121 100644 --- a/src/test/regress/expected/matview.out +++ b/src/test/regress/expected/matview.out @@ -450,3 +450,26 @@ SELECT * FROM boxmv ORDER BY id; DROP TABLE boxes CASCADE; NOTICE: drop cascades to materialized view boxmv +-- make sure that column names are handled correctly +CREATE TABLE v (i int, j int); +CREATE MATERIALIZED VIEW mv_v (ii) AS SELECT i, j AS jj FROM v; +ALTER TABLE v RENAME COLUMN i TO x; +INSERT INTO v values (1, 2); +CREATE UNIQUE INDEX mv_v_ii ON mv_v (ii); +REFRESH MATERIALIZED VIEW mv_v; +UPDATE v SET j = 3 WHERE x = 1; +REFRESH MATERIALIZED VIEW CONCURRENTLY mv_v; +SELECT * FROM v; + x | j +---+--- + 1 | 3 +(1 row) + +SELECT * FROM mv_v; + ii | jj +----+---- + 1 | 3 +(1 row) + +DROP TABLE v CASCADE; +NOTICE: drop cascades to materialized view mv_v diff --git a/src/test/regress/sql/matview.sql b/src/test/regress/sql/matview.sql index 93e7a42480..8d03d331cf 100644 --- a/src/test/regress/sql/matview.sql +++ b/src/test/regress/sql/matview.sql @@ -173,3 +173,16 @@ UPDATE boxes SET b = '(2,2),(1,1)' WHERE id = 2; REFRESH MATERIALIZED VIEW CONCURRENTLY boxmv; SELECT * FROM boxmv ORDER BY id; DROP TABLE boxes CASCADE; + +-- make sure that column names are handled correctly +CREATE TABLE v (i int, j int); +CREATE MATERIALIZED VIEW mv_v (ii) AS SELECT i, j AS jj FROM v; +ALTER TABLE v RENAME COLUMN i TO x; +INSERT INTO v values (1, 2); +CREATE UNIQUE INDEX mv_v_ii ON mv_v (ii); +REFRESH MATERIALIZED VIEW mv_v; +UPDATE v SET j = 3 WHERE x = 1; +REFRESH MATERIALIZED VIEW CONCURRENTLY mv_v; +SELECT * FROM v; +SELECT * FROM mv_v; +DROP TABLE v CASCADE;