On 2015/02/10 14:49, Etsuro Fujita wrote:
> On 2015/02/07 1:09, Tom Lane wrote:
>> IIRC, this code was written at a time when we didn't have NO INHERIT check
>> constraints and so it was impossible for the parent table to get optimized
>> away while leaving children.  So the comment in ExplainModifyTarget was
>> good at the time.  But it no longer is.
>>
>> I think your basic idea of preserving the original parent table's relid
>> is correct; but instead of doing it like this patch does, I'd be inclined
>> to make ModifyTable inherit from Scan not Plan, and use the scan.scanrelid
>> field to carry the parent RTI.  Then you would probably end up with a net
>> savings of code rather than net addition; certainly ExplainModifyTarget
>> would go away entirely since you'd just treat ModifyTable like any other
>> Scan in this part of EXPLAIN.
> 
> Will follow your revision.

Done.  Attached is an updated version of the patch.

Best regards,
Etsuro Fujita
*** a/src/backend/commands/explain.c
--- b/src/backend/commands/explain.c
***************
*** 95,101 **** static const char *explain_get_index_name(Oid indexId);
  static void ExplainIndexScanDetails(Oid indexid, ScanDirection indexorderdir,
  						ExplainState *es);
  static void ExplainScanTarget(Scan *plan, ExplainState *es);
- static void ExplainModifyTarget(ModifyTable *plan, ExplainState *es);
  static void ExplainTargetRel(Plan *plan, Index rti, ExplainState *es);
  static void show_modifytable_info(ModifyTableState *mtstate, ExplainState *es);
  static void ExplainMemberNodes(List *plans, PlanState **planstates,
--- 95,100 ----
***************
*** 724,736 **** ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
  		case T_WorkTableScan:
  		case T_ForeignScan:
  		case T_CustomScan:
- 			*rels_used = bms_add_member(*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;
--- 723,731 ----
  		case T_WorkTableScan:
  		case T_ForeignScan:
  		case T_CustomScan:
  		case T_ModifyTable:
  			*rels_used = bms_add_member(*rels_used,
! 										((Scan *) plan)->scanrelid);
  			break;
  		default:
  			break;
***************
*** 1067,1072 **** ExplainNode(PlanState *planstate, List *ancestors,
--- 1062,1068 ----
  		case T_WorkTableScan:
  		case T_ForeignScan:
  		case T_CustomScan:
+ 		case T_ModifyTable:
  			ExplainScanTarget((Scan *) plan, es);
  			break;
  		case T_IndexScan:
***************
*** 1101,1109 **** ExplainNode(PlanState *planstate, List *ancestors,
  					ExplainPropertyText("Index Name", indexname, es);
  			}
  			break;
- 		case T_ModifyTable:
- 			ExplainModifyTarget((ModifyTable *) plan, es);
- 			break;
  		case T_NestLoop:
  		case T_MergeJoin:
  		case T_HashJoin:
--- 1097,1102 ----
***************
*** 2104,2127 **** ExplainScanTarget(Scan *plan, ExplainState *es)
  }
  
  /*
-  * Show the target of a ModifyTable node
-  */
- 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);
- }
- 
- /*
   * Show the target relation of a scan or modify node
   */
  static void
--- 2097,2102 ----
*** a/src/backend/nodes/copyfuncs.c
--- b/src/backend/nodes/copyfuncs.c
***************
*** 120,125 **** CopyPlanFields(const Plan *from, Plan *newnode)
--- 120,140 ----
  }
  
  /*
+  * CopyScanFields
+  *
+  *		This function copies the fields of the Scan node.  It is used by
+  *		all the copy functions for classes which inherit from Scan.
+  */
+ static void
+ CopyScanFields(const Scan *from, Scan *newnode)
+ {
+ 	CopyPlanFields((const Plan *) from, (Plan *) newnode);
+ 
+ 	COPY_SCALAR_FIELD(scanrelid);
+ }
+ 
+ 
+ /*
   * _copyPlan
   */
  static Plan *
***************
*** 168,174 **** _copyModifyTable(const ModifyTable *from)
  	/*
  	 * copy node superclass fields
  	 */
! 	CopyPlanFields((const Plan *) from, (Plan *) newnode);
  
  	/*
  	 * copy remainder of node
--- 183,189 ----
  	/*
  	 * copy node superclass fields
  	 */
! 	CopyScanFields((const Scan *) from, (Scan *) newnode);
  
  	/*
  	 * copy remainder of node
***************
*** 306,325 **** _copyBitmapOr(const BitmapOr *from)
  
  
  /*
-  * CopyScanFields
-  *
-  *		This function copies the fields of the Scan node.  It is used by
-  *		all the copy functions for classes which inherit from Scan.
-  */
- static void
- CopyScanFields(const Scan *from, Scan *newnode)
- {
- 	CopyPlanFields((const Plan *) from, (Plan *) newnode);
- 
- 	COPY_SCALAR_FIELD(scanrelid);
- }
- 
- /*
   * _copyScan
   */
  static Scan *
--- 321,326 ----
*** a/src/backend/nodes/outfuncs.c
--- b/src/backend/nodes/outfuncs.c
***************
*** 323,329 **** _outModifyTable(StringInfo str, const ModifyTable *node)
  {
  	WRITE_NODE_TYPE("MODIFYTABLE");
  
! 	_outPlanInfo(str, (const Plan *) node);
  
  	WRITE_ENUM_FIELD(operation, CmdType);
  	WRITE_BOOL_FIELD(canSetTag);
--- 323,329 ----
  {
  	WRITE_NODE_TYPE("MODIFYTABLE");
  
! 	_outScanInfo(str, (const Scan *) node);
  
  	WRITE_ENUM_FIELD(operation, CmdType);
  	WRITE_BOOL_FIELD(canSetTag);
*** a/src/backend/optimizer/plan/createplan.c
--- b/src/backend/optimizer/plan/createplan.c
***************
*** 4809,4820 **** make_result(PlannerInfo *root,
  ModifyTable *
  make_modifytable(PlannerInfo *root,
  				 CmdType operation, bool canSetTag,
  				 List *resultRelations, List *subplans,
  				 List *withCheckOptionLists, List *returningLists,
  				 List *rowMarks, int epqParam)
  {
  	ModifyTable *node = makeNode(ModifyTable);
! 	Plan	   *plan = &node->plan;
  	double		total_size;
  	List	   *fdw_private_list;
  	ListCell   *subnode;
--- 4809,4821 ----
  ModifyTable *
  make_modifytable(PlannerInfo *root,
  				 CmdType operation, bool canSetTag,
+ 				 Index resultRelation,
  				 List *resultRelations, List *subplans,
  				 List *withCheckOptionLists, List *returningLists,
  				 List *rowMarks, int epqParam)
  {
  	ModifyTable *node = makeNode(ModifyTable);
! 	Plan	   *plan = &node->scan.plan;
  	double		total_size;
  	List	   *fdw_private_list;
  	ListCell   *subnode;
***************
*** 4849,4860 **** make_modifytable(PlannerInfo *root,
  	else
  		plan->plan_width = 0;
  
! 	node->plan.lefttree = NULL;
! 	node->plan.righttree = NULL;
! 	node->plan.qual = NIL;
  	/* setrefs.c will fill in the targetlist, if needed */
! 	node->plan.targetlist = NIL;
  
  	node->operation = operation;
  	node->canSetTag = canSetTag;
  	node->resultRelations = resultRelations;
--- 4850,4862 ----
  	else
  		plan->plan_width = 0;
  
! 	plan->lefttree = NULL;
! 	plan->righttree = NULL;
! 	plan->qual = NIL;
  	/* setrefs.c will fill in the targetlist, if needed */
! 	plan->targetlist = NIL;
  
+ 	node->scan.scanrelid = resultRelation;
  	node->operation = operation;
  	node->canSetTag = canSetTag;
  	node->resultRelations = resultRelations;
*** 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
***************
*** 707,714 **** set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
  			{
  				ModifyTable *splan = (ModifyTable *) plan;
  
! 				Assert(splan->plan.targetlist == NIL);
! 				Assert(splan->plan.qual == NIL);
  
  				splan->withCheckOptionLists =
  					fix_scan_list(root, splan->withCheckOptionLists, rtoffset);
--- 707,715 ----
  			{
  				ModifyTable *splan = (ModifyTable *) plan;
  
! 				splan->scan.scanrelid += rtoffset;
! 				Assert(splan->scan.plan.targetlist == NIL);
! 				Assert(splan->scan.plan.qual == NIL);
  
  				splan->withCheckOptionLists =
  					fix_scan_list(root, splan->withCheckOptionLists, rtoffset);
***************
*** 751,757 **** set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
  					 * we don't have to do set_returning_clause_references()
  					 * twice on identical targetlists.
  					 */
! 					splan->plan.targetlist = copyObject(linitial(newRL));
  				}
  
  				foreach(l, splan->resultRelations)
--- 752,758 ----
  					 * we don't have to do set_returning_clause_references()
  					 * twice on identical targetlists.
  					 */
! 					splan->scan.plan.targetlist = copyObject(linitial(newRL));
  				}
  
  				foreach(l, splan->resultRelations)
*** a/src/include/nodes/plannodes.h
--- b/src/include/nodes/plannodes.h
***************
*** 144,149 **** typedef struct Plan
--- 144,160 ----
  
  
  /* ----------------
+  *		Scan node
+  * ----------------
+  */
+ typedef struct Scan
+ {
+ 	Plan		plan;
+ 	Index		scanrelid;		/* relid is index into the range table */
+ } Scan;
+ 
+ 
+ /* ----------------
   *	 Result node -
   *		If no outer plan, evaluate a variable-free targetlist.
   *		If outer plan, return tuples from outer plan (after a level of
***************
*** 171,177 **** typedef struct Result
   */
  typedef struct ModifyTable
  {
! 	Plan		plan;
  	CmdType		operation;		/* INSERT, UPDATE, or DELETE */
  	bool		canSetTag;		/* do we set the command tag/es_processed? */
  	List	   *resultRelations;	/* integer list of RT indexes */
--- 182,188 ----
   */
  typedef struct ModifyTable
  {
! 	Scan		scan;
  	CmdType		operation;		/* INSERT, UPDATE, or DELETE */
  	bool		canSetTag;		/* do we set the command tag/es_processed? */
  	List	   *resultRelations;	/* integer list of RT indexes */
***************
*** 265,275 **** typedef struct BitmapOr
   * Scan nodes
   * ==========
   */
- typedef struct Scan
- {
- 	Plan		plan;
- 	Index		scanrelid;		/* relid is index into the range table */
- } Scan;
  
  /* ----------------
   *		sequential scan node
--- 276,281 ----
*** 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