From 1ef6bd2954c4ec63ff8a2c9c4ebc38251d7ef5c5 Mon Sep 17 00:00:00 2001 From: Andres Freund Date: Fri, 9 Nov 2018 17:19:39 -0800 Subject: [PATCH] Don't require return slots for nodes without projection. In a lot of nodes the return slot is not required. That can either be because the node doesn't do any projection (say an Append node), or because the node does perform projections but the projection is optimized away because the projection would yield an identical row. Slots aren't that small, especially for wide rows, so it's worthwhile to avoid creating them. It's not possible to just skip creating the slot - it's currently used to determine the tuple descriptor returned by ExecGetResultType(). So separate the determination of the result type from the slot creation. The work previously done internally ExecInitResultTupleSlotTL() can now also be done separately with ExecInitResultTypeTL() and ExecInitResultSlot(). That way nodes that aren't guaranteed to need a result slot, can use ExecInitResultTypeTL() to determine the result type of the node, and ExecAssignScanProjectionInfo() (via ExecConditionalAssignProjectionInfo()) determines that a result slot is needed, it is created with ExecInitResultSlot(). Besides the advantage of avoiding to create slots that then are unused, this is necessary preparation for later patches around tuple table slot abstraction. In particular separating the return descriptor and slot is a prerequisite to allow JITing of tuple deforming with knowledge of the underlying tuple format, and to avoid unnecessarily creating JITed tuple deforming for virtual slots. This commit removes a redundant argument from ExecInitResultTupleSlotTL(). While this commit touches a lot of the relevant lines anyway, it'd normally still not worthwhile to cause breakage, except that aforementioned later commits will touch *all* ExecInitResultTupleSlotTL() callers anyway (but fits worse thematically). Author: Andres Freund Discussion: https://postgr.es/m/20181105210039.hh4vvi4vwoq5ba2q@alap3.anarazel.de --- src/backend/executor/execTuples.c | 73 ++++++++++++++----- src/backend/executor/execUtils.c | 8 +- src/backend/executor/nodeAgg.c | 2 +- src/backend/executor/nodeAppend.c | 2 +- src/backend/executor/nodeBitmapHeapscan.c | 7 +- src/backend/executor/nodeCtescan.c | 10 ++- src/backend/executor/nodeCustom.c | 2 +- src/backend/executor/nodeForeignscan.c | 5 +- src/backend/executor/nodeFunctionscan.c | 8 +- src/backend/executor/nodeGather.c | 7 +- src/backend/executor/nodeGatherMerge.c | 7 +- src/backend/executor/nodeGroup.c | 2 +- src/backend/executor/nodeHash.c | 2 +- src/backend/executor/nodeHashjoin.c | 2 +- src/backend/executor/nodeIndexonlyscan.c | 10 +-- src/backend/executor/nodeIndexscan.c | 7 +- src/backend/executor/nodeLimit.c | 5 +- src/backend/executor/nodeLockRows.c | 5 +- src/backend/executor/nodeMaterial.c | 2 +- src/backend/executor/nodeMergeAppend.c | 4 +- src/backend/executor/nodeMergejoin.c | 2 +- src/backend/executor/nodeModifyTable.c | 7 +- .../executor/nodeNamedtuplestorescan.c | 21 +++--- src/backend/executor/nodeNestloop.c | 2 +- src/backend/executor/nodeProjectSet.c | 2 +- src/backend/executor/nodeRecursiveunion.c | 7 +- src/backend/executor/nodeResult.c | 2 +- src/backend/executor/nodeSamplescan.c | 8 +- src/backend/executor/nodeSeqscan.c | 7 +- src/backend/executor/nodeSetOp.c | 2 +- src/backend/executor/nodeSort.c | 2 +- src/backend/executor/nodeSubqueryscan.c | 9 ++- src/backend/executor/nodeTableFuncscan.c | 10 ++- src/backend/executor/nodeTidscan.c | 7 +- src/backend/executor/nodeUnique.c | 2 +- src/backend/executor/nodeValuesscan.c | 10 ++- src/backend/executor/nodeWindowAgg.c | 2 +- src/backend/executor/nodeWorktablescan.c | 8 +- src/include/executor/executor.h | 4 +- src/include/nodes/execnodes.h | 1 + 40 files changed, 168 insertions(+), 117 deletions(-) diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c index 015752a93f..eba52dc928 100644 --- a/src/backend/executor/execTuples.c +++ b/src/backend/executor/execTuples.c @@ -19,18 +19,22 @@ * * At ExecutorStart() * ---------------- - * - ExecInitSeqScan() calls ExecInitScanTupleSlot() and - * ExecInitResultTupleSlotTL() to construct TupleTableSlots - * for the tuples returned by the access methods and the - * tuples resulting from performing target list projections. + + * - ExecInitSeqScan() calls ExecInitScanTupleSlot() to construct a + * TupleTableSlots for the tuples returned by the access method, and + * ExecInitResultTypeTL() to define the node's return + * type. ExecAssignScanProjectionInfo() will, if necessary, create + * another TupleTableSlot for the tuples resulting from performing + * target list projections. * * During ExecutorRun() * ---------------- * - SeqNext() calls ExecStoreBufferHeapTuple() to place the tuple - * returned by the access methods into the scan tuple slot. + * returned by the access method into the scan tuple slot. * - * - ExecSeqScan() calls ExecStoreHeapTuple() to take the result - * tuple from ExecProject() and place it into the result tuple slot. + * - ExecSeqScan() (via ExecScan), if necessary, calls ExecProject(), + * putting the result of the projection in the result tuple slot. If + * not necessary, it directly returns the slot returned by SeqNext(). * * - ExecutePlan() calls the output function. * @@ -902,23 +906,14 @@ ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot) * ---------------------------------------------------------------- */ -/* -------------------------------- - * ExecInit{Result,Scan,Extra}TupleSlot[TL] - * - * These are convenience routines to initialize the specified slot - * in nodes inheriting the appropriate state. ExecInitExtraTupleSlot - * is used for initializing special-purpose slots. - * -------------------------------- - */ - /* ---------------- - * ExecInitResultTupleSlotTL + * ExecInitResultTypeTL * - * Initialize result tuple slot, using the plan node's targetlist. + * Initialize result type, using the plan node's targetlist. * ---------------- */ void -ExecInitResultTupleSlotTL(EState *estate, PlanState *planstate) +ExecInitResultTypeTL(PlanState *planstate) { bool hasoid; TupleDesc tupDesc; @@ -934,8 +929,46 @@ ExecInitResultTupleSlotTL(EState *estate, PlanState *planstate) } tupDesc = ExecTypeFromTL(planstate->plan->targetlist, hasoid); + planstate->ps_ResultTupleDesc = tupDesc; +} - planstate->ps_ResultTupleSlot = ExecAllocTableSlot(&estate->es_tupleTable, tupDesc); +/* -------------------------------- + * ExecInit{Result,Scan,Extra}TupleSlot[TL] + * + * These are convenience routines to initialize the specified slot + * in nodes inheriting the appropriate state. ExecInitExtraTupleSlot + * is used for initializing special-purpose slots. + * -------------------------------- + */ + +/* ---------------- + * ExecInitResultTupleSlotTL + * + * Initialize result tuple slot, using the tuple descriptor previously + * computed with ExecInitResultTypeTL(). + * ---------------- + */ +void +ExecInitResultSlot(PlanState *planstate) +{ + TupleTableSlot *slot; + + slot = ExecAllocTableSlot(&planstate->state->es_tupleTable, + planstate->ps_ResultTupleDesc); + planstate->ps_ResultTupleSlot = slot; +} + +/* ---------------- + * ExecInitResultTupleSlotTL + * + * Initialize result tuple slot, using the plan node's targetlist. + * ---------------- + */ +void +ExecInitResultTupleSlotTL(PlanState *planstate) +{ + ExecInitResultTypeTL(planstate); + ExecInitResultSlot(planstate); } /* ---------------- diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c index 71c6b5dc0a..f9e7bb479f 100644 --- a/src/backend/executor/execUtils.c +++ b/src/backend/executor/execUtils.c @@ -451,9 +451,7 @@ ExecAssignExprContext(EState *estate, PlanState *planstate) TupleDesc ExecGetResultType(PlanState *planstate) { - TupleTableSlot *slot = planstate->ps_ResultTupleSlot; - - return slot->tts_tupleDescriptor; + return planstate->ps_ResultTupleDesc; } @@ -496,7 +494,11 @@ ExecConditionalAssignProjectionInfo(PlanState *planstate, TupleDesc inputDesc, inputDesc)) planstate->ps_ProjInfo = NULL; else + { + if (!planstate->ps_ResultTupleSlot) + ExecInitResultSlot(planstate); ExecAssignProjectionInfo(planstate, inputDesc); + } } static bool diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c index 2413f1f87d..85f1ec7140 100644 --- a/src/backend/executor/nodeAgg.c +++ b/src/backend/executor/nodeAgg.c @@ -2219,7 +2219,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags) /* * Initialize result type, slot and projection. */ - ExecInitResultTupleSlotTL(estate, &aggstate->ss.ps); + ExecInitResultTupleSlotTL(&aggstate->ss.ps); ExecAssignProjectionInfo(&aggstate->ss.ps, NULL); /* diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c index a16b6da474..94a17c7c67 100644 --- a/src/backend/executor/nodeAppend.c +++ b/src/backend/executor/nodeAppend.c @@ -196,7 +196,7 @@ ExecInitAppend(Append *node, EState *estate, int eflags) /* * Initialize result tuple type and slot. */ - ExecInitResultTupleSlotTL(estate, &appendstate->ps); + ExecInitResultTupleSlotTL(&appendstate->ps); appendplanstates = (PlanState **) palloc(nplans * sizeof(PlanState *)); diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c index 304ef07f2c..c153d74f41 100644 --- a/src/backend/executor/nodeBitmapHeapscan.c +++ b/src/backend/executor/nodeBitmapHeapscan.c @@ -800,7 +800,8 @@ ExecEndBitmapHeapScan(BitmapHeapScanState *node) /* * clear out tuple table slots */ - ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); + if (node->ss.ps.ps_ResultTupleSlot) + ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); ExecClearTuple(node->ss.ss_ScanTupleSlot); /* @@ -916,9 +917,9 @@ ExecInitBitmapHeapScan(BitmapHeapScan *node, EState *estate, int eflags) /* - * Initialize result slot, type and projection. + * Initialize result type and projection. */ - ExecInitResultTupleSlotTL(estate, &scanstate->ss.ps); + ExecInitResultTypeTL(&scanstate->ss.ps); ExecAssignScanProjectionInfo(&scanstate->ss); /* diff --git a/src/backend/executor/nodeCtescan.c b/src/backend/executor/nodeCtescan.c index 24700dd396..017b877277 100644 --- a/src/backend/executor/nodeCtescan.c +++ b/src/backend/executor/nodeCtescan.c @@ -263,9 +263,9 @@ ExecInitCteScan(CteScan *node, EState *estate, int eflags) ExecGetResultType(scanstate->cteplanstate)); /* - * Initialize result slot, type and projection. + * Initialize result type and projection. */ - ExecInitResultTupleSlotTL(estate, &scanstate->ss.ps); + ExecInitResultTypeTL(&scanstate->ss.ps); ExecAssignScanProjectionInfo(&scanstate->ss); /* @@ -294,7 +294,8 @@ ExecEndCteScan(CteScanState *node) /* * clean out the tuple table */ - ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); + if (node->ss.ps.ps_ResultTupleSlot) + ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); ExecClearTuple(node->ss.ss_ScanTupleSlot); /* @@ -318,7 +319,8 @@ ExecReScanCteScan(CteScanState *node) { Tuplestorestate *tuplestorestate = node->leader->cte_table; - ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); + if (node->ss.ps.ps_ResultTupleSlot) + ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); ExecScanReScan(&node->ss); diff --git a/src/backend/executor/nodeCustom.c b/src/backend/executor/nodeCustom.c index 7972d5a952..ab3e34790e 100644 --- a/src/backend/executor/nodeCustom.c +++ b/src/backend/executor/nodeCustom.c @@ -87,7 +87,7 @@ ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags) /* * Initialize result slot, type and projection. */ - ExecInitResultTupleSlotTL(estate, &css->ss.ps); + ExecInitResultTupleSlotTL(&css->ss.ps); ExecAssignScanProjectionInfoWithVarno(&css->ss, tlistvarno); /* initialize child expressions */ diff --git a/src/backend/executor/nodeForeignscan.c b/src/backend/executor/nodeForeignscan.c index 2ec7fcb962..5d2cd0ed71 100644 --- a/src/backend/executor/nodeForeignscan.c +++ b/src/backend/executor/nodeForeignscan.c @@ -198,7 +198,7 @@ ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags) /* * Initialize result slot, type and projection. */ - ExecInitResultTupleSlotTL(estate, &scanstate->ss.ps); + ExecInitResultTypeTL(&scanstate->ss.ps); ExecAssignScanProjectionInfoWithVarno(&scanstate->ss, tlistvarno); /* @@ -256,7 +256,8 @@ ExecEndForeignScan(ForeignScanState *node) ExecFreeExprContext(&node->ss.ps); /* clean out the tuple table */ - ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); + if (node->ss.ps.ps_ResultTupleSlot) + ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); ExecClearTuple(node->ss.ss_ScanTupleSlot); } diff --git a/src/backend/executor/nodeFunctionscan.c b/src/backend/executor/nodeFunctionscan.c index fb7c9f6787..0596adbb2f 100644 --- a/src/backend/executor/nodeFunctionscan.c +++ b/src/backend/executor/nodeFunctionscan.c @@ -487,7 +487,7 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags) /* * Initialize result slot, type and projection. */ - ExecInitResultTupleSlotTL(estate, &scanstate->ss.ps); + ExecInitResultTypeTL(&scanstate->ss.ps); ExecAssignScanProjectionInfo(&scanstate->ss); /* @@ -529,7 +529,8 @@ ExecEndFunctionScan(FunctionScanState *node) /* * clean out the tuple table */ - ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); + if (node->ss.ps.ps_ResultTupleSlot) + ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); ExecClearTuple(node->ss.ss_ScanTupleSlot); /* @@ -563,7 +564,8 @@ ExecReScanFunctionScan(FunctionScanState *node) int i; Bitmapset *chgparam = node->ss.ps.chgParam; - ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); + if (node->ss.ps.ps_ResultTupleSlot) + ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); for (i = 0; i < node->nfuncs; i++) { FunctionScanPerFuncState *fs = &node->funcstates[i]; diff --git a/src/backend/executor/nodeGather.c b/src/backend/executor/nodeGather.c index ad16c783bd..afddb0a039 100644 --- a/src/backend/executor/nodeGather.c +++ b/src/backend/executor/nodeGather.c @@ -92,9 +92,9 @@ ExecInitGather(Gather *node, EState *estate, int eflags) tupDesc = ExecGetResultType(outerPlanState(gatherstate)); /* - * Initialize result slot, type and projection. + * Initialize result type and projection. */ - ExecInitResultTupleSlotTL(estate, &gatherstate->ps); + ExecInitResultTypeTL(&gatherstate->ps); ExecConditionalAssignProjectionInfo(&gatherstate->ps, tupDesc, OUTER_VAR); /* @@ -231,7 +231,8 @@ ExecEndGather(GatherState *node) ExecEndNode(outerPlanState(node)); /* let children clean up first */ ExecShutdownGather(node); ExecFreeExprContext(&node->ps); - ExecClearTuple(node->ps.ps_ResultTupleSlot); + if (node->ps.ps_ResultTupleSlot) + ExecClearTuple(node->ps.ps_ResultTupleSlot); } /* diff --git a/src/backend/executor/nodeGatherMerge.c b/src/backend/executor/nodeGatherMerge.c index 6362e4497a..7ae067f9eb 100644 --- a/src/backend/executor/nodeGatherMerge.c +++ b/src/backend/executor/nodeGatherMerge.c @@ -117,9 +117,9 @@ ExecInitGatherMerge(GatherMerge *node, EState *estate, int eflags) gm_state->tupDesc = tupDesc; /* - * Initialize result slot, type and projection. + * Initialize result type and projection. */ - ExecInitResultTupleSlotTL(estate, &gm_state->ps); + ExecInitResultTypeTL(&gm_state->ps); ExecConditionalAssignProjectionInfo(&gm_state->ps, tupDesc, OUTER_VAR); /* @@ -272,7 +272,8 @@ ExecEndGatherMerge(GatherMergeState *node) ExecEndNode(outerPlanState(node)); /* let children clean up first */ ExecShutdownGatherMerge(node); ExecFreeExprContext(&node->ps); - ExecClearTuple(node->ps.ps_ResultTupleSlot); + if (node->ps.ps_ResultTupleSlot) + ExecClearTuple(node->ps.ps_ResultTupleSlot); } /* ---------------------------------------------------------------- diff --git a/src/backend/executor/nodeGroup.c b/src/backend/executor/nodeGroup.c index 2ea80e817d..9c1e51bc95 100644 --- a/src/backend/executor/nodeGroup.c +++ b/src/backend/executor/nodeGroup.c @@ -193,7 +193,7 @@ ExecInitGroup(Group *node, EState *estate, int eflags) /* * Initialize result slot, type and projection. */ - ExecInitResultTupleSlotTL(estate, &grpstate->ss.ps); + ExecInitResultTupleSlotTL(&grpstate->ss.ps); ExecAssignProjectionInfo(&grpstate->ss.ps, NULL); /* diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c index 6ffaa751f2..a9f812d66b 100644 --- a/src/backend/executor/nodeHash.c +++ b/src/backend/executor/nodeHash.c @@ -382,7 +382,7 @@ ExecInitHash(Hash *node, EState *estate, int eflags) * initialize our result slot and type. No need to build projection * because this node doesn't do projections. */ - ExecInitResultTupleSlotTL(estate, &hashstate->ps); + ExecInitResultTupleSlotTL(&hashstate->ps); hashstate->ps.ps_ProjInfo = NULL; /* diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c index d017bbfbd3..08a8bb3426 100644 --- a/src/backend/executor/nodeHashjoin.c +++ b/src/backend/executor/nodeHashjoin.c @@ -644,7 +644,7 @@ ExecInitHashJoin(HashJoin *node, EState *estate, int eflags) /* * Initialize result slot, type and projection. */ - ExecInitResultTupleSlotTL(estate, &hjstate->js.ps); + ExecInitResultTupleSlotTL(&hjstate->js.ps); ExecAssignProjectionInfo(&hjstate->js.ps, NULL); /* diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c index daedf342f7..865a056c02 100644 --- a/src/backend/executor/nodeIndexonlyscan.c +++ b/src/backend/executor/nodeIndexonlyscan.c @@ -399,7 +399,8 @@ ExecEndIndexOnlyScan(IndexOnlyScanState *node) /* * clear out tuple table slots */ - ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); + if (node->ss.ps.ps_ResultTupleSlot) + ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); ExecClearTuple(node->ss.ss_ScanTupleSlot); /* @@ -529,11 +530,10 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags) ExecInitScanTupleSlot(estate, &indexstate->ss, tupDesc); /* - * Initialize result slot, type and projection info. The node's - * targetlist will contain Vars with varno = INDEX_VAR, referencing the - * scan tuple. + * Initialize result type and projection info. The node's targetlist will + * contain Vars with varno = INDEX_VAR, referencing the scan tuple. */ - ExecInitResultTupleSlotTL(estate, &indexstate->ss.ps); + ExecInitResultTypeTL(&indexstate->ss.ps); ExecAssignScanProjectionInfoWithVarno(&indexstate->ss, INDEX_VAR); /* diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c index ba7821b0e2..8593c0e305 100644 --- a/src/backend/executor/nodeIndexscan.c +++ b/src/backend/executor/nodeIndexscan.c @@ -822,7 +822,8 @@ ExecEndIndexScan(IndexScanState *node) /* * clear out tuple table slots */ - ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); + if (node->ss.ps.ps_ResultTupleSlot) + ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); ExecClearTuple(node->ss.ss_ScanTupleSlot); /* @@ -947,9 +948,9 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags) RelationGetDescr(currentRelation)); /* - * Initialize result slot, type and projection. + * Initialize result type and projection. */ - ExecInitResultTupleSlotTL(estate, &indexstate->ss.ps); + ExecInitResultTypeTL(&indexstate->ss.ps); ExecAssignScanProjectionInfo(&indexstate->ss); /* diff --git a/src/backend/executor/nodeLimit.c b/src/backend/executor/nodeLimit.c index bb28cf7d1d..f0b6819140 100644 --- a/src/backend/executor/nodeLimit.c +++ b/src/backend/executor/nodeLimit.c @@ -376,10 +376,9 @@ ExecInitLimit(Limit *node, EState *estate, int eflags) (PlanState *) limitstate); /* - * Initialize result slot and type. (XXX not actually used, but upper - * nodes access it to get this node's result tupledesc...) + * Initialize result type. */ - ExecInitResultTupleSlotTL(estate, &limitstate->ps); + ExecInitResultTypeTL(&limitstate->ps); /* * limit nodes do no projections, so initialize projection info for this diff --git a/src/backend/executor/nodeLockRows.c b/src/backend/executor/nodeLockRows.c index 6db345ae7a..961798cecb 100644 --- a/src/backend/executor/nodeLockRows.c +++ b/src/backend/executor/nodeLockRows.c @@ -381,10 +381,9 @@ ExecInitLockRows(LockRows *node, EState *estate, int eflags) */ /* - * Tuple table initialization (XXX not actually used, but upper nodes - * access it to get this node's result tupledesc...) + * Initialize result type. */ - ExecInitResultTupleSlotTL(estate, &lrstate->ps); + ExecInitResultTypeTL(&lrstate->ps); /* * then initialize outer plan diff --git a/src/backend/executor/nodeMaterial.c b/src/backend/executor/nodeMaterial.c index 8c2e57dbd0..4ede428f90 100644 --- a/src/backend/executor/nodeMaterial.c +++ b/src/backend/executor/nodeMaterial.c @@ -223,7 +223,7 @@ ExecInitMaterial(Material *node, EState *estate, int eflags) * * material nodes only return tuples from their materialized relation. */ - ExecInitResultTupleSlotTL(estate, &matstate->ss.ps); + ExecInitResultTupleSlotTL(&matstate->ss.ps); matstate->ss.ps.ps_ProjInfo = NULL; /* diff --git a/src/backend/executor/nodeMergeAppend.c b/src/backend/executor/nodeMergeAppend.c index fde369d622..dbed667d16 100644 --- a/src/backend/executor/nodeMergeAppend.c +++ b/src/backend/executor/nodeMergeAppend.c @@ -165,9 +165,9 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags) * Miscellaneous initialization * * MergeAppend nodes do have Result slots, which hold pointers to tuples, - * so we have to initialize them. + * so we have to initialize them. FIXME */ - ExecInitResultTupleSlotTL(estate, &mergestate->ps); + ExecInitResultTupleSlotTL(&mergestate->ps); /* * call ExecInitNode on each of the valid plans to be executed and save diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c index 5e52b90c00..9c97831331 100644 --- a/src/backend/executor/nodeMergejoin.c +++ b/src/backend/executor/nodeMergejoin.c @@ -1512,7 +1512,7 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags) /* * Initialize result slot, type and projection. */ - ExecInitResultTupleSlotTL(estate, &mergestate->js.ps); + ExecInitResultTupleSlotTL(&mergestate->js.ps); ExecAssignProjectionInfo(&mergestate->js.ps, NULL); /* diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index 528f58717e..e2836b75ff 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -2407,7 +2407,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) mtstate->ps.plan->targetlist = (List *) linitial(node->returningLists); /* Set up a slot for the output of the RETURNING projection(s) */ - ExecInitResultTupleSlotTL(estate, &mtstate->ps); + ExecInitResultTupleSlotTL(&mtstate->ps); slot = mtstate->ps.ps_ResultTupleSlot; /* Need an econtext too */ @@ -2437,7 +2437,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) * expects one (maybe should change that?). */ mtstate->ps.plan->targetlist = NIL; - ExecInitResultTupleSlotTL(estate, &mtstate->ps); + ExecInitResultTypeTL(&mtstate->ps); mtstate->ps.ps_ExprContext = NULL; } @@ -2716,7 +2716,8 @@ ExecEndModifyTable(ModifyTableState *node) /* * clean out the tuple table */ - ExecClearTuple(node->ps.ps_ResultTupleSlot); + if (node->ps.ps_ResultTupleSlot) + ExecClearTuple(node->ps.ps_ResultTupleSlot); /* * Terminate EPQ execution if active diff --git a/src/backend/executor/nodeNamedtuplestorescan.c b/src/backend/executor/nodeNamedtuplestorescan.c index b260ad2594..cf1b7b4f87 100644 --- a/src/backend/executor/nodeNamedtuplestorescan.c +++ b/src/backend/executor/nodeNamedtuplestorescan.c @@ -135,23 +135,22 @@ ExecInitNamedTuplestoreScan(NamedTuplestoreScan *node, EState *estate, int eflag ExecAssignExprContext(estate, &scanstate->ss.ps); /* - * Tuple table and result type initialization. The scan tuple type is - * specified for the tuplestore. + * The scan tuple type is specified for the tuplestore. */ - ExecInitResultTupleSlotTL(estate, &scanstate->ss.ps); ExecInitScanTupleSlot(estate, &scanstate->ss, scanstate->tupdesc); + /* + * Initialize result type and projection. + */ + ExecInitResultTypeTL(&scanstate->ss.ps); + ExecAssignScanProjectionInfo(&scanstate->ss); + /* * initialize child expressions */ scanstate->ss.ps.qual = ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate); - /* - * Initialize projection. - */ - ExecAssignScanProjectionInfo(&scanstate->ss); - return scanstate; } @@ -172,7 +171,8 @@ ExecEndNamedTuplestoreScan(NamedTuplestoreScanState *node) /* * clean out the tuple table */ - ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); + if (node->ss.ps.ps_ResultTupleSlot) + ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); ExecClearTuple(node->ss.ss_ScanTupleSlot); } @@ -187,7 +187,8 @@ ExecReScanNamedTuplestoreScan(NamedTuplestoreScanState *node) { Tuplestorestate *tuplestorestate = node->relation; - ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); + if (node->ss.ps.ps_ResultTupleSlot) + ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); ExecScanReScan(&node->ss); diff --git a/src/backend/executor/nodeNestloop.c b/src/backend/executor/nodeNestloop.c index 9ae9863226..8dbec685eb 100644 --- a/src/backend/executor/nodeNestloop.c +++ b/src/backend/executor/nodeNestloop.c @@ -304,7 +304,7 @@ ExecInitNestLoop(NestLoop *node, EState *estate, int eflags) /* * Initialize result slot, type and projection. */ - ExecInitResultTupleSlotTL(estate, &nlstate->js.ps); + ExecInitResultTupleSlotTL(&nlstate->js.ps); ExecAssignProjectionInfo(&nlstate->js.ps, NULL); /* diff --git a/src/backend/executor/nodeProjectSet.c b/src/backend/executor/nodeProjectSet.c index 6d6ed38cee..e4dd414217 100644 --- a/src/backend/executor/nodeProjectSet.c +++ b/src/backend/executor/nodeProjectSet.c @@ -256,7 +256,7 @@ ExecInitProjectSet(ProjectSet *node, EState *estate, int eflags) /* * tuple table and result type initialization */ - ExecInitResultTupleSlotTL(estate, &state->ps); + ExecInitResultTupleSlotTL(&state->ps); /* Create workspace for per-tlist-entry expr state & SRF-is-done state */ state->nelems = list_length(node->plan.targetlist); diff --git a/src/backend/executor/nodeRecursiveunion.c b/src/backend/executor/nodeRecursiveunion.c index 6b3ea5afb3..2d26cec831 100644 --- a/src/backend/executor/nodeRecursiveunion.c +++ b/src/backend/executor/nodeRecursiveunion.c @@ -229,7 +229,7 @@ ExecInitRecursiveUnion(RecursiveUnion *node, EState *estate, int eflags) * RecursiveUnion nodes still have Result slots, which hold pointers to * tuples, so we have to initialize them. */ - ExecInitResultTupleSlotTL(estate, &rustate->ps); + ExecInitResultTypeTL(&rustate->ps); /* * Initialize result tuple type. (Note: we have to set up the result type @@ -279,11 +279,6 @@ ExecEndRecursiveUnion(RecursiveUnionState *node) if (node->tableContext) MemoryContextDelete(node->tableContext); - /* - * clean out the upper tuple table - */ - ExecClearTuple(node->ps.ps_ResultTupleSlot); - /* * close down subplans */ diff --git a/src/backend/executor/nodeResult.c b/src/backend/executor/nodeResult.c index e4418a29bb..2bbb2e7884 100644 --- a/src/backend/executor/nodeResult.c +++ b/src/backend/executor/nodeResult.c @@ -217,7 +217,7 @@ ExecInitResult(Result *node, EState *estate, int eflags) /* * Initialize result slot, type and projection. */ - ExecInitResultTupleSlotTL(estate, &resstate->ps); + ExecInitResultTupleSlotTL(&resstate->ps); ExecAssignProjectionInfo(&resstate->ps, NULL); /* diff --git a/src/backend/executor/nodeSamplescan.c b/src/backend/executor/nodeSamplescan.c index f01fc3b62a..cfa26535d7 100644 --- a/src/backend/executor/nodeSamplescan.c +++ b/src/backend/executor/nodeSamplescan.c @@ -149,10 +149,9 @@ ExecInitSampleScan(SampleScan *node, EState *estate, int eflags) RelationGetDescr(scanstate->ss.ss_currentRelation)); /* - * Initialize result slot, type and projection. tuple table and result - * tuple initialization + * Initialize result type and projection. */ - ExecInitResultTupleSlotTL(estate, &scanstate->ss.ps); + ExecInitResultTypeTL(&scanstate->ss.ps); ExecAssignScanProjectionInfo(&scanstate->ss); /* @@ -211,7 +210,8 @@ ExecEndSampleScan(SampleScanState *node) /* * clean out the tuple table */ - ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); + if (node->ss.ps.ps_ResultTupleSlot) + ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); ExecClearTuple(node->ss.ss_ScanTupleSlot); /* diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c index 79729dbbec..b4bea67610 100644 --- a/src/backend/executor/nodeSeqscan.c +++ b/src/backend/executor/nodeSeqscan.c @@ -175,9 +175,9 @@ ExecInitSeqScan(SeqScan *node, EState *estate, int eflags) RelationGetDescr(scanstate->ss.ss_currentRelation)); /* - * Initialize result slot, type and projection. + * Initialize result type and projection. */ - ExecInitResultTupleSlotTL(estate, &scanstate->ss.ps); + ExecInitResultTypeTL(&scanstate->ss.ps); ExecAssignScanProjectionInfo(&scanstate->ss); /* @@ -213,7 +213,8 @@ ExecEndSeqScan(SeqScanState *node) /* * clean out the tuple table */ - ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); + if (node->ss.ps.ps_ResultTupleSlot) + ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); ExecClearTuple(node->ss.ss_ScanTupleSlot); /* diff --git a/src/backend/executor/nodeSetOp.c b/src/backend/executor/nodeSetOp.c index 3535b19c41..46bf77775c 100644 --- a/src/backend/executor/nodeSetOp.c +++ b/src/backend/executor/nodeSetOp.c @@ -532,7 +532,7 @@ ExecInitSetOp(SetOp *node, EState *estate, int eflags) * Initialize result slot and type. Setop nodes do no projections, so * initialize projection info for this node appropriately. */ - ExecInitResultTupleSlotTL(estate, &setopstate->ps); + ExecInitResultTupleSlotTL(&setopstate->ps); setopstate->ps.ps_ProjInfo = NULL; /* diff --git a/src/backend/executor/nodeSort.c b/src/backend/executor/nodeSort.c index 0d2acb665a..5492cd4557 100644 --- a/src/backend/executor/nodeSort.c +++ b/src/backend/executor/nodeSort.c @@ -217,7 +217,7 @@ ExecInitSort(Sort *node, EState *estate, int eflags) * Initialize return slot and type. No need to initialize projection info * because this node doesn't do projections. */ - ExecInitResultTupleSlotTL(estate, &sortstate->ss.ps); + ExecInitResultTupleSlotTL(&sortstate->ss.ps); sortstate->ss.ps.ps_ProjInfo = NULL; SO1_printf("ExecInitSort: %s\n", diff --git a/src/backend/executor/nodeSubqueryscan.c b/src/backend/executor/nodeSubqueryscan.c index fa61884785..b84c6892d5 100644 --- a/src/backend/executor/nodeSubqueryscan.c +++ b/src/backend/executor/nodeSubqueryscan.c @@ -126,15 +126,15 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate, int eflags) subquerystate->subplan = ExecInitNode(node->subplan, estate, eflags); /* - * Initialize scan slot and type (needed by ExecInitResultTupleSlotTL) + * Initialize scan slot and type (needed by ExecAssignScanProjectionInfo) */ ExecInitScanTupleSlot(estate, &subquerystate->ss, ExecGetResultType(subquerystate->subplan)); /* - * Initialize result slot, type and projection. + * Initialize result type and projection. */ - ExecInitResultTupleSlotTL(estate, &subquerystate->ss.ps); + ExecInitResultTypeTL(&subquerystate->ss.ps); ExecAssignScanProjectionInfo(&subquerystate->ss); /* @@ -163,7 +163,8 @@ ExecEndSubqueryScan(SubqueryScanState *node) /* * clean out the upper tuple table */ - ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); + if (node->ss.ps.ps_ResultTupleSlot) + ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); ExecClearTuple(node->ss.ss_ScanTupleSlot); /* diff --git a/src/backend/executor/nodeTableFuncscan.c b/src/backend/executor/nodeTableFuncscan.c index a9fd3fda6b..b0c94d7e06 100644 --- a/src/backend/executor/nodeTableFuncscan.c +++ b/src/backend/executor/nodeTableFuncscan.c @@ -150,9 +150,9 @@ ExecInitTableFuncScan(TableFuncScan *node, EState *estate, int eflags) ExecInitScanTupleSlot(estate, &scanstate->ss, tupdesc); /* - * Initialize result slot, type and projection. + * Initialize result type and projection. */ - ExecInitResultTupleSlotTL(estate, &scanstate->ss.ps); + ExecInitResultTypeTL(&scanstate->ss.ps); ExecAssignScanProjectionInfo(&scanstate->ss); /* @@ -221,7 +221,8 @@ ExecEndTableFuncScan(TableFuncScanState *node) /* * clean out the tuple table */ - ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); + if (node->ss.ps.ps_ResultTupleSlot) + ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); ExecClearTuple(node->ss.ss_ScanTupleSlot); /* @@ -243,7 +244,8 @@ ExecReScanTableFuncScan(TableFuncScanState *node) { Bitmapset *chgparam = node->ss.ps.chgParam; - ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); + if (node->ss.ps.ps_ResultTupleSlot) + ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); ExecScanReScan(&node->ss); /* diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c index d21d6553e4..bc859e3d51 100644 --- a/src/backend/executor/nodeTidscan.c +++ b/src/backend/executor/nodeTidscan.c @@ -487,7 +487,8 @@ ExecEndTidScan(TidScanState *node) /* * clear out tuple table slots */ - ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); + if (node->ss.ps.ps_ResultTupleSlot) + ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); ExecClearTuple(node->ss.ss_ScanTupleSlot); } @@ -545,9 +546,9 @@ ExecInitTidScan(TidScan *node, EState *estate, int eflags) RelationGetDescr(currentRelation)); /* - * Initialize result slot, type and projection. + * Initialize result type and projection. */ - ExecInitResultTupleSlotTL(estate, &tidstate->ss.ps); + ExecInitResultTypeTL(&tidstate->ss.ps); ExecAssignScanProjectionInfo(&tidstate->ss); /* diff --git a/src/backend/executor/nodeUnique.c b/src/backend/executor/nodeUnique.c index 05d65330a0..c791f89b48 100644 --- a/src/backend/executor/nodeUnique.c +++ b/src/backend/executor/nodeUnique.c @@ -141,7 +141,7 @@ ExecInitUnique(Unique *node, EState *estate, int eflags) * Initialize result slot and type. Unique nodes do no projections, so * initialize projection info for this node appropriately. */ - ExecInitResultTupleSlotTL(estate, &uniquestate->ps); + ExecInitResultTupleSlotTL(&uniquestate->ps); uniquestate->ps.ps_ProjInfo = NULL; /* diff --git a/src/backend/executor/nodeValuesscan.c b/src/backend/executor/nodeValuesscan.c index f76999d40a..fa49d0470f 100644 --- a/src/backend/executor/nodeValuesscan.c +++ b/src/backend/executor/nodeValuesscan.c @@ -264,9 +264,9 @@ ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags) ExecInitScanTupleSlot(estate, &scanstate->ss, tupdesc); /* - * Initialize result slot, type and projection. + * Initialize result type and projection. */ - ExecInitResultTupleSlotTL(estate, &scanstate->ss.ps); + ExecInitResultTypeTL(&scanstate->ss.ps); ExecAssignScanProjectionInfo(&scanstate->ss); /* @@ -312,7 +312,8 @@ ExecEndValuesScan(ValuesScanState *node) /* * clean out the tuple table */ - ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); + if (node->ss.ps.ps_ResultTupleSlot) + ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); ExecClearTuple(node->ss.ss_ScanTupleSlot); } @@ -325,7 +326,8 @@ ExecEndValuesScan(ValuesScanState *node) void ExecReScanValuesScan(ValuesScanState *node) { - ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); + if (node->ss.ps.ps_ResultTupleSlot) + ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); ExecScanReScan(&node->ss); diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c index 729c376d86..6e597e8285 100644 --- a/src/backend/executor/nodeWindowAgg.c +++ b/src/backend/executor/nodeWindowAgg.c @@ -2349,7 +2349,7 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags) /* * Initialize result slot, type and projection. */ - ExecInitResultTupleSlotTL(estate, &winstate->ss.ps); + ExecInitResultTupleSlotTL(&winstate->ss.ps); ExecAssignProjectionInfo(&winstate->ss.ps, NULL); /* Set up data for comparing tuples */ diff --git a/src/backend/executor/nodeWorktablescan.c b/src/backend/executor/nodeWorktablescan.c index 2ff9a215b1..1ce8ae9f02 100644 --- a/src/backend/executor/nodeWorktablescan.c +++ b/src/backend/executor/nodeWorktablescan.c @@ -159,7 +159,7 @@ ExecInitWorkTableScan(WorkTableScan *node, EState *estate, int eflags) /* * tuple table initialization */ - ExecInitResultTupleSlotTL(estate, &scanstate->ss.ps); + ExecInitResultTypeTL(&scanstate->ss.ps); ExecInitScanTupleSlot(estate, &scanstate->ss, NULL); /* @@ -193,7 +193,8 @@ ExecEndWorkTableScan(WorkTableScanState *node) /* * clean out the tuple table */ - ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); + if (node->ss.ps.ps_ResultTupleSlot) + ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); ExecClearTuple(node->ss.ss_ScanTupleSlot); } @@ -206,7 +207,8 @@ ExecEndWorkTableScan(WorkTableScanState *node) void ExecReScanWorkTableScan(WorkTableScanState *node) { - ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); + if (node->ss.ps.ps_ResultTupleSlot) + ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); ExecScanReScan(&node->ss); diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index edf538365b..8441265784 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -429,7 +429,9 @@ extern void ExecScanReScan(ScanState *node); /* * prototypes from functions in execTuples.c */ -extern void ExecInitResultTupleSlotTL(EState *estate, PlanState *planstate); +extern void ExecInitResultTypeTL(PlanState *planstate); +extern void ExecInitResultSlot(PlanState *planstate); +extern void ExecInitResultTupleSlotTL(PlanState *planstate); extern void ExecInitScanTupleSlot(EState *estate, ScanState *scanstate, TupleDesc tupleDesc); extern TupleTableSlot *ExecInitExtraTupleSlot(EState *estate, TupleDesc tupleDesc); diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index 880a03e4e4..18544566f7 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -966,6 +966,7 @@ typedef struct PlanState /* * Other run-time state needed by most if not all node types. */ + TupleDesc ps_ResultTupleDesc; /* node's return type */ TupleTableSlot *ps_ResultTupleSlot; /* slot for my result tuples */ ExprContext *ps_ExprContext; /* node's expression-evaluation context */ ProjectionInfo *ps_ProjInfo; /* info for doing tuple projection */