]> granicus.if.org Git - postgresql/commitdiff
Fix things so that updatable views work with partitioned tables.
authorRobert Haas <rhaas@postgresql.org>
Tue, 24 Jan 2017 20:46:50 +0000 (15:46 -0500)
committerRobert Haas <rhaas@postgresql.org>
Tue, 24 Jan 2017 20:46:50 +0000 (15:46 -0500)
Previously, ExecInitModifyTable was missing handling for WITH CHECK
OPTION, and view_query_is_auto_updatable was missing handling for
RELKIND_PARTITIONED_TABLE.

Amit Langote, reviewed by me.

src/backend/executor/nodeModifyTable.c
src/backend/rewrite/rewriteHandler.c
src/test/regress/expected/updatable_views.out
src/test/regress/sql/updatable_views.sql

index bbfd1c95543bfc7df00c4bfabcc1122075fa76ad..e35603964b7f494c80a7403aec64e7e115ebf6ab 100644 (file)
@@ -1777,6 +1777,46 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
                i++;
        }
 
+       /*
+        * Build WITH CHECK OPTION constraints for each leaf partition rel.
+        * Note that we didn't build the withCheckOptionList for each partition
+        * within the planner, but simple translation of the varattnos for each
+        * partition will suffice.  This only occurs for the INSERT case;
+        * UPDATE/DELETE cases are handled above.
+        */
+       if (node->withCheckOptionLists != NIL && mtstate->mt_num_partitions > 0)
+       {
+               List            *wcoList;
+
+               Assert(operation == CMD_INSERT);
+               resultRelInfo = mtstate->mt_partitions;
+               wcoList = linitial(node->withCheckOptionLists);
+               for (i = 0; i < mtstate->mt_num_partitions; i++)
+               {
+                       Relation        partrel = resultRelInfo->ri_RelationDesc;
+                       List       *mapped_wcoList;
+                       List       *wcoExprs = NIL;
+                       ListCell   *ll;
+
+                       /* varno = node->nominalRelation */
+                       mapped_wcoList = map_partition_varattnos(wcoList,
+                                                                                                        node->nominalRelation,
+                                                                                                        partrel, rel);
+                       foreach(ll, mapped_wcoList)
+                       {
+                               WithCheckOption *wco = (WithCheckOption *) lfirst(ll);
+                               ExprState  *wcoExpr = ExecInitExpr((Expr *) wco->qual,
+                                                                                          mtstate->mt_plans[i]);
+
+                               wcoExprs = lappend(wcoExprs, wcoExpr);
+                       }
+
+                       resultRelInfo->ri_WithCheckOptions = mapped_wcoList;
+                       resultRelInfo->ri_WithCheckOptionExprs = wcoExprs;
+                       resultRelInfo++;
+               }
+       }
+
        /*
         * Initialize RETURNING projections if needed.
         */
index d1ff3b20b631e6e4e462bd18327c7ea141144209..d3e44fb135056281e04eb4c1ab4e76a02decbd06 100644 (file)
@@ -2249,7 +2249,8 @@ view_query_is_auto_updatable(Query *viewquery, bool check_cols)
        if (base_rte->rtekind != RTE_RELATION ||
                (base_rte->relkind != RELKIND_RELATION &&
                 base_rte->relkind != RELKIND_FOREIGN_TABLE &&
-                base_rte->relkind != RELKIND_VIEW))
+                base_rte->relkind != RELKIND_VIEW &&
+                base_rte->relkind != RELKIND_PARTITIONED_TABLE))
                return gettext_noop("Views that do not select from a single table or view are not automatically updatable.");
 
        if (base_rte->tablesample)
index 2da3c069e11275c6ba7c29b2de0fdc33b48c82c3..2ae3613cec084a1eda0338dcd196acc9b9de5673 100644 (file)
@@ -2367,3 +2367,27 @@ ERROR:  new row violates check option for view "v1"
 DETAIL:  Failing row contains (-1, invalid).
 DROP VIEW v1;
 DROP TABLE t1;
+-- check that an auto-updatable view on a partitioned table works correctly
+create table p (a int, b int) partition by range (a, b);
+create table p1 (b int not null, a int not null) partition by range (b);
+create table p11 (like p1);
+alter table p11 drop a;
+alter table p11 add a int;
+alter table p11 drop a;
+alter table p11 add a int not null;
+alter table p1 attach partition p11 for values from (2) to (5);
+alter table p attach partition p1 for values from (1, 2) to (1, 10);
+create view pv as select * from p;
+insert into pv values (1, 2);
+select tableoid::regclass, * from p;
+ tableoid | a | b 
+----------+---+---
+ p11      | 1 | 2
+(1 row)
+
+create view pv_wco as select * from p where a = 0 with check option;
+insert into pv_wco values (1, 2);
+ERROR:  new row violates check option for view "pv_wco"
+DETAIL:  Failing row contains (2, 1).
+drop view pv, pv_wco;
+drop table p, p1, p11;
index ffc64d2de9abb262d480a696c2108a286ed7c98f..3c19edc8f7e7d07145acc9f1ec66b95e1b866d48 100644 (file)
@@ -1112,3 +1112,22 @@ INSERT INTO v1 VALUES (-1, 'invalid'); -- should fail
 
 DROP VIEW v1;
 DROP TABLE t1;
+
+-- check that an auto-updatable view on a partitioned table works correctly
+create table p (a int, b int) partition by range (a, b);
+create table p1 (b int not null, a int not null) partition by range (b);
+create table p11 (like p1);
+alter table p11 drop a;
+alter table p11 add a int;
+alter table p11 drop a;
+alter table p11 add a int not null;
+alter table p1 attach partition p11 for values from (2) to (5);
+alter table p attach partition p1 for values from (1, 2) to (1, 10);
+
+create view pv as select * from p;
+insert into pv values (1, 2);
+select tableoid::regclass, * from p;
+create view pv_wco as select * from p where a = 0 with check option;
+insert into pv_wco values (1, 2);
+drop view pv, pv_wco;
+drop table p, p1, p11;