aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/execMain.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor/execMain.c')
-rw-r--r--src/backend/executor/execMain.c77
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;
}