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
{
AppendState *appendstate = makeNode(AppendState);
PlanState **appendplanstates;
+ const TupleTableSlotOps *appendops;
Bitmapset *validsubplans;
Bitmapset *asyncplans;
int nplans;
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 *));
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;
{
MergeAppendState *mergestate = makeNode(MergeAppendState);
PlanState **mergeplanstates;
+ const TupleTableSlotOps *mergeops;
Bitmapset *validsubplans;
int nplans;
int i,
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.
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;
/*
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,