Modify executor to use them instead of returning tuples directly.
CHECK_FOR_INTERRUPTS();
+ /* mark any previous result as having been consumed */
+ node->result_ready = false;
+
if (node->chgParam != NULL) /* something changed */
ExecReScan(node); /* let ReScan handle this */
* control nodes
*/
case T_ResultState:
- result = ExecResult((ResultState *) node);
+ ExecResult((ResultState *) node);
break;
case T_ModifyTableState:
- result = ExecModifyTable((ModifyTableState *) node);
+ ExecModifyTable((ModifyTableState *) node);
break;
case T_AppendState:
- result = ExecAppend((AppendState *) node);
+ ExecAppend((AppendState *) node);
break;
case T_MergeAppendState:
- result = ExecMergeAppend((MergeAppendState *) node);
+ ExecMergeAppend((MergeAppendState *) node);
break;
case T_RecursiveUnionState:
- result = ExecRecursiveUnion((RecursiveUnionState *) node);
+ ExecRecursiveUnion((RecursiveUnionState *) node);
break;
/* BitmapAndState does not yield tuples */
* scan nodes
*/
case T_SeqScanState:
- result = ExecSeqScan((SeqScanState *) node);
+ ExecSeqScan((SeqScanState *) node);
break;
case T_SampleScanState:
- result = ExecSampleScan((SampleScanState *) node);
+ ExecSampleScan((SampleScanState *) node);
break;
case T_IndexScanState:
- result = ExecIndexScan((IndexScanState *) node);
+ ExecIndexScan((IndexScanState *) node);
break;
case T_IndexOnlyScanState:
- result = ExecIndexOnlyScan((IndexOnlyScanState *) node);
+ ExecIndexOnlyScan((IndexOnlyScanState *) node);
break;
/* BitmapIndexScanState does not yield tuples */
case T_BitmapHeapScanState:
- result = ExecBitmapHeapScan((BitmapHeapScanState *) node);
+ ExecBitmapHeapScan((BitmapHeapScanState *) node);
break;
case T_TidScanState:
- result = ExecTidScan((TidScanState *) node);
+ ExecTidScan((TidScanState *) node);
break;
case T_SubqueryScanState:
- result = ExecSubqueryScan((SubqueryScanState *) node);
+ ExecSubqueryScan((SubqueryScanState *) node);
break;
case T_FunctionScanState:
- result = ExecFunctionScan((FunctionScanState *) node);
+ ExecFunctionScan((FunctionScanState *) node);
break;
case T_ValuesScanState:
- result = ExecValuesScan((ValuesScanState *) node);
+ ExecValuesScan((ValuesScanState *) node);
break;
case T_CteScanState:
- result = ExecCteScan((CteScanState *) node);
+ ExecCteScan((CteScanState *) node);
break;
case T_WorkTableScanState:
- result = ExecWorkTableScan((WorkTableScanState *) node);
+ ExecWorkTableScan((WorkTableScanState *) node);
break;
case T_ForeignScanState:
- result = ExecForeignScan((ForeignScanState *) node);
+ ExecForeignScan((ForeignScanState *) node);
break;
case T_CustomScanState:
- result = ExecCustomScan((CustomScanState *) node);
+ ExecCustomScan((CustomScanState *) node);
break;
/*
* join nodes
*/
case T_NestLoopState:
- result = ExecNestLoop((NestLoopState *) node);
+ ExecNestLoop((NestLoopState *) node);
break;
case T_MergeJoinState:
- result = ExecMergeJoin((MergeJoinState *) node);
+ ExecMergeJoin((MergeJoinState *) node);
break;
case T_HashJoinState:
- result = ExecHashJoin((HashJoinState *) node);
+ ExecHashJoin((HashJoinState *) node);
break;
/*
* materialization nodes
*/
case T_MaterialState:
- result = ExecMaterial((MaterialState *) node);
+ ExecMaterial((MaterialState *) node);
break;
case T_SortState:
- result = ExecSort((SortState *) node);
+ ExecSort((SortState *) node);
break;
case T_GroupState:
- result = ExecGroup((GroupState *) node);
+ ExecGroup((GroupState *) node);
break;
case T_AggState:
- result = ExecAgg((AggState *) node);
+ ExecAgg((AggState *) node);
break;
case T_WindowAggState:
- result = ExecWindowAgg((WindowAggState *) node);
+ ExecWindowAgg((WindowAggState *) node);
break;
case T_UniqueState:
- result = ExecUnique((UniqueState *) node);
+ ExecUnique((UniqueState *) node);
break;
case T_GatherState:
- result = ExecGather((GatherState *) node);
+ ExecGather((GatherState *) node);
break;
case T_HashState:
- result = ExecHash((HashState *) node);
+ ExecHash((HashState *) node);
break;
case T_SetOpState:
- result = ExecSetOp((SetOpState *) node);
+ ExecSetOp((SetOpState *) node);
break;
case T_LockRowsState:
- result = ExecLockRows((LockRowsState *) node);
+ ExecLockRows((LockRowsState *) node);
break;
case T_LimitState:
- result = ExecLimit((LimitState *) node);
+ ExecLimit((LimitState *) node);
break;
default:
break;
}
+ /* We don't support asynchronous execution yet. */
+ Assert(node->result_ready);
+
+ /* Result should be a TupleTableSlot, unless it's NULL. */
+ Assert(node->result == NULL || IsA(node->result, TupleTableSlot));
+
+ result = (TupleTableSlot *) node->result;
+
if (node->instrument)
InstrStopNode(node->instrument, TupIsNull(result) ? 0.0 : 1.0);
* ExecScan
*
* Scans the relation using the 'access method' indicated and
- * returns the next qualifying tuple in the direction specified
+ * produces the next qualifying tuple in the direction specified
* in the global variable ExecDirection.
* The access method returns the next tuple and ExecScan() is
* responsible for checking the tuple returned against the qual-clause.
* "cursor" is positioned before the first qualifying tuple.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
+void
ExecScan(ScanState *node,
ExecScanAccessMtd accessMtd, /* function returning a tuple */
ExecScanRecheckMtd recheckMtd)
/*
* If we have neither a qual to check nor a projection to do, just skip
- * all the overhead and return the raw scan tuple.
+ * all the overhead and produce the raw scan tuple.
*/
if (!qual && !projInfo)
{
ResetExprContext(econtext);
- return ExecScanFetch(node, accessMtd, recheckMtd);
+ ExecReturnTuple(&node->ps,
+ ExecScanFetch(node, accessMtd, recheckMtd));
+ return;
}
/*
Assert(projInfo); /* can't get here if not projecting */
resultSlot = ExecProject(projInfo, &isDone);
if (isDone == ExprMultipleResult)
- return resultSlot;
+ {
+ ExecReturnTuple(&node->ps, resultSlot);
+ return;
+ }
/* Done with that source tuple... */
node->ps.ps_TupFromTlist = false;
}
if (TupIsNull(slot))
{
if (projInfo)
- return ExecClearTuple(projInfo->pi_slot);
+ ExecReturnTuple(&node->ps, ExecClearTuple(projInfo->pi_slot));
else
- return slot;
+ ExecReturnTuple(&node->ps, slot);
+ return;
}
/*
if (isDone != ExprEndResult)
{
node->ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
- return resultSlot;
+ ExecReturnTuple(&node->ps, resultSlot);
+ return;
}
}
else
/*
* Here, we aren't projecting, so just return scan tuple.
*/
- return slot;
+ ExecReturnTuple(&node->ps, slot);
+ return;
}
}
else
* stored in the expression context to be used when ExecProject evaluates
* the result tuple.
*/
-TupleTableSlot *
+void
ExecAgg(AggState *node)
{
TupleTableSlot *result;
result = ExecProject(node->ss.ps.ps_ProjInfo, &isDone);
if (isDone == ExprMultipleResult)
- return result;
+ {
+ ExecReturnTuple(&node->ss.ps, result);
+ return;
+ }
/* Done with that source tuple... */
node->ss.ps.ps_TupFromTlist = false;
}
* agg_done gets set before we emit the final aggregate tuple, and we have
* to finish running SRFs for it.)
*/
+ result = NULL;
if (!node->agg_done)
{
/* Dispatch based on strategy */
result = agg_retrieve_direct(node);
break;
}
-
- if (!TupIsNull(result))
- return result;
}
- return NULL;
+ ExecReturnTuple(&node->ss.ps, result);
}
/*
* Handles iteration over multiple subplans.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
+void
ExecAppend(AppendState *node)
{
for (;;)
* NOT make use of the result slot that was set up in
* ExecInitAppend; there's no need for it.
*/
- return result;
+ ExecReturnTuple(&node->ps, result);
+ return;
}
/*
else
node->as_whichplan--;
if (!exec_append_initialize_next(node))
- return ExecClearTuple(node->ps.ps_ResultTupleSlot);
+ {
+ ExecReturnTuple(&node->ps,
+ ExecClearTuple(node->ps.ps_ResultTupleSlot));
+ return;
+ }
/* Else loop back and try to get a tuple from the new subplan */
}
* ExecBitmapHeapScan(node)
* ----------------------------------------------------------------
*/
-TupleTableSlot *
+void
ExecBitmapHeapScan(BitmapHeapScanState *node)
{
return ExecScan(&node->ss,
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
+void
ExecCteScan(CteScanState *node)
{
return ExecScan(&node->ss,
return css;
}
-TupleTableSlot *
+void
ExecCustomScan(CustomScanState *node)
{
Assert(node->methods->ExecCustomScan != NULL);
- return node->methods->ExecCustomScan(node);
+ ExecReturnTuple(&node->ss.ps, node->methods->ExecCustomScan(node));
}
void
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
+void
ExecForeignScan(ForeignScanState *node)
{
return ExecScan((ScanState *) node,
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
+void
ExecFunctionScan(FunctionScanState *node)
{
return ExecScan(&node->ss,
* the next qualifying tuple.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
+void
ExecGather(GatherState *node)
{
TupleTableSlot *fslot = node->funnel_slot;
{
resultSlot = ExecProject(node->ps.ps_ProjInfo, &isDone);
if (isDone == ExprMultipleResult)
- return resultSlot;
+ {
+ ExecReturnTuple(&node->ps, resultSlot);
+ return;
+ }
/* Done with that source tuple... */
node->ps.ps_TupFromTlist = false;
}
*/
slot = gather_getnext(node);
if (TupIsNull(slot))
- return NULL;
+ {
+ ExecReturnTuple(&node->ps, NULL);
+ return;
+ }
/*
* form the result tuple using ExecProject(), and return it --- unless
if (isDone != ExprEndResult)
{
node->ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
- return resultSlot;
+ ExecReturnTuple(&node->ps, resultSlot);
+ return;
}
}
- return slot;
+ ExecReturnTuple(&node->ps, slot);
}
/* ----------------------------------------------------------------
*
* Return one tuple for each group of matching input tuples.
*/
-TupleTableSlot *
+void
ExecGroup(GroupState *node)
{
ExprContext *econtext;
* get state info from node
*/
if (node->grp_done)
- return NULL;
+ {
+ ExecReturnTuple(&node->ss.ps, NULL);
+ return;
+ }
econtext = node->ss.ps.ps_ExprContext;
numCols = ((Group *) node->ss.ps.plan)->numCols;
grpColIdx = ((Group *) node->ss.ps.plan)->grpColIdx;
result = ExecProject(node->ss.ps.ps_ProjInfo, &isDone);
if (isDone == ExprMultipleResult)
- return result;
+ {
+ ExecReturnTuple(&node->ss.ps, result);
+ return;
+ }
/* Done with that source tuple... */
node->ss.ps.ps_TupFromTlist = false;
}
{
/* empty input, so return nothing */
node->grp_done = TRUE;
- return NULL;
+ ExecReturnTuple(&node->ss.ps, NULL);
+ return;
}
/* Copy tuple into firsttupleslot */
ExecCopySlot(firsttupleslot, outerslot);
if (isDone != ExprEndResult)
{
node->ss.ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
- return result;
+ ExecReturnTuple(&node->ss.ps, result);
+ return;
}
}
else
{
/* no more groups, so we're done */
node->grp_done = TRUE;
- return NULL;
+ ExecReturnTuple(&node->ss.ps, NULL);
+ return;
}
/*
if (isDone != ExprEndResult)
{
node->ss.ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
- return result;
+ ExecReturnTuple(&node->ss.ps, result);
+ return;
}
}
else
* stub for pro forma compliance
* ----------------------------------------------------------------
*/
-TupleTableSlot *
+void
ExecHash(HashState *node)
{
elog(ERROR, "Hash node does not support ExecProcNode call convention");
- return NULL;
}
/* ----------------------------------------------------------------
* the other one is "outer".
* ----------------------------------------------------------------
*/
-TupleTableSlot * /* return: a tuple or NULL */
+void
ExecHashJoin(HashJoinState *node)
{
PlanState *outerNode;
result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
if (isDone == ExprMultipleResult)
- return result;
+ {
+ ExecReturnTuple(&node->js.ps, result);
+ return;
+ }
/* Done with that source tuple... */
node->js.ps.ps_TupFromTlist = false;
}
if (TupIsNull(node->hj_FirstOuterTupleSlot))
{
node->hj_OuterNotEmpty = false;
- return NULL;
+ ExecReturnTuple(&node->js.ps, NULL);
+ return;
}
else
node->hj_OuterNotEmpty = true;
* outer relation.
*/
if (hashtable->totalTuples == 0 && !HJ_FILL_OUTER(node))
- return NULL;
+ {
+ ExecReturnTuple(&node->js.ps, NULL);
+ return;
+ }
/*
* need to remember whether nbatch has increased since we
{
node->js.ps.ps_TupFromTlist =
(isDone == ExprMultipleResult);
- return result;
+ ExecReturnTuple(&node->js.ps, result);
+ return;
}
}
else
{
node->js.ps.ps_TupFromTlist =
(isDone == ExprMultipleResult);
- return result;
+ ExecReturnTuple(&node->js.ps, result);
+ return;
}
}
else
{
node->js.ps.ps_TupFromTlist =
(isDone == ExprMultipleResult);
- return result;
+ ExecReturnTuple(&node->js.ps, result);
+ return;
}
}
else
* Try to advance to next batch. Done if there are no more.
*/
if (!ExecHashJoinNewBatch(node))
- return NULL; /* end of join */
+ {
+ ExecReturnTuple(&node->js.ps, NULL); /* end of join */
+ return;
+ }
node->hj_JoinState = HJ_NEED_NEW_OUTER;
break;
* ExecIndexOnlyScan(node)
* ----------------------------------------------------------------
*/
-TupleTableSlot *
+void
ExecIndexOnlyScan(IndexOnlyScanState *node)
{
/*
* ExecIndexScan(node)
* ----------------------------------------------------------------
*/
-TupleTableSlot *
+void
ExecIndexScan(IndexScanState *node)
{
/*
* filtering on the stream of tuples returned by a subplan.
* ----------------------------------------------------------------
*/
-TupleTableSlot * /* return: a tuple or NULL */
+void
ExecLimit(LimitState *node)
{
ScanDirection direction;
* If backwards scan, just return NULL without changing state.
*/
if (!ScanDirectionIsForward(direction))
- return NULL;
+ {
+ ExecReturnTuple(&node->ps, NULL);
+ return;
+ }
/*
* Check for empty window; if so, treat like empty subplan.
if (node->count <= 0 && !node->noCount)
{
node->lstate = LIMIT_EMPTY;
- return NULL;
+ ExecReturnTuple(&node->ps, NULL);
+ return;
}
/*
* any output at all.
*/
node->lstate = LIMIT_EMPTY;
- return NULL;
+ ExecReturnTuple(&node->ps, NULL);
+ return;
}
node->subSlot = slot;
if (++node->position > node->offset)
* The subplan is known to return no tuples (or not more than
* OFFSET tuples, in general). So we return no tuples.
*/
- return NULL;
+ ExecReturnTuple(&node->ps, NULL);
+ return;
case LIMIT_INWINDOW:
if (ScanDirectionIsForward(direction))
node->position - node->offset >= node->count)
{
node->lstate = LIMIT_WINDOWEND;
- return NULL;
+ ExecReturnTuple(&node->ps, NULL);
+ return;
}
/*
if (TupIsNull(slot))
{
node->lstate = LIMIT_SUBPLANEOF;
- return NULL;
+ ExecReturnTuple(&node->ps, NULL);
+ return;
}
node->subSlot = slot;
node->position++;
if (node->position <= node->offset + 1)
{
node->lstate = LIMIT_WINDOWSTART;
- return NULL;
+ ExecReturnTuple(&node->ps, NULL);
+ return;
}
/*
case LIMIT_SUBPLANEOF:
if (ScanDirectionIsForward(direction))
- return NULL;
+ {
+ ExecReturnTuple(&node->ps, NULL);
+ return;
+ }
/*
* Backing up from subplan EOF, so re-fetch previous tuple; there
case LIMIT_WINDOWEND:
if (ScanDirectionIsForward(direction))
- return NULL;
+ {
+ ExecReturnTuple(&node->ps, NULL);
+ return;
+ }
/*
* Backing up from window end: simply re-return the last tuple
case LIMIT_WINDOWSTART:
if (!ScanDirectionIsForward(direction))
- return NULL;
+ {
+ ExecReturnTuple(&node->ps, NULL);
+ return;
+ }
/*
* Advancing after having backed off window start: simply
/* Return the current tuple */
Assert(!TupIsNull(slot));
- return slot;
+ ExecReturnTuple(&node->ps, slot);
}
/*
* ExecLockRows
* ----------------------------------------------------------------
*/
-TupleTableSlot * /* return: a tuple or NULL */
+void
ExecLockRows(LockRowsState *node)
{
TupleTableSlot *slot;
slot = ExecProcNode(outerPlan);
if (TupIsNull(slot))
- return NULL;
+ {
+ ExecReturnTuple(&node->ps, NULL);
+ return;
+ }
/* We don't need EvalPlanQual unless we get updated tuple version(s) */
epq_needed = false;
}
/* Got all locks, so return the current tuple */
- return slot;
+ ExecReturnTuple(&node->ps, slot);
}
/* ----------------------------------------------------------------
*
* ----------------------------------------------------------------
*/
-TupleTableSlot * /* result tuple from subplan */
+void
ExecMaterial(MaterialState *node)
{
EState *estate;
* fetch.
*/
if (!tuplestore_advance(tuplestorestate, forward))
- return NULL; /* the tuplestore must be empty */
+ {
+ /* the tuplestore must be empty */
+ ExecReturnTuple(&node->ss.ps, NULL);
+ return;
+ }
}
eof_tuplestore = false;
}
if (!eof_tuplestore)
{
if (tuplestore_gettupleslot(tuplestorestate, forward, false, slot))
- return slot;
+ {
+ ExecReturnTuple(&node->ss.ps, slot);
+ return;
+ }
if (forward)
eof_tuplestore = true;
}
if (TupIsNull(outerslot))
{
node->eof_underlying = true;
- return NULL;
+ ExecReturnTuple(&node->ss.ps, NULL);
+ return;
}
/*
/*
* We can just return the subplan's returned tuple, without copying.
*/
- return outerslot;
+ ExecReturnTuple(&node->ss.ps, outerslot);
+ return;
}
/*
* Nothing left ...
*/
- return ExecClearTuple(slot);
+ ExecReturnTuple(&node->ss.ps, ExecClearTuple(slot));
}
/* ----------------------------------------------------------------
* Handles iteration over multiple subplans.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
+void
ExecMergeAppend(MergeAppendState *node)
{
TupleTableSlot *result;
result = node->ms_slots[i];
}
- return result;
+ ExecReturnTuple(&node->ps, result);
}
/*
* ExecMergeJoin
* ----------------------------------------------------------------
*/
-TupleTableSlot *
+void
ExecMergeJoin(MergeJoinState *node)
{
List *joinqual;
result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
if (isDone == ExprMultipleResult)
- return result;
+ {
+ ExecReturnTuple(&node->js.ps, result);
+ return;
+ }
/* Done with that source tuple... */
node->js.ps.ps_TupFromTlist = false;
}
result = MJFillOuter(node);
if (result)
- return result;
+ {
+ ExecReturnTuple(&node->js.ps, result);
+ return;
+ }
}
break;
case MJEVAL_ENDOFJOIN:
break;
}
/* Otherwise we're done. */
- return NULL;
+ ExecReturnTuple(&node->js.ps, NULL);
+ return;
}
break;
result = MJFillInner(node);
if (result)
- return result;
+ {
+ ExecReturnTuple(&node->js.ps, result);
+ return;
+ }
}
break;
case MJEVAL_ENDOFJOIN:
break;
}
/* Otherwise we're done. */
- return NULL;
+ ExecReturnTuple(&node->js.ps, NULL);
+ return;
}
break;
{
node->js.ps.ps_TupFromTlist =
(isDone == ExprMultipleResult);
- return result;
+ ExecReturnTuple(&node->js.ps, result);
+ return;
}
}
else
result = MJFillInner(node);
if (result)
- return result;
+ {
+ ExecReturnTuple(&node->js.ps, result);
+ return;
+ }
}
/*
result = MJFillOuter(node);
if (result)
- return result;
+ {
+ ExecReturnTuple(&node->js.ps, result);
+ return;
+ }
}
/*
break;
}
/* Otherwise we're done. */
- return NULL;
+ ExecReturnTuple(&node->js.ps, NULL);
+ return;
}
break;
break;
}
/* Otherwise we're done. */
- return NULL;
+ ExecReturnTuple(&node->js.ps, NULL);
+ return;
}
}
break;
result = MJFillOuter(node);
if (result)
- return result;
+ {
+ ExecReturnTuple(&node->js.ps, result);
+ return;
+ }
}
/*
break;
}
/* Otherwise we're done. */
- return NULL;
+ ExecReturnTuple(&node->js.ps, NULL);
+ return;
}
break;
result = MJFillInner(node);
if (result)
- return result;
+ {
+ ExecReturnTuple(&node->js.ps, result);
+ return;
+ }
}
/* Mark before advancing, if wanted */
break;
}
/* Otherwise we're done. */
- return NULL;
+ ExecReturnTuple(&node->js.ps, NULL);
+ return;
}
break;
result = MJFillInner(node);
if (result)
- return result;
+ {
+ ExecReturnTuple(&node->js.ps, result);
+ return;
+ }
}
/* Mark before advancing, if wanted */
if (TupIsNull(innerTupleSlot))
{
MJ_printf("ExecMergeJoin: end of inner subplan\n");
- return NULL;
+ ExecReturnTuple(&node->js.ps, NULL);
+ return;
}
/* Else remain in ENDOUTER state and process next tuple. */
result = MJFillOuter(node);
if (result)
- return result;
+ {
+ ExecReturnTuple(&node->js.ps, result);
+ return;
+ }
}
/*
if (TupIsNull(outerTupleSlot))
{
MJ_printf("ExecMergeJoin: end of outer subplan\n");
- return NULL;
+ ExecReturnTuple(&node->js.ps, NULL);
+ return;
}
/* Else remain in ENDINNER state and process next tuple. */
* if needed.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
+void
ExecModifyTable(ModifyTableState *node)
{
EState *estate = node->ps.state;
* extra times.
*/
if (node->mt_done)
- return NULL;
+ {
+ ExecReturnTuple(&node->ps, NULL);
+ return;
+ }
/*
* On first call, fire BEFORE STATEMENT triggers before proceeding.
slot = ExecProcessReturning(resultRelInfo, NULL, planSlot);
estate->es_result_relation_info = saved_resultRelInfo;
- return slot;
+ ExecReturnTuple(&node->ps, slot);
+ return;
}
EvalPlanQualSetSlot(&node->mt_epqstate, planSlot);
if (slot)
{
estate->es_result_relation_info = saved_resultRelInfo;
- return slot;
+ ExecReturnTuple(&node->ps, slot);
+ return;
}
}
node->mt_done = true;
- return NULL;
+ ExecReturnTuple(&node->ps, NULL);
}
/* ----------------------------------------------------------------
* are prepared to return the first tuple.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
+void
ExecNestLoop(NestLoopState *node)
{
NestLoop *nl;
result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
if (isDone == ExprMultipleResult)
- return result;
+ {
+ ExecReturnTuple(&node->js.ps, result);
+ return;
+ }
/* Done with that source tuple... */
node->js.ps.ps_TupFromTlist = false;
}
if (TupIsNull(outerTupleSlot))
{
ENL1_printf("no outer tuple, ending join");
- return NULL;
+ ExecReturnTuple(&node->js.ps, NULL);
+ return;
}
ENL1_printf("saving new outer tuple information");
{
node->js.ps.ps_TupFromTlist =
(isDone == ExprMultipleResult);
- return result;
+ ExecReturnTuple(&node->js.ps, result);
+ return;
}
}
else
{
node->js.ps.ps_TupFromTlist =
(isDone == ExprMultipleResult);
- return result;
+ ExecReturnTuple(&node->js.ps, result);
+ return;
}
}
else
* 2.6 go back to 2.2
* ----------------------------------------------------------------
*/
-TupleTableSlot *
+void
ExecRecursiveUnion(RecursiveUnionState *node)
{
PlanState *outerPlan = outerPlanState(node);
/* Each non-duplicate tuple goes to the working table ... */
tuplestore_puttupleslot(node->working_table, slot);
/* ... and to the caller */
- return slot;
+ ExecReturnTuple(&node->ps, slot);
+ return;
}
node->recursing = true;
}
node->intermediate_empty = false;
tuplestore_puttupleslot(node->intermediate_table, slot);
/* ... and return it */
- return slot;
+ ExecReturnTuple(&node->ps, slot);
+ return;
}
- return NULL;
+ ExecReturnTuple(&node->ps, NULL);
}
/* ----------------------------------------------------------------
* 'nil' if the constant qualification is not satisfied.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
+void
ExecResult(ResultState *node)
{
TupleTableSlot *outerTupleSlot;
if (!qualResult)
{
node->rs_done = true;
- return NULL;
+ ExecReturnTuple(&node->ps, NULL);
+ return;
}
}
{
resultSlot = ExecProject(node->ps.ps_ProjInfo, &isDone);
if (isDone == ExprMultipleResult)
- return resultSlot;
+ {
+ ExecReturnTuple(&node->ps, resultSlot);
+ return;
+ }
/* Done with that source tuple... */
node->ps.ps_TupFromTlist = false;
}
outerTupleSlot = ExecProcNode(outerPlan);
if (TupIsNull(outerTupleSlot))
- return NULL;
+ {
+ ExecReturnTuple(&node->ps, NULL);
+ return;
+ }
/*
* prepare to compute projection expressions, which will expect to
if (isDone != ExprEndResult)
{
node->ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
- return resultSlot;
+ ExecReturnTuple(&node->ps, resultSlot);
+ return;
}
}
- return NULL;
+ ExecReturnTuple(&node->ps, NULL);
}
/* ----------------------------------------------------------------
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
+void
ExecSampleScan(SampleScanState *node)
{
return ExecScan((ScanState *) node,
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
+void
ExecSeqScan(SeqScanState *node)
{
return ExecScan((ScanState *) node,
* ExecSetOp
* ----------------------------------------------------------------
*/
-TupleTableSlot * /* return: a tuple or NULL */
+void
ExecSetOp(SetOpState *node)
{
SetOp *plannode = (SetOp *) node->ps.plan;
if (node->numOutput > 0)
{
node->numOutput--;
- return resultTupleSlot;
+ ExecReturnTuple(&node->ps, resultTupleSlot);
+ return;
}
/* Otherwise, we're done if we are out of groups */
if (node->setop_done)
- return NULL;
+ {
+ ExecReturnTuple(&node->ps, NULL);
+ return;
+ }
/* Fetch the next tuple group according to the correct strategy */
if (plannode->strategy == SETOP_HASHED)
{
if (!node->table_filled)
setop_fill_hash_table(node);
- return setop_retrieve_hash_table(node);
+ ExecReturnTuple(&node->ps, setop_retrieve_hash_table(node));
}
else
- return setop_retrieve_direct(node);
+ ExecReturnTuple(&node->ps, setop_retrieve_direct(node));
}
/*
* -- the outer child is prepared to return the first tuple.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
+void
ExecSort(SortState *node)
{
EState *estate;
(void) tuplesort_gettupleslot(tuplesortstate,
ScanDirectionIsForward(dir),
slot, NULL);
- return slot;
+ ExecReturnTuple(&node->ss.ps, slot);
}
/* ----------------------------------------------------------------
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
+void
ExecSubqueryScan(SubqueryScanState *node)
{
return ExecScan(&node->ss,
* -- tidPtr is -1.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
+void
ExecTidScan(TidScanState *node)
{
return ExecScan(&node->ss,
* ExecUnique
* ----------------------------------------------------------------
*/
-TupleTableSlot * /* return: a tuple or NULL */
+void
ExecUnique(UniqueState *node)
{
Unique *plannode = (Unique *) node->ps.plan;
if (TupIsNull(slot))
{
/* end of subplan, so we're done */
- ExecClearTuple(resultTupleSlot);
- return NULL;
+ ExecReturnTuple(&node->ps, ExecClearTuple(resultTupleSlot));
+ return;
}
/*
* won't guarantee that this source tuple is still accessible after
* fetching the next source tuple.
*/
- return ExecCopySlot(resultTupleSlot, slot);
+ ExecReturnTuple(&node->ps, ExecCopySlot(resultTupleSlot, slot));
}
/* ----------------------------------------------------------------
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
+void
ExecValuesScan(ValuesScanState *node)
{
return ExecScan(&node->ss,
* (ignoring the case of SRFs in the targetlist, that is).
* -----------------
*/
-TupleTableSlot *
+void
ExecWindowAgg(WindowAggState *winstate)
{
TupleTableSlot *result;
int numfuncs;
if (winstate->all_done)
- return NULL;
+ {
+ ExecReturnTuple(&winstate->ss.ps, NULL);
+ return;
+ }
/*
* Check to see if we're still projecting out tuples from a previous
result = ExecProject(winstate->ss.ps.ps_ProjInfo, &isDone);
if (isDone == ExprMultipleResult)
- return result;
+ {
+ ExecReturnTuple(&winstate->ss.ps, result);
+ return;
+ }
/* Done with that source tuple... */
winstate->ss.ps.ps_TupFromTlist = false;
}
else
{
winstate->all_done = true;
- return NULL;
+ ExecReturnTuple(&winstate->ss.ps, NULL);
+ return;
}
}
winstate->ss.ps.ps_TupFromTlist =
(isDone == ExprMultipleResult);
- return result;
+ ExecReturnTuple(&winstate->ss.ps, result);
}
/* -----------------
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
+void
ExecWorkTableScan(WorkTableScanState *node)
{
/*
extern void ExecEndNode(PlanState *node);
extern bool ExecShutdownNode(PlanState *node);
+/* Convenience function to set a node's result to a TupleTableSlot. */
+static inline void
+ExecReturnTuple(PlanState *node, TupleTableSlot *slot)
+{
+ Assert(!node->result_ready);
+ node->result = (Node *) slot;
+ node->result_ready = true;
+}
+
/*
* prototypes from functions in execQual.c
*/
typedef TupleTableSlot *(*ExecScanAccessMtd) (ScanState *node);
typedef bool (*ExecScanRecheckMtd) (ScanState *node, TupleTableSlot *slot);
-extern TupleTableSlot *ExecScan(ScanState *node, ExecScanAccessMtd accessMtd,
+extern void ExecScan(ScanState *node, ExecScanAccessMtd accessMtd,
ExecScanRecheckMtd recheckMtd);
extern void ExecAssignScanProjectionInfo(ScanState *node);
extern void ExecAssignScanProjectionInfoWithVarno(ScanState *node, Index varno);
#include "nodes/execnodes.h"
extern AggState *ExecInitAgg(Agg *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecAgg(AggState *node);
+extern void ExecAgg(AggState *node);
extern void ExecEndAgg(AggState *node);
extern void ExecReScanAgg(AggState *node);
#include "nodes/execnodes.h"
extern AppendState *ExecInitAppend(Append *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecAppend(AppendState *node);
+extern void ExecAppend(AppendState *node);
extern void ExecEndAppend(AppendState *node);
extern void ExecReScanAppend(AppendState *node);
#include "nodes/execnodes.h"
extern BitmapHeapScanState *ExecInitBitmapHeapScan(BitmapHeapScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecBitmapHeapScan(BitmapHeapScanState *node);
+extern void ExecBitmapHeapScan(BitmapHeapScanState *node);
extern void ExecEndBitmapHeapScan(BitmapHeapScanState *node);
extern void ExecReScanBitmapHeapScan(BitmapHeapScanState *node);
#include "nodes/execnodes.h"
extern CteScanState *ExecInitCteScan(CteScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecCteScan(CteScanState *node);
+extern void ExecCteScan(CteScanState *node);
extern void ExecEndCteScan(CteScanState *node);
extern void ExecReScanCteScan(CteScanState *node);
*/
extern CustomScanState *ExecInitCustomScan(CustomScan *custom_scan,
EState *estate, int eflags);
-extern TupleTableSlot *ExecCustomScan(CustomScanState *node);
+extern void ExecCustomScan(CustomScanState *node);
extern void ExecEndCustomScan(CustomScanState *node);
extern void ExecReScanCustomScan(CustomScanState *node);
#include "nodes/execnodes.h"
extern ForeignScanState *ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecForeignScan(ForeignScanState *node);
+extern void ExecForeignScan(ForeignScanState *node);
extern void ExecEndForeignScan(ForeignScanState *node);
extern void ExecReScanForeignScan(ForeignScanState *node);
#include "nodes/execnodes.h"
extern FunctionScanState *ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecFunctionScan(FunctionScanState *node);
+extern void ExecFunctionScan(FunctionScanState *node);
extern void ExecEndFunctionScan(FunctionScanState *node);
extern void ExecReScanFunctionScan(FunctionScanState *node);
#include "nodes/execnodes.h"
extern GatherState *ExecInitGather(Gather *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecGather(GatherState *node);
+extern void ExecGather(GatherState *node);
extern void ExecEndGather(GatherState *node);
extern void ExecShutdownGather(GatherState *node);
extern void ExecReScanGather(GatherState *node);
#include "nodes/execnodes.h"
extern GroupState *ExecInitGroup(Group *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecGroup(GroupState *node);
+extern void ExecGroup(GroupState *node);
extern void ExecEndGroup(GroupState *node);
extern void ExecReScanGroup(GroupState *node);
#include "nodes/execnodes.h"
extern HashState *ExecInitHash(Hash *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecHash(HashState *node);
+extern void ExecHash(HashState *node);
extern Node *MultiExecHash(HashState *node);
extern void ExecEndHash(HashState *node);
extern void ExecReScanHash(HashState *node);
#include "storage/buffile.h"
extern HashJoinState *ExecInitHashJoin(HashJoin *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecHashJoin(HashJoinState *node);
+extern void ExecHashJoin(HashJoinState *node);
extern void ExecEndHashJoin(HashJoinState *node);
extern void ExecReScanHashJoin(HashJoinState *node);
#include "nodes/execnodes.h"
extern IndexOnlyScanState *ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecIndexOnlyScan(IndexOnlyScanState *node);
+extern void ExecIndexOnlyScan(IndexOnlyScanState *node);
extern void ExecEndIndexOnlyScan(IndexOnlyScanState *node);
extern void ExecIndexOnlyMarkPos(IndexOnlyScanState *node);
extern void ExecIndexOnlyRestrPos(IndexOnlyScanState *node);
#include "nodes/execnodes.h"
extern IndexScanState *ExecInitIndexScan(IndexScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecIndexScan(IndexScanState *node);
+extern void ExecIndexScan(IndexScanState *node);
extern void ExecEndIndexScan(IndexScanState *node);
extern void ExecIndexMarkPos(IndexScanState *node);
extern void ExecIndexRestrPos(IndexScanState *node);
#include "nodes/execnodes.h"
extern LimitState *ExecInitLimit(Limit *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecLimit(LimitState *node);
+extern void ExecLimit(LimitState *node);
extern void ExecEndLimit(LimitState *node);
extern void ExecReScanLimit(LimitState *node);
#include "nodes/execnodes.h"
extern LockRowsState *ExecInitLockRows(LockRows *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecLockRows(LockRowsState *node);
+extern void ExecLockRows(LockRowsState *node);
extern void ExecEndLockRows(LockRowsState *node);
extern void ExecReScanLockRows(LockRowsState *node);
#include "nodes/execnodes.h"
extern MaterialState *ExecInitMaterial(Material *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecMaterial(MaterialState *node);
+extern void ExecMaterial(MaterialState *node);
extern void ExecEndMaterial(MaterialState *node);
extern void ExecMaterialMarkPos(MaterialState *node);
extern void ExecMaterialRestrPos(MaterialState *node);
#include "nodes/execnodes.h"
extern MergeAppendState *ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecMergeAppend(MergeAppendState *node);
+extern void ExecMergeAppend(MergeAppendState *node);
extern void ExecEndMergeAppend(MergeAppendState *node);
extern void ExecReScanMergeAppend(MergeAppendState *node);
#include "nodes/execnodes.h"
extern MergeJoinState *ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecMergeJoin(MergeJoinState *node);
+extern void ExecMergeJoin(MergeJoinState *node);
extern void ExecEndMergeJoin(MergeJoinState *node);
extern void ExecReScanMergeJoin(MergeJoinState *node);
#include "nodes/execnodes.h"
extern ModifyTableState *ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecModifyTable(ModifyTableState *node);
+extern void ExecModifyTable(ModifyTableState *node);
extern void ExecEndModifyTable(ModifyTableState *node);
extern void ExecReScanModifyTable(ModifyTableState *node);
#include "nodes/execnodes.h"
extern NestLoopState *ExecInitNestLoop(NestLoop *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecNestLoop(NestLoopState *node);
+extern void ExecNestLoop(NestLoopState *node);
extern void ExecEndNestLoop(NestLoopState *node);
extern void ExecReScanNestLoop(NestLoopState *node);
#include "nodes/execnodes.h"
extern RecursiveUnionState *ExecInitRecursiveUnion(RecursiveUnion *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecRecursiveUnion(RecursiveUnionState *node);
+extern void ExecRecursiveUnion(RecursiveUnionState *node);
extern void ExecEndRecursiveUnion(RecursiveUnionState *node);
extern void ExecReScanRecursiveUnion(RecursiveUnionState *node);
#include "nodes/execnodes.h"
extern ResultState *ExecInitResult(Result *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecResult(ResultState *node);
+extern void ExecResult(ResultState *node);
extern void ExecEndResult(ResultState *node);
extern void ExecResultMarkPos(ResultState *node);
extern void ExecResultRestrPos(ResultState *node);
#include "nodes/execnodes.h"
extern SampleScanState *ExecInitSampleScan(SampleScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecSampleScan(SampleScanState *node);
+extern void ExecSampleScan(SampleScanState *node);
extern void ExecEndSampleScan(SampleScanState *node);
extern void ExecReScanSampleScan(SampleScanState *node);
#include "nodes/execnodes.h"
extern SeqScanState *ExecInitSeqScan(SeqScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecSeqScan(SeqScanState *node);
+extern void ExecSeqScan(SeqScanState *node);
extern void ExecEndSeqScan(SeqScanState *node);
extern void ExecReScanSeqScan(SeqScanState *node);
#include "nodes/execnodes.h"
extern SetOpState *ExecInitSetOp(SetOp *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecSetOp(SetOpState *node);
+extern void ExecSetOp(SetOpState *node);
extern void ExecEndSetOp(SetOpState *node);
extern void ExecReScanSetOp(SetOpState *node);
#include "nodes/execnodes.h"
extern SortState *ExecInitSort(Sort *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecSort(SortState *node);
+extern void ExecSort(SortState *node);
extern void ExecEndSort(SortState *node);
extern void ExecSortMarkPos(SortState *node);
extern void ExecSortRestrPos(SortState *node);
#include "nodes/execnodes.h"
extern SubqueryScanState *ExecInitSubqueryScan(SubqueryScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecSubqueryScan(SubqueryScanState *node);
+extern void ExecSubqueryScan(SubqueryScanState *node);
extern void ExecEndSubqueryScan(SubqueryScanState *node);
extern void ExecReScanSubqueryScan(SubqueryScanState *node);
#include "nodes/execnodes.h"
extern TidScanState *ExecInitTidScan(TidScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecTidScan(TidScanState *node);
+extern void ExecTidScan(TidScanState *node);
extern void ExecEndTidScan(TidScanState *node);
extern void ExecReScanTidScan(TidScanState *node);
#include "nodes/execnodes.h"
extern UniqueState *ExecInitUnique(Unique *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecUnique(UniqueState *node);
+extern void ExecUnique(UniqueState *node);
extern void ExecEndUnique(UniqueState *node);
extern void ExecReScanUnique(UniqueState *node);
#include "nodes/execnodes.h"
extern ValuesScanState *ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecValuesScan(ValuesScanState *node);
+extern void ExecValuesScan(ValuesScanState *node);
extern void ExecEndValuesScan(ValuesScanState *node);
extern void ExecReScanValuesScan(ValuesScanState *node);
#include "nodes/execnodes.h"
extern WindowAggState *ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecWindowAgg(WindowAggState *node);
+extern void ExecWindowAgg(WindowAggState *node);
extern void ExecEndWindowAgg(WindowAggState *node);
extern void ExecReScanWindowAgg(WindowAggState *node);
#include "nodes/execnodes.h"
extern WorkTableScanState *ExecInitWorkTableScan(WorkTableScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecWorkTableScan(WorkTableScanState *node);
+extern void ExecWorkTableScan(WorkTableScanState *node);
extern void ExecEndWorkTableScan(WorkTableScanState *node);
extern void ExecReScanWorkTableScan(WorkTableScanState *node);
* top-level plan */
struct PlanState *parent; /* node which will receive tuples from us */
+ bool result_ready; /* true if result is ready */
+ Node *result; /* result, most often TupleTableSlot */
Instrumentation *instrument; /* Optional runtime stats for this node */
WorkerInstrumentation *worker_instrument; /* per-worker instrumentation */