Hi,

I think ExplainModifyTarget should show the parent of the inheritance
tree in multi-target-table cases, as described there, but noticed that
it doesn't always work like that.  Here is an example.

postgres=# create table parent (a int check (a < 0) no inherit);
CREATE TABLE
postgres=# create table child (a int check (a >= 0));
CREATE TABLE
postgres=# alter table child inherit parent;
ALTER TABLE
postgres=# explain update parent set a = a * 2 where a >= 0;
                          QUERY PLAN
---------------------------------------------------------------
 Update on child  (cost=0.00..42.00 rows=800 width=10)
   ->  Seq Scan on child  (cost=0.00..42.00 rows=800 width=10)
         Filter: (a >= 0)
(3 rows)

IIUC, I think this is because ExplainModifyTarget doesn't take into
account that the parent *can* be excluded by constraint exclusion.  So,
I added a field to ModifyTable to record the parent, apart from
resultRelations.  (More precisely, the parent in its role as a simple
member of the inheritance tree is recorded so that appending digits to
refname in select_rtable_names_for_explain works as before.)  Attached
is a proposed patch for that.

Thanks,

Best regards,
Etsuro Fujita
*** a/src/backend/commands/explain.c
--- b/src/backend/commands/explain.c
***************
*** 728,736 **** ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
  										((Scan *) plan)->scanrelid);
  			break;
  		case T_ModifyTable:
- 			/* cf ExplainModifyTarget */
  			*rels_used = bms_add_member(*rels_used,
! 					  linitial_int(((ModifyTable *) plan)->resultRelations));
  			break;
  		default:
  			break;
--- 728,735 ----
  										((Scan *) plan)->scanrelid);
  			break;
  		case T_ModifyTable:
  			*rels_used = bms_add_member(*rels_used,
! 										((ModifyTable *) plan)->resultRelation);
  			break;
  		default:
  			break;
***************
*** 2109,2122 **** ExplainScanTarget(Scan *plan, ExplainState *es)
  static void
  ExplainModifyTarget(ModifyTable *plan, ExplainState *es)
  {
! 	Index		rti;
! 
! 	/*
! 	 * We show the name of the first target relation.  In multi-target-table
! 	 * cases this should always be the parent of the inheritance tree.
! 	 */
! 	Assert(plan->resultRelations != NIL);
! 	rti = linitial_int(plan->resultRelations);
  
  	ExplainTargetRel((Plan *) plan, rti, es);
  }
--- 2108,2114 ----
  static void
  ExplainModifyTarget(ModifyTable *plan, ExplainState *es)
  {
! 	Index		rti = plan->resultRelation;
  
  	ExplainTargetRel((Plan *) plan, rti, es);
  }
*** a/src/backend/nodes/copyfuncs.c
--- b/src/backend/nodes/copyfuncs.c
***************
*** 175,180 **** _copyModifyTable(const ModifyTable *from)
--- 175,181 ----
  	 */
  	COPY_SCALAR_FIELD(operation);
  	COPY_SCALAR_FIELD(canSetTag);
+ 	COPY_SCALAR_FIELD(resultRelation);
  	COPY_NODE_FIELD(resultRelations);
  	COPY_SCALAR_FIELD(resultRelIndex);
  	COPY_NODE_FIELD(plans);
*** a/src/backend/nodes/outfuncs.c
--- b/src/backend/nodes/outfuncs.c
***************
*** 327,332 **** _outModifyTable(StringInfo str, const ModifyTable *node)
--- 327,333 ----
  
  	WRITE_ENUM_FIELD(operation, CmdType);
  	WRITE_BOOL_FIELD(canSetTag);
+ 	WRITE_UINT_FIELD(resultRelation);
  	WRITE_NODE_FIELD(resultRelations);
  	WRITE_INT_FIELD(resultRelIndex);
  	WRITE_NODE_FIELD(plans);
*** a/src/backend/optimizer/plan/createplan.c
--- b/src/backend/optimizer/plan/createplan.c
***************
*** 4809,4814 **** make_result(PlannerInfo *root,
--- 4809,4815 ----
  ModifyTable *
  make_modifytable(PlannerInfo *root,
  				 CmdType operation, bool canSetTag,
+ 				 Index resultRelation,
  				 List *resultRelations, List *subplans,
  				 List *withCheckOptionLists, List *returningLists,
  				 List *rowMarks, int epqParam)
***************
*** 4857,4862 **** make_modifytable(PlannerInfo *root,
--- 4858,4864 ----
  
  	node->operation = operation;
  	node->canSetTag = canSetTag;
+ 	node->resultRelation = resultRelation;
  	node->resultRelations = resultRelations;
  	node->resultRelIndex = -1;	/* will be set correctly in setrefs.c */
  	node->plans = subplans;
*** a/src/backend/optimizer/plan/planner.c
--- b/src/backend/optimizer/plan/planner.c
***************
*** 607,612 **** subquery_planner(PlannerGlobal *glob, Query *parse,
--- 607,613 ----
  			plan = (Plan *) make_modifytable(root,
  											 parse->commandType,
  											 parse->canSetTag,
+ 											 parse->resultRelation,
  									   list_make1_int(parse->resultRelation),
  											 list_make1(plan),
  											 withCheckOptionLists,
***************
*** 790,795 **** inheritance_planner(PlannerInfo *root)
--- 791,797 ----
  {
  	Query	   *parse = root->parse;
  	int			parentRTindex = parse->resultRelation;
+ 	int			pseudoParentRTindex = -1;
  	List	   *final_rtable = NIL;
  	int			save_rel_array_size = 0;
  	RelOptInfo **save_rel_array = NULL;
***************
*** 925,930 **** inheritance_planner(PlannerInfo *root)
--- 927,940 ----
  		appinfo->child_relid = subroot.parse->resultRelation;
  
  		/*
+ 		 * If this child rel was the first target relation, it should always be
+ 		 * the parent rel in its role as a simple member of the inheritance set.
+ 		 * Get it for use of EXPLAIN.
+ 		 */
+ 		if (pseudoParentRTindex == -1)
+ 			pseudoParentRTindex = appinfo->child_relid;
+ 
+ 		/*
  		 * If this child rel was excluded by constraint exclusion, exclude it
  		 * from the result plan.
  		 */
***************
*** 1051,1056 **** inheritance_planner(PlannerInfo *root)
--- 1061,1067 ----
  	return (Plan *) make_modifytable(root,
  									 parse->commandType,
  									 parse->canSetTag,
+ 									 pseudoParentRTindex,
  									 resultRelations,
  									 subplans,
  									 withCheckOptionLists,
*** a/src/backend/optimizer/plan/setrefs.c
--- b/src/backend/optimizer/plan/setrefs.c
***************
*** 754,759 **** set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
--- 754,761 ----
  					splan->plan.targetlist = copyObject(linitial(newRL));
  				}
  
+ 				splan->resultRelation += rtoffset;
+ 
  				foreach(l, splan->resultRelations)
  				{
  					lfirst_int(l) += rtoffset;
*** a/src/include/nodes/plannodes.h
--- b/src/include/nodes/plannodes.h
***************
*** 174,179 **** typedef struct ModifyTable
--- 174,180 ----
  	Plan		plan;
  	CmdType		operation;		/* INSERT, UPDATE, or DELETE */
  	bool		canSetTag;		/* do we set the command tag/es_processed? */
+ 	Index		resultRelation;	/* Parent RT index for use of EXPLAIN */
  	List	   *resultRelations;	/* integer list of RT indexes */
  	int			resultRelIndex; /* index of first resultRel in plan's list */
  	List	   *plans;			/* plan(s) producing source data */
*** a/src/include/optimizer/planmain.h
--- b/src/include/optimizer/planmain.h
***************
*** 82,87 **** extern Result *make_result(PlannerInfo *root, List *tlist,
--- 82,88 ----
  			Node *resconstantqual, Plan *subplan);
  extern ModifyTable *make_modifytable(PlannerInfo *root,
  				 CmdType operation, bool canSetTag,
+ 				 Index resultRelation,
  				 List *resultRelations, List *subplans,
  				 List *withCheckOptionLists, List *returningLists,
  				 List *rowMarks, int epqParam);
-- 
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