Don't require return slots for nodes without projection.
authorAndres Freund <[email protected]>
Sat, 10 Nov 2018 01:19:39 +0000 (17:19 -0800)
committerAndres Freund <[email protected]>
Sat, 10 Nov 2018 01:19:39 +0000 (17:19 -0800)
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 es 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[email protected]

40 files changed:
src/backend/executor/execTuples.c
src/backend/executor/execUtils.c
src/backend/executor/nodeAgg.c
src/backend/executor/nodeAppend.c
src/backend/executor/nodeBitmapHeapscan.c
src/backend/executor/nodeCtescan.c
src/backend/executor/nodeCustom.c
src/backend/executor/nodeForeignscan.c
src/backend/executor/nodeFunctionscan.c
src/backend/executor/nodeGather.c
src/backend/executor/nodeGatherMerge.c
src/backend/executor/nodeGroup.c
src/backend/executor/nodeHash.c
src/backend/executor/nodeHashjoin.c
src/backend/executor/nodeIndexonlyscan.c
src/backend/executor/nodeIndexscan.c
src/backend/executor/nodeLimit.c
src/backend/executor/nodeLockRows.c
src/backend/executor/nodeMaterial.c
src/backend/executor/nodeMergeAppend.c
src/backend/executor/nodeMergejoin.c
src/backend/executor/nodeModifyTable.c
src/backend/executor/nodeNamedtuplestorescan.c
src/backend/executor/nodeNestloop.c
src/backend/executor/nodeProjectSet.c
src/backend/executor/nodeRecursiveunion.c
src/backend/executor/nodeResult.c
src/backend/executor/nodeSamplescan.c
src/backend/executor/nodeSeqscan.c
src/backend/executor/nodeSetOp.c
src/backend/executor/nodeSort.c
src/backend/executor/nodeSubqueryscan.c
src/backend/executor/nodeTableFuncscan.c
src/backend/executor/nodeTidscan.c
src/backend/executor/nodeUnique.c
src/backend/executor/nodeValuesscan.c
src/backend/executor/nodeWindowAgg.c
src/backend/executor/nodeWorktablescan.c
src/include/executor/executor.h
src/include/nodes/execnodes.h

index 015752a93f18d224489badf6ff33ef451fea4791..eba52dc928f90682bfba078a367a613d0c6af2aa 100644 (file)
  *
  *     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);
 }
 
 /* ----------------
index 71c6b5dc0a85cfdd3c40f1ceebc6b3343d7b1ed0..f9e7bb479f1c73ca192efed65f36280c6a0af9d2 100644 (file)
@@ -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
index 2413f1f87db87d727bf51d15ce18a0d35ac1ed4d..85f1ec7140f9bd6b1e0a27a54eb5f1378a23bb83 100644 (file)
@@ -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);
 
    /*
index a16b6da47404608bd372fd04c23f7ef37acb8360..94a17c7c67c530660ac7b19e8c08b1c27b1a34f2 100644 (file)
@@ -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 *));
index 304ef07f2cc4e3fde33c4683683e884f239a0e37..c153d74f411702526086335312db80aef7940653 100644 (file)
@@ -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);
 
    /*
index 24700dd3965ba84c75b46a6c34f8664bb450fd6f..017b8772775fbff72c61ee520f0a47a75b816ff6 100644 (file)
@@ -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);
 
index 7972d5a952a28784a4763610328884f50e7d6dbf..ab3e34790e87eedf1562b3b84b8f2bc751c7af23 100644 (file)
@@ -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 */
index 2ec7fcb9621cce038ba23a3645e06bbcd58343df..5d2cd0ed717580a1317f088f4d4efcea5eca5361 100644 (file)
@@ -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);
 }
 
index fb7c9f678758752e000f8bc69e76e2cf143f825c..0596adbb2f1939714eada44fba6768fd2d19a250 100644 (file)
@@ -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];
index ad16c783bd826152c55a890afc3bdb9746d00984..afddb0a039485f8343ba120264e351750983e846 100644 (file)
@@ -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);
 }
 
 /*
index 6362e4497a027c328c20098478e703aa7865b1ca..7ae067f9ebf381f28890dfc9dcccefdc574d4d0f 100644 (file)
@@ -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);
 }
 
 /* ----------------------------------------------------------------
index 2ea80e817d4e3e388747a88226a4aeeeed892769..9c1e51bc9548092d4328ee9b637b488be190d9d0 100644 (file)
@@ -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);
 
    /*
index 6ffaa751f23fa7aa286abde5b41d9b3649a3a06c..a9f812d66b8ead3bb14b587513fd398dc501b8d5 100644 (file)
@@ -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;
 
    /*
index d017bbfbd33fcaeca09bd0b044baa74d0428ffc5..08a8bb3426c633a92a82527d1045a6ad212cca24 100644 (file)
@@ -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);
 
    /*
index daedf342f726d876e93673cab9139fb6de0b9719..865a056c02787582616895f23fca24fa6555c3dc 100644 (file)
@@ -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);
 
    /*
index ba7821b0e2b3a5b120036971eaf28ff1a6bc9213..8593c0e3050f36bb1becee767cf82d1b23cd3a70 100644 (file)
@@ -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);
 
    /*
index bb28cf7d1db8f219b96afd57e416a5ae5a9a7671..f0b6819140016afaeb77dcb4873d93e36b27ef4f 100644 (file)
@@ -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
index 6db345ae7acf160e4afb73252da38269cc273928..961798cecb363e13c375053d9619bee2019087e8 100644 (file)
@@ -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
index 8c2e57dbd074474af5584302258e469f9c988986..4ede428f908ba5e123c6135df1ac14739a3573bc 100644 (file)
@@ -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;
 
    /*
index fde369d62203d54e1129e1ade89c34f374157fc5..dbed667d1647a3c6daf2d7e8947f1422d303abce 100644 (file)
@@ -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
index 5e52b90c007bd14bf4ec0a2c20ac795d7a236ab5..9c978313318bdf64eb06e11d103bf09731dd933a 100644 (file)
@@ -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);
 
    /*
index 528f58717e2ccfbdf643e712f7757be9f5071a2c..e2836b75ff32b651d5223c5b25d6093a7fa544af 100644 (file)
@@ -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
index b260ad25948a68d67d0c5cc2ebd6bb1d94ff7227..cf1b7b4f87266437639f42495402a3612dae90ad 100644 (file)
@@ -135,22 +135,21 @@ 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 child expressions
+    * Initialize result type and projection.
     */
-   scanstate->ss.ps.qual =
-       ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate);
+   ExecInitResultTypeTL(&scanstate->ss.ps);
+   ExecAssignScanProjectionInfo(&scanstate->ss);
 
    /*
-    * Initialize projection.
+    * initialize child expressions
     */
-   ExecAssignScanProjectionInfo(&scanstate->ss);
+   scanstate->ss.ps.qual =
+       ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate);
 
    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);
 
index 9ae9863226c02fd2b649a54397bd61d6d996421d..8dbec685eb1a3d511ea371cf80207fed06df7b8b 100644 (file)
@@ -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);
 
    /*
index 6d6ed38ceeb45a4e12fe9a1022e96d0fe5c4b3ce..e4dd4142177677179ddd099d345ece6615544299 100644 (file)
@@ -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);
index 6b3ea5afb31946d133200c70cfc80b3a2b37e978..2d26cec83152bc103cfed50431d715f462a625b1 100644 (file)
@@ -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
     */
index e4418a29bba743cde9cd66976ffb08a800cc2c66..2bbb2e788480293b0ef7a5ae34f13b5856e83237 100644 (file)
@@ -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);
 
    /*
index f01fc3b62a088c96d6319455631e83915016970c..cfa26535d7b42b985c99f0cd90f44ccf4588ed3f 100644 (file)
@@ -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);
 
    /*
index 79729dbbecb3019b519bf6c1353ca58951fe45cd..b4bea67610f1dfec6511ab6290d1f2409bb73d12 100644 (file)
@@ -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);
 
    /*
index 3535b19c41d04d2d7a47574e757e37eb5ba5f476..46bf77775c479e9a222936c99934bb6c5853e21f 100644 (file)
@@ -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;
 
    /*
index 0d2acb665af2c40fec6a68fce9ef0615fe0b567c..5492cd455796ca0429259683070044acdc3efb1f 100644 (file)
@@ -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",
index fa6188478511a44d49762f680222597fb9d44368..b84c6892d503d661fcdebc9e27872a966f4acfda 100644 (file)
@@ -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);
 
    /*
index a9fd3fda6be67f050ff69064e9087a52feec9f29..b0c94d7e063af90d23f3e9f7eb297499d40ee318 100644 (file)
@@ -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);
 
    /*
index d21d6553e4247e5202e64eac7c4b8972f627a331..bc859e3d516eff72e141a235f35f55388254e2bf 100644 (file)
@@ -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);
 
    /*
index 05d65330a0eb5f5559dcb3bae58c43af47927363..c791f89b48c046f8d5ddb71744beb304fa67120e 100644 (file)
@@ -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;
 
    /*
index f76999d40ae83e1a0a75f1919e2c26ed1f5dab91..fa49d0470fcf191d379f02e6934534757be1c961 100644 (file)
@@ -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);
 
index 729c376d86bb6e3858244047ed4d3cca84b3388d..6e597e82856be99f70af2391d9c753194051efc2 100644 (file)
@@ -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 */
index 2ff9a215b12f8d17040e7613db48e5b5cb2c22b7..1ce8ae9f026318401fb015f943c0b46483dcbcaf 100644 (file)
@@ -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);
 
index edf538365be397c3dbb5a7d1a0f8430243d7ad82..84412657845efafdbfe3adedea42b57d95e2bc17 100644 (file)
@@ -429,7 +429,9 @@ extern void ExecScanReScan(ScanState *node);
 /*
  * s 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);
index 880a03e4e4b7d83555a5a6777e5501a2656ddc55..18544566f70f17fd1187184e4c44591dc12118ca 100644 (file)
@@ -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 */