diff options
Diffstat (limited to 'src/backend/executor/execMain.c')
-rw-r--r-- | src/backend/executor/execMain.c | 77 |
1 files changed, 64 insertions, 13 deletions
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index ef2fd46092e..0ba61fd5471 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -2441,7 +2441,7 @@ ExecBuildAuxRowMark(ExecRowMark *erm, List *targetlist) * relation - table containing tuple * rti - rangetable index of table containing tuple * inputslot - tuple for processing - this can be the slot from - * EvalPlanQualSlot(), for the increased efficiency. + * EvalPlanQualSlot() for this rel, for increased efficiency. * * This tests whether the tuple in inputslot still matches the relevant * quals. For that result to be useful, typically the input tuple has to be @@ -2476,6 +2476,14 @@ EvalPlanQual(EPQState *epqstate, Relation relation, ExecCopySlot(testslot, inputslot); /* + * Mark that an EPQ tuple is available for this relation. (If there is + * more than one result relation, the others remain marked as having no + * tuple available.) + */ + epqstate->relsubs_done[rti - 1] = false; + epqstate->epqExtra->relsubs_blocked[rti - 1] = false; + + /* * Run the EPQ query. We assume it will return at most one tuple. */ slot = EvalPlanQualNext(epqstate); @@ -2491,11 +2499,12 @@ EvalPlanQual(EPQState *epqstate, Relation relation, ExecMaterializeSlot(slot); /* - * Clear out the test tuple. This is needed in case the EPQ query is - * re-used to test a tuple for a different relation. (Not clear that can - * really happen, but let's be safe.) + * Clear out the test tuple, and mark that no tuple is available here. + * This is needed in case the EPQ state is re-used to test a tuple for a + * different target relation. */ ExecClearTuple(testslot); + epqstate->epqExtra->relsubs_blocked[rti - 1] = true; return slot; } @@ -2511,11 +2520,33 @@ void EvalPlanQualInit(EPQState *epqstate, EState *parentestate, Plan *subplan, List *auxrowmarks, int epqParam) { + EvalPlanQualInitExt(epqstate, parentestate, + subplan, auxrowmarks, epqParam, NIL); +} + +/* + * EvalPlanQualInitExt -- same, but allow specification of resultRelations + * + * If the caller intends to use EvalPlanQual(), resultRelations should be + * a list of RT indexes of potential target relations for EvalPlanQual(), + * and we will arrange that the other listed relations don't return any + * tuple during an EvalPlanQual() call. Otherwise resultRelations + * should be NIL. + */ +void +EvalPlanQualInitExt(EPQState *epqstate, EState *parentestate, + Plan *subplan, List *auxrowmarks, + int epqParam, List *resultRelations) +{ Index rtsize = parentestate->es_range_table_size; + /* create some extra space to avoid ABI break */ + epqstate->epqExtra = (EPQStateExtra *) palloc(sizeof(EPQStateExtra)); + /* initialize data not changing over EPQState's lifetime */ epqstate->parentestate = parentestate; epqstate->epqParam = epqParam; + epqstate->epqExtra->resultRelations = resultRelations; /* * Allocate space to reference a slot for each potential rti - do so now @@ -2524,7 +2555,7 @@ EvalPlanQualInit(EPQState *epqstate, EState *parentestate, * that *may* need EPQ later, without forcing the overhead of * EvalPlanQualBegin(). */ - epqstate->tuple_table = NIL; + epqstate->epqExtra->tuple_table = NIL; epqstate->relsubs_slot = (TupleTableSlot **) palloc0(rtsize * sizeof(TupleTableSlot *)); @@ -2538,6 +2569,7 @@ EvalPlanQualInit(EPQState *epqstate, EState *parentestate, epqstate->recheckplanstate = NULL; epqstate->relsubs_rowmark = NULL; epqstate->relsubs_done = NULL; + epqstate->epqExtra->relsubs_blocked = NULL; } /* @@ -2578,7 +2610,7 @@ EvalPlanQualSlot(EPQState *epqstate, MemoryContext oldcontext; oldcontext = MemoryContextSwitchTo(epqstate->parentestate->es_query_cxt); - *slot = table_slot_create(relation, &epqstate->tuple_table); + *slot = table_slot_create(relation, &epqstate->epqExtra->tuple_table); MemoryContextSwitchTo(oldcontext); } @@ -2735,7 +2767,13 @@ EvalPlanQualBegin(EPQState *epqstate) Index rtsize = parentestate->es_range_table_size; PlanState *rcplanstate = epqstate->recheckplanstate; - MemSet(epqstate->relsubs_done, 0, rtsize * sizeof(bool)); + /* + * Reset the relsubs_done[] flags to equal relsubs_blocked[], so that + * the EPQ run will never attempt to fetch tuples from blocked target + * relations. + */ + memcpy(epqstate->relsubs_done, epqstate->epqExtra->relsubs_blocked, + rtsize * sizeof(bool)); /* Recopy current values of parent parameters */ if (parentestate->es_plannedstmt->paramExecTypes != NIL) @@ -2902,10 +2940,22 @@ EvalPlanQualStart(EPQState *epqstate, Plan *planTree) } /* - * Initialize per-relation EPQ tuple states to not-fetched. + * Initialize per-relation EPQ tuple states. Result relations, if any, + * get marked as blocked; others as not-fetched. */ - epqstate->relsubs_done = (bool *) - palloc0(rtsize * sizeof(bool)); + epqstate->relsubs_done = palloc_array(bool, rtsize); + epqstate->epqExtra->relsubs_blocked = palloc0_array(bool, rtsize); + + foreach(l, epqstate->epqExtra->resultRelations) + { + int rtindex = lfirst_int(l); + + Assert(rtindex > 0 && rtindex <= rtsize); + epqstate->epqExtra->relsubs_blocked[rtindex - 1] = true; + } + + memcpy(epqstate->relsubs_done, epqstate->epqExtra->relsubs_blocked, + rtsize * sizeof(bool)); /* * Initialize the private state information for all the nodes in the part @@ -2942,12 +2992,12 @@ EvalPlanQualEnd(EPQState *epqstate) * We may have a tuple table, even if EPQ wasn't started, because we allow * use of EvalPlanQualSlot() without calling EvalPlanQualBegin(). */ - if (epqstate->tuple_table != NIL) + if (epqstate->epqExtra->tuple_table != NIL) { memset(epqstate->relsubs_slot, 0, rtsize * sizeof(TupleTableSlot *)); - ExecResetTupleTable(epqstate->tuple_table, true); - epqstate->tuple_table = NIL; + ExecResetTupleTable(epqstate->epqExtra->tuple_table, true); + epqstate->epqExtra->tuple_table = NIL; } /* EPQ wasn't started, nothing further to do */ @@ -2981,4 +3031,5 @@ EvalPlanQualEnd(EPQState *epqstate) epqstate->recheckplanstate = NULL; epqstate->relsubs_rowmark = NULL; epqstate->relsubs_done = NULL; + epqstate->epqExtra->relsubs_blocked = NULL; } |