Thanks a lot Amit for looking at this and providing some useful pointers.

On 2017/07/28 20:46, Amit Khandekar wrote:
> On 28 July 2017 at 11:17, Amit Langote <langote_amit...@lab.ntt.co.jp> wrote:
>> On 2017/07/26 16:58, Amit Langote wrote:
>>> Rajkumar Raghuwanshi reported [1] on the "UPDATE partition key" thread
>>> that whole-row vars don't play nicely with partitioned table operations.
>>>
>>> For example, when used to convert WITH CHECK OPTION constraint expressions
>>> and RETURNING target list expressions, it will error out if the
>>> expressions contained whole-row vars.  That's a bug, because whole-row
>>> vars are legal in those expressions.  I think the decision to output error
>>> upon encountering a whole-row in the input expression was based on the
>>> assumption that it will only ever be used to convert partition constraint
>>> expressions, which cannot contain those.  So, we can relax that
>>> requirement so that its other users are not bitten by it.
>>>
>>> Attached fixes that.
>>
>> Attached a revised version of the patch.
>>
>> Updated patch moves the if (found_whole_row) elog(ERROR) bit in
>> map_partition_varattnos to the callers.  Only the callers know if
>> whole-row vars are not expected in the expression it's getting converted
>> from map_partition_varattnos.  Given the current message text (mentioning
>> "partition key"), it didn't seem appropriate to have the elog inside this
>> function, since it's callable from places where it wouldn't make sense.
> 
> create table foo (a int, b text) partition by list (a);
> create table foo1 partition of foo for values in (1);
> create table foo2(b text, a int) ;
> alter table foo attach partition foo2 for values in (2);
> 
> postgres=# insert into foo values (1, 'hi there');
> INSERT 0 1
> postgres=# insert into foo values (2, 'bi there');
> INSERT 0 1
> postgres=# insert into foo values (2, 'error there') returning foo;
> ERROR:  table row type and query-specified row type do not match
> DETAIL:  Table has type text at ordinal position 1, but query expects integer.

Didn't see that coming.

> This is due to a mismatch between the composite type tuple descriptor
> of the leaf partition doesn't match the RETURNING slot tuple
> descriptor.
> 
> We probably need to do what
> inheritance_planner()=>adjust_appendrel_attrs() does for adjusting the
> attrs in the child rel parse tree; i.e., handle some specific nodes
> other than just simple var nodes. In adjust_appendrel_attrs_mutator(),
> for whole row node, it updates var->vartype to the child rel.

Yes, that's what's needed here.  So we need to teach
map_variable_attnos_mutator() to convert whole-row vars just like it's
done in adjust_appendrel_attrs_mutator().

> I suspect that the other nodes that adjust_appendrel_attrs_mutator
> handles (like JoinExpr, CurrentOfExpr, etc ) may also require similar
> adjustments for our case, because WithCheckOptions (and I think even
> RETURNING) can have a subquery.

Actually, WITH CHECK and RETURNING expressions that are processed in the
executor (i.e., in ExecInitModifyTable) are finished plan tree expressions
(not parse or rewritten parse tree expressions), so we need not have to
worry about having to convert those things in this case.

Remember that adjust_appendrel_attrs_mutator() has to handle raw Query
trees, because we plan the whole query separately for each partition in
the UPDATE and DELETE (inheritance_planner).  Since we don't need to plan
an INSERT query for each partition separately (at least without the
foreign tuple-routing support), we need not worry about converting
anything beside Vars (with proper support for converting whole-row ones
which you discovered has been missing), which we can do within the
executor on the finished plan tree expressions.

Attached 2 patches:

0001: Addresses the bug that Rajkumar reported (handling whole-row vars in
      WITH CHECK and RETURNING expressions at all)

0002: Addressed the bug that Amit reported (converting whole-row vars
      that could occur in WITH CHECK and RETURNING expressions)

Thanks,
Amit
From d6b2169360d7951e229bb39ef53992edde70627b Mon Sep 17 00:00:00 2001
From: amit <amitlangot...@gmail.com>
Date: Wed, 26 Jul 2017 16:45:46 +0900
Subject: [PATCH 1/2] Fix map_partition_varattnos to sometimes accept wholerow
 vars

It was thought that it would never encount wholerow vars in its input
expressions (partition constraint expressions for example).  But then
it was used to convert expressions where wholerow vars are legal, such
as, WCO constraint expressions and RETURNING target list members.  So,
add an argument to tell it whether or not to error on finding wholerows.

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               | 17 ++++++++++-------
 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, 68 insertions(+), 13 deletions(-)

diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c
index e20ddce2db..824898939e 100644
--- a/src/backend/catalog/partition.c
+++ b/src/backend/catalog/partition.c
@@ -904,10 +904,10 @@ get_qual_from_partbound(Relation rel, Relation parent,
  */
 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;
 
        if (expr == NIL)
                return NIL;
@@ -915,14 +915,12 @@ map_partition_varattnos(List *expr, int target_varno,
        part_attnos = convert_tuples_by_name_map(RelationGetDescr(partrel),
                                                                                
         RelationGetDescr(parent),
                                                                                
         gettext_noop("could not convert row type"));
+       *found_whole_row = false;
        expr = (List *) map_variable_attnos((Node *) expr,
                                                                                
target_varno, 0,
                                                                                
part_attnos,
                                                                                
RelationGetDescr(parent)->natts,
-                                                                               
&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");
+                                                                               
found_whole_row);
 
        return expr;
 }
@@ -1783,6 +1781,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 +1824,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..21205244da 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -1992,11 +1992,16 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, 
int eflags)
                        List       *mapped_wcoList;
                        List       *wcoExprs = NIL;
                        ListCell   *ll;
+                       bool            found_whole_row;
 
-                       /* varno = node->nominalRelation */
+                       /*
+                        * We are passing node->nominalRelation as the varno.  
wcoList
+                        * might contain whole-row vars which is legal.
+                        */
                        mapped_wcoList = map_partition_varattnos(wcoList,
                                                                                
                         node->nominalRelation,
-                                                                               
                         partrel, rel);
+                                                                               
                         partrel, rel,
+                                                                               
                         &found_whole_row);
                        foreach(ll, mapped_wcoList)
                        {
                                WithCheckOption *wco = 
castNode(WithCheckOption, lfirst(ll));
@@ -2065,11 +2070,16 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, 
int eflags)
                {
                        Relation        partrel = 
resultRelInfo->ri_RelationDesc;
                        List       *rlist;
+                       bool            found_whole_row;
 
-                       /* varno = node->nominalRelation */
+                       /*
+                        * We are passing node->nominalRelation as the varno.
+                        * returningList might contain wholerow vars which is 
legal.
+                        */
                        rlist = map_partition_varattnos(returningList,
                                                                                
        node->nominalRelation,
-                                                                               
        partrel, rel);
+                                                                               
        partrel, rel,
+                                                                               
        &found_whole_row);
                        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..b642de39d5 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 RETUNING 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..2eff832e59 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 RETUNING 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 d99c50cf7714e55ccde77bf67a16ea66f54764fe Mon Sep 17 00:00:00 2001
From: amit <amitlangot...@gmail.com>
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               |  7 +++-
 src/backend/commands/tablecmds.c              |  2 ++
 src/backend/executor/nodeModifyTable.c        | 10 ++----
 src/backend/parser/parse_utilcmd.c            |  3 ++
 src/backend/rewrite/rewriteManip.c            | 49 +++++++++++++++++++++------
 src/include/rewrite/rewriteManip.h            |  1 +
 src/include/utils/rel.h                       |  7 ++++
 src/test/regress/expected/insert.out          | 10 ++++++
 src/test/regress/expected/updatable_views.out | 20 +++++++++--
 src/test/regress/sql/insert.sql               |  6 ++++
 src/test/regress/sql/updatable_views.sql      | 22 ++++++++++--
 11 files changed, 114 insertions(+), 23 deletions(-)

diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c
index 824898939e..23bbb03ecb 100644
--- a/src/backend/catalog/partition.c
+++ b/src/backend/catalog/partition.c
@@ -908,6 +908,8 @@ map_partition_varattnos(List *expr, int target_varno,
                                                bool *found_whole_row)
 {
        AttrNumber *part_attnos;
+       Oid             from_rowtype,
+                       to_rowtype;
 
        if (expr == NIL)
                return NIL;
@@ -915,11 +917,14 @@ map_partition_varattnos(List *expr, int target_varno,
        part_attnos = convert_tuples_by_name_map(RelationGetDescr(partrel),
                                                                                
         RelationGetDescr(parent),
                                                                                
         gettext_noop("could not convert row type"));
-       *found_whole_row = false;
+
+       from_rowtype = RelationGetRelType(parent);
+       to_rowtype = RelationGetRelType(partrel);
        expr = (List *) map_variable_attnos((Node *) expr,
                                                                                
target_varno, 0,
                                                                                
part_attnos,
                                                                                
RelationGetDescr(parent)->natts,
+                                                                               
from_rowtype, to_rowtype,
                                                                                
found_whole_row);
 
        return expr;
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index cc5d3d6faf..71072d68ce 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -1989,6 +1989,7 @@ MergeAttributes(List *schema, List *supers, char 
relpersistence,
                                expr = 
map_variable_attnos(stringToNode(check[i].ccbin),
                                                                                
   1, 0,
                                                                                
   newattno, tupleDesc->natts,
+                                                                               
   InvalidOid, InvalidOid,
                                                                                
   &found_whole_row);
 
                                /*
@@ -8874,6 +8875,7 @@ ATPrepAlterColumnType(List **wqueue,
                                        map_variable_attnos(def->cooked_default,
                                                                                
1, 0,
                                                                                
attmap, RelationGetDescr(rel)->natts,
+                                                                               
InvalidOid, InvalidOid,
                                                                                
&found_whole_row);
                                if (found_whole_row)
                                        ereport(ERROR,
diff --git a/src/backend/executor/nodeModifyTable.c 
b/src/backend/executor/nodeModifyTable.c
index 21205244da..fecf264b21 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -1994,10 +1994,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, 
int eflags)
                        ListCell   *ll;
                        bool            found_whole_row;
 
-                       /*
-                        * We are passing node->nominalRelation as the varno.  
wcoList
-                        * might contain whole-row vars which is legal.
-                        */
+                       /* varno = node->nominalRelation */
                        mapped_wcoList = map_partition_varattnos(wcoList,
                                                                                
                         node->nominalRelation,
                                                                                
                         partrel, rel,
@@ -2072,10 +2069,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, 
int eflags)
                        List       *rlist;
                        bool            found_whole_row;
 
-                       /*
-                        * We are passing node->nominalRelation as the varno.
-                        * returningList might contain wholerow vars which is 
legal.
-                        */
+                       /* varno = node->nominalRelation */
                        rlist = map_partition_varattnos(returningList,
                                                                                
        node->nominalRelation,
                                                                                
        partrel, rel,
diff --git a/src/backend/parser/parse_utilcmd.c 
b/src/backend/parser/parse_utilcmd.c
index 9f37f1b920..025d616421 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -1107,6 +1107,7 @@ transformTableLikeClause(CreateStmtContext *cxt, 
TableLikeClause *table_like_cla
                        ccbin_node = map_variable_attnos(stringToNode(ccbin),
                                                                                
         1, 0,
                                                                                
         attmap, tupleDesc->natts,
+                                                                               
         InvalidOid, InvalidOid,
                                                                                
         &found_whole_row);
 
                        /*
@@ -1463,6 +1464,7 @@ generateClonedIndexStmt(CreateStmtContext *cxt, Relation 
source_idx,
                        indexkey = map_variable_attnos(indexkey,
                                                                                
   1, 0,
                                                                                
   attmap, attmap_length,
+                                                                               
   InvalidOid, InvalidOid,
                                                                                
   &found_whole_row);
 
                        /* As in transformTableLikeClause, reject whole-row 
variables */
@@ -1539,6 +1541,7 @@ generateClonedIndexStmt(CreateStmtContext *cxt, Relation 
source_idx,
                pred_tree = map_variable_attnos(pred_tree,
                                                                                
1, 0,
                                                                                
attmap, attmap_length,
+                                                                               
InvalidOid, InvalidOid,
                                                                                
&found_whole_row);
 
                /* As in transformTableLikeClause, reject whole-row variables */
diff --git a/src/backend/rewrite/rewriteManip.c 
b/src/backend/rewrite/rewriteManip.c
index b89b435da0..d39b5f7fa1 100644
--- a/src/backend/rewrite/rewriteManip.c
+++ b/src/backend/rewrite/rewriteManip.c
@@ -1202,15 +1202,19 @@ 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 from_towtype 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
@@ -1224,6 +1228,9 @@ typedef struct
        const AttrNumber *attno_map;    /* map array for user attnos */
        int                     map_length;             /* number of entries in 
attno_map[] */
        bool       *found_whole_row;    /* output flag */
+       /* Information needed to convert whole-row vars */
+       Oid                     from_rowtype;
+       Oid                     to_rowtype;
 } map_variable_attnos_context;
 
 static Node *
@@ -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;
@@ -1257,6 +1264,25 @@ 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
+                                * necessary.
+                                */
+                               if (OidIsValid(context->to_rowtype) &&
+                                       OidIsValid(context->from_rowtype) &&
+                                       context->to_rowtype != 
context->from_rowtype)
+                               {
+                                       ConvertRowtypeExpr *r = 
makeNode(ConvertRowtypeExpr);
+
+                                       r->arg = (Expr *) newvar;
+                                       r->resulttype = context->from_rowtype;
+                                       r->convertformat = COERCE_IMPLICIT_CAST;
+                                       r->location = -1;
+                                       /* Make sure the Var node has the right 
type ID, too */
+                                       newvar->vartype = context->to_rowtype;
+                                       return (Node *) r;
+                               }
                        }
                        return (Node *) newvar;
                }
@@ -1283,6 +1309,7 @@ Node *
 map_variable_attnos(Node *node,
                                        int target_varno, int sublevels_up,
                                        const AttrNumber *attno_map, int 
map_length,
+                                       Oid from_rowtype, Oid to_rowtype,
                                        bool *found_whole_row)
 {
        map_variable_attnos_context context;
@@ -1291,6 +1318,8 @@ map_variable_attnos(Node *node,
        context.sublevels_up = sublevels_up;
        context.attno_map = attno_map;
        context.map_length = map_length;
+       context.from_rowtype = from_rowtype;
+       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..68db9c15f1 100644
--- a/src/include/rewrite/rewriteManip.h
+++ b/src/include/rewrite/rewriteManip.h
@@ -72,6 +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,
+                                       Oid from_rowtype, Oid to_rowtype,
                                        bool *found_whole_row);
 
 extern Node *ReplaceVarsFromTargetList(Node *node,
diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h
index 4bc61e5380..bd5428f72f 100644
--- a/src/include/utils/rel.h
+++ b/src/include/utils/rel.h
@@ -444,6 +444,13 @@ typedef struct ViewOptions
        ((relation)->rd_rel->relnamespace)
 
 /*
+ * RelationGetRelType
+ *             Returns the rel's pg_type OID.
+ */
+#define RelationGetRelType(relation) \
+       ((relation)->rd_rel->reltype)
+
+/*
  * RelationIsMapped
  *             True if the relation uses the relfilenode map.
  *
diff --git a/src/test/regress/expected/insert.out 
b/src/test/regress/expected/insert.out
index b642de39d5..38b364d10f 100644
--- a/src/test/regress/expected/insert.out
+++ b/src/test/regress/expected/insert.out
@@ -668,4 +668,14 @@ insert into returningwrtest values (1) returning 
returningwrtest;
  (1)
 (1 row)
 
+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 2eff832e59..f51d72484d 100644
--- a/src/test/regress/sql/insert.sql
+++ b/src/test/regress/sql/insert.sql
@@ -404,4 +404,10 @@ 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;
+
+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 (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to