Fujita-san,
Thanks for the review.
On 2017/08/03 16:01, Etsuro Fujita wrote:
> On 2017/08/02 15:21, Amit Langote wrote:
>> On 2017/08/02 1:33, Amit Khandekar wrote:
>>> -------
>>>
>>> Few more comments :
>>>
>>> @@ -1240,7 +1247,7 @@ map_variable_attnos_mutator(Node *node,
>>> var->varlevelsup == context->sublevels_up)
>>> {
>>> /* Found a matching variable, make the substitution */
>>>
>>> - Var *newvar = (Var *) palloc(sizeof(Var));
>>> + Var *newvar = copyObject(var);
>>> int attno = var->varattno;
>>>
>>> *newvar = *var;
>>>
>>> Here, "*newvar = *var" should be removed.
>>
>> Done.
>
> I'm not sure this change is a good idea, because the copy by "*newvar =
> *var" would be more efficient than the copyObject(). (We have this
> optimization in other places as well. See eg, copyVar() in setrefs.c.)
OK, done.
> Here are some other comments:
>
> + /* If the callers expects us to convert the same, do so. */
> + if (OidIsValid(context->to_rowtype))
> + {
> + ConvertRowtypeExpr *r;
> +
> + /* Var itself is converted to the requested rowtype. */
> + newvar->vartype = context->to_rowtype;
> +
> + /*
> + * And a conversion step on top to convert back to the
> + * original type.
> + */
> + r = makeNode(ConvertRowtypeExpr);
> + r->arg = (Expr *) newvar;
> + r->resulttype = var->vartype;
> + r->convertformat = COERCE_IMPLICIT_CAST;
> + r->location = -1;
> +
> + return (Node *) r;
> + }
>
> Why not do this conversion if to_rowtype is valid and it's different from
> the rowtype of the original whole-row Var like the previous patch? Also, I
> think it's better to add an assertion that the rowtype of the original
> whole-row Var is a named one. So, what I have in mind is:
>
> if (OidIsValid(context->to_rowtype))
> {
> Assert(var->vartype != RECORDOID)
> if (var->vartype != context->to_rowtype)
> {
> ConvertRowtypeExpr *r;
>
> /* Var itself is converted to the requested rowtype. */
> ...
> /* And a conversion step on top to convert back to the ... */
> ...
> return (Node *) r;
> }
> }
Sounds good, so done.
> Here is the modification to the map_variable_attnos()'s API:
>
> map_variable_attnos(Node *node,
> int target_varno, int sublevels_up,
> const AttrNumber *attno_map, int
> map_length,
> - bool *found_whole_row)
> + bool *found_whole_row, Oid
> to_rowtype)
>
> This is nitpicking, but I think it would be better to put the new argument
> to_rowtype right before the output argument found_whole_row.
I consider this a good suggestion. I guess we tend to list all the input
arguments before any output arguments. So done as you suggest.
> + * RelationGetRelType
> + * Returns the rel's pg_type OID.
> + */
> +#define RelationGetRelType(relation) \
> + ((relation)->rd_rel->reltype)
>
> This macro is used in only one place. Do we really need that? (This
> macro would be useful for other places such as expand_inherited_rtentry,
> but I think it's better to introduce this in a separate patch, maybe for
> PG11.)
Alright, dropped RelationGetRelType from the patch.
> +-- check that wholerow vars in the RETUNING list work with partitioned
> tables
>
> Typo: s/RETUNING/RETURNING/
Fixed.
Attached updated patches.
Thanks,
Amit
From 9b2d16ec4c8eadd7261849d5aa0f34ee2577b405 Mon Sep 17 00:00:00 2001
From: amit <[email protected]>
Date: Wed, 26 Jul 2017 16:45:46 +0900
Subject: [PATCH 1/2] Fix map_partition_varattnos to not error on
found_whole_row
It was designed assuming that the expressions passed to it can never
contain whole-row vars, but it's wrong since it's called from places
that pass it WCO constraint expressions and RETURNING target list
expressions, which can very well contain whole-row vars.
Move the responsibility of error'ing out to the callers, because they
are in position to know that finding whole-row vars is an error
condition.
Adds test in insert.sql and updatable_views.sql.
Reported by: Rajkumar Raghuwanshi
Report:
https://postgr.es/m/CAKcux6%3Dz38gH4K6YAFi%2BYvo5tHTwBL4tam4VM33CAPZ5dDMk1Q%40mail.gmail.com
---
src/backend/catalog/partition.c | 20 ++++++++++++++------
src/backend/commands/tablecmds.c | 8 +++++++-
src/backend/executor/nodeModifyTable.c | 18 ++++++++++++++----
src/include/catalog/partition.h | 3 ++-
src/test/regress/expected/insert.out | 10 ++++++++++
src/test/regress/expected/updatable_views.out | 10 ++++++++++
src/test/regress/sql/insert.sql | 6 ++++++
src/test/regress/sql/updatable_views.sql | 9 +++++++++
8 files changed, 72 insertions(+), 12 deletions(-)
diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c
index 9d50efb6a0..80ca928a9c 100644
--- a/src/backend/catalog/partition.c
+++ b/src/backend/catalog/partition.c
@@ -898,16 +898,20 @@ get_qual_from_partbound(Relation rel, Relation parent,
* We must allow for cases where physical attnos of a partition can be
* different from the parent's.
*
+ * If found_whole_row is not NULL, *found_whole_row returns whether a
+ * whole-row variable was found in the input expression.
+ *
* Note: this will work on any node tree, so really the argument and result
* should be declared "Node *". But a substantial majority of the callers
* are working on Lists, so it's less messy to do the casts internally.
*/
List *
map_partition_varattnos(List *expr, int target_varno,
- Relation partrel, Relation
parent)
+ Relation partrel, Relation
parent,
+ bool *found_whole_row)
{
AttrNumber *part_attnos;
- bool found_whole_row;
+ bool my_found_whole_row;
if (expr == NIL)
return NIL;
@@ -919,10 +923,9 @@ map_partition_varattnos(List *expr, int target_varno,
target_varno, 0,
part_attnos,
RelationGetDescr(parent)->natts,
-
&found_whole_row);
- /* There can never be a whole-row reference here */
+
&my_found_whole_row);
if (found_whole_row)
- elog(ERROR, "unexpected whole-row reference found in partition
key");
+ *found_whole_row = my_found_whole_row;
return expr;
}
@@ -1783,6 +1786,7 @@ generate_partition_qual(Relation rel)
List *my_qual = NIL,
*result = NIL;
Relation parent;
+ bool found_whole_row;
/* Guard against stack overflow due to overly deep partition tree */
check_stack_depth();
@@ -1825,7 +1829,11 @@ generate_partition_qual(Relation rel)
* in it to bear this relation's attnos. It's safe to assume varno = 1
* here.
*/
- result = map_partition_varattnos(result, 1, rel, parent);
+ result = map_partition_varattnos(result, 1, rel, parent,
+
&found_whole_row);
+ /* There can never be a whole-row reference here */
+ if (found_whole_row)
+ elog(ERROR, "unexpected whole-row reference found in partition
key");
/* Save a copy in the relcache */
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index bb00858ad1..cc5d3d6faf 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -13713,6 +13713,7 @@ ATExecAttachPartition(List **wqueue, Relation rel,
PartitionCmd *cmd)
Oid part_relid = lfirst_oid(lc);
Relation part_rel;
Expr *constr;
+ bool found_whole_row;
/* Lock already taken */
if (part_relid != RelationGetRelid(attachRel))
@@ -13738,7 +13739,12 @@ ATExecAttachPartition(List **wqueue, Relation rel,
PartitionCmd *cmd)
constr = linitial(partConstraint);
tab->partition_constraint = (Expr *)
map_partition_varattnos((List *) constr, 1,
-
part_rel, rel);
+
part_rel, rel,
+
&found_whole_row);
+ /* There can never be a whole-row reference here */
+ if (found_whole_row)
+ elog(ERROR, "unexpected whole-row reference
found in partition key");
+
/* keep our lock until commit */
if (part_rel != attachRel)
heap_close(part_rel, NoLock);
diff --git a/src/backend/executor/nodeModifyTable.c
b/src/backend/executor/nodeModifyTable.c
index 0dde0ed6eb..c60a9f7952 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -1993,10 +1993,15 @@ ExecInitModifyTable(ModifyTable *node, EState *estate,
int eflags)
List *wcoExprs = NIL;
ListCell *ll;
- /* varno = node->nominalRelation */
+ /*
+ * We are passing node->nominalRelation as the varno to
match
+ * Vars to be changed. We don't care to know whether
wcoList
+ * contains a whole-row Var, so passing NULL for the
last
+ * argument.
+ */
mapped_wcoList = map_partition_varattnos(wcoList,
node->nominalRelation,
-
partrel, rel);
+
partrel, rel, NULL);
foreach(ll, mapped_wcoList)
{
WithCheckOption *wco =
castNode(WithCheckOption, lfirst(ll));
@@ -2066,10 +2071,15 @@ ExecInitModifyTable(ModifyTable *node, EState *estate,
int eflags)
Relation partrel =
resultRelInfo->ri_RelationDesc;
List *rlist;
- /* varno = node->nominalRelation */
+ /*
+ * We are passing node->nominalRelation as the varno to
match
+ * Vars to be changed. We don't care to know whether
+ * returningList contains a whole-row Var, so passing
NULL for
+ * the last argument.
+ */
rlist = map_partition_varattnos(returningList,
node->nominalRelation,
-
partrel, rel);
+
partrel, rel, NULL);
resultRelInfo->ri_projectReturning =
ExecBuildProjectionInfo(rlist, econtext, slot,
&mtstate->ps,
resultRelInfo->ri_RelationDesc->rd_att);
diff --git a/src/include/catalog/partition.h b/src/include/catalog/partition.h
index f10879a162..434ded37d7 100644
--- a/src/include/catalog/partition.h
+++ b/src/include/catalog/partition.h
@@ -80,7 +80,8 @@ extern Oid get_partition_parent(Oid relid);
extern List *get_qual_from_partbound(Relation rel, Relation parent,
PartitionBoundSpec *spec);
extern List *map_partition_varattnos(List *expr, int target_varno,
- Relation partrel, Relation
parent);
+ Relation partrel, Relation
parent,
+ bool *found_whole_row);
extern List *RelationGetPartitionQual(Relation rel);
extern Expr *get_partition_qual_relid(Oid relid);
diff --git a/src/test/regress/expected/insert.out
b/src/test/regress/expected/insert.out
index 0dcc86fef4..da08062b4a 100644
--- a/src/test/regress/expected/insert.out
+++ b/src/test/regress/expected/insert.out
@@ -659,3 +659,13 @@ select tableoid::regclass, * from mcrparted order by a, b;
(11 rows)
drop table mcrparted;
+-- check that wholerow vars in the RETURNING list work with partitioned tables
+create table returningwrtest (a int) partition by list (a);
+create table returningwrtest1 partition of returningwrtest for values in (1);
+insert into returningwrtest values (1) returning returningwrtest;
+ returningwrtest
+-----------------
+ (1)
+(1 row)
+
+drop table returningwrtest;
diff --git a/src/test/regress/expected/updatable_views.out
b/src/test/regress/expected/updatable_views.out
index eab5c0334c..51a21f10c2 100644
--- a/src/test/regress/expected/updatable_views.out
+++ b/src/test/regress/expected/updatable_views.out
@@ -2428,3 +2428,13 @@ ERROR: new row violates check option for view "ptv_wco"
DETAIL: Failing row contains (1, 2, null).
drop view ptv, ptv_wco;
drop table pt, pt1, pt11;
+-- check that wholerow vars appearing in WITH CHECK OPTION constraint
expressions
+-- work fine with partitioned tables
+create table wcowrtest (a int) partition by list (a);
+create table wcowrtest1 partition of wcowrtest for values in (1);
+create view wcowrtest_v as select * from wcowrtest where wcowrtest =
'(2)'::wcowrtest with check option;
+insert into wcowrtest_v values (1);
+ERROR: new row violates check option for view "wcowrtest_v"
+DETAIL: Failing row contains (1).
+drop view wcowrtest_v;
+drop table wcowrtest;
diff --git a/src/test/regress/sql/insert.sql b/src/test/regress/sql/insert.sql
index 6adf25da40..de7d54ee5e 100644
--- a/src/test/regress/sql/insert.sql
+++ b/src/test/regress/sql/insert.sql
@@ -399,3 +399,9 @@ insert into mcrparted values ('aaa', 0), ('b', 0), ('bz',
10), ('c', -10),
('commons', 0), ('d', -10), ('e', 0);
select tableoid::regclass, * from mcrparted order by a, b;
drop table mcrparted;
+
+-- check that wholerow vars in the RETURNING list work with partitioned tables
+create table returningwrtest (a int) partition by list (a);
+create table returningwrtest1 partition of returningwrtest for values in (1);
+insert into returningwrtest values (1) returning returningwrtest;
+drop table returningwrtest;
diff --git a/src/test/regress/sql/updatable_views.sql
b/src/test/regress/sql/updatable_views.sql
index 2ede44c02b..af8499a019 100644
--- a/src/test/regress/sql/updatable_views.sql
+++ b/src/test/regress/sql/updatable_views.sql
@@ -1141,3 +1141,12 @@ create view ptv_wco as select * from pt where a = 0 with
check option;
insert into ptv_wco values (1, 2);
drop view ptv, ptv_wco;
drop table pt, pt1, pt11;
+
+-- check that wholerow vars appearing in WITH CHECK OPTION constraint
expressions
+-- work fine with partitioned tables
+create table wcowrtest (a int) partition by list (a);
+create table wcowrtest1 partition of wcowrtest for values in (1);
+create view wcowrtest_v as select * from wcowrtest where wcowrtest =
'(2)'::wcowrtest with check option;
+insert into wcowrtest_v values (1);
+drop view wcowrtest_v;
+drop table wcowrtest;
--
2.11.0
From a6e3c8d8cd99e513bc0ab417adc9cd0ea8527249 Mon Sep 17 00:00:00 2001
From: amit <[email protected]>
Date: Mon, 31 Jul 2017 17:48:07 +0900
Subject: [PATCH 2/2] Teach map_variable_attnos_mutator to convert whole-row
Vars
Partitioning code that uses it requires it.
---
src/backend/catalog/partition.c | 1 +
src/backend/commands/tablecmds.c | 4 +-
src/backend/parser/parse_utilcmd.c | 6 +--
src/backend/rewrite/rewriteManip.c | 57 ++++++++++++++++++++++-----
src/include/rewrite/rewriteManip.h | 2 +-
src/test/regress/expected/insert.out | 11 ++++++
src/test/regress/expected/updatable_views.out | 20 +++++++++-
src/test/regress/sql/insert.sql | 7 ++++
src/test/regress/sql/updatable_views.sql | 22 ++++++++++-
9 files changed, 110 insertions(+), 20 deletions(-)
diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c
index 80ca928a9c..dcc7f8af27 100644
--- a/src/backend/catalog/partition.c
+++ b/src/backend/catalog/partition.c
@@ -923,6 +923,7 @@ map_partition_varattnos(List *expr, int target_varno,
target_varno, 0,
part_attnos,
RelationGetDescr(parent)->natts,
+
RelationGetForm(partrel)->reltype,
&my_found_whole_row);
if (found_whole_row)
*found_whole_row = my_found_whole_row;
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index cc5d3d6faf..b58c92d846 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -1989,7 +1989,7 @@ MergeAttributes(List *schema, List *supers, char
relpersistence,
expr =
map_variable_attnos(stringToNode(check[i].ccbin),
1, 0,
newattno, tupleDesc->natts,
-
&found_whole_row);
+
InvalidOid, &found_whole_row);
/*
* For the moment we have to reject whole-row
variables. We
@@ -8874,7 +8874,7 @@ ATPrepAlterColumnType(List **wqueue,
map_variable_attnos(def->cooked_default,
1, 0,
attmap, RelationGetDescr(rel)->natts,
-
&found_whole_row);
+
InvalidOid, &found_whole_row);
if (found_whole_row)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
diff --git a/src/backend/parser/parse_utilcmd.c
b/src/backend/parser/parse_utilcmd.c
index 9f37f1b920..a86c2341f5 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -1107,7 +1107,7 @@ transformTableLikeClause(CreateStmtContext *cxt,
TableLikeClause *table_like_cla
ccbin_node = map_variable_attnos(stringToNode(ccbin),
1, 0,
attmap, tupleDesc->natts,
-
&found_whole_row);
+
InvalidOid, &found_whole_row);
/*
* We reject whole-row variables because the whole
point of LIKE
@@ -1463,7 +1463,7 @@ generateClonedIndexStmt(CreateStmtContext *cxt, Relation
source_idx,
indexkey = map_variable_attnos(indexkey,
1, 0,
attmap, attmap_length,
-
&found_whole_row);
+
InvalidOid, &found_whole_row);
/* As in transformTableLikeClause, reject whole-row
variables */
if (found_whole_row)
@@ -1539,7 +1539,7 @@ generateClonedIndexStmt(CreateStmtContext *cxt, Relation
source_idx,
pred_tree = map_variable_attnos(pred_tree,
1, 0,
attmap, attmap_length,
-
&found_whole_row);
+
InvalidOid, &found_whole_row);
/* As in transformTableLikeClause, reject whole-row variables */
if (found_whole_row)
diff --git a/src/backend/rewrite/rewriteManip.c
b/src/backend/rewrite/rewriteManip.c
index b89b435da0..297473f409 100644
--- a/src/backend/rewrite/rewriteManip.c
+++ b/src/backend/rewrite/rewriteManip.c
@@ -1202,15 +1202,18 @@ replace_rte_variables_mutator(Node *node,
* A zero in the mapping array represents a dropped column, which should not
* appear in the expression.
*
- * If the expression tree contains a whole-row Var for the target RTE,
- * the Var is not changed but *found_whole_row is returned as TRUE.
- * For most callers this is an error condition, but we leave it to the caller
- * to report the error so that useful context can be provided. (In some
- * usages it would be appropriate to modify the Var's vartype and insert a
- * ConvertRowtypeExpr node to map back to the original vartype. We might
- * someday extend this function's API to support that. For now, the only
- * concession to that future need is that this function is a tree mutator
- * not just a walker.)
+ * Depending on the caller, whole-row Vars in the expression tree are
+ * converted if the necessary information is provided (see below.) If the
+ * caller cannot provide the information, it might mean that finding a
+ * whole-row Var in the first place is an error. In that case, we let the
+ * caller know that a whole-row Var was found by returning *found_whole_row
+ * as TRUE, which the caller then can report as an error by providing useful
+ * context information.
+ *
+ * When the information necessary to convert whole-row Vars is present, we
+ * substitute the Var's vartype (replace by to_rowtype) and add a
+ * ConvertRowtypeExpr node to map back to the original vartype. Currently,
+ * only map_partition_varattnos() requests conversion of whole-row Vars.
*
* This could be built using replace_rte_variables and a callback function,
* but since we don't ever need to insert sublinks, replace_rte_variables is
@@ -1223,6 +1226,8 @@ typedef struct
int sublevels_up; /* (current) nesting depth */
const AttrNumber *attno_map; /* map array for user attnos */
int map_length; /* number of entries in
attno_map[] */
+ /* Target type when converting whole-row vars */
+ Oid to_rowtype;
bool *found_whole_row; /* output flag */
} map_variable_attnos_context;
@@ -1257,6 +1262,37 @@ map_variable_attnos_mutator(Node *node,
{
/* whole-row variable, warn caller */
*(context->found_whole_row) = true;
+
+ /* If the callers expects us to convert the
same, do so. */
+ if (OidIsValid(context->to_rowtype))
+ {
+ /*
+ * Considering that the only caller who
wants to get
+ * whole-row variables converted is
concerned with
+ * partitioning, we can be sure that
var is a named
+ * whole-row variable.
+ */
+ Assert(var->vartype != RECORDOID);
+ if (context->to_rowtype != var->vartype)
+ {
+ ConvertRowtypeExpr *r;
+
+ /* Var itself is converted to
the requested type. */
+ newvar->vartype =
context->to_rowtype;
+
+ /*
+ * And a conversion node on top
to convert back to
+ * the original type.
+ */
+ r =
makeNode(ConvertRowtypeExpr);
+ r->arg = (Expr *) newvar;
+ r->resulttype = var->vartype;
+ r->convertformat =
COERCE_IMPLICIT_CAST;
+ r->location = -1;
+
+ return (Node *) r;
+ }
+ }
}
return (Node *) newvar;
}
@@ -1283,7 +1319,7 @@ Node *
map_variable_attnos(Node *node,
int target_varno, int sublevels_up,
const AttrNumber *attno_map, int
map_length,
- bool *found_whole_row)
+ Oid to_rowtype, bool *found_whole_row)
{
map_variable_attnos_context context;
@@ -1291,6 +1327,7 @@ map_variable_attnos(Node *node,
context.sublevels_up = sublevels_up;
context.attno_map = attno_map;
context.map_length = map_length;
+ context.to_rowtype = to_rowtype;
context.found_whole_row = found_whole_row;
*found_whole_row = false;
diff --git a/src/include/rewrite/rewriteManip.h
b/src/include/rewrite/rewriteManip.h
index 282ff9967f..f0a7a8b2cd 100644
--- a/src/include/rewrite/rewriteManip.h
+++ b/src/include/rewrite/rewriteManip.h
@@ -72,7 +72,7 @@ extern Node *replace_rte_variables_mutator(Node *node,
extern Node *map_variable_attnos(Node *node,
int target_varno, int sublevels_up,
const AttrNumber *attno_map, int
map_length,
- bool *found_whole_row);
+ Oid to_rowtype, bool *found_whole_row);
extern Node *ReplaceVarsFromTargetList(Node *node,
int target_varno, int
sublevels_up,
diff --git a/src/test/regress/expected/insert.out
b/src/test/regress/expected/insert.out
index da08062b4a..a2d9469592 100644
--- a/src/test/regress/expected/insert.out
+++ b/src/test/regress/expected/insert.out
@@ -668,4 +668,15 @@ insert into returningwrtest values (1) returning
returningwrtest;
(1)
(1 row)
+-- check also that the wholerow vars in RETURNING list are converted as needed
+alter table returningwrtest add b text;
+create table returningwrtest2 (b text, c int, a int);
+alter table returningwrtest2 drop c;
+alter table returningwrtest attach partition returningwrtest2 for values in
(2);
+insert into returningwrtest values (2, 'foo') returning returningwrtest;
+ returningwrtest
+-----------------
+ (2,foo)
+(1 row)
+
drop table returningwrtest;
diff --git a/src/test/regress/expected/updatable_views.out
b/src/test/regress/expected/updatable_views.out
index 51a21f10c2..2090a411fe 100644
--- a/src/test/regress/expected/updatable_views.out
+++ b/src/test/regress/expected/updatable_views.out
@@ -2436,5 +2436,21 @@ create view wcowrtest_v as select * from wcowrtest where
wcowrtest = '(2)'::wcow
insert into wcowrtest_v values (1);
ERROR: new row violates check option for view "wcowrtest_v"
DETAIL: Failing row contains (1).
-drop view wcowrtest_v;
-drop table wcowrtest;
+alter table wcowrtest add b text;
+create table wcowrtest2 (b text, c int, a int);
+alter table wcowrtest2 drop c;
+alter table wcowrtest attach partition wcowrtest2 for values in (2);
+create table sometable (a int, b text);
+insert into sometable values (1, 'a'), (2, 'b');
+create view wcowrtest_v2 as
+ select *
+ from wcowrtest r
+ where r in (select s from sometable s where r.a = s.a)
+with check option;
+-- WITH CHECK qual will be processed with wcowrtest2's
+-- rowtype after tuple-routing
+insert into wcowrtest_v2 values (2, 'no such row in sometable');
+ERROR: new row violates check option for view "wcowrtest_v2"
+DETAIL: Failing row contains (2, no such row in sometable).
+drop view wcowrtest_v, wcowrtest_v2;
+drop table wcowrtest, sometable;
diff --git a/src/test/regress/sql/insert.sql b/src/test/regress/sql/insert.sql
index de7d54ee5e..6f17872087 100644
--- a/src/test/regress/sql/insert.sql
+++ b/src/test/regress/sql/insert.sql
@@ -404,4 +404,11 @@ drop table mcrparted;
create table returningwrtest (a int) partition by list (a);
create table returningwrtest1 partition of returningwrtest for values in (1);
insert into returningwrtest values (1) returning returningwrtest;
+
+-- check also that the wholerow vars in RETURNING list are converted as needed
+alter table returningwrtest add b text;
+create table returningwrtest2 (b text, c int, a int);
+alter table returningwrtest2 drop c;
+alter table returningwrtest attach partition returningwrtest2 for values in
(2);
+insert into returningwrtest values (2, 'foo') returning returningwrtest;
drop table returningwrtest;
diff --git a/src/test/regress/sql/updatable_views.sql
b/src/test/regress/sql/updatable_views.sql
index af8499a019..a6ba5aad9e 100644
--- a/src/test/regress/sql/updatable_views.sql
+++ b/src/test/regress/sql/updatable_views.sql
@@ -1148,5 +1148,23 @@ create table wcowrtest (a int) partition by list (a);
create table wcowrtest1 partition of wcowrtest for values in (1);
create view wcowrtest_v as select * from wcowrtest where wcowrtest =
'(2)'::wcowrtest with check option;
insert into wcowrtest_v values (1);
-drop view wcowrtest_v;
-drop table wcowrtest;
+
+alter table wcowrtest add b text;
+create table wcowrtest2 (b text, c int, a int);
+alter table wcowrtest2 drop c;
+alter table wcowrtest attach partition wcowrtest2 for values in (2);
+
+create table sometable (a int, b text);
+insert into sometable values (1, 'a'), (2, 'b');
+create view wcowrtest_v2 as
+ select *
+ from wcowrtest r
+ where r in (select s from sometable s where r.a = s.a)
+with check option;
+
+-- WITH CHECK qual will be processed with wcowrtest2's
+-- rowtype after tuple-routing
+insert into wcowrtest_v2 values (2, 'no such row in sometable');
+
+drop view wcowrtest_v, wcowrtest_v2;
+drop table wcowrtest, sometable;
--
2.11.0
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers