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 ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers