Kevin Grittner <kgri...@ymail.com> wrote:
> Michael Paquier <michael.paqu...@gmail.com> wrote:
>
>> I am not sure that adding a boolean flag introducing a concept
>> related to matview inside checkRuleResultList is the best
>> approach to solve that. checkRuleResultList is something related
>> only to rules, and has nothing related to matviews in it yet.
>
> Well, I was tempted to keep that concept in DefineQueryRewrite()
> where the call is made, by calling the new bool something like
> requireColumnNameMatch and not having checkRuleResultList()
> continue to use isSelect for that purpose at all.
> DefineQueryRewrite() already references RELKIND_RELATION once,
> RELKIND_MATVIEW twice, and RELKIND_VIEW three times, so it would
> hardly be introducing a new concept there.
Upon reflection, that seemed to be cleaner. Pushed fix that way.
Not much of a change from the previously posted patch, but attached
here in case anyone wants to argue against this approach.
Thanks for the report!
--
Kevin Grittner
EDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
*** a/src/backend/rewrite/rewriteDefine.c
--- b/src/backend/rewrite/rewriteDefine.c
***************
*** 44,50 ****
static void checkRuleResultList(List *targetList, TupleDesc resultDesc,
! bool isSelect);
static bool setRuleCheckAsUser_walker(Node *node, Oid *context);
static void setRuleCheckAsUser_Query(Query *qry, Oid userid);
--- 44,50 ----
static void checkRuleResultList(List *targetList, TupleDesc resultDesc,
! bool isSelect, bool requireColumnNameMatch);
static bool setRuleCheckAsUser_walker(Node *node, Oid *context);
static void setRuleCheckAsUser_Query(Query *qry, Oid userid);
***************
*** 355,361 **** DefineQueryRewrite(char *rulename,
*/
checkRuleResultList(query->targetList,
RelationGetDescr(event_relation),
! true);
/*
* ... there must not be another ON SELECT rule already ...
--- 355,363 ----
*/
checkRuleResultList(query->targetList,
RelationGetDescr(event_relation),
! true,
! event_relation->rd_rel->relkind !=
! RELKIND_MATVIEW);
/*
* ... there must not be another ON SELECT rule already ...
***************
*** 484,490 **** DefineQueryRewrite(char *rulename,
errmsg("RETURNING lists are not supported in non-INSTEAD rules")));
checkRuleResultList(query->returningList,
RelationGetDescr(event_relation),
! false);
}
}
--- 486,492 ----
errmsg("RETURNING lists are not supported in non-INSTEAD rules")));
checkRuleResultList(query->returningList,
RelationGetDescr(event_relation),
! false, false);
}
}
***************
*** 613,627 **** 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.)
*/
static void
! checkRuleResultList(List *targetList, TupleDesc resultDesc, bool isSelect)
{
ListCell *tllist;
int i;
i = 0;
foreach(tllist, targetList)
{
--- 615,634 ----
* 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 used for choosing error messages.
! *
! * A SELECT targetlist may optionally require that column names match.
*/
static void
! 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,663 **** 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)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("SELECT rule's target entry %d has different column name from \"%s\"", i, attname)));
--- 664,670 ----
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot convert relation containing dropped columns to view")));
! 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)));
*** a/src/test/regress/expected/matview.out
--- b/src/test/regress/expected/matview.out
***************
*** 450,452 **** SELECT * FROM boxmv ORDER BY id;
--- 450,475 ----
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
*** a/src/test/regress/sql/matview.sql
--- b/src/test/regress/sql/matview.sql
***************
*** 173,175 **** UPDATE boxes SET b = '(2,2),(1,1)' WHERE id = 2;
--- 173,188 ----
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;
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers