diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 600f7e03345841b1ef6a0dc68cdbeb07ad1ac722..7df7f5cdf0d3a23ae3439445d695bcad7421ff57 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -742,6 +742,7 @@ InitPlan(QueryDesc *queryDesc, int eflags) erm->relation = relation; erm->rti = rc->rti; erm->prti = rc->prti; + erm->rowmarkId = rc->rowmarkId; erm->markType = rc->markType; erm->noWait = rc->noWait; ItemPointerSetInvalid(&(erm->curCtid)); @@ -1425,23 +1426,29 @@ ExecBuildAuxRowMark(ExecRowMark *erm, List *targetlist) /* if child rel, need tableoid */ if (erm->rti != erm->prti) { - snprintf(resname, sizeof(resname), "tableoid%u", erm->prti); + snprintf(resname, sizeof(resname), "tableoid%u", erm->rowmarkId); aerm->toidAttNo = ExecFindJunkAttributeInTlist(targetlist, resname); + if (!AttributeNumberIsValid(aerm->toidAttNo)) + elog(ERROR, "could not find junk %s column", resname); } /* always need ctid for real relations */ - snprintf(resname, sizeof(resname), "ctid%u", erm->prti); + snprintf(resname, sizeof(resname), "ctid%u", erm->rowmarkId); aerm->ctidAttNo = ExecFindJunkAttributeInTlist(targetlist, resname); + if (!AttributeNumberIsValid(aerm->ctidAttNo)) + elog(ERROR, "could not find junk %s column", resname); } else { Assert(erm->markType == ROW_MARK_COPY); - snprintf(resname, sizeof(resname), "wholerow%u", erm->prti); + snprintf(resname, sizeof(resname), "wholerow%u", erm->rowmarkId); aerm->wholeAttNo = ExecFindJunkAttributeInTlist(targetlist, resname); + if (!AttributeNumberIsValid(aerm->wholeAttNo)) + elog(ERROR, "could not find junk %s column", resname); } return aerm; diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 3d898326d7a946497749069222c2f4250745ea22..83630924f6386ad89021854c96f499d47cb56d59 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -906,6 +906,7 @@ _copyPlanRowMark(PlanRowMark *from) COPY_SCALAR_FIELD(rti); COPY_SCALAR_FIELD(prti); + COPY_SCALAR_FIELD(rowmarkId); COPY_SCALAR_FIELD(markType); COPY_SCALAR_FIELD(noWait); COPY_SCALAR_FIELD(isParent); diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 3b3e5448fd50eca66d8b8c36f8fa8855c0a68fee..5c943bc2543b90ee678a51804473fc9aef700d66 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -808,6 +808,7 @@ _outPlanRowMark(StringInfo str, PlanRowMark *node) WRITE_UINT_FIELD(rti); WRITE_UINT_FIELD(prti); + WRITE_UINT_FIELD(rowmarkId); WRITE_ENUM_FIELD(markType, RowMarkType); WRITE_BOOL_FIELD(noWait); WRITE_BOOL_FIELD(isParent); @@ -1609,6 +1610,7 @@ _outPlannerGlobal(StringInfo str, PlannerGlobal *node) WRITE_NODE_FIELD(relationOids); WRITE_NODE_FIELD(invalItems); WRITE_UINT_FIELD(lastPHId); + WRITE_UINT_FIELD(lastRowMarkId); WRITE_BOOL_FIELD(transientPlan); } diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index b52eebe2aac590dee553784a15114a61cf839853..01b90383cf38bdc89aea57de46ac57e195846f9b 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -166,6 +166,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) glob->relationOids = NIL; glob->invalItems = NIL; glob->lastPHId = 0; + glob->lastRowMarkId = 0; glob->transientPlan = false; /* Determine what fraction of the plan is likely to be scanned */ @@ -1885,6 +1886,7 @@ preprocess_rowmarks(PlannerInfo *root) newrc = makeNode(PlanRowMark); newrc->rti = newrc->prti = rc->rti; + newrc->rowmarkId = ++(root->glob->lastRowMarkId); if (rc->forUpdate) newrc->markType = ROW_MARK_EXCLUSIVE; else @@ -1910,6 +1912,7 @@ preprocess_rowmarks(PlannerInfo *root) newrc = makeNode(PlanRowMark); newrc->rti = newrc->prti = i; + newrc->rowmarkId = ++(root->glob->lastRowMarkId); /* real tables support REFERENCE, anything else needs COPY */ if (rte->rtekind == RTE_RELATION) newrc->markType = ROW_MARK_REFERENCE; diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index 867238ecc8b62b533f226e957a51ba88657416f5..d004f6cf12f57854baa043190588dc7cfdeb11bd 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -252,7 +252,7 @@ set_plan_references(PlannerGlobal *glob, Plan *plan, newrc = (PlanRowMark *) palloc(sizeof(PlanRowMark)); memcpy(newrc, rc, sizeof(PlanRowMark)); - /* adjust indexes */ + /* adjust indexes ... but *not* the rowmarkId */ newrc->rti += rtoffset; newrc->prti += rtoffset; diff --git a/src/backend/optimizer/prep/preptlist.c b/src/backend/optimizer/prep/preptlist.c index 34b38eb329843bd8744245a9c4e5a87197463dc2..63447aa536eaa17caefc908aae1d0a0311c1683e 100644 --- a/src/backend/optimizer/prep/preptlist.c +++ b/src/backend/optimizer/prep/preptlist.c @@ -102,7 +102,7 @@ preprocess_targetlist(PlannerInfo *root, List *tlist) -1, InvalidOid, 0); - snprintf(resname, sizeof(resname), "ctid%u", rc->rti); + snprintf(resname, sizeof(resname), "ctid%u", rc->rowmarkId); tle = makeTargetEntry((Expr *) var, list_length(tlist) + 1, pstrdup(resname), @@ -118,7 +118,7 @@ preprocess_targetlist(PlannerInfo *root, List *tlist) -1, InvalidOid, 0); - snprintf(resname, sizeof(resname), "tableoid%u", rc->rti); + snprintf(resname, sizeof(resname), "tableoid%u", rc->rowmarkId); tle = makeTargetEntry((Expr *) var, list_length(tlist) + 1, pstrdup(resname), @@ -132,7 +132,7 @@ preprocess_targetlist(PlannerInfo *root, List *tlist) var = makeWholeRowVar(rt_fetch(rc->rti, range_table), rc->rti, 0); - snprintf(resname, sizeof(resname), "wholerow%u", rc->rti); + snprintf(resname, sizeof(resname), "wholerow%u", rc->rowmarkId); tle = makeTargetEntry((Expr *) var, list_length(tlist) + 1, pstrdup(resname), diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c index f62af6c37daca9756f7d75fb4e5bf206027de416..606e5fe60a5f4becda1835170360692bc2103394 100644 --- a/src/backend/optimizer/prep/prepunion.c +++ b/src/backend/optimizer/prep/prepunion.c @@ -1294,6 +1294,7 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti) newrc->rti = childRTindex; newrc->prti = rti; + newrc->rowmarkId = oldrc->rowmarkId; newrc->markType = oldrc->markType; newrc->noWait = oldrc->noWait; newrc->isParent = false; diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index 546b581b6d8923b735d0085c0741f7ab583be2df..44da70ff60854458d8d617416c260ab4da410b97 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -417,6 +417,7 @@ typedef struct ExecRowMark Relation relation; /* opened and suitably locked relation */ Index rti; /* its range table index */ Index prti; /* parent range table index, if child */ + Index rowmarkId; /* unique identifier for resjunk columns */ RowMarkType markType; /* see enum in nodes/plannodes.h */ bool noWait; /* NOWAIT option */ ItemPointerData curCtid; /* ctid of currently locked tuple, if any */ diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h index 6ba2f6005a2cad52cb6318ee2e9fbbfd8ea66824..b4fb4f211b537777699b93c769e3b13a259658a3 100644 --- a/src/include/nodes/plannodes.h +++ b/src/include/nodes/plannodes.h @@ -749,7 +749,11 @@ typedef enum RowMarkType * The tableoid column is only present for an inheritance hierarchy. * When markType == ROW_MARK_COPY, there is instead a single column named * wholerow%u whole-row value of relation - * In all three cases, %u represents the parent rangetable index (prti). + * In all three cases, %u represents the rowmark ID number (rowmarkId). + * This number is unique within a plan tree, except that child relation + * entries copy their parent's rowmarkId. (Assigning unique numbers + * means we needn't renumber rowmarkIds when flattening subqueries, which + * would require finding and renaming the resjunk columns as well.) * Note this means that all tables in an inheritance hierarchy share the * same resjunk column names. However, in an inherited UPDATE/DELETE the * columns could have different physical column numbers in each subplan. @@ -759,6 +763,7 @@ typedef struct PlanRowMark NodeTag type; Index rti; /* range table index of markable relation */ Index prti; /* range table index of parent relation */ + Index rowmarkId; /* unique identifier for resjunk columns */ RowMarkType markType; /* see enum above */ bool noWait; /* NOWAIT option */ bool isParent; /* true if this is a "dummy" parent entry */ diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h index b3ca5b5e329f42551ab5c355d3a85ae3edeb6de6..49ce441e6248424852a2a1592ee28a9b9f72f743 100644 --- a/src/include/nodes/relation.h +++ b/src/include/nodes/relation.h @@ -82,6 +82,8 @@ typedef struct PlannerGlobal Index lastPHId; /* highest PlaceHolderVar ID assigned */ + Index lastRowMarkId; /* highest PlanRowMark ID assigned */ + bool transientPlan; /* redo plan when TransactionXmin changes? */ } PlannerGlobal;