diff options
Diffstat (limited to 'src/backend/executor')
-rw-r--r-- | src/backend/executor/execJunk.c | 14 | ||||
-rw-r--r-- | src/backend/executor/execMain.c | 107 | ||||
-rw-r--r-- | src/backend/executor/nodeLockRows.c | 51 | ||||
-rw-r--r-- | src/backend/executor/nodeModifyTable.c | 42 |
4 files changed, 143 insertions, 71 deletions
diff --git a/src/backend/executor/execJunk.c b/src/backend/executor/execJunk.c index 2fa7e68a8ed..da227093f30 100644 --- a/src/backend/executor/execJunk.c +++ b/src/backend/executor/execJunk.c @@ -208,9 +208,21 @@ ExecInitJunkFilterConversion(List *targetList, AttrNumber ExecFindJunkAttribute(JunkFilter *junkfilter, const char *attrName) { + return ExecFindJunkAttributeInTlist(junkfilter->jf_targetList, attrName); +} + +/* + * ExecFindJunkAttributeInTlist + * + * Find a junk attribute given a subplan's targetlist (not necessarily + * part of a JunkFilter). + */ +AttrNumber +ExecFindJunkAttributeInTlist(List *targetlist, const char *attrName) +{ ListCell *t; - foreach(t, junkfilter->jf_targetList) + foreach(t, targetlist) { TargetEntry *tle = lfirst(t); diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 0b6cbcc4af0..6d4a77328a4 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -728,9 +728,6 @@ InitPlan(QueryDesc *queryDesc, int eflags) erm->prti = rc->prti; erm->markType = rc->markType; erm->noWait = rc->noWait; - erm->ctidAttNo = rc->ctidAttNo; - erm->toidAttNo = rc->toidAttNo; - erm->wholeAttNo = rc->wholeAttNo; ItemPointerSetInvalid(&(erm->curCtid)); estate->es_rowMarks = lappend(estate->es_rowMarks, erm); } @@ -1335,6 +1332,71 @@ ExecConstraints(ResultRelInfo *resultRelInfo, /* + * ExecFindRowMark -- find the ExecRowMark struct for given rangetable index + */ +ExecRowMark * +ExecFindRowMark(EState *estate, Index rti) +{ + ListCell *lc; + + foreach(lc, estate->es_rowMarks) + { + ExecRowMark *erm = (ExecRowMark *) lfirst(lc); + + if (erm->rti == rti) + return erm; + } + elog(ERROR, "failed to find ExecRowMark for rangetable index %u", rti); + return NULL; /* keep compiler quiet */ +} + +/* + * ExecBuildAuxRowMark -- create an ExecAuxRowMark struct + * + * Inputs are the underlying ExecRowMark struct and the targetlist of the + * input plan node (not planstate node!). We need the latter to find out + * the column numbers of the resjunk columns. + */ +ExecAuxRowMark * +ExecBuildAuxRowMark(ExecRowMark *erm, List *targetlist) +{ + ExecAuxRowMark *aerm = (ExecAuxRowMark *) palloc0(sizeof(ExecAuxRowMark)); + char resname[32]; + + aerm->rowmark = erm; + + /* Look up the resjunk columns associated with this rowmark */ + if (erm->relation) + { + Assert(erm->markType != ROW_MARK_COPY); + + /* if child rel, need tableoid */ + if (erm->rti != erm->prti) + { + snprintf(resname, sizeof(resname), "tableoid%u", erm->prti); + aerm->toidAttNo = ExecFindJunkAttributeInTlist(targetlist, + resname); + } + + /* always need ctid for real relations */ + snprintf(resname, sizeof(resname), "ctid%u", erm->prti); + aerm->ctidAttNo = ExecFindJunkAttributeInTlist(targetlist, + resname); + } + else + { + Assert(erm->markType == ROW_MARK_COPY); + + snprintf(resname, sizeof(resname), "wholerow%u", erm->prti); + aerm->wholeAttNo = ExecFindJunkAttributeInTlist(targetlist, + resname); + } + + return aerm; +} + + +/* * EvalPlanQual logic --- recheck modified tuple(s) to see if we want to * process the updated version under READ COMMITTED rules. * @@ -1624,11 +1686,13 @@ EvalPlanQualFetch(EState *estate, Relation relation, int lockmode, /* * EvalPlanQualInit -- initialize during creation of a plan state node * that might need to invoke EPQ processing. - * Note: subplan can be NULL if it will be set later with EvalPlanQualSetPlan. + * + * Note: subplan/auxrowmarks can be NULL/NIL if they will be set later + * with EvalPlanQualSetPlan. */ void EvalPlanQualInit(EPQState *epqstate, EState *estate, - Plan *subplan, int epqParam) + Plan *subplan, List *auxrowmarks, int epqParam) { /* Mark the EPQ state inactive */ epqstate->estate = NULL; @@ -1636,7 +1700,7 @@ EvalPlanQualInit(EPQState *epqstate, EState *estate, epqstate->origslot = NULL; /* ... and remember data that EvalPlanQualBegin will need */ epqstate->plan = subplan; - epqstate->rowMarks = NIL; + epqstate->arowMarks = auxrowmarks; epqstate->epqParam = epqParam; } @@ -1646,25 +1710,14 @@ EvalPlanQualInit(EPQState *epqstate, EState *estate, * We need this so that ModifyTuple can deal with multiple subplans. */ void -EvalPlanQualSetPlan(EPQState *epqstate, Plan *subplan) +EvalPlanQualSetPlan(EPQState *epqstate, Plan *subplan, List *auxrowmarks) { /* If we have a live EPQ query, shut it down */ EvalPlanQualEnd(epqstate); /* And set/change the plan pointer */ epqstate->plan = subplan; -} - -/* - * EvalPlanQualAddRowMark -- add an ExecRowMark that EPQ needs to handle. - * - * Currently, only non-locking RowMarks are supported. - */ -void -EvalPlanQualAddRowMark(EPQState *epqstate, ExecRowMark *erm) -{ - if (RowMarkRequiresRowShareLock(erm->markType)) - elog(ERROR, "EvalPlanQual doesn't support locking rowmarks"); - epqstate->rowMarks = lappend(epqstate->rowMarks, erm); + /* The rowmarks depend on the plan, too */ + epqstate->arowMarks = auxrowmarks; } /* @@ -1714,13 +1767,17 @@ EvalPlanQualFetchRowMarks(EPQState *epqstate) Assert(epqstate->origslot != NULL); - foreach(l, epqstate->rowMarks) + foreach(l, epqstate->arowMarks) { - ExecRowMark *erm = (ExecRowMark *) lfirst(l); + ExecAuxRowMark *aerm = (ExecAuxRowMark *) lfirst(l); + ExecRowMark *erm = aerm->rowmark; Datum datum; bool isNull; HeapTupleData tuple; + if (RowMarkRequiresRowShareLock(erm->markType)) + elog(ERROR, "EvalPlanQual doesn't support locking rowmarks"); + /* clear any leftover test tuple for this rel */ EvalPlanQualSetTuple(epqstate, erm->rti, NULL); @@ -1736,7 +1793,7 @@ EvalPlanQualFetchRowMarks(EPQState *epqstate) Oid tableoid; datum = ExecGetJunkAttribute(epqstate->origslot, - erm->toidAttNo, + aerm->toidAttNo, &isNull); /* non-locked rels could be on the inside of outer joins */ if (isNull) @@ -1752,7 +1809,7 @@ EvalPlanQualFetchRowMarks(EPQState *epqstate) /* fetch the tuple's ctid */ datum = ExecGetJunkAttribute(epqstate->origslot, - erm->ctidAttNo, + aerm->ctidAttNo, &isNull); /* non-locked rels could be on the inside of outer joins */ if (isNull) @@ -1777,7 +1834,7 @@ EvalPlanQualFetchRowMarks(EPQState *epqstate) /* fetch the whole-row Var for the relation */ datum = ExecGetJunkAttribute(epqstate->origslot, - erm->wholeAttNo, + aerm->wholeAttNo, &isNull); /* non-locked rels could be on the inside of outer joins */ if (isNull) diff --git a/src/backend/executor/nodeLockRows.c b/src/backend/executor/nodeLockRows.c index 1f203b4fe6b..8798a3b0a4d 100644 --- a/src/backend/executor/nodeLockRows.c +++ b/src/backend/executor/nodeLockRows.c @@ -58,12 +58,13 @@ lnext: /* * Attempt to lock the source tuple(s). (Note we only have locking - * rowmarks in lr_rowMarks.) + * rowmarks in lr_arowMarks.) */ epq_started = false; - foreach(lc, node->lr_rowMarks) + foreach(lc, node->lr_arowMarks) { - ExecRowMark *erm = (ExecRowMark *) lfirst(lc); + ExecAuxRowMark *aerm = (ExecAuxRowMark *) lfirst(lc); + ExecRowMark *erm = aerm->rowmark; Datum datum; bool isNull; HeapTupleData tuple; @@ -84,7 +85,7 @@ lnext: Oid tableoid; datum = ExecGetJunkAttribute(slot, - erm->toidAttNo, + aerm->toidAttNo, &isNull); /* shouldn't ever get a null result... */ if (isNull) @@ -101,7 +102,7 @@ lnext: /* fetch the tuple's ctid */ datum = ExecGetJunkAttribute(slot, - erm->ctidAttNo, + aerm->ctidAttNo, &isNull); /* shouldn't ever get a null result... */ if (isNull) @@ -189,9 +190,10 @@ lnext: * so as to avoid overhead in the common case where there are no * concurrent updates.) */ - foreach(lc, node->lr_rowMarks) + foreach(lc, node->lr_arowMarks) { - ExecRowMark *erm = (ExecRowMark *) lfirst(lc); + ExecAuxRowMark *aerm = (ExecAuxRowMark *) lfirst(lc); + ExecRowMark *erm = aerm->rowmark; HeapTupleData tuple; Buffer buffer; @@ -251,6 +253,7 @@ ExecInitLockRows(LockRows *node, EState *estate, int eflags) { LockRowsState *lrstate; Plan *outerPlan = outerPlan(node); + List *epq_arowmarks; ListCell *lc; /* check for unsupported flags */ @@ -262,7 +265,6 @@ ExecInitLockRows(LockRows *node, EState *estate, int eflags) lrstate = makeNode(LockRowsState); lrstate->ps.plan = (Plan *) node; lrstate->ps.state = estate; - EvalPlanQualInit(&lrstate->lr_epqstate, estate, outerPlan, node->epqParam); /* * Miscellaneous initialization @@ -288,15 +290,17 @@ ExecInitLockRows(LockRows *node, EState *estate, int eflags) lrstate->ps.ps_ProjInfo = NULL; /* - * Locate the ExecRowMark(s) that this node is responsible for. (InitPlan - * should already have built the global list of ExecRowMarks.) + * Locate the ExecRowMark(s) that this node is responsible for, and + * construct ExecAuxRowMarks for them. (InitPlan should already have + * built the global list of ExecRowMarks.) */ - lrstate->lr_rowMarks = NIL; + lrstate->lr_arowMarks = NIL; + epq_arowmarks = NIL; foreach(lc, node->rowMarks) { PlanRowMark *rc = (PlanRowMark *) lfirst(lc); - ExecRowMark *erm = NULL; - ListCell *lce; + ExecRowMark *erm; + ExecAuxRowMark *aerm; Assert(IsA(rc, PlanRowMark)); @@ -304,16 +308,9 @@ ExecInitLockRows(LockRows *node, EState *estate, int eflags) if (rc->isParent) continue; - foreach(lce, estate->es_rowMarks) - { - erm = (ExecRowMark *) lfirst(lce); - if (erm->rti == rc->rti) - break; - erm = NULL; - } - if (erm == NULL) - elog(ERROR, "failed to find ExecRowMark for PlanRowMark %u", - rc->rti); + /* find ExecRowMark and build ExecAuxRowMark */ + erm = ExecFindRowMark(estate, rc->rti); + aerm = ExecBuildAuxRowMark(erm, outerPlan->targetlist); /* * Only locking rowmarks go into our own list. Non-locking marks are @@ -322,11 +319,15 @@ ExecInitLockRows(LockRows *node, EState *estate, int eflags) * do an EPQ recheck. */ if (RowMarkRequiresRowShareLock(erm->markType)) - lrstate->lr_rowMarks = lappend(lrstate->lr_rowMarks, erm); + lrstate->lr_arowMarks = lappend(lrstate->lr_arowMarks, aerm); else - EvalPlanQualAddRowMark(&lrstate->lr_epqstate, erm); + epq_arowmarks = lappend(epq_arowmarks, aerm); } + /* Now we have the info needed to set up EPQ state */ + EvalPlanQualInit(&lrstate->lr_epqstate, estate, + outerPlan, epq_arowmarks, node->epqParam); + return lrstate; } diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index 969938130ec..f4b2b16b69e 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -701,7 +701,8 @@ ExecModifyTable(ModifyTableState *node) estate->es_result_relation_info++; subplanstate = node->mt_plans[node->mt_whichplan]; junkfilter = estate->es_result_relation_info->ri_junkFilter; - EvalPlanQualSetPlan(&node->mt_epqstate, subplanstate->plan); + EvalPlanQualSetPlan(&node->mt_epqstate, subplanstate->plan, + node->mt_arowmarks[node->mt_whichplan]); continue; } else @@ -815,10 +816,11 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) mtstate->ps.targetlist = NIL; /* not actually used */ mtstate->mt_plans = (PlanState **) palloc0(sizeof(PlanState *) * nplans); + mtstate->mt_arowmarks = (List **) palloc0(sizeof(List *) * nplans); mtstate->mt_nplans = nplans; mtstate->operation = operation; - /* set up epqstate with dummy subplan pointer for the moment */ - EvalPlanQualInit(&mtstate->mt_epqstate, estate, NULL, node->epqParam); + /* set up epqstate with dummy subplan data for the moment */ + EvalPlanQualInit(&mtstate->mt_epqstate, estate, NULL, NIL, node->epqParam); mtstate->fireBSTriggers = true; /* For the moment, assume our targets are exactly the global result rels */ @@ -840,11 +842,6 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) } estate->es_result_relation_info = NULL; - /* select first subplan */ - mtstate->mt_whichplan = 0; - subplan = (Plan *) linitial(node->plans); - EvalPlanQualSetPlan(&mtstate->mt_epqstate, subplan); - /* * Initialize RETURNING projections if needed. */ @@ -908,8 +905,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) foreach(l, node->rowMarks) { PlanRowMark *rc = (PlanRowMark *) lfirst(l); - ExecRowMark *erm = NULL; - ListCell *lce; + ExecRowMark *erm; Assert(IsA(rc, PlanRowMark)); @@ -917,20 +913,26 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) if (rc->isParent) continue; - foreach(lce, estate->es_rowMarks) + /* find ExecRowMark (same for all subplans) */ + erm = ExecFindRowMark(estate, rc->rti); + + /* build ExecAuxRowMark for each subplan */ + for (i = 0; i < nplans; i++) { - erm = (ExecRowMark *) lfirst(lce); - if (erm->rti == rc->rti) - break; - erm = NULL; - } - if (erm == NULL) - elog(ERROR, "failed to find ExecRowMark for PlanRowMark %u", - rc->rti); + ExecAuxRowMark *aerm; - EvalPlanQualAddRowMark(&mtstate->mt_epqstate, erm); + subplan = mtstate->mt_plans[i]->plan; + aerm = ExecBuildAuxRowMark(erm, subplan->targetlist); + mtstate->mt_arowmarks[i] = lappend(mtstate->mt_arowmarks[i], aerm); + } } + /* select first subplan */ + mtstate->mt_whichplan = 0; + subplan = (Plan *) linitial(node->plans); + EvalPlanQualSetPlan(&mtstate->mt_epqstate, subplan, + mtstate->mt_arowmarks[0]); + /* * Initialize the junk filter(s) if needed. INSERT queries need a filter * if there are any junk attrs in the tlist. UPDATE and DELETE always |