diff options
Diffstat (limited to 'src')
| -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 | ||||
| -rw-r--r-- | src/backend/nodes/copyfuncs.c | 3 | ||||
| -rw-r--r-- | src/backend/nodes/outfuncs.c | 3 | ||||
| -rw-r--r-- | src/backend/optimizer/plan/planner.c | 8 | ||||
| -rw-r--r-- | src/backend/optimizer/prep/preptlist.c | 17 | ||||
| -rw-r--r-- | src/backend/optimizer/prep/prepunion.c | 4 | ||||
| -rw-r--r-- | src/include/executor/executor.h | 10 | ||||
| -rw-r--r-- | src/include/nodes/execnodes.h | 34 | ||||
| -rw-r--r-- | src/include/nodes/plannodes.h | 21 | 
12 files changed, 192 insertions, 122 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 diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 5f83e4fc98d..0b2aa3dfff8 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -859,9 +859,6 @@ _copyPlanRowMark(PlanRowMark *from)  	COPY_SCALAR_FIELD(markType);  	COPY_SCALAR_FIELD(noWait);  	COPY_SCALAR_FIELD(isParent); -	COPY_SCALAR_FIELD(ctidAttNo); -	COPY_SCALAR_FIELD(toidAttNo); -	COPY_SCALAR_FIELD(wholeAttNo);  	return newnode;  } diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 030a675b7b6..032150e1bb7 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -759,9 +759,6 @@ _outPlanRowMark(StringInfo str, PlanRowMark *node)  	WRITE_ENUM_FIELD(markType, RowMarkType);  	WRITE_BOOL_FIELD(noWait);  	WRITE_BOOL_FIELD(isParent); -	WRITE_INT_FIELD(ctidAttNo); -	WRITE_INT_FIELD(toidAttNo); -	WRITE_INT_FIELD(wholeAttNo);  }  static void diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 317a7e87f33..45ba902fbab 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -1858,10 +1858,6 @@ preprocess_rowmarks(PlannerInfo *root)  			newrc->markType = ROW_MARK_SHARE;  		newrc->noWait = rc->noWait;  		newrc->isParent = false; -		/* attnos will be assigned in preprocess_targetlist */ -		newrc->ctidAttNo = InvalidAttrNumber; -		newrc->toidAttNo = InvalidAttrNumber; -		newrc->wholeAttNo = InvalidAttrNumber;  		prowmarks = lappend(prowmarks, newrc);  	} @@ -1888,10 +1884,6 @@ preprocess_rowmarks(PlannerInfo *root)  			newrc->markType = ROW_MARK_COPY;  		newrc->noWait = false;	/* doesn't matter */  		newrc->isParent = false; -		/* attnos will be assigned in preprocess_targetlist */ -		newrc->ctidAttNo = InvalidAttrNumber; -		newrc->toidAttNo = InvalidAttrNumber; -		newrc->wholeAttNo = InvalidAttrNumber;  		prowmarks = lappend(prowmarks, newrc);  	} diff --git a/src/backend/optimizer/prep/preptlist.c b/src/backend/optimizer/prep/preptlist.c index 2ea01a7f08d..7a09d1f8309 100644 --- a/src/backend/optimizer/prep/preptlist.c +++ b/src/backend/optimizer/prep/preptlist.c @@ -111,8 +111,7 @@ preprocess_targetlist(PlannerInfo *root, List *tlist)  	/*  	 * Add necessary junk columns for rowmarked rels.  These values are needed  	 * for locking of rels selected FOR UPDATE/SHARE, and to do EvalPlanQual -	 * rechecking.	While we are at it, store these junk attnos in the -	 * PlanRowMark list so that we don't have to redetermine them at runtime. +	 * rechecking.  See comments for PlanRowMark in plannodes.h.  	 */  	foreach(lc, root->rowMarks)  	{ @@ -121,18 +120,9 @@ preprocess_targetlist(PlannerInfo *root, List *tlist)  		char		resname[32];  		TargetEntry *tle; -		/* child rels should just use the same junk attrs as their parents */ +		/* child rels use the same junk attrs as their parents */  		if (rc->rti != rc->prti) -		{ -			PlanRowMark *prc = get_plan_rowmark(root->rowMarks, rc->prti); - -			/* parent should have appeared earlier in list */ -			if (prc == NULL || prc->toidAttNo == InvalidAttrNumber) -				elog(ERROR, "parent PlanRowMark not processed yet"); -			rc->ctidAttNo = prc->ctidAttNo; -			rc->toidAttNo = prc->toidAttNo;  			continue; -		}  		if (rc->markType != ROW_MARK_COPY)  		{ @@ -148,7 +138,6 @@ preprocess_targetlist(PlannerInfo *root, List *tlist)  								  pstrdup(resname),  								  true);  			tlist = lappend(tlist, tle); -			rc->ctidAttNo = tle->resno;  			/* if parent of inheritance tree, need the tableoid too */  			if (rc->isParent) @@ -164,7 +153,6 @@ preprocess_targetlist(PlannerInfo *root, List *tlist)  									  pstrdup(resname),  									  true);  				tlist = lappend(tlist, tle); -				rc->toidAttNo = tle->resno;  			}  		}  		else @@ -179,7 +167,6 @@ preprocess_targetlist(PlannerInfo *root, List *tlist)  								  pstrdup(resname),  								  true);  			tlist = lappend(tlist, tle); -			rc->wholeAttNo = tle->resno;  		}  	} diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c index 3cb5ed977b0..35f9f980e90 100644 --- a/src/backend/optimizer/prep/prepunion.c +++ b/src/backend/optimizer/prep/prepunion.c @@ -1291,10 +1291,6 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)  			newrc->markType = oldrc->markType;  			newrc->noWait = oldrc->noWait;  			newrc->isParent = false; -			/* junk attrs for children are not identified yet */ -			newrc->ctidAttNo = InvalidAttrNumber; -			newrc->toidAttNo = InvalidAttrNumber; -			newrc->wholeAttNo = InvalidAttrNumber;  			root->rowMarks = lappend(root->rowMarks, newrc);  		} diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index b2424a0d087..13b6aa57bea 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -138,6 +138,8 @@ extern JunkFilter *ExecInitJunkFilterConversion(List *targetList,  							 TupleTableSlot *slot);  extern AttrNumber ExecFindJunkAttribute(JunkFilter *junkfilter,  					  const char *attrName); +extern AttrNumber ExecFindJunkAttributeInTlist(List *targetlist, +					  const char *attrName);  extern Datum ExecGetJunkAttribute(TupleTableSlot *slot, AttrNumber attno,  					 bool *isNull);  extern TupleTableSlot *ExecFilterJunk(JunkFilter *junkfilter, @@ -166,15 +168,17 @@ extern ResultRelInfo *ExecGetTriggerResultRel(EState *estate, Oid relid);  extern bool ExecContextForcesOids(PlanState *planstate, bool *hasoids);  extern void ExecConstraints(ResultRelInfo *resultRelInfo,  				TupleTableSlot *slot, EState *estate); +extern ExecRowMark *ExecFindRowMark(EState *estate, Index rti); +extern ExecAuxRowMark *ExecBuildAuxRowMark(ExecRowMark *erm, List *targetlist);  extern TupleTableSlot *EvalPlanQual(EState *estate, EPQState *epqstate,  			 Relation relation, Index rti,  			 ItemPointer tid, TransactionId priorXmax);  extern HeapTuple EvalPlanQualFetch(EState *estate, Relation relation,  				  int lockmode, ItemPointer tid, TransactionId priorXmax);  extern void EvalPlanQualInit(EPQState *epqstate, EState *estate, -				 Plan *subplan, int epqParam); -extern void EvalPlanQualSetPlan(EPQState *epqstate, Plan *subplan); -extern void EvalPlanQualAddRowMark(EPQState *epqstate, ExecRowMark *erm); +				 Plan *subplan, List *auxrowmarks, int epqParam); +extern void EvalPlanQualSetPlan(EPQState *epqstate, +								Plan *subplan, List *auxrowmarks);  extern void EvalPlanQualSetTuple(EPQState *epqstate, Index rti,  					 HeapTuple tuple);  extern HeapTuple EvalPlanQualGetTuple(EPQState *epqstate, Index rti); diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index 928cf4c5a55..fda44255b08 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -407,12 +407,10 @@ typedef struct EState   * When doing UPDATE, DELETE, or SELECT FOR UPDATE/SHARE, we should have an   * ExecRowMark for each non-target relation in the query (except inheritance   * parent RTEs, which can be ignored at runtime).  See PlanRowMark for details - * about most of the fields. + * about most of the fields.  In addition to fields directly derived from + * PlanRowMark, we store curCtid, which is used by the WHERE CURRENT OF code.   * - * es_rowMarks is a list of these structs.	Each LockRows node has its own - * list, which is the subset of locks that it is supposed to enforce; note - * that the per-node lists point to the same structs that are in the global - * list. + * EState->es_rowMarks is a list of these structs.   */  typedef struct ExecRowMark  { @@ -421,11 +419,28 @@ typedef struct ExecRowMark  	Index		prti;			/* parent range table index, if child */  	RowMarkType markType;		/* see enum in nodes/plannodes.h */  	bool		noWait;			/* NOWAIT option */ +	ItemPointerData curCtid;	/* ctid of currently locked tuple, if any */ +} ExecRowMark; + +/* + * ExecAuxRowMark - + *	   additional runtime representation of FOR UPDATE/SHARE clauses + * + * Each LockRows and ModifyTable node keeps a list of the rowmarks it needs to + * deal with.  In addition to a pointer to the related entry in es_rowMarks, + * this struct carries the column number(s) of the resjunk columns associated + * with the rowmark (see comments for PlanRowMark for more detail).  In the + * case of ModifyTable, there has to be a separate ExecAuxRowMark list for + * each child plan, because the resjunk columns could be at different physical + * column positions in different subplans. + */ +typedef struct ExecAuxRowMark +{ +	ExecRowMark *rowmark;		/* related entry in es_rowMarks */  	AttrNumber	ctidAttNo;		/* resno of ctid junk attribute, if any */  	AttrNumber	toidAttNo;		/* resno of tableoid junk attribute, if any */  	AttrNumber	wholeAttNo;		/* resno of whole-row junk attribute, if any */ -	ItemPointerData curCtid;	/* ctid of currently locked tuple, if any */ -} ExecRowMark; +} ExecAuxRowMark;  /* ---------------------------------------------------------------- @@ -1002,7 +1017,7 @@ typedef struct EPQState  	PlanState  *planstate;		/* plan state tree ready to be executed */  	TupleTableSlot *origslot;	/* original output tuple to be rechecked */  	Plan	   *plan;			/* plan tree to be executed */ -	List	   *rowMarks;		/* ExecRowMarks (non-locking only) */ +	List	   *arowMarks;		/* ExecAuxRowMarks (non-locking only) */  	int			epqParam;		/* ID of Param to force scan node re-eval */  } EPQState; @@ -1030,6 +1045,7 @@ typedef struct ModifyTableState  	PlanState **mt_plans;		/* subplans (one per target rel) */  	int			mt_nplans;		/* number of plans in the array */  	int			mt_whichplan;	/* which one is being executed (0..n-1) */ +	List	  **mt_arowmarks;	/* per-subplan ExecAuxRowMark lists */  	EPQState	mt_epqstate;	/* for evaluating EvalPlanQual rechecks */  	bool		fireBSTriggers; /* do we need to fire stmt triggers? */  } ModifyTableState; @@ -1706,7 +1722,7 @@ typedef struct SetOpState  typedef struct LockRowsState  {  	PlanState	ps;				/* its first field is NodeTag */ -	List	   *lr_rowMarks;	/* List of ExecRowMarks */ +	List	   *lr_arowMarks;	/* List of ExecAuxRowMarks */  	EPQState	lr_epqstate;	/* for evaluating EvalPlanQual rechecks */  } LockRowsState; diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h index 79876100d5a..e14257932e6 100644 --- a/src/include/nodes/plannodes.h +++ b/src/include/nodes/plannodes.h @@ -158,6 +158,9 @@ typedef struct Result   *	 ModifyTable node -   *		Apply rows produced by subplan(s) to result table(s),   *		by inserting, updating, or deleting. + * + * Note that rowMarks and epqParam are presumed to be valid for all the + * subplan(s); they can't contain any info that varies across subplans.   * ----------------   */  typedef struct ModifyTable @@ -690,9 +693,18 @@ typedef enum RowMarkType   * prti == parent's RT index, and can therefore be recognized as children by   * the fact that prti != rti.   * - * The AttrNumbers are filled in during preprocess_targetlist.	We use - * different subsets of them for plain relations, inheritance children, - * and non-table relations. + * The planner also adds resjunk output columns to the plan that carry + * information sufficient to identify the locked or fetched rows.  For + * tables (markType != ROW_MARK_COPY), these columns are named + *		tableoid%u			OID of table + *		ctid%u				TID of row + * 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). + * 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.   */  typedef struct PlanRowMark  { @@ -702,9 +714,6 @@ typedef struct PlanRowMark  	RowMarkType markType;		/* see enum above */  	bool		noWait;			/* NOWAIT option */  	bool		isParent;		/* true if this is a "dummy" parent entry */ -	AttrNumber	ctidAttNo;		/* resno of ctid junk attribute, if any */ -	AttrNumber	toidAttNo;		/* resno of tableoid junk attribute, if any */ -	AttrNumber	wholeAttNo;		/* resno of whole-row junk attribute, if any */  } PlanRowMark; | 
