querytarget.patch

text/plain

Filename: querytarget.patch
Type: text/plain
Part: 0
Message: Query::targetList and RETURNING

Patch

Format: context
File+
src/backend/executor/functions.c 2 0
src/backend/nodes/copyfuncs.c 2 0
src/backend/nodes/equalfuncs.c 2 0
src/backend/nodes/nodeFuncs.c 3 0
src/backend/nodes/outfuncs.c 2 0
src/backend/nodes/readfuncs.c 2 0
src/backend/optimizer/plan/planagg.c 2 0
src/backend/optimizer/plan/planner.c 8 0
src/backend/optimizer/prep/prepjointree.c 2 0
src/backend/optimizer/prep/preptlist.c 2 0
src/backend/optimizer/prep/prepunion.c 2 0
src/backend/parser/analyze.c 31 0
src/backend/rewrite/rewriteDefine.c 2 0
src/backend/rewrite/rewriteHandler.c 18 0
src/backend/tcop/pquery.c 3 0
src/backend/utils/adt/ruleutils.c 8 0
src/backend/utils/cache/plancache.c 2 0
src/include/nodes/parsenodes.h 2 0
*** 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 */