From 1c8d3fa278824ba83043aa106d35419f6824ab3f Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Fri, 6 May 2016 13:01:48 -0400 Subject: [PATCH 2/3] Modify PlanState to have result/result_ready fields. Modify executor to use them instead of returning tuples directly. --- src/backend/executor/execProcnode.c | 75 ++++++++++++++++++------------- src/backend/executor/execScan.c | 26 +++++++---- src/backend/executor/nodeAgg.c | 13 +++--- src/backend/executor/nodeAppend.c | 11 +++-- src/backend/executor/nodeBitmapHeapscan.c | 2 +- src/backend/executor/nodeCtescan.c | 2 +- src/backend/executor/nodeCustom.c | 4 +- src/backend/executor/nodeForeignscan.c | 2 +- src/backend/executor/nodeFunctionscan.c | 2 +- src/backend/executor/nodeGather.c | 17 ++++--- src/backend/executor/nodeGroup.c | 24 +++++++--- src/backend/executor/nodeHash.c | 3 +- src/backend/executor/nodeHashjoin.c | 29 ++++++++---- src/backend/executor/nodeIndexonlyscan.c | 2 +- src/backend/executor/nodeIndexscan.c | 2 +- src/backend/executor/nodeLimit.c | 42 ++++++++++++----- src/backend/executor/nodeLockRows.c | 9 ++-- src/backend/executor/nodeMaterial.c | 21 ++++++--- src/backend/executor/nodeMergeAppend.c | 4 +- src/backend/executor/nodeMergejoin.c | 74 ++++++++++++++++++++++-------- src/backend/executor/nodeModifyTable.c | 15 ++++--- src/backend/executor/nodeNestloop.c | 16 ++++--- src/backend/executor/nodeRecursiveunion.c | 10 +++-- src/backend/executor/nodeResult.c | 20 ++++++--- src/backend/executor/nodeSamplescan.c | 2 +- src/backend/executor/nodeSeqscan.c | 2 +- src/backend/executor/nodeSetOp.c | 14 +++--- src/backend/executor/nodeSort.c | 4 +- src/backend/executor/nodeSubqueryscan.c | 2 +- src/backend/executor/nodeTidscan.c | 2 +- src/backend/executor/nodeUnique.c | 8 ++-- src/backend/executor/nodeValuesscan.c | 2 +- src/backend/executor/nodeWindowAgg.c | 17 ++++--- src/backend/executor/nodeWorktablescan.c | 2 +- src/include/executor/executor.h | 11 ++++- src/include/executor/nodeAgg.h | 2 +- src/include/executor/nodeAppend.h | 2 +- src/include/executor/nodeBitmapHeapscan.h | 2 +- src/include/executor/nodeCtescan.h | 2 +- src/include/executor/nodeCustom.h | 2 +- src/include/executor/nodeForeignscan.h | 2 +- src/include/executor/nodeFunctionscan.h | 2 +- src/include/executor/nodeGather.h | 2 +- src/include/executor/nodeGroup.h | 2 +- src/include/executor/nodeHash.h | 2 +- src/include/executor/nodeHashjoin.h | 2 +- src/include/executor/nodeIndexonlyscan.h | 2 +- src/include/executor/nodeIndexscan.h | 2 +- src/include/executor/nodeLimit.h | 2 +- src/include/executor/nodeLockRows.h | 2 +- src/include/executor/nodeMaterial.h | 2 +- src/include/executor/nodeMergeAppend.h | 2 +- src/include/executor/nodeMergejoin.h | 2 +- src/include/executor/nodeModifyTable.h | 2 +- src/include/executor/nodeNestloop.h | 2 +- src/include/executor/nodeRecursiveunion.h | 2 +- src/include/executor/nodeResult.h | 2 +- src/include/executor/nodeSamplescan.h | 2 +- src/include/executor/nodeSeqscan.h | 2 +- src/include/executor/nodeSetOp.h | 2 +- src/include/executor/nodeSort.h | 2 +- src/include/executor/nodeSubqueryscan.h | 2 +- src/include/executor/nodeTidscan.h | 2 +- src/include/executor/nodeUnique.h | 2 +- src/include/executor/nodeValuesscan.h | 2 +- src/include/executor/nodeWindowAgg.h | 2 +- src/include/executor/nodeWorktablescan.h | 2 +- src/include/nodes/execnodes.h | 2 + 68 files changed, 360 insertions(+), 197 deletions(-) diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c index 680ca4b..3f2ebff 100644 --- a/src/backend/executor/execProcnode.c +++ b/src/backend/executor/execProcnode.c @@ -380,6 +380,9 @@ ExecProcNode(PlanState *node) 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 */ @@ -392,23 +395,23 @@ ExecProcNode(PlanState *node) * 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 */ @@ -419,119 +422,119 @@ ExecProcNode(PlanState *node) * 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: @@ -540,6 +543,14 @@ ExecProcNode(PlanState *node) 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); diff --git a/src/backend/executor/execScan.c b/src/backend/executor/execScan.c index fb0013d..095d40b 100644 --- a/src/backend/executor/execScan.c +++ b/src/backend/executor/execScan.c @@ -99,7 +99,7 @@ ExecScanFetch(ScanState *node, * 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. @@ -117,7 +117,7 @@ ExecScanFetch(ScanState *node, * "cursor" is positioned before the first qualifying tuple. * ---------------------------------------------------------------- */ -TupleTableSlot * +void ExecScan(ScanState *node, ExecScanAccessMtd accessMtd, /* function returning a tuple */ ExecScanRecheckMtd recheckMtd) @@ -137,12 +137,14 @@ ExecScan(ScanState *node, /* * 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; } /* @@ -155,7 +157,10 @@ ExecScan(ScanState *node, 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; } @@ -188,9 +193,10 @@ ExecScan(ScanState *node, 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; } /* @@ -221,7 +227,8 @@ ExecScan(ScanState *node, if (isDone != ExprEndResult) { node->ps.ps_TupFromTlist = (isDone == ExprMultipleResult); - return resultSlot; + ExecReturnTuple(&node->ps, resultSlot); + return; } } else @@ -229,7 +236,8 @@ ExecScan(ScanState *node, /* * Here, we aren't projecting, so just return scan tuple. */ - return slot; + ExecReturnTuple(&node->ps, slot); + return; } } else diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c index e37551e..b23065d 100644 --- a/src/backend/executor/nodeAgg.c +++ b/src/backend/executor/nodeAgg.c @@ -1816,7 +1816,7 @@ lookup_hash_entry(AggState *aggstate, TupleTableSlot *inputslot) * stored in the expression context to be used when ExecProject evaluates * the result tuple. */ -TupleTableSlot * +void ExecAgg(AggState *node) { TupleTableSlot *result; @@ -1832,7 +1832,10 @@ ExecAgg(AggState *node) 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; } @@ -1842,6 +1845,7 @@ ExecAgg(AggState *node) * 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 */ @@ -1856,12 +1860,9 @@ ExecAgg(AggState *node) result = agg_retrieve_direct(node); break; } - - if (!TupIsNull(result)) - return result; } - return NULL; + ExecReturnTuple(&node->ss.ps, result); } /* diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c index beb4ab8..e0ce8c6 100644 --- a/src/backend/executor/nodeAppend.c +++ b/src/backend/executor/nodeAppend.c @@ -191,7 +191,7 @@ ExecInitAppend(Append *node, EState *estate, int eflags) * Handles iteration over multiple subplans. * ---------------------------------------------------------------- */ -TupleTableSlot * +void ExecAppend(AppendState *node) { for (;;) @@ -216,7 +216,8 @@ ExecAppend(AppendState *node) * 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; } /* @@ -229,7 +230,11 @@ ExecAppend(AppendState *node) 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 */ } diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c index 2ba5cd0..31133ff 100644 --- a/src/backend/executor/nodeBitmapHeapscan.c +++ b/src/backend/executor/nodeBitmapHeapscan.c @@ -434,7 +434,7 @@ BitmapHeapRecheck(BitmapHeapScanState *node, TupleTableSlot *slot) * ExecBitmapHeapScan(node) * ---------------------------------------------------------------- */ -TupleTableSlot * +void ExecBitmapHeapScan(BitmapHeapScanState *node) { return ExecScan(&node->ss, diff --git a/src/backend/executor/nodeCtescan.c b/src/backend/executor/nodeCtescan.c index 3c2f684..1f1fdf5 100644 --- a/src/backend/executor/nodeCtescan.c +++ b/src/backend/executor/nodeCtescan.c @@ -149,7 +149,7 @@ CteScanRecheck(CteScanState *node, TupleTableSlot *slot) * access method functions. * ---------------------------------------------------------------- */ -TupleTableSlot * +void ExecCteScan(CteScanState *node) { return ExecScan(&node->ss, diff --git a/src/backend/executor/nodeCustom.c b/src/backend/executor/nodeCustom.c index 322abca..7162348 100644 --- a/src/backend/executor/nodeCustom.c +++ b/src/backend/executor/nodeCustom.c @@ -107,11 +107,11 @@ ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags) 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 diff --git a/src/backend/executor/nodeForeignscan.c b/src/backend/executor/nodeForeignscan.c index 8418c5a..13f0c3a 100644 --- a/src/backend/executor/nodeForeignscan.c +++ b/src/backend/executor/nodeForeignscan.c @@ -113,7 +113,7 @@ ForeignRecheck(ForeignScanState *node, TupleTableSlot *slot) * access method functions. * ---------------------------------------------------------------- */ -TupleTableSlot * +void ExecForeignScan(ForeignScanState *node) { return ExecScan((ScanState *) node, diff --git a/src/backend/executor/nodeFunctionscan.c b/src/backend/executor/nodeFunctionscan.c index a03f6e7..3cccd8f 100644 --- a/src/backend/executor/nodeFunctionscan.c +++ b/src/backend/executor/nodeFunctionscan.c @@ -262,7 +262,7 @@ FunctionRecheck(FunctionScanState *node, TupleTableSlot *slot) * access method functions. * ---------------------------------------------------------------- */ -TupleTableSlot * +void ExecFunctionScan(FunctionScanState *node) { return ExecScan(&node->ss, diff --git a/src/backend/executor/nodeGather.c b/src/backend/executor/nodeGather.c index 2ac0c8d..a4d3a16 100644 --- a/src/backend/executor/nodeGather.c +++ b/src/backend/executor/nodeGather.c @@ -126,7 +126,7 @@ ExecInitGather(Gather *node, EState *estate, int eflags) * the next qualifying tuple. * ---------------------------------------------------------------- */ -TupleTableSlot * +void ExecGather(GatherState *node) { TupleTableSlot *fslot = node->funnel_slot; @@ -207,7 +207,10 @@ ExecGather(GatherState *node) { 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; } @@ -229,7 +232,10 @@ ExecGather(GatherState *node) */ slot = gather_getnext(node); if (TupIsNull(slot)) - return NULL; + { + ExecReturnTuple(&node->ps, NULL); + return; + } /* * form the result tuple using ExecProject(), and return it --- unless @@ -242,11 +248,12 @@ ExecGather(GatherState *node) if (isDone != ExprEndResult) { node->ps.ps_TupFromTlist = (isDone == ExprMultipleResult); - return resultSlot; + ExecReturnTuple(&node->ps, resultSlot); + return; } } - return slot; + ExecReturnTuple(&node->ps, slot); } /* ---------------------------------------------------------------- diff --git a/src/backend/executor/nodeGroup.c b/src/backend/executor/nodeGroup.c index 3c066fc..f33a316 100644 --- a/src/backend/executor/nodeGroup.c +++ b/src/backend/executor/nodeGroup.c @@ -31,7 +31,7 @@ * * Return one tuple for each group of matching input tuples. */ -TupleTableSlot * +void ExecGroup(GroupState *node) { ExprContext *econtext; @@ -44,7 +44,10 @@ ExecGroup(GroupState *node) * 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; @@ -61,7 +64,10 @@ ExecGroup(GroupState *node) 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; } @@ -87,7 +93,8 @@ ExecGroup(GroupState *node) { /* empty input, so return nothing */ node->grp_done = TRUE; - return NULL; + ExecReturnTuple(&node->ss.ps, NULL); + return; } /* Copy tuple into firsttupleslot */ ExecCopySlot(firsttupleslot, outerslot); @@ -115,7 +122,8 @@ ExecGroup(GroupState *node) if (isDone != ExprEndResult) { node->ss.ps.ps_TupFromTlist = (isDone == ExprMultipleResult); - return result; + ExecReturnTuple(&node->ss.ps, result); + return; } } else @@ -139,7 +147,8 @@ ExecGroup(GroupState *node) { /* no more groups, so we're done */ node->grp_done = TRUE; - return NULL; + ExecReturnTuple(&node->ss.ps, NULL); + return; } /* @@ -178,7 +187,8 @@ ExecGroup(GroupState *node) if (isDone != ExprEndResult) { node->ss.ps.ps_TupFromTlist = (isDone == ExprMultipleResult); - return result; + ExecReturnTuple(&node->ss.ps, result); + return; } } else diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c index 5e78de0..905eb30 100644 --- a/src/backend/executor/nodeHash.c +++ b/src/backend/executor/nodeHash.c @@ -56,11 +56,10 @@ static void *dense_alloc(HashJoinTable hashtable, Size size); * stub for pro forma compliance * ---------------------------------------------------------------- */ -TupleTableSlot * +void ExecHash(HashState *node) { elog(ERROR, "Hash node does not support ExecProcNode call convention"); - return NULL; } /* ---------------------------------------------------------------- diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c index a7a908a..cc92fc3 100644 --- a/src/backend/executor/nodeHashjoin.c +++ b/src/backend/executor/nodeHashjoin.c @@ -58,7 +58,7 @@ static bool ExecHashJoinNewBatch(HashJoinState *hjstate); * the other one is "outer". * ---------------------------------------------------------------- */ -TupleTableSlot * /* return: a tuple or NULL */ +void ExecHashJoin(HashJoinState *node) { PlanState *outerNode; @@ -93,7 +93,10 @@ ExecHashJoin(HashJoinState *node) 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; } @@ -155,7 +158,8 @@ ExecHashJoin(HashJoinState *node) if (TupIsNull(node->hj_FirstOuterTupleSlot)) { node->hj_OuterNotEmpty = false; - return NULL; + ExecReturnTuple(&node->js.ps, NULL); + return; } else node->hj_OuterNotEmpty = true; @@ -183,7 +187,10 @@ ExecHashJoin(HashJoinState *node) * 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 @@ -323,7 +330,8 @@ ExecHashJoin(HashJoinState *node) { node->js.ps.ps_TupFromTlist = (isDone == ExprMultipleResult); - return result; + ExecReturnTuple(&node->js.ps, result); + return; } } else @@ -362,7 +370,8 @@ ExecHashJoin(HashJoinState *node) { node->js.ps.ps_TupFromTlist = (isDone == ExprMultipleResult); - return result; + ExecReturnTuple(&node->js.ps, result); + return; } } else @@ -401,7 +410,8 @@ ExecHashJoin(HashJoinState *node) { node->js.ps.ps_TupFromTlist = (isDone == ExprMultipleResult); - return result; + ExecReturnTuple(&node->js.ps, result); + return; } } else @@ -414,7 +424,10 @@ ExecHashJoin(HashJoinState *node) * 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; diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c index 4f6f91c..47285a1 100644 --- a/src/backend/executor/nodeIndexonlyscan.c +++ b/src/backend/executor/nodeIndexonlyscan.c @@ -249,7 +249,7 @@ IndexOnlyRecheck(IndexOnlyScanState *node, TupleTableSlot *slot) * ExecIndexOnlyScan(node) * ---------------------------------------------------------------- */ -TupleTableSlot * +void ExecIndexOnlyScan(IndexOnlyScanState *node) { /* diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c index bf16cb1..b08e1b2 100644 --- a/src/backend/executor/nodeIndexscan.c +++ b/src/backend/executor/nodeIndexscan.c @@ -482,7 +482,7 @@ reorderqueue_pop(IndexScanState *node) * ExecIndexScan(node) * ---------------------------------------------------------------- */ -TupleTableSlot * +void ExecIndexScan(IndexScanState *node) { /* diff --git a/src/backend/executor/nodeLimit.c b/src/backend/executor/nodeLimit.c index 97267c5..4e70183 100644 --- a/src/backend/executor/nodeLimit.c +++ b/src/backend/executor/nodeLimit.c @@ -36,7 +36,7 @@ static void pass_down_bound(LimitState *node, PlanState *child_node); * filtering on the stream of tuples returned by a subplan. * ---------------------------------------------------------------- */ -TupleTableSlot * /* return: a tuple or NULL */ +void ExecLimit(LimitState *node) { ScanDirection direction; @@ -72,7 +72,10 @@ ExecLimit(LimitState *node) * 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. @@ -80,7 +83,8 @@ ExecLimit(LimitState *node) if (node->count <= 0 && !node->noCount) { node->lstate = LIMIT_EMPTY; - return NULL; + ExecReturnTuple(&node->ps, NULL); + return; } /* @@ -96,7 +100,8 @@ ExecLimit(LimitState *node) * any output at all. */ node->lstate = LIMIT_EMPTY; - return NULL; + ExecReturnTuple(&node->ps, NULL); + return; } node->subSlot = slot; if (++node->position > node->offset) @@ -115,7 +120,8 @@ ExecLimit(LimitState *node) * 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)) @@ -130,7 +136,8 @@ ExecLimit(LimitState *node) node->position - node->offset >= node->count) { node->lstate = LIMIT_WINDOWEND; - return NULL; + ExecReturnTuple(&node->ps, NULL); + return; } /* @@ -140,7 +147,8 @@ ExecLimit(LimitState *node) if (TupIsNull(slot)) { node->lstate = LIMIT_SUBPLANEOF; - return NULL; + ExecReturnTuple(&node->ps, NULL); + return; } node->subSlot = slot; node->position++; @@ -154,7 +162,8 @@ ExecLimit(LimitState *node) if (node->position <= node->offset + 1) { node->lstate = LIMIT_WINDOWSTART; - return NULL; + ExecReturnTuple(&node->ps, NULL); + return; } /* @@ -170,7 +179,10 @@ ExecLimit(LimitState *node) case LIMIT_SUBPLANEOF: if (ScanDirectionIsForward(direction)) - return NULL; + { + ExecReturnTuple(&node->ps, NULL); + return; + } /* * Backing up from subplan EOF, so re-fetch previous tuple; there @@ -186,7 +198,10 @@ ExecLimit(LimitState *node) case LIMIT_WINDOWEND: if (ScanDirectionIsForward(direction)) - return NULL; + { + ExecReturnTuple(&node->ps, NULL); + return; + } /* * Backing up from window end: simply re-return the last tuple @@ -199,7 +214,10 @@ ExecLimit(LimitState *node) case LIMIT_WINDOWSTART: if (!ScanDirectionIsForward(direction)) - return NULL; + { + ExecReturnTuple(&node->ps, NULL); + return; + } /* * Advancing after having backed off window start: simply @@ -220,7 +238,7 @@ ExecLimit(LimitState *node) /* Return the current tuple */ Assert(!TupIsNull(slot)); - return slot; + ExecReturnTuple(&node->ps, slot); } /* diff --git a/src/backend/executor/nodeLockRows.c b/src/backend/executor/nodeLockRows.c index c4b5333..8daa203 100644 --- a/src/backend/executor/nodeLockRows.c +++ b/src/backend/executor/nodeLockRows.c @@ -35,7 +35,7 @@ * ExecLockRows * ---------------------------------------------------------------- */ -TupleTableSlot * /* return: a tuple or NULL */ +void ExecLockRows(LockRowsState *node) { TupleTableSlot *slot; @@ -57,7 +57,10 @@ lnext: 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; @@ -334,7 +337,7 @@ lnext: } /* Got all locks, so return the current tuple */ - return slot; + ExecReturnTuple(&node->ps, slot); } /* ---------------------------------------------------------------- diff --git a/src/backend/executor/nodeMaterial.c b/src/backend/executor/nodeMaterial.c index 82e31c1..fd3b013 100644 --- a/src/backend/executor/nodeMaterial.c +++ b/src/backend/executor/nodeMaterial.c @@ -35,7 +35,7 @@ * * ---------------------------------------------------------------- */ -TupleTableSlot * /* result tuple from subplan */ +void ExecMaterial(MaterialState *node) { EState *estate; @@ -93,7 +93,11 @@ ExecMaterial(MaterialState *node) * 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; } @@ -105,7 +109,10 @@ ExecMaterial(MaterialState *node) if (!eof_tuplestore) { if (tuplestore_gettupleslot(tuplestorestate, forward, false, slot)) - return slot; + { + ExecReturnTuple(&node->ss.ps, slot); + return; + } if (forward) eof_tuplestore = true; } @@ -132,7 +139,8 @@ ExecMaterial(MaterialState *node) if (TupIsNull(outerslot)) { node->eof_underlying = true; - return NULL; + ExecReturnTuple(&node->ss.ps, NULL); + return; } /* @@ -146,13 +154,14 @@ ExecMaterial(MaterialState *node) /* * 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)); } /* ---------------------------------------------------------------- diff --git a/src/backend/executor/nodeMergeAppend.c b/src/backend/executor/nodeMergeAppend.c index ae0e8dc..3ef8120 100644 --- a/src/backend/executor/nodeMergeAppend.c +++ b/src/backend/executor/nodeMergeAppend.c @@ -164,7 +164,7 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags) * Handles iteration over multiple subplans. * ---------------------------------------------------------------- */ -TupleTableSlot * +void ExecMergeAppend(MergeAppendState *node) { TupleTableSlot *result; @@ -214,7 +214,7 @@ ExecMergeAppend(MergeAppendState *node) result = node->ms_slots[i]; } - return result; + ExecReturnTuple(&node->ps, result); } /* diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c index cd8d6c6..d73d9f4 100644 --- a/src/backend/executor/nodeMergejoin.c +++ b/src/backend/executor/nodeMergejoin.c @@ -615,7 +615,7 @@ ExecMergeTupleDump(MergeJoinState *mergestate) * ExecMergeJoin * ---------------------------------------------------------------- */ -TupleTableSlot * +void ExecMergeJoin(MergeJoinState *node) { List *joinqual; @@ -653,7 +653,10 @@ ExecMergeJoin(MergeJoinState *node) 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; } @@ -710,7 +713,10 @@ ExecMergeJoin(MergeJoinState *node) result = MJFillOuter(node); if (result) - return result; + { + ExecReturnTuple(&node->js.ps, result); + return; + } } break; case MJEVAL_ENDOFJOIN: @@ -728,7 +734,8 @@ ExecMergeJoin(MergeJoinState *node) break; } /* Otherwise we're done. */ - return NULL; + ExecReturnTuple(&node->js.ps, NULL); + return; } break; @@ -765,7 +772,10 @@ ExecMergeJoin(MergeJoinState *node) result = MJFillInner(node); if (result) - return result; + { + ExecReturnTuple(&node->js.ps, result); + return; + } } break; case MJEVAL_ENDOFJOIN: @@ -785,7 +795,8 @@ ExecMergeJoin(MergeJoinState *node) break; } /* Otherwise we're done. */ - return NULL; + ExecReturnTuple(&node->js.ps, NULL); + return; } break; @@ -868,7 +879,8 @@ ExecMergeJoin(MergeJoinState *node) { node->js.ps.ps_TupFromTlist = (isDone == ExprMultipleResult); - return result; + ExecReturnTuple(&node->js.ps, result); + return; } } else @@ -901,7 +913,10 @@ ExecMergeJoin(MergeJoinState *node) result = MJFillInner(node); if (result) - return result; + { + ExecReturnTuple(&node->js.ps, result); + return; + } } /* @@ -1003,7 +1018,10 @@ ExecMergeJoin(MergeJoinState *node) result = MJFillOuter(node); if (result) - return result; + { + ExecReturnTuple(&node->js.ps, result); + return; + } } /* @@ -1039,7 +1057,8 @@ ExecMergeJoin(MergeJoinState *node) break; } /* Otherwise we're done. */ - return NULL; + ExecReturnTuple(&node->js.ps, NULL); + return; } break; @@ -1174,7 +1193,8 @@ ExecMergeJoin(MergeJoinState *node) break; } /* Otherwise we're done. */ - return NULL; + ExecReturnTuple(&node->js.ps, NULL); + return; } } break; @@ -1256,7 +1276,10 @@ ExecMergeJoin(MergeJoinState *node) result = MJFillOuter(node); if (result) - return result; + { + ExecReturnTuple(&node->js.ps, result); + return; + } } /* @@ -1292,7 +1315,8 @@ ExecMergeJoin(MergeJoinState *node) break; } /* Otherwise we're done. */ - return NULL; + ExecReturnTuple(&node->js.ps, NULL); + return; } break; @@ -1318,7 +1342,10 @@ ExecMergeJoin(MergeJoinState *node) result = MJFillInner(node); if (result) - return result; + { + ExecReturnTuple(&node->js.ps, result); + return; + } } /* Mark before advancing, if wanted */ @@ -1362,7 +1389,8 @@ ExecMergeJoin(MergeJoinState *node) break; } /* Otherwise we're done. */ - return NULL; + ExecReturnTuple(&node->js.ps, NULL); + return; } break; @@ -1388,7 +1416,10 @@ ExecMergeJoin(MergeJoinState *node) result = MJFillInner(node); if (result) - return result; + { + ExecReturnTuple(&node->js.ps, result); + return; + } } /* Mark before advancing, if wanted */ @@ -1406,7 +1437,8 @@ ExecMergeJoin(MergeJoinState *node) 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. */ @@ -1434,7 +1466,10 @@ ExecMergeJoin(MergeJoinState *node) result = MJFillOuter(node); if (result) - return result; + { + ExecReturnTuple(&node->js.ps, result); + return; + } } /* @@ -1448,7 +1483,8 @@ ExecMergeJoin(MergeJoinState *node) 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. */ diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index 7bb318a..90107bd 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -1298,7 +1298,7 @@ fireASTriggers(ModifyTableState *node) * if needed. * ---------------------------------------------------------------- */ -TupleTableSlot * +void ExecModifyTable(ModifyTableState *node) { EState *estate = node->ps.state; @@ -1333,7 +1333,10 @@ ExecModifyTable(ModifyTableState *node) * extra times. */ if (node->mt_done) - return NULL; + { + ExecReturnTuple(&node->ps, NULL); + return; + } /* * On first call, fire BEFORE STATEMENT triggers before proceeding. @@ -1411,7 +1414,8 @@ ExecModifyTable(ModifyTableState *node) slot = ExecProcessReturning(resultRelInfo, NULL, planSlot); estate->es_result_relation_info = saved_resultRelInfo; - return slot; + ExecReturnTuple(&node->ps, slot); + return; } EvalPlanQualSetSlot(&node->mt_epqstate, planSlot); @@ -1517,7 +1521,8 @@ ExecModifyTable(ModifyTableState *node) if (slot) { estate->es_result_relation_info = saved_resultRelInfo; - return slot; + ExecReturnTuple(&node->ps, slot); + return; } } @@ -1531,7 +1536,7 @@ ExecModifyTable(ModifyTableState *node) node->mt_done = true; - return NULL; + ExecReturnTuple(&node->ps, NULL); } /* ---------------------------------------------------------------- diff --git a/src/backend/executor/nodeNestloop.c b/src/backend/executor/nodeNestloop.c index 1895b60..54eff56 100644 --- a/src/backend/executor/nodeNestloop.c +++ b/src/backend/executor/nodeNestloop.c @@ -56,7 +56,7 @@ * are prepared to return the first tuple. * ---------------------------------------------------------------- */ -TupleTableSlot * +void ExecNestLoop(NestLoopState *node) { NestLoop *nl; @@ -93,7 +93,10 @@ ExecNestLoop(NestLoopState *node) 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; } @@ -128,7 +131,8 @@ ExecNestLoop(NestLoopState *node) 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"); @@ -212,7 +216,8 @@ ExecNestLoop(NestLoopState *node) { node->js.ps.ps_TupFromTlist = (isDone == ExprMultipleResult); - return result; + ExecReturnTuple(&node->js.ps, result); + return; } } else @@ -270,7 +275,8 @@ ExecNestLoop(NestLoopState *node) { node->js.ps.ps_TupFromTlist = (isDone == ExprMultipleResult); - return result; + ExecReturnTuple(&node->js.ps, result); + return; } } else diff --git a/src/backend/executor/nodeRecursiveunion.c b/src/backend/executor/nodeRecursiveunion.c index 2328ef3..6e78eb2 100644 --- a/src/backend/executor/nodeRecursiveunion.c +++ b/src/backend/executor/nodeRecursiveunion.c @@ -72,7 +72,7 @@ build_hash_table(RecursiveUnionState *rustate) * 2.6 go back to 2.2 * ---------------------------------------------------------------- */ -TupleTableSlot * +void ExecRecursiveUnion(RecursiveUnionState *node) { PlanState *outerPlan = outerPlanState(node); @@ -102,7 +102,8 @@ ExecRecursiveUnion(RecursiveUnionState *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; } @@ -151,10 +152,11 @@ ExecRecursiveUnion(RecursiveUnionState *node) 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); } /* ---------------------------------------------------------------- diff --git a/src/backend/executor/nodeResult.c b/src/backend/executor/nodeResult.c index 0d2de14..a830ffd 100644 --- a/src/backend/executor/nodeResult.c +++ b/src/backend/executor/nodeResult.c @@ -63,7 +63,7 @@ * 'nil' if the constant qualification is not satisfied. * ---------------------------------------------------------------- */ -TupleTableSlot * +void ExecResult(ResultState *node) { TupleTableSlot *outerTupleSlot; @@ -87,7 +87,8 @@ ExecResult(ResultState *node) if (!qualResult) { node->rs_done = true; - return NULL; + ExecReturnTuple(&node->ps, NULL); + return; } } @@ -100,7 +101,10 @@ ExecResult(ResultState *node) { 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; } @@ -130,7 +134,10 @@ ExecResult(ResultState *node) outerTupleSlot = ExecProcNode(outerPlan); if (TupIsNull(outerTupleSlot)) - return NULL; + { + ExecReturnTuple(&node->ps, NULL); + return; + } /* * prepare to compute projection expressions, which will expect to @@ -157,11 +164,12 @@ ExecResult(ResultState *node) if (isDone != ExprEndResult) { node->ps.ps_TupFromTlist = (isDone == ExprMultipleResult); - return resultSlot; + ExecReturnTuple(&node->ps, resultSlot); + return; } } - return NULL; + ExecReturnTuple(&node->ps, NULL); } /* ---------------------------------------------------------------- diff --git a/src/backend/executor/nodeSamplescan.c b/src/backend/executor/nodeSamplescan.c index 9ce7c02..89cce0e 100644 --- a/src/backend/executor/nodeSamplescan.c +++ b/src/backend/executor/nodeSamplescan.c @@ -95,7 +95,7 @@ SampleRecheck(SampleScanState *node, TupleTableSlot *slot) * access method functions. * ---------------------------------------------------------------- */ -TupleTableSlot * +void ExecSampleScan(SampleScanState *node) { return ExecScan((ScanState *) node, diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c index f12921d..1c12e27 100644 --- a/src/backend/executor/nodeSeqscan.c +++ b/src/backend/executor/nodeSeqscan.c @@ -121,7 +121,7 @@ SeqRecheck(SeqScanState *node, TupleTableSlot *slot) * access method functions. * ---------------------------------------------------------------- */ -TupleTableSlot * +void ExecSeqScan(SeqScanState *node) { return ExecScan((ScanState *) node, diff --git a/src/backend/executor/nodeSetOp.c b/src/backend/executor/nodeSetOp.c index 7a3b67c..b7a593f 100644 --- a/src/backend/executor/nodeSetOp.c +++ b/src/backend/executor/nodeSetOp.c @@ -191,7 +191,7 @@ set_output_count(SetOpState *setopstate, SetOpStatePerGroup pergroup) * ExecSetOp * ---------------------------------------------------------------- */ -TupleTableSlot * /* return: a tuple or NULL */ +void ExecSetOp(SetOpState *node) { SetOp *plannode = (SetOp *) node->ps.plan; @@ -204,22 +204,26 @@ ExecSetOp(SetOpState *node) 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)); } /* diff --git a/src/backend/executor/nodeSort.c b/src/backend/executor/nodeSort.c index 0286a7f..13f721a 100644 --- a/src/backend/executor/nodeSort.c +++ b/src/backend/executor/nodeSort.c @@ -35,7 +35,7 @@ * -- the outer child is prepared to return the first tuple. * ---------------------------------------------------------------- */ -TupleTableSlot * +void ExecSort(SortState *node) { EState *estate; @@ -138,7 +138,7 @@ ExecSort(SortState *node) (void) tuplesort_gettupleslot(tuplesortstate, ScanDirectionIsForward(dir), slot, NULL); - return slot; + ExecReturnTuple(&node->ss.ps, slot); } /* ---------------------------------------------------------------- diff --git a/src/backend/executor/nodeSubqueryscan.c b/src/backend/executor/nodeSubqueryscan.c index 75a28fd..5fae5c5 100644 --- a/src/backend/executor/nodeSubqueryscan.c +++ b/src/backend/executor/nodeSubqueryscan.c @@ -87,7 +87,7 @@ SubqueryRecheck(SubqueryScanState *node, TupleTableSlot *slot) * access method functions. * ---------------------------------------------------------------- */ -TupleTableSlot * +void ExecSubqueryScan(SubqueryScanState *node) { return ExecScan(&node->ss, diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c index 2604103..e2a0479 100644 --- a/src/backend/executor/nodeTidscan.c +++ b/src/backend/executor/nodeTidscan.c @@ -387,7 +387,7 @@ TidRecheck(TidScanState *node, TupleTableSlot *slot) * -- tidPtr is -1. * ---------------------------------------------------------------- */ -TupleTableSlot * +void ExecTidScan(TidScanState *node) { return ExecScan(&node->ss, diff --git a/src/backend/executor/nodeUnique.c b/src/backend/executor/nodeUnique.c index 5d13a89..2daa001 100644 --- a/src/backend/executor/nodeUnique.c +++ b/src/backend/executor/nodeUnique.c @@ -42,7 +42,7 @@ * ExecUnique * ---------------------------------------------------------------- */ -TupleTableSlot * /* return: a tuple or NULL */ +void ExecUnique(UniqueState *node) { Unique *plannode = (Unique *) node->ps.plan; @@ -70,8 +70,8 @@ ExecUnique(UniqueState *node) if (TupIsNull(slot)) { /* end of subplan, so we're done */ - ExecClearTuple(resultTupleSlot); - return NULL; + ExecReturnTuple(&node->ps, ExecClearTuple(resultTupleSlot)); + return; } /* @@ -98,7 +98,7 @@ ExecUnique(UniqueState *node) * 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)); } /* ---------------------------------------------------------------- diff --git a/src/backend/executor/nodeValuesscan.c b/src/backend/executor/nodeValuesscan.c index 2c4bd9c..6a7dadf 100644 --- a/src/backend/executor/nodeValuesscan.c +++ b/src/backend/executor/nodeValuesscan.c @@ -172,7 +172,7 @@ ValuesRecheck(ValuesScanState *node, TupleTableSlot *slot) * access method functions. * ---------------------------------------------------------------- */ -TupleTableSlot * +void ExecValuesScan(ValuesScanState *node) { return ExecScan(&node->ss, diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c index 3dc6757..67f9574 100644 --- a/src/backend/executor/nodeWindowAgg.c +++ b/src/backend/executor/nodeWindowAgg.c @@ -1555,7 +1555,7 @@ update_frametailpos(WindowObject winobj, TupleTableSlot *slot) * (ignoring the case of SRFs in the targetlist, that is). * ----------------- */ -TupleTableSlot * +void ExecWindowAgg(WindowAggState *winstate) { TupleTableSlot *result; @@ -1565,7 +1565,10 @@ ExecWindowAgg(WindowAggState *winstate) 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 @@ -1579,7 +1582,10 @@ ExecWindowAgg(WindowAggState *winstate) 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; } @@ -1687,7 +1693,8 @@ restart: else { winstate->all_done = true; - return NULL; + ExecReturnTuple(&winstate->ss.ps, NULL); + return; } } @@ -1753,7 +1760,7 @@ restart: winstate->ss.ps.ps_TupFromTlist = (isDone == ExprMultipleResult); - return result; + ExecReturnTuple(&winstate->ss.ps, result); } /* ----------------- diff --git a/src/backend/executor/nodeWorktablescan.c b/src/backend/executor/nodeWorktablescan.c index cfed6e6..c3615b2 100644 --- a/src/backend/executor/nodeWorktablescan.c +++ b/src/backend/executor/nodeWorktablescan.c @@ -77,7 +77,7 @@ WorkTableScanRecheck(WorkTableScanState *node, TupleTableSlot *slot) * access method functions. * ---------------------------------------------------------------- */ -TupleTableSlot * +void ExecWorkTableScan(WorkTableScanState *node) { /* diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index f1be8fa..087735a 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -228,6 +228,15 @@ extern Node *MultiExecProcNode(PlanState *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 */ @@ -256,7 +265,7 @@ extern TupleTableSlot *ExecProject(ProjectionInfo *projInfo, 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); diff --git a/src/include/executor/nodeAgg.h b/src/include/executor/nodeAgg.h index 54c75e8..b86ec6a 100644 --- a/src/include/executor/nodeAgg.h +++ b/src/include/executor/nodeAgg.h @@ -17,7 +17,7 @@ #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); diff --git a/src/include/executor/nodeAppend.h b/src/include/executor/nodeAppend.h index 51c381e..70a6b62 100644 --- a/src/include/executor/nodeAppend.h +++ b/src/include/executor/nodeAppend.h @@ -17,7 +17,7 @@ #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); diff --git a/src/include/executor/nodeBitmapHeapscan.h b/src/include/executor/nodeBitmapHeapscan.h index 0ed9c78..069dbc7 100644 --- a/src/include/executor/nodeBitmapHeapscan.h +++ b/src/include/executor/nodeBitmapHeapscan.h @@ -17,7 +17,7 @@ #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); diff --git a/src/include/executor/nodeCtescan.h b/src/include/executor/nodeCtescan.h index ef5c2bc..8411fa1 100644 --- a/src/include/executor/nodeCtescan.h +++ b/src/include/executor/nodeCtescan.h @@ -17,7 +17,7 @@ #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); diff --git a/src/include/executor/nodeCustom.h b/src/include/executor/nodeCustom.h index 9d0b393..f6de3ab 100644 --- a/src/include/executor/nodeCustom.h +++ b/src/include/executor/nodeCustom.h @@ -21,7 +21,7 @@ */ 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); diff --git a/src/include/executor/nodeForeignscan.h b/src/include/executor/nodeForeignscan.h index c255329..c34a3d6 100644 --- a/src/include/executor/nodeForeignscan.h +++ b/src/include/executor/nodeForeignscan.h @@ -18,7 +18,7 @@ #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); diff --git a/src/include/executor/nodeFunctionscan.h b/src/include/executor/nodeFunctionscan.h index d6e7a61..15beb13 100644 --- a/src/include/executor/nodeFunctionscan.h +++ b/src/include/executor/nodeFunctionscan.h @@ -17,7 +17,7 @@ #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); diff --git a/src/include/executor/nodeGather.h b/src/include/executor/nodeGather.h index f76d9be..100a827 100644 --- a/src/include/executor/nodeGather.h +++ b/src/include/executor/nodeGather.h @@ -17,7 +17,7 @@ #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); diff --git a/src/include/executor/nodeGroup.h b/src/include/executor/nodeGroup.h index 92639f5..446ded5 100644 --- a/src/include/executor/nodeGroup.h +++ b/src/include/executor/nodeGroup.h @@ -17,7 +17,7 @@ #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); diff --git a/src/include/executor/nodeHash.h b/src/include/executor/nodeHash.h index 8cf6d15..b395fd9 100644 --- a/src/include/executor/nodeHash.h +++ b/src/include/executor/nodeHash.h @@ -17,7 +17,7 @@ #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); diff --git a/src/include/executor/nodeHashjoin.h b/src/include/executor/nodeHashjoin.h index f24127a..072c610 100644 --- a/src/include/executor/nodeHashjoin.h +++ b/src/include/executor/nodeHashjoin.h @@ -18,7 +18,7 @@ #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); diff --git a/src/include/executor/nodeIndexonlyscan.h b/src/include/executor/nodeIndexonlyscan.h index d63d194..0fbcf80 100644 --- a/src/include/executor/nodeIndexonlyscan.h +++ b/src/include/executor/nodeIndexonlyscan.h @@ -17,7 +17,7 @@ #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); diff --git a/src/include/executor/nodeIndexscan.h b/src/include/executor/nodeIndexscan.h index 194fadb..341dab3 100644 --- a/src/include/executor/nodeIndexscan.h +++ b/src/include/executor/nodeIndexscan.h @@ -17,7 +17,7 @@ #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); diff --git a/src/include/executor/nodeLimit.h b/src/include/executor/nodeLimit.h index 96166b4..03dde30 100644 --- a/src/include/executor/nodeLimit.h +++ b/src/include/executor/nodeLimit.h @@ -17,7 +17,7 @@ #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); diff --git a/src/include/executor/nodeLockRows.h b/src/include/executor/nodeLockRows.h index e828e9c..eda3cbec 100644 --- a/src/include/executor/nodeLockRows.h +++ b/src/include/executor/nodeLockRows.h @@ -17,7 +17,7 @@ #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); diff --git a/src/include/executor/nodeMaterial.h b/src/include/executor/nodeMaterial.h index 2b8cae1..20bc7f6 100644 --- a/src/include/executor/nodeMaterial.h +++ b/src/include/executor/nodeMaterial.h @@ -17,7 +17,7 @@ #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); diff --git a/src/include/executor/nodeMergeAppend.h b/src/include/executor/nodeMergeAppend.h index 0efc489..e43b5e6 100644 --- a/src/include/executor/nodeMergeAppend.h +++ b/src/include/executor/nodeMergeAppend.h @@ -17,7 +17,7 @@ #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); diff --git a/src/include/executor/nodeMergejoin.h b/src/include/executor/nodeMergejoin.h index 74d691c..dfdbc1b 100644 --- a/src/include/executor/nodeMergejoin.h +++ b/src/include/executor/nodeMergejoin.h @@ -17,7 +17,7 @@ #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); diff --git a/src/include/executor/nodeModifyTable.h b/src/include/executor/nodeModifyTable.h index 6b66353..fe67248 100644 --- a/src/include/executor/nodeModifyTable.h +++ b/src/include/executor/nodeModifyTable.h @@ -16,7 +16,7 @@ #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); diff --git a/src/include/executor/nodeNestloop.h b/src/include/executor/nodeNestloop.h index eeb42d6..cab1885 100644 --- a/src/include/executor/nodeNestloop.h +++ b/src/include/executor/nodeNestloop.h @@ -17,7 +17,7 @@ #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); diff --git a/src/include/executor/nodeRecursiveunion.h b/src/include/executor/nodeRecursiveunion.h index 1c08790..fb11eca 100644 --- a/src/include/executor/nodeRecursiveunion.h +++ b/src/include/executor/nodeRecursiveunion.h @@ -17,7 +17,7 @@ #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); diff --git a/src/include/executor/nodeResult.h b/src/include/executor/nodeResult.h index 356027f..951fae6 100644 --- a/src/include/executor/nodeResult.h +++ b/src/include/executor/nodeResult.h @@ -17,7 +17,7 @@ #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); diff --git a/src/include/executor/nodeSamplescan.h b/src/include/executor/nodeSamplescan.h index c8f03d8..4ab6e5a 100644 --- a/src/include/executor/nodeSamplescan.h +++ b/src/include/executor/nodeSamplescan.h @@ -17,7 +17,7 @@ #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); diff --git a/src/include/executor/nodeSeqscan.h b/src/include/executor/nodeSeqscan.h index f2e61ff..816d1a5 100644 --- a/src/include/executor/nodeSeqscan.h +++ b/src/include/executor/nodeSeqscan.h @@ -18,7 +18,7 @@ #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); diff --git a/src/include/executor/nodeSetOp.h b/src/include/executor/nodeSetOp.h index c6e9603..dd88afb 100644 --- a/src/include/executor/nodeSetOp.h +++ b/src/include/executor/nodeSetOp.h @@ -17,7 +17,7 @@ #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); diff --git a/src/include/executor/nodeSort.h b/src/include/executor/nodeSort.h index 481065f..f65037d 100644 --- a/src/include/executor/nodeSort.h +++ b/src/include/executor/nodeSort.h @@ -17,7 +17,7 @@ #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); diff --git a/src/include/executor/nodeSubqueryscan.h b/src/include/executor/nodeSubqueryscan.h index 427699b..a3962c7 100644 --- a/src/include/executor/nodeSubqueryscan.h +++ b/src/include/executor/nodeSubqueryscan.h @@ -17,7 +17,7 @@ #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); diff --git a/src/include/executor/nodeTidscan.h b/src/include/executor/nodeTidscan.h index 76c2a9f..5b7bbfd 100644 --- a/src/include/executor/nodeTidscan.h +++ b/src/include/executor/nodeTidscan.h @@ -17,7 +17,7 @@ #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); diff --git a/src/include/executor/nodeUnique.h b/src/include/executor/nodeUnique.h index aa8491d..b53a553 100644 --- a/src/include/executor/nodeUnique.h +++ b/src/include/executor/nodeUnique.h @@ -17,7 +17,7 @@ #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); diff --git a/src/include/executor/nodeValuesscan.h b/src/include/executor/nodeValuesscan.h index 026f261..90288fc 100644 --- a/src/include/executor/nodeValuesscan.h +++ b/src/include/executor/nodeValuesscan.h @@ -17,7 +17,7 @@ #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); diff --git a/src/include/executor/nodeWindowAgg.h b/src/include/executor/nodeWindowAgg.h index 94ed037..f5e2c98 100644 --- a/src/include/executor/nodeWindowAgg.h +++ b/src/include/executor/nodeWindowAgg.h @@ -17,7 +17,7 @@ #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); diff --git a/src/include/executor/nodeWorktablescan.h b/src/include/executor/nodeWorktablescan.h index 217208a..7b1eecb 100644 --- a/src/include/executor/nodeWorktablescan.h +++ b/src/include/executor/nodeWorktablescan.h @@ -17,7 +17,7 @@ #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); diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index 7d33b6d..a0bc8af 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -1031,6 +1031,8 @@ typedef struct PlanState * 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 */ -- 2.5.4 (Apple Git-61)