Hi,

While working on writeable CTEs, I noticed I have to special-case the
output of a Query node frequently because in INSERT/UPDATE/DELETE query
targetList is the target list which is used for modifying the result
relation and returningList is the output of that Query.  However, this
is different from SELECT where targetList actually is the output of that
Query node.  Attached is a patch which avoids this special-casing by
making Query's targetList always be the output target list.  The target
list for the result relation is stored separately.  The patch needs a
bit more work but I'll be glad to do it if people think this is useful.

Thoughts?


Regards,
Marko Tiikkaja

*** a/src/backend/executor/functions.c
--- b/src/backend/executor/functions.c
***************
*** 1070,1078 **** check_sql_fn_retval(Oid func_id, Oid rettype, List 
*queryTreeList,
                         (parse->commandType == CMD_INSERT ||
                          parse->commandType == CMD_UPDATE ||
                          parse->commandType == CMD_DELETE) &&
!                        parse->returningList)
        {
!               tlist = parse->returningList;
        }
        else
        {
--- 1070,1078 ----
                         (parse->commandType == CMD_INSERT ||
                          parse->commandType == CMD_UPDATE ||
                          parse->commandType == CMD_DELETE) &&
!                        parse->hasReturning) 
        {
!               tlist = parse->targetList;
        }
        else
        {
*** a/src/backend/nodes/copyfuncs.c
--- b/src/backend/nodes/copyfuncs.c
***************
*** 2225,2235 **** _copyQuery(Query *from)
        COPY_SCALAR_FIELD(hasDistinctOn);
        COPY_SCALAR_FIELD(hasRecursive);
        COPY_SCALAR_FIELD(hasForUpdate);
        COPY_NODE_FIELD(cteList);
        COPY_NODE_FIELD(rtable);
        COPY_NODE_FIELD(jointree);
        COPY_NODE_FIELD(targetList);
!       COPY_NODE_FIELD(returningList);
        COPY_NODE_FIELD(groupClause);
        COPY_NODE_FIELD(havingQual);
        COPY_NODE_FIELD(windowClause);
--- 2225,2236 ----
        COPY_SCALAR_FIELD(hasDistinctOn);
        COPY_SCALAR_FIELD(hasRecursive);
        COPY_SCALAR_FIELD(hasForUpdate);
+       COPY_SCALAR_FIELD(hasReturning);
        COPY_NODE_FIELD(cteList);
        COPY_NODE_FIELD(rtable);
        COPY_NODE_FIELD(jointree);
        COPY_NODE_FIELD(targetList);
!       COPY_NODE_FIELD(resultTargetList);
        COPY_NODE_FIELD(groupClause);
        COPY_NODE_FIELD(havingQual);
        COPY_NODE_FIELD(windowClause);
*** a/src/backend/nodes/equalfuncs.c
--- b/src/backend/nodes/equalfuncs.c
***************
*** 861,871 **** _equalQuery(Query *a, Query *b)
        COMPARE_SCALAR_FIELD(hasDistinctOn);
        COMPARE_SCALAR_FIELD(hasRecursive);
        COMPARE_SCALAR_FIELD(hasForUpdate);
        COMPARE_NODE_FIELD(cteList);
        COMPARE_NODE_FIELD(rtable);
        COMPARE_NODE_FIELD(jointree);
        COMPARE_NODE_FIELD(targetList);
!       COMPARE_NODE_FIELD(returningList);
        COMPARE_NODE_FIELD(groupClause);
        COMPARE_NODE_FIELD(havingQual);
        COMPARE_NODE_FIELD(windowClause);
--- 861,872 ----
        COMPARE_SCALAR_FIELD(hasDistinctOn);
        COMPARE_SCALAR_FIELD(hasRecursive);
        COMPARE_SCALAR_FIELD(hasForUpdate);
+       COMPARE_SCALAR_FIELD(hasReturning);
        COMPARE_NODE_FIELD(cteList);
        COMPARE_NODE_FIELD(rtable);
        COMPARE_NODE_FIELD(jointree);
        COMPARE_NODE_FIELD(targetList);
!       COMPARE_NODE_FIELD(resultTargetList);
        COMPARE_NODE_FIELD(groupClause);
        COMPARE_NODE_FIELD(havingQual);
        COMPARE_NODE_FIELD(windowClause);
*** a/src/backend/nodes/nodeFuncs.c
--- b/src/backend/nodes/nodeFuncs.c
***************
*** 1392,1400 **** query_tree_walker(Query *query,
  {
        Assert(query != NULL && IsA(query, Query));
  
!       if (walker((Node *) query->targetList, context))
                return true;
!       if (walker((Node *) query->returningList, context))
                return true;
        if (walker((Node *) query->jointree, context))
                return true;
--- 1392,1400 ----
  {
        Assert(query != NULL && IsA(query, Query));
  
!       if (walker((Node *) query->resultTargetList, context))
                return true;
!       if (walker((Node *) query->targetList, context))
                return true;
        if (walker((Node *) query->jointree, context))
                return true;
***************
*** 2090,2097 **** query_tree_mutator(Query *query,
                query = newquery;
        }
  
        MUTATE(query->targetList, query->targetList, List *);
-       MUTATE(query->returningList, query->returningList, List *);
        MUTATE(query->jointree, query->jointree, FromExpr *);
        MUTATE(query->setOperations, query->setOperations, Node *);
        MUTATE(query->havingQual, query->havingQual, Node *);
--- 2090,2097 ----
                query = newquery;
        }
  
+       MUTATE(query->resultTargetList, query->resultTargetList, List *);
        MUTATE(query->targetList, query->targetList, List *);
        MUTATE(query->jointree, query->jointree, FromExpr *);
        MUTATE(query->setOperations, query->setOperations, Node *);
        MUTATE(query->havingQual, query->havingQual, Node *);
*** a/src/backend/nodes/outfuncs.c
--- b/src/backend/nodes/outfuncs.c
***************
*** 1988,1998 **** _outQuery(StringInfo str, Query *node)
        WRITE_BOOL_FIELD(hasDistinctOn);
        WRITE_BOOL_FIELD(hasRecursive);
        WRITE_BOOL_FIELD(hasForUpdate);
        WRITE_NODE_FIELD(cteList);
        WRITE_NODE_FIELD(rtable);
        WRITE_NODE_FIELD(jointree);
        WRITE_NODE_FIELD(targetList);
!       WRITE_NODE_FIELD(returningList);
        WRITE_NODE_FIELD(groupClause);
        WRITE_NODE_FIELD(havingQual);
        WRITE_NODE_FIELD(windowClause);
--- 1988,1999 ----
        WRITE_BOOL_FIELD(hasDistinctOn);
        WRITE_BOOL_FIELD(hasRecursive);
        WRITE_BOOL_FIELD(hasForUpdate);
+       WRITE_BOOL_FIELD(hasReturning);
        WRITE_NODE_FIELD(cteList);
        WRITE_NODE_FIELD(rtable);
        WRITE_NODE_FIELD(jointree);
        WRITE_NODE_FIELD(targetList);
!       WRITE_NODE_FIELD(resultTargetList);
        WRITE_NODE_FIELD(groupClause);
        WRITE_NODE_FIELD(havingQual);
        WRITE_NODE_FIELD(windowClause);
*** a/src/backend/nodes/readfuncs.c
--- b/src/backend/nodes/readfuncs.c
***************
*** 204,214 **** _readQuery(void)
        READ_BOOL_FIELD(hasDistinctOn);
        READ_BOOL_FIELD(hasRecursive);
        READ_BOOL_FIELD(hasForUpdate);
        READ_NODE_FIELD(cteList);
        READ_NODE_FIELD(rtable);
        READ_NODE_FIELD(jointree);
        READ_NODE_FIELD(targetList);
!       READ_NODE_FIELD(returningList);
        READ_NODE_FIELD(groupClause);
        READ_NODE_FIELD(havingQual);
        READ_NODE_FIELD(windowClause);
--- 204,215 ----
        READ_BOOL_FIELD(hasDistinctOn);
        READ_BOOL_FIELD(hasRecursive);
        READ_BOOL_FIELD(hasForUpdate);
+       READ_BOOL_FIELD(hasReturning);
        READ_NODE_FIELD(cteList);
        READ_NODE_FIELD(rtable);
        READ_NODE_FIELD(jointree);
        READ_NODE_FIELD(targetList);
!       READ_NODE_FIELD(resultTargetList);
        READ_NODE_FIELD(groupClause);
        READ_NODE_FIELD(havingQual);
        READ_NODE_FIELD(windowClause);
*** a/src/backend/optimizer/plan/planagg.c
--- b/src/backend/optimizer/plan/planagg.c
***************
*** 488,494 **** make_agg_subplan(PlannerInfo *root, MinMaxAggInfo *info)
        subroot.parse = subparse = (Query *) copyObject(root->parse);
        subparse->commandType = CMD_SELECT;
        subparse->resultRelation = 0;
!       subparse->returningList = NIL;
        subparse->utilityStmt = NULL;
        subparse->intoClause = NULL;
        subparse->hasAggs = false;
--- 488,495 ----
        subroot.parse = subparse = (Query *) copyObject(root->parse);
        subparse->commandType = CMD_SELECT;
        subparse->resultRelation = 0;
!       subparse->hasReturning = false;
!       subparse->resultTargetList = NIL;
        subparse->utilityStmt = NULL;
        subparse->intoClause = NULL;
        subparse->hasAggs = false;
*** a/src/backend/optimizer/plan/planner.c
--- b/src/backend/optimizer/plan/planner.c
***************
*** 232,238 **** standard_planner(Query *parse, int cursorOptions, 
ParamListInfo boundParams)
        result = makeNode(PlannedStmt);
  
        result->commandType = parse->commandType;
!       result->hasReturning = (parse->returningList != NIL);
        result->canSetTag = parse->canSetTag;
        result->transientPlan = glob->transientPlan;
        result->planTree = top_plan;
--- 232,238 ----
        result = makeNode(PlannedStmt);
  
        result->commandType = parse->commandType;
!       result->hasReturning = parse->hasReturning;
        result->canSetTag = parse->canSetTag;
        result->transientPlan = glob->transientPlan;
        result->planTree = top_plan;
***************
*** 400,407 **** subquery_planner(PlannerGlobal *glob, Query *parse,
                preprocess_expression(root, (Node *) parse->targetList,
                                                          EXPRKIND_TARGET);
  
!       parse->returningList = (List *)
!               preprocess_expression(root, (Node *) parse->returningList,
                                                          EXPRKIND_TARGET);
  
        preprocess_qual_conditions(root, (Node *) parse->jointree);
--- 400,407 ----
                preprocess_expression(root, (Node *) parse->targetList,
                                                          EXPRKIND_TARGET);
  
!       parse->resultTargetList = (List *)
!               preprocess_expression(root, (Node *) parse->resultTargetList,
                                                          EXPRKIND_TARGET);
  
        preprocess_qual_conditions(root, (Node *) parse->jointree);
***************
*** 516,528 **** subquery_planner(PlannerGlobal *glob, Query *parse,
                         * level (if we waited, handling inherited 
UPDATE/DELETE would be
                         * much harder).
                         */
!                       if (parse->returningList)
                        {
                                List       *rlist;
  
                                Assert(parse->resultRelation);
                                rlist = 
set_returning_clause_references(root->glob,
!                                                                               
                                parse->returningList,
                                                                                
                                plan,
                                                                                
                                parse->resultRelation);
                                returningLists = list_make1(rlist);
--- 516,528 ----
                         * level (if we waited, handling inherited 
UPDATE/DELETE would be
                         * much harder).
                         */
!                       if (parse->hasReturning)
                        {
                                List       *rlist;
  
                                Assert(parse->resultRelation);
                                rlist = 
set_returning_clause_references(root->glob,
!                                                                               
                                parse->targetList,
                                                                                
                                plan,
                                                                                
                                parse->resultRelation);
                                returningLists = list_make1(rlist);
***************
*** 760,771 **** inheritance_planner(PlannerInfo *root)
                resultRelations = lappend_int(resultRelations, 
appinfo->child_relid);
  
                /* Build list of per-relation RETURNING targetlists */
!               if (parse->returningList)
                {
                        List       *rlist;
  
                        rlist = set_returning_clause_references(root->glob,
!                                                                               
                        subroot.parse->returningList,
                                                                                
                        subplan,
                                                                                
                        appinfo->child_relid);
                        returningLists = lappend(returningLists, rlist);
--- 760,771 ----
                resultRelations = lappend_int(resultRelations, 
appinfo->child_relid);
  
                /* Build list of per-relation RETURNING targetlists */
!               if (parse->hasReturning)
                {
                        List       *rlist;
  
                        rlist = set_returning_clause_references(root->glob,
!                                                                               
                        subroot.parse->targetList,
                                                                                
                        subplan,
                                                                                
                        appinfo->child_relid);
                        returningLists = lappend(returningLists, rlist);
***************
*** 848,854 **** static Plan *
  grouping_planner(PlannerInfo *root, double tuple_fraction)
  {
        Query      *parse = root->parse;
!       List       *tlist = parse->targetList;
        int64           offset_est = 0;
        int64           count_est = 0;
        double          limit_tuples = -1.0;
--- 848,854 ----
  grouping_planner(PlannerInfo *root, double tuple_fraction)
  {
        Query      *parse = root->parse;
!       List       *tlist = (parse->commandType == CMD_SELECT ? 
parse->targetList : parse->resultTargetList);
        int64           offset_est = 0;
        int64           count_est = 0;
        double          limit_tuples = -1.0;
*** a/src/backend/optimizer/prep/prepjointree.c
--- b/src/backend/optimizer/prep/prepjointree.c
***************
*** 734,741 **** pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, 
RangeTblEntry *rte,
         */
        parse->targetList = (List *)
                pullup_replace_vars((Node *) parse->targetList, &rvcontext);
!       parse->returningList = (List *)
!               pullup_replace_vars((Node *) parse->returningList, &rvcontext);
        replace_vars_in_jointree((Node *) parse->jointree, &rvcontext,
                                                         lowest_outer_join);
        Assert(parse->setOperations == NULL);
--- 734,741 ----
         */
        parse->targetList = (List *)
                pullup_replace_vars((Node *) parse->targetList, &rvcontext);
!       parse->resultTargetList = (List *)
!               pullup_replace_vars((Node *) parse->resultTargetList, 
&rvcontext);
        replace_vars_in_jointree((Node *) parse->jointree, &rvcontext,
                                                         lowest_outer_join);
        Assert(parse->setOperations == NULL);
*** a/src/backend/optimizer/prep/preptlist.c
--- b/src/backend/optimizer/prep/preptlist.c
***************
*** 193,204 **** preprocess_targetlist(PlannerInfo *root, List *tlist)
         * belong to the result rel don't need to be added, because they will be
         * made to refer to the actual heap tuple.
         */
!       if (parse->returningList && list_length(parse->rtable) > 1)
        {
                List       *vars;
                ListCell   *l;
  
!               vars = pull_var_clause((Node *) parse->returningList,
                                                           
PVC_INCLUDE_PLACEHOLDERS);
                foreach(l, vars)
                {
--- 193,204 ----
         * belong to the result rel don't need to be added, because they will be
         * made to refer to the actual heap tuple.
         */
!       if (parse->hasReturning && list_length(parse->rtable) > 1)
        {
                List       *vars;
                ListCell   *l;
  
!               vars = pull_var_clause((Node *) parse->targetList,
                                                           
PVC_INCLUDE_PLACEHOLDERS);
                foreach(l, vars)
                {
*** a/src/backend/optimizer/prep/prepunion.c
--- b/src/backend/optimizer/prep/prepunion.c
***************
*** 1507,1514 **** adjust_appendrel_attrs(Node *node, AppendRelInfo *appinfo)
                        newnode->resultRelation = appinfo->child_relid;
                        /* Fix tlist resnos too, if it's inherited UPDATE */
                        if (newnode->commandType == CMD_UPDATE)
!                               newnode->targetList =
!                                       
adjust_inherited_tlist(newnode->targetList,
                                                                                
   appinfo);
                }
                result = (Node *) newnode;
--- 1507,1514 ----
                        newnode->resultRelation = appinfo->child_relid;
                        /* Fix tlist resnos too, if it's inherited UPDATE */
                        if (newnode->commandType == CMD_UPDATE)
!                               newnode->resultTargetList =
!                                       
adjust_inherited_tlist(newnode->resultTargetList,
                                                                                
   appinfo);
                }
                result = (Node *) newnode;
*** a/src/backend/parser/analyze.c
--- b/src/backend/parser/analyze.c
***************
*** 304,310 **** transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt)
  
        qual = transformWhereClause(pstate, stmt->whereClause, "WHERE");
  
!       qry->returningList = transformReturningList(pstate, 
stmt->returningList);
  
        /* done building the range table and jointree */
        qry->rtable = pstate->p_rtable;
--- 304,319 ----
  
        qual = transformWhereClause(pstate, stmt->whereClause, "WHERE");
  
!       if (stmt->returningList)
!       {
!               qry->targetList = transformReturningList(pstate, 
stmt->returningList);
!               qry->hasReturning = true;
!       }
!       else
!       {
!               qry->targetList = NIL;
!               qry->hasReturning = false;
!       }
  
        /* done building the range table and jointree */
        qry->rtable = pstate->p_rtable;
***************
*** 638,644 **** transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
         * Also, mark all the target columns as needing insert permissions.
         */
        rte = pstate->p_target_rangetblentry;
!       qry->targetList = NIL;
        icols = list_head(icolumns);
        attnos = list_head(attrnos);
        foreach(lc, exprList)
--- 647,653 ----
         * Also, mark all the target columns as needing insert permissions.
         */
        rte = pstate->p_target_rangetblentry;
!       qry->resultTargetList = NIL;
        icols = list_head(icolumns);
        attnos = list_head(attrnos);
        foreach(lc, exprList)
***************
*** 656,662 **** transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
                                                          attr_num,
                                                          col->name,
                                                          false);
!               qry->targetList = lappend(qry->targetList, tle);
  
                rte->modifiedCols = bms_add_member(rte->modifiedCols,
                                                          attr_num - 
FirstLowInvalidHeapAttributeNumber);
--- 665,671 ----
                                                          attr_num,
                                                          col->name,
                                                          false);
!               qry->resultTargetList = lappend(qry->resultTargetList, tle);
  
                rte->modifiedCols = bms_add_member(rte->modifiedCols,
                                                          attr_num - 
FirstLowInvalidHeapAttributeNumber);
***************
*** 677,684 **** transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
                pstate->p_varnamespace = NIL;
                addRTEtoQuery(pstate, pstate->p_target_rangetblentry,
                                          false, true, true);
!               qry->returningList = transformReturningList(pstate,
                                                                                
                        stmt->returningList);
        }
  
        /* done building the range table and jointree */
--- 686,699 ----
                pstate->p_varnamespace = NIL;
                addRTEtoQuery(pstate, pstate->p_target_rangetblentry,
                                          false, true, true);
!               qry->targetList = transformReturningList(pstate,
                                                                                
                        stmt->returningList);
+               qry->hasReturning = true;
+       }
+       else
+       {
+               qry->hasReturning = false;
+               qry->targetList = NIL;
        }
  
        /* done building the range table and jointree */
***************
*** 1727,1737 **** transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
         */
        transformFromClause(pstate, stmt->fromClause);
  
!       qry->targetList = transformTargetList(pstate, stmt->targetList);
  
        qual = transformWhereClause(pstate, stmt->whereClause, "WHERE");
  
!       qry->returningList = transformReturningList(pstate, 
stmt->returningList);
  
        qry->rtable = pstate->p_rtable;
        qry->jointree = makeFromExpr(pstate->p_joinlist, qual);
--- 1742,1761 ----
         */
        transformFromClause(pstate, stmt->fromClause);
  
!       qry->resultTargetList = transformTargetList(pstate, stmt->targetList);
  
        qual = transformWhereClause(pstate, stmt->whereClause, "WHERE");
  
!       if (stmt->returningList)
!       {
!               qry->hasReturning = true;
!               qry->targetList = transformReturningList(pstate, 
stmt->returningList);
!       }
!       else
!       {
!               qry->hasReturning = false;
!               qry->targetList = NIL;
!       }
  
        qry->rtable = pstate->p_rtable;
        qry->jointree = makeFromExpr(pstate->p_joinlist, qual);
***************
*** 1769,1775 **** transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
        target_rte = pstate->p_target_rangetblentry;
        origTargetList = list_head(stmt->targetList);
  
!       foreach(tl, qry->targetList)
        {
                TargetEntry *tle = (TargetEntry *) lfirst(tl);
                ResTarget  *origTarget;
--- 1793,1799 ----
        target_rte = pstate->p_target_rangetblentry;
        origTargetList = list_head(stmt->targetList);
  
!       foreach(tl, qry->resultTargetList)
        {
                TargetEntry *tle = (TargetEntry *) lfirst(tl);
                ResTarget  *origTarget;
*** a/src/backend/rewrite/rewriteDefine.c
--- b/src/backend/rewrite/rewriteDefine.c
***************
*** 444,450 **** DefineQueryRewrite(char *rulename,
                {
                        query = (Query *) lfirst(l);
  
!                       if (!query->returningList)
                                continue;
                        if (haveReturning)
                                ereport(ERROR,
--- 444,450 ----
                {
                        query = (Query *) lfirst(l);
  
!                       if (!query->hasReturning)
                                continue;
                        if (haveReturning)
                                ereport(ERROR,
***************
*** 459,465 **** DefineQueryRewrite(char *rulename,
                                ereport(ERROR,
                                                
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                                 errmsg("RETURNING lists are 
not supported in non-INSTEAD rules")));
!                       checkRuleResultList(query->returningList,
                                                                
RelationGetDescr(event_relation),
                                                                false);
                }
--- 459,465 ----
                                ereport(ERROR,
                                                
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                                 errmsg("RETURNING lists are 
not supported in non-INSTEAD rules")));
!                       checkRuleResultList(query->targetList,
                                                                
RelationGetDescr(event_relation),
                                                                false);
                }
*** a/src/backend/rewrite/rewriteHandler.c
--- b/src/backend/rewrite/rewriteHandler.c
***************
*** 469,475 **** rewriteRuleAction(Query *parsetree,
                                                                                
  0,
                                                                                
  rt_fetch(new_varno,
                                                                                
                   sub_action->rtable),
!                                                                               
  parsetree->targetList,
                                                                                
  event,
                                                                                
  current_varno,
                                                                                
  NULL);
--- 469,475 ----
                                                                                
  0,
                                                                                
  rt_fetch(new_varno,
                                                                                
                   sub_action->rtable),
!                                                                               
  parsetree->resultTargetList,
                                                                                
  event,
                                                                                
  current_varno,
                                                                                
  NULL);
***************
*** 485,506 **** rewriteRuleAction(Query *parsetree,
         * the triggering query's RETURNING clause asks for.  Throw an error if
         * more than one rule has a RETURNING clause.
         */
!       if (!parsetree->returningList)
!               rule_action->returningList = NIL;
!       else if (rule_action->returningList)
        {
                if (*returning_flag)
                        ereport(ERROR,
                                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                   errmsg("cannot have RETURNING lists in 
multiple rules")));
                *returning_flag = true;
!               rule_action->returningList = (List *)
!                       ResolveNew((Node *) parsetree->returningList,
                                           parsetree->resultRelation,
                                           0,
                                           rt_fetch(parsetree->resultRelation,
                                                                
parsetree->rtable),
!                                          rule_action->returningList,
                                           CMD_SELECT,
                                           0,
                                           &rule_action->hasSubLinks);
--- 485,509 ----
         * the triggering query's RETURNING clause asks for.  Throw an error if
         * more than one rule has a RETURNING clause.
         */
!       if (!parsetree->hasReturning)
!       {
!               rule_action->hasReturning = false;
!               rule_action->targetList = NIL;
!       }
!       else if (rule_action->hasReturning)
        {
                if (*returning_flag)
                        ereport(ERROR,
                                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                   errmsg("cannot have RETURNING lists in 
multiple rules")));
                *returning_flag = true;
!               rule_action->targetList = (List *)
!                       ResolveNew((Node *) parsetree->targetList,
                                           parsetree->resultRelation,
                                           0,
                                           rt_fetch(parsetree->resultRelation,
                                                                
parsetree->rtable),
!                                          rule_action->targetList,
                                           CMD_SELECT,
                                           0,
                                           &rule_action->hasSubLinks);
***************
*** 511,517 **** rewriteRuleAction(Query *parsetree,
                 */
                if (parsetree->hasSubLinks && !rule_action->hasSubLinks)
                        rule_action->hasSubLinks =
!                               checkExprHasSubLink((Node *) 
rule_action->returningList);
        }
  
        return rule_action;
--- 514,520 ----
                 */
                if (parsetree->hasSubLinks && !rule_action->hasSubLinks)
                        rule_action->hasSubLinks =
!                               checkExprHasSubLink((Node *) 
rule_action->targetList);
        }
  
        return rule_action;
***************
*** 554,560 **** adjustJoinTreeList(Query *parsetree, bool removert, int 
rt_index)
  
  
  /*
!  * rewriteTargetList - rewrite INSERT/UPDATE targetlist into standard form
   *
   * This has the following responsibilities:
   *
--- 557,563 ----
  
  
  /*
!  * rewriteTargetList - rewrite INSERT/UPDATE result targetlist into standard 
form
   *
   * This has the following responsibilities:
   *
***************
*** 601,606 **** rewriteTargetList(Query *parsetree, Relation target_relation,
--- 604,611 ----
                                numattrs;
        ListCell   *temp;
  
+       Assert(commandType == CMD_INSERT || commandType == CMD_UPDATE);
+ 
        if (attrno_list)                        /* initialize optional result 
list */
                *attrno_list = NIL;
  
***************
*** 617,623 **** rewriteTargetList(Query *parsetree, Relation target_relation,
        new_tles = (TargetEntry **) palloc0(numattrs * sizeof(TargetEntry *));
        next_junk_attrno = numattrs + 1;
  
!       foreach(temp, parsetree->targetList)
        {
                TargetEntry *old_tle = (TargetEntry *) lfirst(temp);
  
--- 622,628 ----
        new_tles = (TargetEntry **) palloc0(numattrs * sizeof(TargetEntry *));
        next_junk_attrno = numattrs + 1;
  
!       foreach(temp, parsetree->resultTargetList)
        {
                TargetEntry *old_tle = (TargetEntry *) lfirst(temp);
  
***************
*** 730,736 **** rewriteTargetList(Query *parsetree, Relation target_relation,
  
        pfree(new_tles);
  
!       parsetree->targetList = list_concat(new_tlist, junk_tlist);
  }
  
  
--- 735,741 ----
  
        pfree(new_tles);
  
!       parsetree->resultTargetList = list_concat(new_tlist, junk_tlist);
  }
  
  
***************
*** 1496,1502 **** CopyAndAddInvertedQual(Query *parsetree,
                                                          PRS2_NEW_VARNO,
                                                          0,
                                                          rt_fetch(rt_index, 
parsetree->rtable),
!                                                         parsetree->targetList,
                                                          event,
                                                          rt_index,
                                                          
&parsetree->hasSubLinks);
--- 1501,1507 ----
                                                          PRS2_NEW_VARNO,
                                                          0,
                                                          rt_fetch(rt_index, 
parsetree->rtable),
!                                                         
parsetree->resultTargetList,
                                                          event,
                                                          rt_index,
                                                          
&parsetree->hasSubLinks);
***************
*** 1767,1773 **** RewriteQuery(Query *parsetree, List *rewrite_events)
                 * will actually be executed --- it must be.)
                 */
                if ((instead || qual_product != NULL) &&
!                       parsetree->returningList &&
                        !returning)
                {
                        switch (event)
--- 1772,1778 ----
                 * will actually be executed --- it must be.)
                 */
                if ((instead || qual_product != NULL) &&
!                       parsetree->hasReturning &&
                        !returning)
                {
                        switch (event)
*** a/src/backend/tcop/pquery.c
--- b/src/backend/tcop/pquery.c
***************
*** 326,332 **** ChoosePortalStrategy(List *stmts)
                        {
                                if (++nSetTag > 1)
                                        return PORTAL_MULTI_QUERY;      /* no 
need to look further */
!                               if (query->returningList == NIL)
                                        return PORTAL_MULTI_QUERY;      /* no 
need to look further */
                        }
                }
--- 326,332 ----
                        {
                                if (++nSetTag > 1)
                                        return PORTAL_MULTI_QUERY;      /* no 
need to look further */
!                               if (!query->hasReturning)
                                        return PORTAL_MULTI_QUERY;      /* no 
need to look further */
                        }
                }
***************
*** 401,408 **** FetchStatementTargetList(Node *stmt)
                                query->utilityStmt == NULL &&
                                query->intoClause == NULL)
                                return query->targetList;
!                       if (query->returningList)
!                               return query->returningList;
                        return NIL;
                }
        }
--- 401,408 ----
                                query->utilityStmt == NULL &&
                                query->intoClause == NULL)
                                return query->targetList;
!                       if (query->hasReturning)
!                               return query->targetList;
                        return NIL;
                }
        }
*** a/src/backend/utils/adt/ruleutils.c
--- b/src/backend/utils/adt/ruleutils.c
***************
*** 3125,3131 **** get_insert_query_def(Query *query, deparse_context *context)
                values_cell = NULL;
        strippedexprs = NIL;
        sep = "";
!       foreach(l, query->targetList)
        {
                TargetEntry *tle = (TargetEntry *) lfirst(l);
  
--- 3125,3131 ----
                values_cell = NULL;
        strippedexprs = NIL;
        sep = "";
!       foreach(l, query->resultTargetList)
        {
                TargetEntry *tle = (TargetEntry *) lfirst(l);
  
***************
*** 3188,3198 **** get_insert_query_def(Query *query, deparse_context *context)
        }
  
        /* Add RETURNING if present */
!       if (query->returningList)
        {
                appendContextKeyword(context, " RETURNING",
                                                         -PRETTYINDENT_STD, 
PRETTYINDENT_STD, 1);
!               get_target_list(query->returningList, context, NULL);
        }
  }
  
--- 3188,3198 ----
        }
  
        /* Add RETURNING if present */
!       if (query->hasReturning)
        {
                appendContextKeyword(context, " RETURNING",
                                                         -PRETTYINDENT_STD, 
PRETTYINDENT_STD, 1);
!               get_target_list(query->targetList, context, NULL);
        }
  }
  
***************
*** 3229,3235 **** get_update_query_def(Query *query, deparse_context *context)
  
        /* Add the comma separated list of 'attname = value' */
        sep = "";
!       foreach(l, query->targetList)
        {
                TargetEntry *tle = (TargetEntry *) lfirst(l);
                Node       *expr;
--- 3229,3235 ----
  
        /* Add the comma separated list of 'attname = value' */
        sep = "";
!       foreach(l, query->resultTargetList)
        {
                TargetEntry *tle = (TargetEntry *) lfirst(l);
                Node       *expr;
***************
*** 3271,3281 **** get_update_query_def(Query *query, deparse_context *context)
        }
  
        /* Add RETURNING if present */
!       if (query->returningList)
        {
                appendContextKeyword(context, " RETURNING",
                                                         -PRETTYINDENT_STD, 
PRETTYINDENT_STD, 1);
!               get_target_list(query->returningList, context, NULL);
        }
  }
  
--- 3271,3281 ----
        }
  
        /* Add RETURNING if present */
!       if (query->hasReturning)
        {
                appendContextKeyword(context, " RETURNING",
                                                         -PRETTYINDENT_STD, 
PRETTYINDENT_STD, 1);
!               get_target_list(query->targetList, context, NULL);
        }
  }
  
***************
*** 3319,3329 **** get_delete_query_def(Query *query, deparse_context *context)
        }
  
        /* Add RETURNING if present */
!       if (query->returningList)
        {
                appendContextKeyword(context, " RETURNING",
                                                         -PRETTYINDENT_STD, 
PRETTYINDENT_STD, 1);
!               get_target_list(query->returningList, context, NULL);
        }
  }
  
--- 3319,3329 ----
        }
  
        /* Add RETURNING if present */
!       if (query->hasReturning)
        {
                appendContextKeyword(context, " RETURNING",
                                                         -PRETTYINDENT_STD, 
PRETTYINDENT_STD, 1);
!               get_target_list(query->targetList, context, NULL);
        }
  }
  
*** a/src/backend/utils/cache/plancache.c
--- b/src/backend/utils/cache/plancache.c
***************
*** 892,899 **** PlanCacheComputeResultDesc(List *stmt_list)
                        if (IsA(node, Query))
                        {
                                query = (Query *) node;
!                               Assert(query->returningList);
!                               return 
ExecCleanTypeFromTL(query->returningList, false);
                        }
                        if (IsA(node, PlannedStmt))
                        {
--- 892,899 ----
                        if (IsA(node, Query))
                        {
                                query = (Query *) node;
!                               Assert(query->hasReturning && 
query->targetList);
!                               return ExecCleanTypeFromTL(query->targetList, 
false);
                        }
                        if (IsA(node, PlannedStmt))
                        {
*** a/src/include/nodes/parsenodes.h
--- b/src/include/nodes/parsenodes.h
***************
*** 119,124 **** typedef struct Query
--- 119,125 ----
        bool            hasDistinctOn;  /* distinctClause is from DISTINCT ON */
        bool            hasRecursive;   /* WITH RECURSIVE was specified */
        bool            hasForUpdate;   /* FOR UPDATE or FOR SHARE was 
specified */
+       bool            hasReturning;   /* targetList is from RETURNING clause 
*/
  
        List       *cteList;            /* WITH list (of CommonTableExpr's) */
  
***************
*** 127,133 **** typedef struct Query
  
        List       *targetList;         /* target list (of TargetEntry) */
  
!       List       *returningList;      /* return-values list (of TargetEntry) 
*/
  
        List       *groupClause;        /* a list of SortGroupClause's */
  
--- 128,134 ----
  
        List       *targetList;         /* target list (of TargetEntry) */
  
!       List       *resultTargetList; /* result relation target list (of 
TargetEntry) */
  
        List       *groupClause;        /* a list of SortGroupClause's */
  


-- 
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