Query::targetList and RETURNING

Поиск
Список
Период
Сортировка
От Marko Tiikkaja
Тема Query::targetList and RETURNING
Дата
Msg-id 4AF94096.1090309@cs.helsinki.fi
обсуждение исходный текст
Ответы Re: Query::targetList and RETURNING
Список pgsql-hackers
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 */




В списке pgsql-hackers по дате отправления:

Предыдущее
От: "rgc.tech"
Дата:
Сообщение: accent-insensitive
Следующее
От: "Albe Laurenz"
Дата:
Сообщение: Re: [GENERAL] PostgreSQL 8.3.8 on AIX5.3 : compilation failed