diff options
Diffstat (limited to 'src/backend/executor')
-rw-r--r-- | src/backend/executor/execMain.c | 77 | ||||
-rw-r--r-- | src/backend/executor/execScan.c | 18 | ||||
-rw-r--r-- | src/backend/executor/nodeModifyTable.c | 3 |
3 files changed, 77 insertions, 21 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; } diff --git a/src/backend/executor/execScan.c b/src/backend/executor/execScan.c index 043bb83f558..5ae8f4da72c 100644 --- a/src/backend/executor/execScan.c +++ b/src/backend/executor/execScan.c @@ -69,13 +69,12 @@ ExecScanFetch(ScanState *node, else if (epqstate->relsubs_done[scanrelid - 1]) { /* - * Return empty slot, as we already performed an EPQ substitution - * for this relation. + * Return empty slot, as either there is no EPQ tuple for this rel + * or we already returned it. */ TupleTableSlot *slot = node->ss_ScanTupleSlot; - /* Return empty slot, as we already returned a tuple */ return ExecClearTuple(slot); } else if (epqstate->relsubs_slot[scanrelid - 1] != NULL) @@ -88,7 +87,7 @@ ExecScanFetch(ScanState *node, Assert(epqstate->relsubs_rowmark[scanrelid - 1] == NULL); - /* Mark to remember that we shouldn't return more */ + /* Mark to remember that we shouldn't return it again */ epqstate->relsubs_done[scanrelid - 1] = true; /* Return empty slot if we haven't got a test tuple */ @@ -306,14 +305,18 @@ ExecScanReScan(ScanState *node) */ ExecClearTuple(node->ss_ScanTupleSlot); - /* Rescan EvalPlanQual tuple if we're inside an EvalPlanQual recheck */ + /* + * Rescan EvalPlanQual tuple(s) if we're inside an EvalPlanQual recheck. + * But don't lose the "blocked" status of blocked target relations. + */ if (estate->es_epq_active != NULL) { EPQState *epqstate = estate->es_epq_active; Index scanrelid = ((Scan *) node->ps.plan)->scanrelid; if (scanrelid > 0) - epqstate->relsubs_done[scanrelid - 1] = false; + epqstate->relsubs_done[scanrelid - 1] = + epqstate->epqExtra->relsubs_blocked[scanrelid - 1]; else { Bitmapset *relids; @@ -335,7 +338,8 @@ ExecScanReScan(ScanState *node) while ((rtindex = bms_next_member(relids, rtindex)) >= 0) { Assert(rtindex > 0); - epqstate->relsubs_done[rtindex - 1] = false; + epqstate->relsubs_done[rtindex - 1] = + epqstate->epqExtra->relsubs_blocked[rtindex - 1]; } } } diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index ea6d7012650..ca62cb707a4 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -3966,7 +3966,8 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) } /* set up epqstate with dummy subplan data for the moment */ - EvalPlanQualInit(&mtstate->mt_epqstate, estate, NULL, NIL, node->epqParam); + EvalPlanQualInitExt(&mtstate->mt_epqstate, estate, NULL, NIL, + node->epqParam, node->resultRelations); mtstate->fireBSTriggers = true; /* |