diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 62355aa..4b4ddec 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -112,6 +112,7 @@ CopyPlanFields(const Plan *from, Plan *newnode) COPY_SCALAR_FIELD(total_cost); COPY_SCALAR_FIELD(plan_rows); COPY_SCALAR_FIELD(plan_width); + COPY_SCALAR_FIELD(plan_node_id); COPY_NODE_FIELD(targetlist); COPY_NODE_FIELD(qual); COPY_NODE_FIELD(lefttree); diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index e1b49d5..d7d00c0 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -269,6 +269,7 @@ _outPlanInfo(StringInfo str, const Plan *node) WRITE_FLOAT_FIELD(total_cost, "%.2f"); WRITE_FLOAT_FIELD(plan_rows, "%.0f"); WRITE_INT_FIELD(plan_width); + WRITE_INT_FIELD(plan_node_id); WRITE_NODE_FIELD(targetlist); WRITE_NODE_FIELD(qual); WRITE_NODE_FIELD(lefttree); diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 06be922..e1ee67c 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -196,6 +196,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) glob->nParamExec = 0; glob->lastPHId = 0; glob->lastRowMarkId = 0; + glob->lastPlanNodeId = 0; glob->transientPlan = false; glob->hasRowSecurity = false; diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index daeb584..e3e1a1d 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -174,6 +174,8 @@ static bool extract_query_dependencies_walker(Node *node, * Currently, relations and user-defined functions are the only types of * objects that are explicitly tracked this way. * + * 7. We assign every plan node in the tree a unique ID. + * * We also perform one final optimization step, which is to delete * SubqueryScan plan nodes that aren't doing anything useful (ie, have * no qual and a no-op targetlist). The reason for doing this last is that @@ -437,6 +439,12 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset) return NULL; /* + * Assign this node a unique ID. We want to do this before traversing + * subplans so that every Plan has an ID greater than that of its parent. + */ + plan->plan_node_id = root->glob->lastPlanNodeId++; + + /* * Plan-type-specific fixes */ switch (nodeTag(plan)) diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h index cc259f1..1e2d2bb 100644 --- a/src/include/nodes/plannodes.h +++ b/src/include/nodes/plannodes.h @@ -111,6 +111,7 @@ typedef struct Plan /* * Common structural data for all Plan types. */ + int plan_node_id; /* unique across entire final plan tree */ List *targetlist; /* target list to be computed at this node */ List *qual; /* implicitly-ANDed qual conditions */ struct Plan *lefttree; /* input plan tree(s) */ diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h index 79bed33..961b5d1 100644 --- a/src/include/nodes/relation.h +++ b/src/include/nodes/relation.h @@ -99,6 +99,8 @@ typedef struct PlannerGlobal Index lastRowMarkId; /* highest PlanRowMark ID assigned */ + int lastPlanNodeId; /* highest plan node ID assigned */ + bool transientPlan; /* redo plan when TransactionXmin changes? */ bool hasRowSecurity; /* row security applied? */