Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/executor/execMain.c55
-rw-r--r--src/backend/executor/execScan.c18
-rw-r--r--src/backend/executor/nodeLockRows.c3
-rw-r--r--src/backend/executor/nodeModifyTable.c3
-rw-r--r--src/backend/replication/logical/worker.c6
5 files changed, 63 insertions, 22 deletions
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 0186be452cb..c76fdf59ec4 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -2469,7 +2469,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
@@ -2504,6 +2504,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->relsubs_blocked[rti - 1] = false;
+
+ /*
* Run the EPQ query. We assume it will return at most one tuple.
*/
slot = EvalPlanQualNext(epqstate);
@@ -2519,11 +2527,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->relsubs_blocked[rti - 1] = true;
return slot;
}
@@ -2532,18 +2541,26 @@ EvalPlanQual(EPQState *epqstate, Relation relation,
* EvalPlanQualInit -- initialize during creation of a plan state node
* that might need to invoke EPQ processing.
*
+ * 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.
+ *
* Note: subplan/auxrowmarks can be NULL/NIL if they will be set later
* with EvalPlanQualSetPlan.
*/
void
EvalPlanQualInit(EPQState *epqstate, EState *parentestate,
- Plan *subplan, List *auxrowmarks, int epqParam)
+ Plan *subplan, List *auxrowmarks,
+ int epqParam, List *resultRelations)
{
Index rtsize = parentestate->es_range_table_size;
/* initialize data not changing over EPQState's lifetime */
epqstate->parentestate = parentestate;
epqstate->epqParam = epqParam;
+ epqstate->resultRelations = resultRelations;
/*
* Allocate space to reference a slot for each potential rti - do so now
@@ -2566,6 +2583,7 @@ EvalPlanQualInit(EPQState *epqstate, EState *parentestate,
epqstate->recheckplanstate = NULL;
epqstate->relsubs_rowmark = NULL;
epqstate->relsubs_done = NULL;
+ epqstate->relsubs_blocked = NULL;
}
/*
@@ -2763,7 +2781,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->relsubs_blocked,
+ rtsize * sizeof(bool));
/* Recopy current values of parent parameters */
if (parentestate->es_plannedstmt->paramExecTypes != NIL)
@@ -2931,10 +2955,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->relsubs_blocked = palloc0_array(bool, rtsize);
+
+ foreach(l, epqstate->resultRelations)
+ {
+ int rtindex = lfirst_int(l);
+
+ Assert(rtindex > 0 && rtindex <= rtsize);
+ epqstate->relsubs_blocked[rtindex - 1] = true;
+ }
+
+ memcpy(epqstate->relsubs_done, epqstate->relsubs_blocked,
+ rtsize * sizeof(bool));
/*
* Initialize the private state information for all the nodes in the part
@@ -3010,4 +3046,5 @@ EvalPlanQualEnd(EPQState *epqstate)
epqstate->recheckplanstate = NULL;
epqstate->relsubs_rowmark = NULL;
epqstate->relsubs_done = NULL;
+ epqstate->relsubs_blocked = NULL;
}
diff --git a/src/backend/executor/execScan.c b/src/backend/executor/execScan.c
index cf1871b0f53..a47c8f5f712 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->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->relsubs_blocked[rtindex - 1];
}
}
}
diff --git a/src/backend/executor/nodeLockRows.c b/src/backend/executor/nodeLockRows.c
index 407414fc0cf..e459971d32e 100644
--- a/src/backend/executor/nodeLockRows.c
+++ b/src/backend/executor/nodeLockRows.c
@@ -108,7 +108,6 @@ lnext:
/* this child is inactive right now */
erm->ermActive = false;
ItemPointerSetInvalid(&(erm->curCtid));
- ExecClearTuple(markSlot);
continue;
}
}
@@ -370,7 +369,7 @@ ExecInitLockRows(LockRows *node, EState *estate, int eflags)
/* Now we have the info needed to set up EPQ state */
EvalPlanQualInit(&lrstate->lr_epqstate, estate,
- outerPlan, epq_arowmarks, node->epqParam);
+ outerPlan, epq_arowmarks, node->epqParam, NIL);
return lrstate;
}
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index dc1a2ec551a..7f5002527f0 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -3985,7 +3985,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);
+ EvalPlanQualInit(&mtstate->mt_epqstate, estate, NULL, NIL,
+ node->epqParam, node->resultRelations);
mtstate->fireBSTriggers = true;
/*
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index 879309b316c..4b670988144 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -2674,7 +2674,7 @@ apply_handle_update_internal(ApplyExecutionData *edata,
bool found;
MemoryContext oldctx;
- EvalPlanQualInit(&epqstate, estate, NULL, NIL, -1);
+ EvalPlanQualInit(&epqstate, estate, NULL, NIL, -1, NIL);
ExecOpenIndices(relinfo, false);
found = FindReplTupleInLocalRel(estate, localrel,
@@ -2827,7 +2827,7 @@ apply_handle_delete_internal(ApplyExecutionData *edata,
TupleTableSlot *localslot;
bool found;
- EvalPlanQualInit(&epqstate, estate, NULL, NIL, -1);
+ EvalPlanQualInit(&epqstate, estate, NULL, NIL, -1, NIL);
ExecOpenIndices(relinfo, false);
found = FindReplTupleInLocalRel(estate, localrel, remoterel, localindexoid,
@@ -3054,7 +3054,7 @@ apply_handle_tuple_routing(ApplyExecutionData *edata,
*/
EPQState epqstate;
- EvalPlanQualInit(&epqstate, estate, NULL, NIL, -1);
+ EvalPlanQualInit(&epqstate, estate, NULL, NIL, -1, NIL);
ExecOpenIndices(partrelinfo, false);
EvalPlanQualSetSlot(&epqstate, remoteslot_part);