Use ExecGetCommonSlotOps infrastructure in more places.
authorTom Lane <[email protected]>
Thu, 19 Dec 2024 22:07:14 +0000 (17:07 -0500)
committerTom Lane <[email protected]>
Thu, 19 Dec 2024 22:07:14 +0000 (17:07 -0500)
Append, MergeAppend, and RecursiveUnion can all use the support
functions added in commit 276279295.  The first two can report a
fixed result slot type if all their children return the same fixed
slot type.  That does nothing for the append step itself, but might
allow optimizations in the parent plan node.  RecursiveUnion can
optimize tuple hash table operations in the same way as SetOp now
does.

Patch by me; thanks to Richard Guo and David Rowley for review.

Discussion: https://postgr.es/m/1850138.1731549611@sss.pgh.pa.us

src/backend/executor/nodeAppend.c
src/backend/executor/nodeMergeAppend.c
src/backend/executor/nodeRecursiveunion.c

index ca0f54d676f4a67d5cac42524bd149e62b9eacf5..b5d56569f7f1254b317908e7321a920d5723cea5 100644 (file)
@@ -110,6 +110,7 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
 {
    AppendState *appendstate = makeNode(AppendState);
    PlanState **appendplanstates;
+   const TupleTableSlotOps *appendops;
    Bitmapset  *validsubplans;
    Bitmapset  *asyncplans;
    int         nplans;
@@ -176,15 +177,6 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
        appendstate->as_prune_state = NULL;
    }
 
-   /*
-    * Initialize result tuple type and slot.
-    */
-   ExecInitResultTupleSlotTL(&appendstate->ps, &TTSOpsVirtual);
-
-   /* node returns slots from each of its subnodes, therefore not fixed */
-   appendstate->ps.resultopsset = true;
-   appendstate->ps.resultopsfixed = false;
-
    appendplanstates = (PlanState **) palloc(nplans *
                                             sizeof(PlanState *));
 
@@ -227,6 +219,28 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
    appendstate->appendplans = appendplanstates;
    appendstate->as_nplans = nplans;
 
+   /*
+    * Initialize Append's result tuple type and slot.  If the child plans all
+    * produce the same fixed slot type, we can use that slot type; otherwise
+    * make a virtual slot.  (Note that the result slot itself is used only to
+    * return a null tuple at end of execution; real tuples are returned to
+    * the caller in the children's own result slots.  What we are doing here
+    * is allowing the parent plan node to optimize if the Append will return
+    * only one kind of slot.)
+    */
+   appendops = ExecGetCommonSlotOps(appendplanstates, j);
+   if (appendops != NULL)
+   {
+       ExecInitResultTupleSlotTL(&appendstate->ps, appendops);
+   }
+   else
+   {
+       ExecInitResultTupleSlotTL(&appendstate->ps, &TTSOpsVirtual);
+       /* show that the output slot type is not fixed */
+       appendstate->ps.resultopsset = true;
+       appendstate->ps.resultopsfixed = false;
+   }
+
    /* Initialize async state */
    appendstate->as_asyncplans = asyncplans;
    appendstate->as_nasyncplans = nasyncplans;
index e1b9b984a7a32f74e8a6cc14aeb9805975da3424..081734e8172da1a1e7c95cebf4fad4ea7b0e47b1 100644 (file)
@@ -66,6 +66,7 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
 {
    MergeAppendState *mergestate = makeNode(MergeAppendState);
    PlanState **mergeplanstates;
+   const TupleTableSlotOps *mergeops;
    Bitmapset  *validsubplans;
    int         nplans;
    int         i,
@@ -128,18 +129,6 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
    mergestate->ms_heap = binaryheap_allocate(nplans, heap_compare_slots,
                                              mergestate);
 
-   /*
-    * Miscellaneous initialization
-    *
-    * MergeAppend nodes do have Result slots, which hold pointers to tuples,
-    * so we have to initialize them.  FIXME
-    */
-   ExecInitResultTupleSlotTL(&mergestate->ps, &TTSOpsVirtual);
-
-   /* node returns slots from each of its subnodes, therefore not fixed */
-   mergestate->ps.resultopsset = true;
-   mergestate->ps.resultopsfixed = false;
-
    /*
     * call ExecInitNode on each of the valid plans to be executed and save
     * the results into the mergeplanstates array.
@@ -153,6 +142,31 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
        mergeplanstates[j++] = ExecInitNode(initNode, estate, eflags);
    }
 
+   /*
+    * Initialize MergeAppend's result tuple type and slot.  If the child
+    * plans all produce the same fixed slot type, we can use that slot type;
+    * otherwise make a virtual slot.  (Note that the result slot itself is
+    * used only to return a null tuple at end of execution; real tuples are
+    * returned to the caller in the children's own result slots.  What we are
+    * doing here is allowing the parent plan node to optimize if the
+    * MergeAppend will return only one kind of slot.)
+    */
+   mergeops = ExecGetCommonSlotOps(mergeplanstates, j);
+   if (mergeops != NULL)
+   {
+       ExecInitResultTupleSlotTL(&mergestate->ps, mergeops);
+   }
+   else
+   {
+       ExecInitResultTupleSlotTL(&mergestate->ps, &TTSOpsVirtual);
+       /* show that the output slot type is not fixed */
+       mergestate->ps.resultopsset = true;
+       mergestate->ps.resultopsfixed = false;
+   }
+
+   /*
+    * Miscellaneous initialization
+    */
    mergestate->ps.ps_ProjInfo = NULL;
 
    /*
index 39be4cdc3b1094c7a44a66db8df4d6c8a541c3b5..b577b72b50cdcd5bf5d0b3c07a35dc3620390b6e 100644 (file)
@@ -37,10 +37,14 @@ build_hash_table(RecursiveUnionState *rustate)
    Assert(node->numCols > 0);
    Assert(node->numGroups > 0);
 
-   /* XXX is it worth working a bit harder to determine the inputOps here? */
+   /*
+    * If both child plans deliver the same fixed tuple slot type, we can tell
+    * BuildTupleHashTableExt to expect that slot type as input.  Otherwise,
+    * we'll pass NULL denoting that any slot type is possible.
+    */
    rustate->hashtable = BuildTupleHashTableExt(&rustate->ps,
                                                desc,
-                                               NULL,
+                                               ExecGetCommonChildSlotOps(&rustate->ps),
                                                node->numCols,
                                                node->dupColIdx,
                                                rustate->eqfuncoids,