From 587cda35ca331128db6c61d406d312654572834a Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Tue, 24 Jan 2017 15:46:50 -0500 Subject: [PATCH] Fix things so that updatable views work with partitioned tables. 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 | 40 +++++++++++++++++++ src/backend/rewrite/rewriteHandler.c | 3 +- src/test/regress/expected/updatable_views.out | 24 +++++++++++ src/test/regress/sql/updatable_views.sql | 19 +++++++++ 4 files changed, 85 insertions(+), 1 deletion(-) diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index bbfd1c9554..e35603964b 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -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. */ diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c index d1ff3b20b6..d3e44fb135 100644 --- a/src/backend/rewrite/rewriteHandler.c +++ b/src/backend/rewrite/rewriteHandler.c @@ -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) diff --git a/src/test/regress/expected/updatable_views.out b/src/test/regress/expected/updatable_views.out index 2da3c069e1..2ae3613cec 100644 --- a/src/test/regress/expected/updatable_views.out +++ b/src/test/regress/expected/updatable_views.out @@ -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; diff --git a/src/test/regress/sql/updatable_views.sql b/src/test/regress/sql/updatable_views.sql index ffc64d2de9..3c19edc8f7 100644 --- a/src/test/regress/sql/updatable_views.sql +++ b/src/test/regress/sql/updatable_views.sql @@ -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;