]> granicus.if.org Git - postgresql/commitdiff
Introduce notion of different types of slots (without implementing them).
authorAndres Freund <andres@anarazel.de>
Fri, 16 Nov 2018 06:00:30 +0000 (22:00 -0800)
committerAndres Freund <andres@anarazel.de>
Fri, 16 Nov 2018 06:00:30 +0000 (22:00 -0800)
Upcoming work intends to allow pluggable ways to introduce new ways of
storing table data. Accessing those table access methods from the
executor requires TupleTableSlots to be carry tuples in the native
format of such storage methods; otherwise there'll be a significant
conversion overhead.

Different access methods will require different data to store tuples
efficiently (just like virtual, minimal, heap already require fields
in TupleTableSlot). To allow that without requiring additional pointer
indirections, we want to have different structs (embedding
TupleTableSlot) for different types of slots.  Thus different types of
slots are needed, which requires adapting creators of slots.

The slot that most efficiently can represent a type of tuple in an
executor node will often depend on the type of slot a child node
uses. Therefore we need to track the type of slot is returned by
nodes, so parent slots can create slots based on that.

Relatedly, JIT compilation of tuple deforming needs to know which type
of slot a certain expression refers to, so it can create an
appropriate deforming function for the type of tuple in the slot.

But not all nodes will only return one type of slot, e.g. an append
node will potentially return different types of slots for each of its
subplans.

Therefore add function that allows to query the type of a node's
result slot, and whether it'll always be the same type (whether it's
fixed). This can be queried using ExecGetResultSlotOps().

The scan, result, inner, outer type of slots are automatically
inferred from ExecInitScanTupleSlot(), ExecInitResultSlot(),
left/right subtrees respectively. If that's not correct for a node,
that can be overwritten using new fields in PlanState.

This commit does not introduce the actually abstracted implementation
of different kind of TupleTableSlots, that will be left for a followup
commit.  The different types of slots introduced will, for now, still
use the same backing implementation.

While this already partially invalidates the big comment in
tuptable.h, it seems to make more sense to update it later, when the
different TupleTableSlot implementations actually exist.

Author: Ashutosh Bapat and Andres Freund, with changes by Amit Khandekar
Discussion: https://postgr.es/m/20181105210039.hh4vvi4vwoq5ba2q@alap3.anarazel.de

69 files changed:
src/backend/access/heap/heapam.c
src/backend/catalog/index.c
src/backend/catalog/indexing.c
src/backend/commands/analyze.c
src/backend/commands/constraint.c
src/backend/commands/copy.c
src/backend/commands/explain.c
src/backend/commands/functioncmds.c
src/backend/commands/subscriptioncmds.c
src/backend/commands/tablecmds.c
src/backend/commands/trigger.c
src/backend/executor/execExpr.c
src/backend/executor/execGrouping.c
src/backend/executor/execIndexing.c
src/backend/executor/execJunk.c
src/backend/executor/execMain.c
src/backend/executor/execPartition.c
src/backend/executor/execSRF.c
src/backend/executor/execTuples.c
src/backend/executor/execUtils.c
src/backend/executor/functions.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/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/nodeSubplan.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/backend/partitioning/partbounds.c
src/backend/replication/logical/tablesync.c
src/backend/replication/logical/worker.c
src/backend/replication/walsender.c
src/backend/tcop/pquery.c
src/backend/utils/adt/orderedsetaggs.c
src/backend/utils/adt/selfuncs.c
src/backend/utils/misc/guc.c
src/backend/utils/sort/tuplesort.c
src/include/executor/executor.h
src/include/executor/tuptable.h
src/include/nodes/execnodes.h

index fb63471a0e02753eb7cfc913c0e107b813eb9d9f..da2a8f34c20145d49123f5ecff9473a590b11820 100644 (file)
@@ -4503,7 +4503,8 @@ ProjIndexIsUnchanged(Relation relation, HeapTuple oldtup, HeapTuple newtup)
        List       *indexoidlist = RelationGetIndexList(relation);
        EState     *estate = CreateExecutorState();
        ExprContext *econtext = GetPerTupleExprContext(estate);
-       TupleTableSlot *slot = MakeSingleTupleTableSlot(RelationGetDescr(relation));
+       TupleTableSlot *slot = MakeSingleTupleTableSlot(RelationGetDescr(relation),
+                                                                                                       &TTSOpsHeapTuple);
        bool            equals = true;
        Datum           old_values[INDEX_MAX_KEYS];
        bool            old_isnull[INDEX_MAX_KEYS];
index 4088286151af0a2c42499da71784cdeb7be19460..21bdf794da6a25c73a40f9575c2a2f11c0173bb6 100644 (file)
@@ -2510,7 +2510,8 @@ IndexBuildHeapRangeScan(Relation heapRelation,
         */
        estate = CreateExecutorState();
        econtext = GetPerTupleExprContext(estate);
-       slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation));
+       slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation),
+                                                                       &TTSOpsHeapTuple);
 
        /* Arrange for econtext's scan tuple to be the tuple under test */
        econtext->ecxt_scantuple = slot;
@@ -2997,7 +2998,8 @@ IndexCheckExclusion(Relation heapRelation,
         */
        estate = CreateExecutorState();
        econtext = GetPerTupleExprContext(estate);
-       slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation));
+       slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation),
+                                                                       &TTSOpsHeapTuple);
 
        /* Arrange for econtext's scan tuple to be the tuple under test */
        econtext->ecxt_scantuple = slot;
@@ -3315,7 +3317,8 @@ validate_index_heapscan(Relation heapRelation,
         */
        estate = CreateExecutorState();
        econtext = GetPerTupleExprContext(estate);
-       slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation));
+       slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation),
+                                                                       &TTSOpsHeapTuple);
 
        /* Arrange for econtext's scan tuple to be the tuple under test */
        econtext->ecxt_scantuple = slot;
index daf7ae2eb2b07cc4648862fce0fd8228ecdff3d8..c5f6efba2b628b026ec5db494fd0c83da61e2079 100644 (file)
@@ -95,7 +95,8 @@ CatalogIndexInsert(CatalogIndexState indstate, HeapTuple heapTuple)
        heapRelation = indstate->ri_RelationDesc;
 
        /* Need a slot to hold the tuple being examined */
-       slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation));
+       slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation),
+                                                                       &TTSOpsHeapTuple);
        ExecStoreHeapTuple(heapTuple, slot, false);
 
        /*
index 8ac868ad73394acf0fb86c247eec93b0e3f6022a..b8445dc372881acb4cd314c19072e0fa41b1a588 100644 (file)
@@ -730,7 +730,8 @@ compute_index_stats(Relation onerel, double totalrows,
                estate = CreateExecutorState();
                econtext = GetPerTupleExprContext(estate);
                /* Need a slot to hold the current heap tuple, too */
-               slot = MakeSingleTupleTableSlot(RelationGetDescr(onerel));
+               slot = MakeSingleTupleTableSlot(RelationGetDescr(onerel),
+                                                                               &TTSOpsHeapTuple);
 
                /* Arrange for econtext's scan tuple to be the tuple under test */
                econtext->ecxt_scantuple = slot;
index f472355b48f676972c948ff55bf0052c90fac554..b0b2cb2a1461bb0792b161f36cb6e70074a51138 100644 (file)
@@ -122,7 +122,8 @@ unique_key_recheck(PG_FUNCTION_ARGS)
        /*
         * The heap tuple must be put into a slot for FormIndexDatum.
         */
-       slot = MakeSingleTupleTableSlot(RelationGetDescr(trigdata->tg_relation));
+       slot = MakeSingleTupleTableSlot(RelationGetDescr(trigdata->tg_relation),
+                                                                       &TTSOpsHeapTuple);
 
        ExecStoreHeapTuple(new_row, slot, false);
 
index a9471c5ef6a1a380a4988e9f24354fd909e423d0..e62e3d8fba2029467681fb8fcb2232e79ae0de7f 100644 (file)
@@ -2488,9 +2488,11 @@ CopyFrom(CopyState cstate)
        ExecInitRangeTable(estate, cstate->range_table);
 
        /* Set up a tuple slot too */
-       myslot = ExecInitExtraTupleSlot(estate, tupDesc);
+       myslot = ExecInitExtraTupleSlot(estate, tupDesc,
+                                                                       &TTSOpsHeapTuple);
        /* Triggers might need a slot as well */
-       estate->es_trig_tuple_slot = ExecInitExtraTupleSlot(estate, NULL);
+       estate->es_trig_tuple_slot = ExecInitExtraTupleSlot(estate, NULL,
+                                                                                                               &TTSOpsHeapTuple);
 
        /*
         * Set up a ModifyTableState so we can let FDW(s) init themselves for
index 799a22e9d5537a6ce97a4512fe9321c9b2c4a0a9..ab2c84ff98a1c13bf8aa466d7e848b1bcc9644c7 100644 (file)
@@ -266,7 +266,8 @@ ExplainQuery(ParseState *pstate, ExplainStmt *stmt, const char *queryString,
        Assert(es->indent == 0);
 
        /* output tuples */
-       tstate = begin_tup_output_tupdesc(dest, ExplainResultDesc(stmt));
+       tstate = begin_tup_output_tupdesc(dest, ExplainResultDesc(stmt),
+                                                                         &TTSOpsVirtual);
        if (es->format == EXPLAIN_FORMAT_TEXT)
                do_text_output_multiline(tstate, es->str->data);
        else
index 3925fb83a5438e09fb1f5dee5c9f77f71170ed54..f6e12a33532720d4992801d764664c37071f551e 100644 (file)
@@ -2347,7 +2347,8 @@ ExecuteCallStmt(CallStmt *stmt, ParamListInfo params, bool atomic, DestReceiver
                tupTypmod = HeapTupleHeaderGetTypMod(td);
                retdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
 
-               tstate = begin_tup_output_tupdesc(dest, retdesc);
+               tstate = begin_tup_output_tupdesc(dest, retdesc,
+                                                                                 &TTSOpsHeapTuple);
 
                rettupdata.t_len = HeapTupleHeaderGetDatumLength(td);
                ItemPointerSetInvalid(&(rettupdata.t_self));
index f138e61a8d3d9d111e52b5fe59742df1967e9042..0efbfec4751f3253b4bf734709b04d86e7776750 100644 (file)
@@ -1148,7 +1148,7 @@ fetch_table_list(WalReceiverConn *wrconn, List *publications)
                                                res->err)));
 
        /* Process tables. */
-       slot = MakeSingleTupleTableSlot(res->tupledesc);
+       slot = MakeSingleTupleTableSlot(res->tupledesc, &TTSOpsMinimalTuple);
        while (tuplestore_gettupleslot(res->tuplestore, true, false, slot))
        {
                char       *nspname;
index 73da6c39c22bf1aa9aa6e19bd386e882f4375bb1..a15e6045075af90fb9adb83dc78da61f50cfd664 100644 (file)
@@ -4736,8 +4736,8 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
                 * tuples are the same, the tupDescs might not be (consider ADD COLUMN
                 * without a default).
                 */
-               oldslot = MakeSingleTupleTableSlot(oldTupDesc);
-               newslot = MakeSingleTupleTableSlot(newTupDesc);
+               oldslot = MakeSingleTupleTableSlot(oldTupDesc, &TTSOpsHeapTuple);
+               newslot = MakeSingleTupleTableSlot(newTupDesc, &TTSOpsHeapTuple);
 
                /* Preallocate values/isnull arrays */
                i = Max(newTupDesc->natts, oldTupDesc->natts);
@@ -8527,7 +8527,7 @@ validateCheckConstraint(Relation rel, HeapTuple constrtup)
 
        econtext = GetPerTupleExprContext(estate);
        tupdesc = RelationGetDescr(rel);
-       slot = MakeSingleTupleTableSlot(tupdesc);
+       slot = MakeSingleTupleTableSlot(tupdesc, &TTSOpsHeapTuple);
        econtext->ecxt_scantuple = slot;
 
        snapshot = RegisterSnapshot(GetLatestSnapshot());
index d6f33ecbd04317be76b8cf4488386001ab58e7c5..b91ebdb3d0477c26b617cd8d3cfa15007a80d36f 100644 (file)
@@ -3525,7 +3525,7 @@ TriggerEnabled(EState *estate, ResultRelInfo *relinfo,
                        {
                                oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
                                estate->es_trig_oldtup_slot =
-                                       ExecInitExtraTupleSlot(estate, NULL);
+                                       ExecInitExtraTupleSlot(estate, NULL, &TTSOpsHeapTuple);
                                MemoryContextSwitchTo(oldContext);
                        }
                        oldslot = estate->es_trig_oldtup_slot;
@@ -3539,7 +3539,7 @@ TriggerEnabled(EState *estate, ResultRelInfo *relinfo,
                        {
                                oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
                                estate->es_trig_newtup_slot =
-                                       ExecInitExtraTupleSlot(estate, NULL);
+                                       ExecInitExtraTupleSlot(estate, NULL, &TTSOpsHeapTuple);
                                MemoryContextSwitchTo(oldContext);
                        }
                        newslot = estate->es_trig_newtup_slot;
@@ -4546,8 +4546,10 @@ afterTriggerInvokeEvents(AfterTriggerEventList *events,
                                                        ExecDropSingleTupleTableSlot(slot1);
                                                        ExecDropSingleTupleTableSlot(slot2);
                                                }
-                                               slot1 = MakeSingleTupleTableSlot(rel->rd_att);
-                                               slot2 = MakeSingleTupleTableSlot(rel->rd_att);
+                                               slot1 = MakeSingleTupleTableSlot(rel->rd_att,
+                                                                                                                &TTSOpsMinimalTuple);
+                                               slot2 = MakeSingleTupleTableSlot(rel->rd_att,
+                                                                                                                &TTSOpsMinimalTuple);
                                        }
                                        if (trigdesc == NULL)   /* should not happen */
                                                elog(ERROR, "relation %u has no triggers",
index 885da18306a40e50f10bc4d90c244542424b7b51..cd5ee91cd435db556b34f94ef1feaa70b3b5d66b 100644 (file)
@@ -2423,7 +2423,8 @@ ExecInitWholeRowVar(ExprEvalStep *scratch, Var *variable, ExprState *state)
                                scratch->d.wholerow.junkFilter =
                                        ExecInitJunkFilter(subplan->plan->targetlist,
                                                                           ExecGetResultType(subplan)->tdhasoid,
-                                                                          ExecInitExtraTupleSlot(parent->state, NULL));
+                                                                          ExecInitExtraTupleSlot(parent->state, NULL,
+                                                                                                                         &TTSOpsVirtual));
                        }
                }
        }
@@ -3214,6 +3215,7 @@ ExecBuildAggTransCall(ExprState *state, AggState *aggstate,
  */
 ExprState *
 ExecBuildGroupingEqual(TupleDesc ldesc, TupleDesc rdesc,
+                                          const TupleTableSlotOps *lops, const TupleTableSlotOps *rops,
                                           int numCols,
                                           AttrNumber *keyColIdx,
                                           Oid *eqfunctions,
index c4d0e0405873517dcf9b6e9cc0d2c4c1b5b72596..abce1e95cb65a33819687d63635264b856b8f402 100644 (file)
@@ -75,7 +75,8 @@ execTuplesMatchPrepare(TupleDesc desc,
                eqFunctions[i] = get_opcode(eqOperators[i]);
 
        /* build actual expression */
-       expr = ExecBuildGroupingEqual(desc, desc, numCols, keyColIdx, eqFunctions,
+       expr = ExecBuildGroupingEqual(desc, desc, NULL, NULL,
+                                                                 numCols, keyColIdx, eqFunctions,
                                                                  parent);
 
        return expr;
@@ -202,10 +203,13 @@ BuildTupleHashTable(PlanState *parent,
         * We copy the input tuple descriptor just for safety --- we assume all
         * input tuples will have equivalent descriptors.
         */
-       hashtable->tableslot = MakeSingleTupleTableSlot(CreateTupleDescCopy(inputDesc));
+       hashtable->tableslot = MakeSingleTupleTableSlot(CreateTupleDescCopy(inputDesc),
+                                                                                                       &TTSOpsMinimalTuple);
 
        /* build comparator for all columns */
+       /* XXX: should we support non-minimal tuples for the inputslot? */
        hashtable->tab_eq_func = ExecBuildGroupingEqual(inputDesc, inputDesc,
+                                                                                                       &TTSOpsMinimalTuple, &TTSOpsMinimalTuple,
                                                                                                        numCols,
                                                                                                        keyColIdx, eqfuncoids,
                                                                                                        parent);
index 9927ad70e66c948f8477c399fb19ad2c8122c65f..8b35bb458de3992cde113a7dee8561d72f73a84d 100644 (file)
@@ -706,7 +706,8 @@ check_exclusion_or_unique_constraint(Relation heap, Relation index,
         * to this slot.  Be sure to save and restore caller's value for
         * scantuple.
         */
-       existing_slot = MakeSingleTupleTableSlot(RelationGetDescr(heap));
+       existing_slot = MakeSingleTupleTableSlot(RelationGetDescr(heap),
+                                                                                        &TTSOpsHeapTuple);
 
        econtext = GetPerTupleExprContext(estate);
        save_scantuple = econtext->ecxt_scantuple;
index 57d74e57c1a5d2312e76a5b10cbf8f8810104f1d..26558282e9c8c126c090c92d8ba397a5213e48d4 100644 (file)
@@ -78,7 +78,7 @@ ExecInitJunkFilter(List *targetList, bool hasoid, TupleTableSlot *slot)
        if (slot)
                ExecSetSlotDescriptor(slot, cleanTupType);
        else
-               slot = MakeSingleTupleTableSlot(cleanTupType);
+               slot = MakeSingleTupleTableSlot(cleanTupType, &TTSOpsVirtual);
 
        /*
         * Now calculate the mapping between the original tuple's attributes and
@@ -149,7 +149,7 @@ ExecInitJunkFilterConversion(List *targetList,
        if (slot)
                ExecSetSlotDescriptor(slot, cleanTupType);
        else
-               slot = MakeSingleTupleTableSlot(cleanTupType);
+               slot = MakeSingleTupleTableSlot(cleanTupType, &TTSOpsVirtual);
 
        /*
         * Calculate the mapping between the original tuple's attributes and the
index d10e533fd1663b100fe3dc558b96baad49d419cd..74398eb46433c8f744e22c20c84f915e6460c4d2 100644 (file)
@@ -1052,10 +1052,12 @@ InitPlan(QueryDesc *queryDesc, int eflags)
                if (junk_filter_needed)
                {
                        JunkFilter *j;
+                       TupleTableSlot *slot;
 
+                       slot = ExecInitExtraTupleSlot(estate, NULL, &TTSOpsVirtual);
                        j = ExecInitJunkFilter(planstate->plan->targetlist,
                                                                   tupType->tdhasoid,
-                                                                  ExecInitExtraTupleSlot(estate, NULL));
+                                                                  slot);
                        estate->es_junkFilter = j;
 
                        /* Want to return the cleaned tuple type */
@@ -1928,7 +1930,7 @@ ExecPartitionCheckEmitError(ResultRelInfo *resultRelInfo,
                 */
                if (map != NULL)
                        slot = execute_attr_map_slot(map, slot,
-                                                                                MakeTupleTableSlot(tupdesc));
+                                                                                MakeTupleTableSlot(tupdesc, &TTSOpsVirtual));
        }
 
        insertedCols = GetInsertedColumns(resultRelInfo, estate);
@@ -2009,7 +2011,7 @@ ExecConstraints(ResultRelInfo *resultRelInfo,
                                         */
                                        if (map != NULL)
                                                slot = execute_attr_map_slot(map, slot,
-                                                                                                        MakeTupleTableSlot(tupdesc));
+                                                                                                        MakeTupleTableSlot(tupdesc, &TTSOpsVirtual));
                                }
 
                                insertedCols = GetInsertedColumns(resultRelInfo, estate);
@@ -2059,7 +2061,7 @@ ExecConstraints(ResultRelInfo *resultRelInfo,
                                 */
                                if (map != NULL)
                                        slot = execute_attr_map_slot(map, slot,
-                                                                                                MakeTupleTableSlot(tupdesc));
+                                                                                                MakeTupleTableSlot(tupdesc, &TTSOpsVirtual));
                        }
 
                        insertedCols = GetInsertedColumns(resultRelInfo, estate);
@@ -2167,7 +2169,7 @@ ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo,
                                                 */
                                                if (map != NULL)
                                                        slot = execute_attr_map_slot(map, slot,
-                                                                                                                MakeTupleTableSlot(tupdesc));
+                                                                                                                MakeTupleTableSlot(tupdesc, &TTSOpsVirtual));
                                        }
 
                                        insertedCols = GetInsertedColumns(resultRelInfo, estate);
index 45fc75937ab42492a3f4cdf2d384b5f9af1bbc01..e11fe68712175ca9073ac71f4fb876c7dbf9b2b5 100644 (file)
@@ -144,7 +144,8 @@ ExecSetupPartitionTupleRouting(ModifyTableState *mtstate, Relation rel)
                 * We need an additional tuple slot for storing transient tuples that
                 * are converted to the root table descriptor.
                 */
-               proute->root_tuple_slot = MakeTupleTableSlot(RelationGetDescr(rel));
+               proute->root_tuple_slot = MakeTupleTableSlot(RelationGetDescr(rel),
+                                                                                                        &TTSOpsHeapTuple);
        }
 
        i = 0;
@@ -740,7 +741,8 @@ ExecInitRoutingInfo(ModifyTableState *mtstate,
                 */
                proute->partition_tuple_slots[partidx] =
                        ExecInitExtraTupleSlot(estate,
-                                                                  RelationGetDescr(partrel));
+                                                                  RelationGetDescr(partrel),
+                                                                  &TTSOpsHeapTuple);
        }
 
        /*
@@ -974,7 +976,7 @@ get_partition_dispatch_recurse(Relation rel, Relation parent,
                 * using the correct tuple descriptor when computing its partition key
                 * for tuple routing.
                 */
-               pd->tupslot = MakeSingleTupleTableSlot(tupdesc);
+               pd->tupslot = MakeSingleTupleTableSlot(tupdesc, &TTSOpsHeapTuple);
                pd->tupmap = convert_tuples_by_name_map_if_req(RelationGetDescr(parent),
                                                                                                           tupdesc,
                                                                                                           gettext_noop("could not convert row type"));
index 3bffb0ea71f38375cc1ee5e0b77f5caafd24d0b8..248283f25438bbf1d9776a0bbd37029f720557a0 100644 (file)
@@ -873,7 +873,8 @@ ExecPrepareTuplestoreResult(SetExprState *sexpr,
                        slotDesc = NULL;        /* keep compiler quiet */
                }
 
-               sexpr->funcResultSlot = MakeSingleTupleTableSlot(slotDesc);
+               sexpr->funcResultSlot = MakeSingleTupleTableSlot(slotDesc,
+                                                                                                                &TTSOpsMinimalTuple);
                MemoryContextSwitchTo(oldcontext);
        }
 
index 391db672d1d6b5d2bb82d9a59cbcf3f51e19594a..2cd7e5c86698728a5207bf82f3935f0cf10b00b5 100644 (file)
@@ -73,6 +73,12 @@ static TupleDesc ExecTypeFromTLInternal(List *targetList,
                                           bool hasoid, bool skipjunk);
 
 
+const TupleTableSlotOps TTSOpsVirtual;
+const TupleTableSlotOps TTSOpsHeapTuple;
+const TupleTableSlotOps TTSOpsMinimalTuple;
+const TupleTableSlotOps TTSOpsBufferTuple;
+
+
 /* ----------------------------------------------------------------
  *                               tuple table create/delete functions
  * ----------------------------------------------------------------
@@ -87,7 +93,8 @@ static TupleDesc ExecTypeFromTLInternal(List *targetList,
  * --------------------------------
  */
 TupleTableSlot *
-MakeTupleTableSlot(TupleDesc tupleDesc)
+MakeTupleTableSlot(TupleDesc tupleDesc,
+                                  const TupleTableSlotOps *tts_ops)
 {
        Size            sz;
        TupleTableSlot *slot;
@@ -104,6 +111,8 @@ MakeTupleTableSlot(TupleDesc tupleDesc)
                sz = sizeof(TupleTableSlot);
 
        slot = palloc0(sz);
+       /* const for optimization purposes, OK to modify at allocation time */
+       *((const TupleTableSlotOps **) &slot->tts_ops) = tts_ops;
        slot->type = T_TupleTableSlot;
        slot->tts_flags |= TTS_FLAG_EMPTY;
        if (tupleDesc != NULL)
@@ -140,9 +149,10 @@ MakeTupleTableSlot(TupleDesc tupleDesc)
  * --------------------------------
  */
 TupleTableSlot *
-ExecAllocTableSlot(List **tupleTable, TupleDesc desc)
+ExecAllocTableSlot(List **tupleTable, TupleDesc desc,
+                                  const TupleTableSlotOps *tts_ops)
 {
-       TupleTableSlot *slot = MakeTupleTableSlot(desc);
+       TupleTableSlot *slot = MakeTupleTableSlot(desc, tts_ops);
 
        *tupleTable = lappend(*tupleTable, slot);
 
@@ -198,16 +208,17 @@ ExecResetTupleTable(List *tupleTable,     /* tuple table */
 /* --------------------------------
  *             MakeSingleTupleTableSlot
  *
- *             This is a convenience routine for operations that need a
- *             standalone TupleTableSlot not gotten from the main executor
- *             tuple table.  It makes a single slot and initializes it
- *             to use the given tuple descriptor.
+ *             This is a convenience routine for operations that need a standalone
+ *             TupleTableSlot not gotten from the main executor tuple table.  It makes
+ *             a single slot of given TupleTableSlotType and initializes it to use the
+ *             given tuple descriptor.
  * --------------------------------
  */
 TupleTableSlot *
-MakeSingleTupleTableSlot(TupleDesc tupdesc)
+MakeSingleTupleTableSlot(TupleDesc tupdesc,
+                                                const TupleTableSlotOps *tts_ops)
 {
-       TupleTableSlot *slot = MakeTupleTableSlot(tupdesc);
+       TupleTableSlot *slot = MakeTupleTableSlot(tupdesc, tts_ops);
 
        return slot;
 }
@@ -964,13 +975,17 @@ ExecInitResultTypeTL(PlanState *planstate)
  * ----------------
  */
 void
-ExecInitResultSlot(PlanState *planstate)
+ExecInitResultSlot(PlanState *planstate, const TupleTableSlotOps *tts_ops)
 {
        TupleTableSlot *slot;
 
        slot = ExecAllocTableSlot(&planstate->state->es_tupleTable,
-                                                         planstate->ps_ResultTupleDesc);
+                                                         planstate->ps_ResultTupleDesc, tts_ops);
        planstate->ps_ResultTupleSlot = slot;
+
+       planstate->resultopsfixed = planstate->ps_ResultTupleDesc != NULL;
+       planstate->resultops = tts_ops;
+       planstate->resultopsset = true;
 }
 
 /* ----------------
@@ -980,10 +995,11 @@ ExecInitResultSlot(PlanState *planstate)
  * ----------------
  */
 void
-ExecInitResultTupleSlotTL(PlanState *planstate)
+ExecInitResultTupleSlotTL(PlanState *planstate,
+                                                 const TupleTableSlotOps *tts_ops)
 {
        ExecInitResultTypeTL(planstate);
-       ExecInitResultSlot(planstate);
+       ExecInitResultSlot(planstate, tts_ops);
 }
 
 /* ----------------
@@ -991,11 +1007,15 @@ ExecInitResultTupleSlotTL(PlanState *planstate)
  * ----------------
  */
 void
-ExecInitScanTupleSlot(EState *estate, ScanState *scanstate, TupleDesc tupledesc)
+ExecInitScanTupleSlot(EState *estate, ScanState *scanstate,
+                                         TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
 {
        scanstate->ss_ScanTupleSlot = ExecAllocTableSlot(&estate->es_tupleTable,
-                                                                                                        tupledesc);
+                                                                                                        tupledesc, tts_ops);
        scanstate->ps.scandesc = tupledesc;
+       scanstate->ps.scanopsfixed = tupledesc != NULL;
+       scanstate->ps.scanops = tts_ops;
+       scanstate->ps.scanopsset = true;
 }
 
 /* ----------------
@@ -1007,9 +1027,11 @@ ExecInitScanTupleSlot(EState *estate, ScanState *scanstate, TupleDesc tupledesc)
  * ----------------
  */
 TupleTableSlot *
-ExecInitExtraTupleSlot(EState *estate, TupleDesc tupledesc)
+ExecInitExtraTupleSlot(EState *estate,
+                                          TupleDesc tupledesc,
+                                          const TupleTableSlotOps *tts_ops)
 {
-       return ExecAllocTableSlot(&estate->es_tupleTable, tupledesc);
+       return ExecAllocTableSlot(&estate->es_tupleTable, tupledesc, tts_ops);
 }
 
 /* ----------------
@@ -1021,9 +1043,10 @@ ExecInitExtraTupleSlot(EState *estate, TupleDesc tupledesc)
  * ----------------
  */
 TupleTableSlot *
-ExecInitNullTupleSlot(EState *estate, TupleDesc tupType)
+ExecInitNullTupleSlot(EState *estate, TupleDesc tupType,
+                                         const TupleTableSlotOps *tts_ops)
 {
-       TupleTableSlot *slot = ExecInitExtraTupleSlot(estate, tupType);
+       TupleTableSlot *slot = ExecInitExtraTupleSlot(estate, tupType, tts_ops);
 
        return ExecStoreAllNullTuple(slot);
 }
@@ -1547,13 +1570,15 @@ HeapTupleHeaderGetDatum(HeapTupleHeader tuple)
  * table function capability. Currently used by EXPLAIN and SHOW ALL.
  */
 TupOutputState *
-begin_tup_output_tupdesc(DestReceiver *dest, TupleDesc tupdesc)
+begin_tup_output_tupdesc(DestReceiver *dest,
+                                                TupleDesc tupdesc,
+                                                const TupleTableSlotOps *tts_ops)
 {
        TupOutputState *tstate;
 
        tstate = (TupOutputState *) palloc(sizeof(TupOutputState));
 
-       tstate->slot = MakeSingleTupleTableSlot(tupdesc);
+       tstate->slot = MakeSingleTupleTableSlot(tupdesc, tts_ops);
        tstate->dest = dest;
 
        tstate->dest->rStartup(tstate->dest, (int) CMD_SELECT, tupdesc);
index f9e7bb479f1c73ca192efed65f36280c6a0af9d2..f39be12c54dfa7e979682076d255a55090322713 100644 (file)
@@ -454,6 +454,35 @@ ExecGetResultType(PlanState *planstate)
        return planstate->ps_ResultTupleDesc;
 }
 
+/*
+ * ExecGetResultSlotOps - information about node's type of result slot
+ */
+const TupleTableSlotOps *
+ExecGetResultSlotOps(PlanState *planstate, bool *isfixed)
+{
+       if (planstate->resultopsset && planstate->resultops)
+       {
+               if (isfixed)
+                       *isfixed = planstate->resultopsfixed;
+               return planstate->resultops;
+       }
+
+       if (isfixed)
+       {
+               if (planstate->resultopsset)
+                       *isfixed = planstate->resultopsfixed;
+               else if (planstate->ps_ResultTupleSlot)
+                       *isfixed = TTS_FIXED(planstate->ps_ResultTupleSlot);
+               else
+                       *isfixed = false;
+       }
+
+       if (!planstate->ps_ResultTupleSlot)
+               return &TTSOpsVirtual;
+
+       return planstate->ps_ResultTupleSlot->tts_ops;
+}
+
 
 /* ----------------
  *             ExecAssignProjectionInfo
@@ -492,11 +521,21 @@ ExecConditionalAssignProjectionInfo(PlanState *planstate, TupleDesc inputDesc,
                                                          planstate->plan->targetlist,
                                                          varno,
                                                          inputDesc))
+       {
                planstate->ps_ProjInfo = NULL;
+               planstate->resultopsset = planstate->scanopsset;
+               planstate->resultopsfixed = planstate->scanopsfixed;
+               planstate->resultops = planstate->scanops;
+       }
        else
        {
                if (!planstate->ps_ResultTupleSlot)
-                       ExecInitResultSlot(planstate);
+               {
+                       ExecInitResultSlot(planstate, &TTSOpsVirtual);
+                       planstate->resultops = &TTSOpsVirtual;
+                       planstate->resultopsfixed = true;
+                       planstate->resultopsset = true;
+               }
                ExecAssignProjectionInfo(planstate, inputDesc);
        }
 }
@@ -611,7 +650,9 @@ ExecAssignScanType(ScanState *scanstate, TupleDesc tupDesc)
  * ----------------
  */
 void
-ExecCreateScanSlotFromOuterPlan(EState *estate, ScanState *scanstate)
+ExecCreateScanSlotFromOuterPlan(EState *estate,
+                                                               ScanState *scanstate,
+                                                               const TupleTableSlotOps *tts_ops)
 {
        PlanState  *outerPlan;
        TupleDesc       tupDesc;
@@ -619,7 +660,7 @@ ExecCreateScanSlotFromOuterPlan(EState *estate, ScanState *scanstate)
        outerPlan = outerPlanState(scanstate);
        tupDesc = ExecGetResultType(outerPlan);
 
-       ExecInitScanTupleSlot(estate, scanstate, tupDesc);
+       ExecInitScanTupleSlot(estate, scanstate, tupDesc, tts_ops);
 }
 
 /* ----------------------------------------------------------------
index f4dd5732198bb55581c9af056155eee25a14ad79..ae5c7c5490b436f4df2d1f4e929ae938a67496b2 100644 (file)
@@ -1717,7 +1717,8 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
 
                /* Set up junk filter if needed */
                if (junkFilter)
-                       *junkFilter = ExecInitJunkFilter(tlist, false, NULL);
+                       *junkFilter = ExecInitJunkFilter(tlist, false,
+                                                                                        MakeSingleTupleTableSlot(NULL, &TTSOpsMinimalTuple));
        }
        else if (fn_typtype == TYPTYPE_COMPOSITE || rettype == RECORDOID)
        {
@@ -1770,7 +1771,12 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
                                }
                                /* Set up junk filter if needed */
                                if (junkFilter)
-                                       *junkFilter = ExecInitJunkFilter(tlist, false, NULL);
+                               {
+                                       TupleTableSlot *slot =
+                                               MakeSingleTupleTableSlot(NULL, &TTSOpsMinimalTuple);
+
+                                       *junkFilter = ExecInitJunkFilter(tlist, false, slot);
+                               }
                                return false;   /* NOT returning whole tuple */
                        }
                }
@@ -1786,7 +1792,12 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
                         * what the caller expects will happen at runtime.
                         */
                        if (junkFilter)
-                               *junkFilter = ExecInitJunkFilter(tlist, false, NULL);
+                       {
+                               TupleTableSlot *slot;
+
+                               slot = MakeSingleTupleTableSlot(NULL, &TTSOpsMinimalTuple);
+                               *junkFilter = ExecInitJunkFilter(tlist, false, slot);
+                       }
                        return true;
                }
                Assert(tupdesc);
@@ -1927,9 +1938,14 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
 
                /* Set up junk filter if needed */
                if (junkFilter)
+               {
+                       TupleTableSlot *slot =
+                               MakeSingleTupleTableSlot(NULL, &TTSOpsMinimalTuple);
+
                        *junkFilter = ExecInitJunkFilterConversion(tlist,
                                                                                                           CreateTupleDescCopy(tupdesc),
-                                                                                                          NULL);
+                                                                                                          slot);
+               }
 
                /* Report that we are returning entire tuple result */
                return true;
index 85f1ec7140f9bd6b1e0a27a54eb5f1378a23bb83..20d6d8e9cbba70369c97ca65355656af4d901da2 100644 (file)
@@ -1403,7 +1403,8 @@ find_hash_columns(AggState *aggstate)
                                                          &perhash->eqfuncoids,
                                                          &perhash->hashfunctions);
                perhash->hashslot =
-                       ExecAllocTableSlot(&estate->es_tupleTable, hashDesc);
+                       ExecAllocTableSlot(&estate->es_tupleTable, hashDesc,
+                                                          &TTSOpsMinimalTuple);
 
                list_free(hashTlist);
                bms_free(colnos);
@@ -2211,15 +2212,17 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
        /*
         * initialize source tuple type.
         */
-       ExecCreateScanSlotFromOuterPlan(estate, &aggstate->ss);
+       ExecCreateScanSlotFromOuterPlan(estate, &aggstate->ss,
+                                                                       ExecGetResultSlotOps(outerPlanState(&aggstate->ss), NULL));
        scanDesc = aggstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor;
        if (node->chain)
-               aggstate->sort_slot = ExecInitExtraTupleSlot(estate, scanDesc);
+               aggstate->sort_slot = ExecInitExtraTupleSlot(estate, scanDesc,
+                                                                                                        &TTSOpsMinimalTuple);
 
        /*
         * Initialize result type, slot and projection.
         */
-       ExecInitResultTupleSlotTL(&aggstate->ss.ps);
+       ExecInitResultTupleSlotTL(&aggstate->ss.ps, &TTSOpsVirtual);
        ExecAssignProjectionInfo(&aggstate->ss.ps, NULL);
 
        /*
@@ -3062,7 +3065,8 @@ build_pertrans_for_aggref(AggStatePerTrans pertrans,
        {
                pertrans->sortdesc = ExecTypeFromTL(aggref->args, false);
                pertrans->sortslot =
-                       ExecInitExtraTupleSlot(estate, pertrans->sortdesc);
+                       ExecInitExtraTupleSlot(estate, pertrans->sortdesc,
+                                                                  &TTSOpsMinimalTuple);
        }
 
        if (numSortCols > 0)
@@ -3084,7 +3088,8 @@ build_pertrans_for_aggref(AggStatePerTrans pertrans,
                {
                        /* we will need an extra slot to store prior values */
                        pertrans->uniqslot =
-                               ExecInitExtraTupleSlot(estate, pertrans->sortdesc);
+                               ExecInitExtraTupleSlot(estate, pertrans->sortdesc,
+                                                                          &TTSOpsMinimalTuple);
                }
 
                /* Extract the sort information for use later */
index 94a17c7c67c530660ac7b19e8c08b1c27b1a34f2..8c4abe128825cd904cdf6092b2e2d57afeb1b02d 100644 (file)
@@ -196,7 +196,11 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
        /*
         * Initialize result tuple type and slot.
         */
-       ExecInitResultTupleSlotTL(&appendstate->ps);
+       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 *));
index c153d74f411702526086335312db80aef7940653..1c27bfc412cc27080f1d10c9fb8483b03820c40a 100644 (file)
@@ -913,7 +913,8 @@ ExecInitBitmapHeapScan(BitmapHeapScan *node, EState *estate, int eflags)
         * get the scan type from the relation descriptor.
         */
        ExecInitScanTupleSlot(estate, &scanstate->ss,
-                                                 RelationGetDescr(currentRelation));
+                                                 RelationGetDescr(currentRelation),
+                                                 &TTSOpsBufferTuple);
 
 
        /*
index 017b8772775fbff72c61ee520f0a47a75b816ff6..133aaf2d3b758b9d22784879b3b31cf3cf1b2e07 100644 (file)
@@ -260,7 +260,8 @@ ExecInitCteScan(CteScan *node, EState *estate, int eflags)
         * table) is the same as the result rowtype of the CTE query.
         */
        ExecInitScanTupleSlot(estate, &scanstate->ss,
-                                                 ExecGetResultType(scanstate->cteplanstate));
+                                                 ExecGetResultType(scanstate->cteplanstate),
+                                                 &TTSOpsMinimalTuple);
 
        /*
         * Initialize result type and projection.
index ab3e34790e87eedf1562b3b84b8f2bc751c7af23..a2e67074a87ecde846300b89a96b381a209778b6 100644 (file)
@@ -73,13 +73,14 @@ ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags)
                TupleDesc       scan_tupdesc;
 
                scan_tupdesc = ExecTypeFromTL(cscan->custom_scan_tlist, false);
-               ExecInitScanTupleSlot(estate, &css->ss, scan_tupdesc);
+               ExecInitScanTupleSlot(estate, &css->ss, scan_tupdesc, &TTSOpsVirtual);
                /* Node's targetlist will contain Vars with varno = INDEX_VAR */
                tlistvarno = INDEX_VAR;
        }
        else
        {
-               ExecInitScanTupleSlot(estate, &css->ss, RelationGetDescr(scan_rel));
+               ExecInitScanTupleSlot(estate, &css->ss, RelationGetDescr(scan_rel),
+                                                         &TTSOpsVirtual);
                /* Node's targetlist will contain Vars with varno = scanrelid */
                tlistvarno = scanrelid;
        }
@@ -87,7 +88,7 @@ ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags)
        /*
         * Initialize result slot, type and projection.
         */
-       ExecInitResultTupleSlotTL(&css->ss.ps);
+       ExecInitResultTupleSlotTL(&css->ss.ps, &TTSOpsVirtual);
        ExecAssignScanProjectionInfoWithVarno(&css->ss, tlistvarno);
 
        /* initialize child expressions */
index f7eef32f6fef7b53e768f4553228cddebd3e38ef..a2ab2d265b3e72ee61eb228fffdf5cb1761ff4da 100644 (file)
@@ -180,7 +180,8 @@ ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags)
                TupleDesc       scan_tupdesc;
 
                scan_tupdesc = ExecTypeFromTL(node->fdw_scan_tlist, false);
-               ExecInitScanTupleSlot(estate, &scanstate->ss, scan_tupdesc);
+               ExecInitScanTupleSlot(estate, &scanstate->ss, scan_tupdesc,
+                                                         &TTSOpsHeapTuple);
                /* Node's targetlist will contain Vars with varno = INDEX_VAR */
                tlistvarno = INDEX_VAR;
        }
@@ -190,11 +191,16 @@ ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags)
 
                /* don't trust FDWs to return tuples fulfilling NOT NULL constraints */
                scan_tupdesc = CreateTupleDescCopy(RelationGetDescr(currentRelation));
-               ExecInitScanTupleSlot(estate, &scanstate->ss, scan_tupdesc);
+               ExecInitScanTupleSlot(estate, &scanstate->ss, scan_tupdesc,
+                                                         &TTSOpsHeapTuple);
                /* Node's targetlist will contain Vars with varno = scanrelid */
                tlistvarno = scanrelid;
        }
 
+       /* Don't know what an FDW might return */
+       scanstate->ss.ps.scanopsfixed = false;
+       scanstate->ss.ps.scanopsset = true;
+
        /*
         * Initialize result slot, type and projection.
         */
index 0596adbb2f1939714eada44fba6768fd2d19a250..b6a1fa1456060c720d8c898033eec2ca9cc329a3 100644 (file)
@@ -424,7 +424,8 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags)
                 */
                if (!scanstate->simple)
                {
-                       fs->func_slot = ExecInitExtraTupleSlot(estate, fs->tupdesc);
+                       fs->func_slot = ExecInitExtraTupleSlot(estate, fs->tupdesc,
+                                                                                                  &TTSOpsMinimalTuple);
                }
                else
                        fs->func_slot = NULL;
@@ -482,7 +483,8 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags)
        /*
         * Initialize scan slot and type.
         */
-       ExecInitScanTupleSlot(estate, &scanstate->ss, scan_tupdesc);
+       ExecInitScanTupleSlot(estate, &scanstate->ss, scan_tupdesc,
+                                                 &TTSOpsMinimalTuple);
 
        /*
         * Initialize result slot, type and projection.
index afddb0a039485f8343ba120264e351750983e846..e45e07f0a1a628d102e7d3bd4f935e90528f3c4f 100644 (file)
@@ -91,6 +91,11 @@ ExecInitGather(Gather *node, EState *estate, int eflags)
        outerPlanState(gatherstate) = ExecInitNode(outerNode, estate, eflags);
        tupDesc = ExecGetResultType(outerPlanState(gatherstate));
 
+       /* this node uses tuples from the tuple queue as scan slot */
+       gatherstate->ps.scanops = &TTSOpsHeapTuple;
+       gatherstate->ps.scanopsfixed = true;
+       gatherstate->ps.scanopsset = true;
+
        /*
         * Initialize result type and projection.
         */
@@ -100,7 +105,8 @@ ExecInitGather(Gather *node, EState *estate, int eflags)
        /*
         * Initialize funnel slot to same tuple descriptor as outer plan.
         */
-       gatherstate->funnel_slot = ExecInitExtraTupleSlot(estate, tupDesc);
+       gatherstate->funnel_slot = ExecInitExtraTupleSlot(estate, tupDesc,
+                                                                                                         &TTSOpsHeapTuple);
 
        /*
         * Gather doesn't support checking a qual (it's always more efficient to
index 7ae067f9ebf381f28890dfc9dcccefdc574d4d0f..651565123befdbc558e3176f84423797241e9b07 100644 (file)
@@ -122,6 +122,13 @@ ExecInitGatherMerge(GatherMerge *node, EState *estate, int eflags)
        ExecInitResultTypeTL(&gm_state->ps);
        ExecConditionalAssignProjectionInfo(&gm_state->ps, tupDesc, OUTER_VAR);
 
+       /* leader accesses ExecProcNode result directly, others go through tuple queue */
+       if (gm_state->ps.ps_ProjInfo == NULL)
+       {
+               gm_state->ps.resultopsset = true;
+               gm_state->ps.resultopsfixed = false;
+       }
+
        /*
         * initialize sort-key information
         */
@@ -404,7 +411,8 @@ gather_merge_setup(GatherMergeState *gm_state)
 
                /* Initialize tuple slot for worker */
                gm_state->gm_slots[i + 1] =
-                       ExecInitExtraTupleSlot(gm_state->ps.state, gm_state->tupDesc);
+                       ExecInitExtraTupleSlot(gm_state->ps.state, gm_state->tupDesc,
+                                                                  &TTSOpsHeapTuple);
        }
 
        /* Allocate the resources for the merge */
index 9c1e51bc9548092d4328ee9b637b488be190d9d0..58e0b10cd161fbdf75d7cdc143a24bd6861ad9b1 100644 (file)
@@ -162,6 +162,7 @@ GroupState *
 ExecInitGroup(Group *node, EState *estate, int eflags)
 {
        GroupState *grpstate;
+       const TupleTableSlotOps *tts_ops;
 
        /* check for unsupported flags */
        Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
@@ -188,12 +189,13 @@ ExecInitGroup(Group *node, EState *estate, int eflags)
        /*
         * Initialize scan slot and type.
         */
-       ExecCreateScanSlotFromOuterPlan(estate, &grpstate->ss);
+       tts_ops = ExecGetResultSlotOps(outerPlanState(&grpstate->ss), NULL);
+       ExecCreateScanSlotFromOuterPlan(estate, &grpstate->ss, tts_ops);
 
        /*
         * Initialize result slot, type and projection.
         */
-       ExecInitResultTupleSlotTL(&grpstate->ss.ps);
+       ExecInitResultTupleSlotTL(&grpstate->ss.ps, &TTSOpsVirtual);
        ExecAssignProjectionInfo(&grpstate->ss.ps, NULL);
 
        /*
index 5a9f1ea3c550faaabb2e85df6599c2f5d50fee72..ba2f6686cf6ce2a6e1eb209e268317c0326b50cf 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(&hashstate->ps);
+       ExecInitResultTupleSlotTL(&hashstate->ps, &TTSOpsMinimalTuple);
        hashstate->ps.ps_ProjInfo = NULL;
 
        /*
index d6a6ef770dd201b2471f23f4e75d1c4eca244b3d..c78b92d8a6068717453eb85bd780791fa1663e08 100644 (file)
@@ -606,6 +606,7 @@ ExecInitHashJoin(HashJoin *node, EState *estate, int eflags)
        TupleDesc       outerDesc,
                                innerDesc;
        ListCell   *l;
+       const TupleTableSlotOps *ops;
 
        /* check for unsupported flags */
        Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
@@ -650,13 +651,15 @@ ExecInitHashJoin(HashJoin *node, EState *estate, int eflags)
        /*
         * Initialize result slot, type and projection.
         */
-       ExecInitResultTupleSlotTL(&hjstate->js.ps);
+       ExecInitResultTupleSlotTL(&hjstate->js.ps, &TTSOpsVirtual);
        ExecAssignProjectionInfo(&hjstate->js.ps, NULL);
 
        /*
         * tuple table initialization
         */
-       hjstate->hj_OuterTupleSlot = ExecInitExtraTupleSlot(estate, outerDesc);
+       ops = ExecGetResultSlotOps(outerPlanState(hjstate), NULL);
+       hjstate->hj_OuterTupleSlot = ExecInitExtraTupleSlot(estate, outerDesc,
+                                                                                                               ops);
 
        /*
         * detect whether we need only consider the first matching inner tuple
@@ -673,17 +676,17 @@ ExecInitHashJoin(HashJoin *node, EState *estate, int eflags)
                case JOIN_LEFT:
                case JOIN_ANTI:
                        hjstate->hj_NullInnerTupleSlot =
-                               ExecInitNullTupleSlot(estate, innerDesc);
+                               ExecInitNullTupleSlot(estate, innerDesc, &TTSOpsVirtual);
                        break;
                case JOIN_RIGHT:
                        hjstate->hj_NullOuterTupleSlot =
-                               ExecInitNullTupleSlot(estate, outerDesc);
+                               ExecInitNullTupleSlot(estate, outerDesc, &TTSOpsVirtual);
                        break;
                case JOIN_FULL:
                        hjstate->hj_NullOuterTupleSlot =
-                               ExecInitNullTupleSlot(estate, outerDesc);
+                               ExecInitNullTupleSlot(estate, outerDesc, &TTSOpsVirtual);
                        hjstate->hj_NullInnerTupleSlot =
-                               ExecInitNullTupleSlot(estate, innerDesc);
+                               ExecInitNullTupleSlot(estate, innerDesc, &TTSOpsVirtual);
                        break;
                default:
                        elog(ERROR, "unrecognized join type: %d",
index 865a056c02787582616895f23fca24fa6555c3dc..4e5e52cec3b37eda2c04d097db9725251dacc186 100644 (file)
@@ -527,7 +527,7 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
         * suitable data anyway.)
         */
        tupDesc = ExecTypeFromTL(node->indextlist, false);
-       ExecInitScanTupleSlot(estate, &indexstate->ss, tupDesc);
+       ExecInitScanTupleSlot(estate, &indexstate->ss, tupDesc, &TTSOpsHeapTuple);
 
        /*
         * Initialize result type and projection info.  The node's targetlist will
index 8593c0e3050f36bb1becee767cf82d1b23cd3a70..479cbf9df4fcc1c141d24c0b5318cfac5c9dbcf9 100644 (file)
@@ -208,8 +208,6 @@ IndexNextWithReorder(IndexScanState *node)
 
        scandesc = node->iss_ScanDesc;
        econtext = node->ss.ps.ps_ExprContext;
-       slot = node->ss.ss_ScanTupleSlot;
-
        if (scandesc == NULL)
        {
                /*
@@ -245,6 +243,7 @@ IndexNextWithReorder(IndexScanState *node)
                 */
                if (!pairingheap_is_empty(node->iss_ReorderQueue))
                {
+                       slot = node->iss_ReorderQueueSlot;
                        topmost = (ReorderTuple *) pairingheap_first(node->iss_ReorderQueue);
 
                        if (node->iss_ReachedEnd ||
@@ -264,13 +263,15 @@ IndexNextWithReorder(IndexScanState *node)
                else if (node->iss_ReachedEnd)
                {
                        /* Queue is empty, and no more tuples from index.  We're done. */
-                       return ExecClearTuple(slot);
+                       ExecClearTuple(node->iss_ReorderQueueSlot);
+                       return ExecClearTuple(node->ss.ss_ScanTupleSlot);
                }
 
                /*
                 * Fetch next tuple from the index.
                 */
 next_indextuple:
+               slot = node->ss.ss_ScanTupleSlot;
                tuple = index_getnext(scandesc, ForwardScanDirection);
                if (!tuple)
                {
@@ -372,7 +373,8 @@ next_indextuple:
         * if we get here it means the index scan failed so we are at the end of
         * the scan..
         */
-       return ExecClearTuple(slot);
+       ExecClearTuple(node->iss_ReorderQueueSlot);
+       return ExecClearTuple(node->ss.ss_ScanTupleSlot);
 }
 
 /*
@@ -824,6 +826,8 @@ ExecEndIndexScan(IndexScanState *node)
         */
        if (node->ss.ps.ps_ResultTupleSlot)
                ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
+       if (node->iss_ReorderQueueSlot)
+               ExecClearTuple(node->iss_ReorderQueueSlot);
        ExecClearTuple(node->ss.ss_ScanTupleSlot);
 
        /*
@@ -945,7 +949,8 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
         * get the scan type from the relation descriptor.
         */
        ExecInitScanTupleSlot(estate, &indexstate->ss,
-                                                 RelationGetDescr(currentRelation));
+                                                 RelationGetDescr(currentRelation),
+                                                 &TTSOpsBufferTuple);
 
        /*
         * Initialize result type and projection.
@@ -1076,9 +1081,13 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
                indexstate->iss_OrderByNulls = (bool *)
                        palloc(numOrderByKeys * sizeof(bool));
 
-               /* and initialize the reorder queue */
+               /* and initialize the reorder queue and the corresponding slot */
                indexstate->iss_ReorderQueue = pairingheap_allocate(reorderqueue_cmp,
                                                                                                                        indexstate);
+               indexstate->iss_ReorderQueueSlot =
+                       ExecAllocTableSlot(&estate->es_tupleTable,
+                                                          RelationGetDescr(currentRelation),
+                                                          &TTSOpsHeapTuple);
        }
 
        /*
index f0b6819140016afaeb77dcb4873d93e36b27ef4f..6792f9e86c70f0639abced3f72e58df729c9d36f 100644 (file)
@@ -380,6 +380,10 @@ ExecInitLimit(Limit *node, EState *estate, int eflags)
         */
        ExecInitResultTypeTL(&limitstate->ps);
 
+       limitstate->ps.resultopsset = true;
+       limitstate->ps.resultops = ExecGetResultSlotOps(outerPlanState(limitstate),
+                                                                                                       &limitstate->ps.resultopsfixed);
+
        /*
         * limit nodes do no projections, so initialize projection info for this
         * node appropriately
index 961798cecb363e13c375053d9619bee2019087e8..7887388b9e9fb3bf2356f09904adc57e7b12f641 100644 (file)
@@ -390,6 +390,11 @@ ExecInitLockRows(LockRows *node, EState *estate, int eflags)
         */
        outerPlanState(lrstate) = ExecInitNode(outerPlan, estate, eflags);
 
+       /* node returns unmodified slots from the outer plan */
+       lrstate->ps.resultopsset = true;
+       lrstate->ps.resultops = ExecGetResultSlotOps(outerPlanState(lrstate),
+                                                                                                       &lrstate->ps.resultopsfixed);
+
        /*
         * LockRows nodes do no projections, so initialize projection info for
         * this node appropriately
index 4ede428f908ba5e123c6135df1ac14739a3573bc..657814cd0db1ba47555a9c92b41d9ef9390682fb 100644 (file)
@@ -146,10 +146,8 @@ ExecMaterial(PlanState *pstate)
                if (tuplestorestate)
                        tuplestore_puttupleslot(tuplestorestate, outerslot);
 
-               /*
-                * We can just return the subplan's returned tuple, without copying.
-                */
-               return outerslot;
+               ExecCopySlot(slot, outerslot);
+               return slot;
        }
 
        /*
@@ -223,13 +221,13 @@ ExecInitMaterial(Material *node, EState *estate, int eflags)
         *
         * material nodes only return tuples from their materialized relation.
         */
-       ExecInitResultTupleSlotTL(&matstate->ss.ps);
+       ExecInitResultTupleSlotTL(&matstate->ss.ps, &TTSOpsMinimalTuple);
        matstate->ss.ps.ps_ProjInfo = NULL;
 
        /*
         * initialize tuple type.
         */
-       ExecCreateScanSlotFromOuterPlan(estate, &matstate->ss);
+       ExecCreateScanSlotFromOuterPlan(estate, &matstate->ss, &TTSOpsMinimalTuple);
 
        return matstate;
 }
index dbed667d1647a3c6daf2d7e8947f1422d303abce..188e76b60cd5e54dda991540cf09479f2732804f 100644 (file)
@@ -167,7 +167,11 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
         * MergeAppend nodes do have Result slots, which hold pointers to tuples,
         * so we have to initialize them.  FIXME
         */
-       ExecInitResultTupleSlotTL(&mergestate->ps);
+       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
index 9c978313318bdf64eb06e11d103bf09731dd933a..1c90291d1279f69836c592882d1129b9e09cc850 100644 (file)
@@ -1438,6 +1438,7 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags)
        MergeJoinState *mergestate;
        TupleDesc       outerDesc,
                                innerDesc;
+       const TupleTableSlotOps *innerOps;
 
        /* check for unsupported flags */
        Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
@@ -1512,13 +1513,15 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags)
        /*
         * Initialize result slot, type and projection.
         */
-       ExecInitResultTupleSlotTL(&mergestate->js.ps);
+       ExecInitResultTupleSlotTL(&mergestate->js.ps, &TTSOpsVirtual);
        ExecAssignProjectionInfo(&mergestate->js.ps, NULL);
 
        /*
         * tuple table initialization
         */
-       mergestate->mj_MarkedTupleSlot = ExecInitExtraTupleSlot(estate, innerDesc);
+       innerOps = ExecGetResultSlotOps(innerPlanState(mergestate), NULL);
+       mergestate->mj_MarkedTupleSlot = ExecInitExtraTupleSlot(estate, innerDesc,
+                                                                                                                       innerOps);
 
        /*
         * initialize child expressions
@@ -1548,13 +1551,13 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags)
                        mergestate->mj_FillOuter = true;
                        mergestate->mj_FillInner = false;
                        mergestate->mj_NullInnerTupleSlot =
-                               ExecInitNullTupleSlot(estate, innerDesc);
+                               ExecInitNullTupleSlot(estate, innerDesc, &TTSOpsVirtual);
                        break;
                case JOIN_RIGHT:
                        mergestate->mj_FillOuter = false;
                        mergestate->mj_FillInner = true;
                        mergestate->mj_NullOuterTupleSlot =
-                               ExecInitNullTupleSlot(estate, outerDesc);
+                               ExecInitNullTupleSlot(estate, outerDesc, &TTSOpsVirtual);
 
                        /*
                         * Can't handle right or full join with non-constant extra
@@ -1570,9 +1573,9 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags)
                        mergestate->mj_FillOuter = true;
                        mergestate->mj_FillInner = true;
                        mergestate->mj_NullOuterTupleSlot =
-                               ExecInitNullTupleSlot(estate, outerDesc);
+                               ExecInitNullTupleSlot(estate, outerDesc, &TTSOpsVirtual);
                        mergestate->mj_NullInnerTupleSlot =
-                               ExecInitNullTupleSlot(estate, innerDesc);
+                               ExecInitNullTupleSlot(estate, innerDesc, &TTSOpsVirtual);
 
                        /*
                         * Can't handle right or full join with non-constant extra
index a3ca336f2acdb090c7d5c65b3cc47cfaf9db1437..bb344a7070abcfb42d929da811e001828203953f 100644 (file)
@@ -2055,6 +2055,15 @@ ExecModifyTable(PlanState *pstate)
                                break;
                }
 
+               /*
+                * Ensure input tuple is the right format for the target relation.
+                */
+               if (node->mt_scans[node->mt_whichplan]->tts_ops != planSlot->tts_ops)
+               {
+                       ExecCopySlot(node->mt_scans[node->mt_whichplan], planSlot);
+                       planSlot = node->mt_scans[node->mt_whichplan];
+               }
+
                /*
                 * If resultRelInfo->ri_usesFdwDirectModify is true, all we need to do
                 * here is compute the RETURNING expressions.
@@ -2238,6 +2247,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
 
        mtstate->mt_plans = (PlanState **) palloc0(sizeof(PlanState *) * nplans);
        mtstate->resultRelInfo = estate->es_result_relations + node->resultRelIndex;
+       mtstate->mt_scans = (TupleTableSlot **) palloc0(sizeof(TupleTableSlot *) * nplans);
 
        /* If modifying a partitioned table, initialize the root table info */
        if (node->rootResultRelIndex >= 0)
@@ -2304,6 +2314,9 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
                /* Now init the plan for this result rel */
                estate->es_result_relation_info = resultRelInfo;
                mtstate->mt_plans[i] = ExecInitNode(subplan, estate, eflags);
+               mtstate->mt_scans[i] =
+                       ExecInitExtraTupleSlot(mtstate->ps.state, ExecGetResultType(mtstate->mt_plans[i]),
+                                                                  &TTSOpsHeapTuple);
 
                /* Also let FDWs init themselves for foreign-table result rels */
                if (!resultRelInfo->ri_usesFdwDirectModify &&
@@ -2403,7 +2416,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(&mtstate->ps);
+               ExecInitResultTupleSlotTL(&mtstate->ps, &TTSOpsVirtual);
                slot = mtstate->ps.ps_ResultTupleSlot;
 
                /* Need an econtext too */
@@ -2472,7 +2485,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
                mtstate->mt_existing =
                        ExecInitExtraTupleSlot(mtstate->ps.state,
                                                                   mtstate->mt_partition_tuple_routing ?
-                                                                  NULL : relationDesc);
+                                                                  NULL : relationDesc, &TTSOpsBufferTuple);
 
                /* carried forward solely for the benefit of explain */
                mtstate->mt_excludedtlist = node->exclRelTlist;
@@ -2494,7 +2507,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
                mtstate->mt_conflproj =
                        ExecInitExtraTupleSlot(mtstate->ps.state,
                                                                   mtstate->mt_partition_tuple_routing ?
-                                                                  NULL : tupDesc);
+                                                                  NULL : tupDesc, &TTSOpsHeapTuple);
                resultRelInfo->ri_onConflict->oc_ProjTupdesc = tupDesc;
 
                /* build UPDATE SET projection state */
@@ -2605,7 +2618,8 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
 
                                j = ExecInitJunkFilter(subplan->targetlist,
                                                                           resultRelInfo->ri_RelationDesc->rd_att->tdhasoid,
-                                                                          ExecInitExtraTupleSlot(estate, NULL));
+                                                                          ExecInitExtraTupleSlot(estate, NULL,
+                                                                                                                         &TTSOpsHeapTuple));
 
                                if (operation == CMD_UPDATE || operation == CMD_DELETE)
                                {
@@ -2652,10 +2666,12 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
        /*
         * Set up a tuple table slot for use for trigger output tuples. In a plan
         * containing multiple ModifyTable nodes, all can share one such slot, so
-        * we keep it in the estate.
+        * we keep it in the estate. The tuple being inserted doesn't come from a
+        * buffer.
         */
        if (estate->es_trig_tuple_slot == NULL)
-               estate->es_trig_tuple_slot = ExecInitExtraTupleSlot(estate, NULL);
+               estate->es_trig_tuple_slot = ExecInitExtraTupleSlot(estate, NULL,
+                                                                                                                       &TTSOpsHeapTuple);
 
        /*
         * Lastly, if this is not the primary (canSetTag) ModifyTable node, add it
index cf1b7b4f87266437639f42495402a3612dae90ad..cd8a1fceac562e7e03ddcae3af28cafc2d34b1ef 100644 (file)
@@ -137,7 +137,8 @@ ExecInitNamedTuplestoreScan(NamedTuplestoreScan *node, EState *estate, int eflag
        /*
         * The scan tuple type is specified for the tuplestore.
         */
-       ExecInitScanTupleSlot(estate, &scanstate->ss, scanstate->tupdesc);
+       ExecInitScanTupleSlot(estate, &scanstate->ss, scanstate->tupdesc,
+                                                 &TTSOpsMinimalTuple);
 
        /*
         * Initialize result type and projection.
index 8dbec685eb1a3d511ea371cf80207fed06df7b8b..0cb6f9dd4cd8ef1fec4e847c738b5ec2eb7c0e26 100644 (file)
@@ -304,7 +304,7 @@ ExecInitNestLoop(NestLoop *node, EState *estate, int eflags)
        /*
         * Initialize result slot, type and projection.
         */
-       ExecInitResultTupleSlotTL(&nlstate->js.ps);
+       ExecInitResultTupleSlotTL(&nlstate->js.ps, &TTSOpsVirtual);
        ExecAssignProjectionInfo(&nlstate->js.ps, NULL);
 
        /*
@@ -332,7 +332,8 @@ ExecInitNestLoop(NestLoop *node, EState *estate, int eflags)
                case JOIN_ANTI:
                        nlstate->nl_NullInnerTupleSlot =
                                ExecInitNullTupleSlot(estate,
-                                                                         ExecGetResultType(innerPlanState(nlstate)));
+                                                                         ExecGetResultType(innerPlanState(nlstate)),
+                                                                         &TTSOpsVirtual);
                        break;
                default:
                        elog(ERROR, "unrecognized join type: %d",
index e4dd4142177677179ddd099d345ece6615544299..06a7da8f77e9ff39cfd9c95d2ef844305f4da4ff 100644 (file)
@@ -256,7 +256,7 @@ ExecInitProjectSet(ProjectSet *node, EState *estate, int eflags)
        /*
         * tuple table and result type initialization
         */
-       ExecInitResultTupleSlotTL(&state->ps);
+       ExecInitResultTupleSlotTL(&state->ps, &TTSOpsVirtual);
 
        /* Create workspace for per-tlist-entry expr state & SRF-is-done state */
        state->nelems = list_length(node->plan.targetlist);
index 2bbb2e788480293b0ef7a5ae34f13b5856e83237..63428c7ffe02ecaca2b3296674c2145f5114f90e 100644 (file)
@@ -217,7 +217,7 @@ ExecInitResult(Result *node, EState *estate, int eflags)
        /*
         * Initialize result slot, type and projection.
         */
-       ExecInitResultTupleSlotTL(&resstate->ps);
+       ExecInitResultTupleSlotTL(&resstate->ps, &TTSOpsVirtual);
        ExecAssignProjectionInfo(&resstate->ps, NULL);
 
        /*
index cfa26535d7b42b985c99f0cd90f44ccf4588ed3f..55e7bd2f6cf836a92f4bd7a6d16aba3e11c6fcf0 100644 (file)
@@ -146,7 +146,8 @@ ExecInitSampleScan(SampleScan *node, EState *estate, int eflags)
 
        /* and create slot with appropriate rowtype */
        ExecInitScanTupleSlot(estate, &scanstate->ss,
-                                                 RelationGetDescr(scanstate->ss.ss_currentRelation));
+                                                 RelationGetDescr(scanstate->ss.ss_currentRelation),
+                                                 &TTSOpsBufferTuple);
 
        /*
         * Initialize result type and projection.
index b4bea67610f1dfec6511ab6290d1f2409bb73d12..307ad9ccd53e972cc966499723c262bbf32ba9c6 100644 (file)
@@ -172,7 +172,8 @@ ExecInitSeqScan(SeqScan *node, EState *estate, int eflags)
 
        /* and create slot with the appropriate rowtype */
        ExecInitScanTupleSlot(estate, &scanstate->ss,
-                                                 RelationGetDescr(scanstate->ss.ss_currentRelation));
+                                                 RelationGetDescr(scanstate->ss.ss_currentRelation),
+                                                 &TTSOpsBufferTuple);
 
        /*
         * Initialize result type and projection.
index 46bf77775c479e9a222936c99934bb6c5853e21f..44c43e99a027799071c74c08cb982ee025424b7c 100644 (file)
@@ -532,7 +532,9 @@ 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(&setopstate->ps);
+       ExecInitResultTupleSlotTL(&setopstate->ps,
+                                                         node->strategy == SETOP_HASHED ?
+                                                         &TTSOpsMinimalTuple : &TTSOpsHeapTuple);
        setopstate->ps.ps_ProjInfo = NULL;
 
        /*
index 5492cd455796ca0429259683070044acdc3efb1f..750292b101445a2a02a11e79dd3bfdeb63f4b3ee 100644 (file)
@@ -211,13 +211,13 @@ ExecInitSort(Sort *node, EState *estate, int eflags)
        /*
         * Initialize scan slot and type.
         */
-       ExecCreateScanSlotFromOuterPlan(estate, &sortstate->ss);
+       ExecCreateScanSlotFromOuterPlan(estate, &sortstate->ss, &TTSOpsVirtual);
 
        /*
         * Initialize return slot and type. No need to initialize projection info
         * because this node doesn't do projections.
         */
-       ExecInitResultTupleSlotTL(&sortstate->ss.ps);
+       ExecInitResultTupleSlotTL(&sortstate->ss.ps, &TTSOpsMinimalTuple);
        sortstate->ss.ps.ps_ProjInfo = NULL;
 
        SO1_printf("ExecInitSort: %s\n",
index 63de981034d544a5e3a13cc19d7dce8686607034..b42e60576e34524c25ac34bf6f6c55e7c4dd0138 100644 (file)
@@ -968,7 +968,7 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
                 * own innerecontext.
                 */
                tupDescLeft = ExecTypeFromTL(lefttlist, false);
-               slot = ExecInitExtraTupleSlot(estate, tupDescLeft);
+               slot = ExecInitExtraTupleSlot(estate, tupDescLeft, &TTSOpsVirtual);
                sstate->projLeft = ExecBuildProjectionInfo(lefttlist,
                                                                                                   NULL,
                                                                                                   slot,
@@ -976,7 +976,7 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
                                                                                                   NULL);
 
                sstate->descRight = tupDescRight = ExecTypeFromTL(righttlist, false);
-               slot = ExecInitExtraTupleSlot(estate, tupDescRight);
+               slot = ExecInitExtraTupleSlot(estate, tupDescRight, &TTSOpsVirtual);
                sstate->projRight = ExecBuildProjectionInfo(righttlist,
                                                                                                        sstate->innerecontext,
                                                                                                        slot,
@@ -988,6 +988,7 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
                 * across-type comparison).
                 */
                sstate->cur_eq_comp = ExecBuildGroupingEqual(tupDescLeft, tupDescRight,
+                                                                                                        &TTSOpsVirtual, &TTSOpsMinimalTuple,
                                                                                                         ncols,
                                                                                                         sstate->keyColIdx,
                                                                                                         sstate->tab_eq_funcoids,
index b84c6892d503d661fcdebc9e27872a966f4acfda..c9058ab0e94c44d1324e7745ee9831ce5417e327 100644 (file)
@@ -129,7 +129,18 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate, int eflags)
         * Initialize scan slot and type (needed by ExecAssignScanProjectionInfo)
         */
        ExecInitScanTupleSlot(estate, &subquerystate->ss,
-                                                 ExecGetResultType(subquerystate->subplan));
+                                                 ExecGetResultType(subquerystate->subplan),
+                                                 ExecGetResultSlotOps(subquerystate->subplan, NULL));
+       /*
+        * The slot used as the scantuple isn't the slot above (outside of EPQ),
+        * but the one from the node below.
+        */
+       subquerystate->ss.ps.scanopsset = true;
+       subquerystate->ss.ps.scanops = ExecGetResultSlotOps(subquerystate->subplan,
+                                                                                                               &subquerystate->ss.ps.scanopsfixed);
+       subquerystate->ss.ps.resultopsset = true;
+       subquerystate->ss.ps.resultops = subquerystate->ss.ps.scanops;
+       subquerystate->ss.ps.resultopsfixed = subquerystate->ss.ps.scanopsfixed;
 
        /*
         * Initialize result type and projection.
index b0c94d7e063af90d23f3e9f7eb297499d40ee318..a79e4cb2cf56c68300d699acef18dff0f9cc8c0d 100644 (file)
@@ -147,7 +147,8 @@ ExecInitTableFuncScan(TableFuncScan *node, EState *estate, int eflags)
                                                                 tf->coltypmods,
                                                                 tf->colcollations);
        /* and the corresponding scan slot */
-       ExecInitScanTupleSlot(estate, &scanstate->ss, tupdesc);
+       ExecInitScanTupleSlot(estate, &scanstate->ss, tupdesc,
+                                                 &TTSOpsMinimalTuple);
 
        /*
         * Initialize result type and projection.
index bc859e3d516eff72e141a235f35f55388254e2bf..939ece2faa18b17e6821577c54406053899eac4e 100644 (file)
@@ -543,7 +543,8 @@ ExecInitTidScan(TidScan *node, EState *estate, int eflags)
         * get the scan type from the relation descriptor.
         */
        ExecInitScanTupleSlot(estate, &tidstate->ss,
-                                                 RelationGetDescr(currentRelation));
+                                                 RelationGetDescr(currentRelation),
+                                                 &TTSOpsBufferTuple);
 
        /*
         * Initialize result type and projection.
index c791f89b48c046f8d5ddb71744beb304fa67120e..c5e4232e68c0770fba2f575cdf15c30041db9fc5 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(&uniquestate->ps);
+       ExecInitResultTupleSlotTL(&uniquestate->ps, &TTSOpsMinimalTuple);
        uniquestate->ps.ps_ProjInfo = NULL;
 
        /*
index fa49d0470fcf191d379f02e6934534757be1c961..6351cdac27a5e17dbe4a3433c334cdbff0aed4a2 100644 (file)
@@ -261,7 +261,7 @@ ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags)
         * Get info about values list, initialize scan slot with it.
         */
        tupdesc = ExecTypeFromExprList((List *) linitial(node->values_lists));
-       ExecInitScanTupleSlot(estate, &scanstate->ss, tupdesc);
+       ExecInitScanTupleSlot(estate, &scanstate->ss, tupdesc, &TTSOpsVirtual);
 
        /*
         * Initialize result type and projection.
index 6e597e82856be99f70af2391d9c753194051efc2..298e3707450d0dc3b5c0f8e4b7239b1477ffdbd5 100644 (file)
@@ -2316,16 +2316,25 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags)
         * initialize source tuple type (which is also the tuple type that we'll
         * store in the tuplestore and use in all our working slots).
         */
-       ExecCreateScanSlotFromOuterPlan(estate, &winstate->ss);
+       ExecCreateScanSlotFromOuterPlan(estate, &winstate->ss, &TTSOpsMinimalTuple);
        scanDesc = winstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor;
 
+       /* the outer tuple isn't the child's tuple, but always a minimal tuple */
+       winstate->ss.ps.outeropsset = true;
+       winstate->ss.ps.outerops = &TTSOpsMinimalTuple;
+       winstate->ss.ps.outeropsfixed = true;
+
        /*
         * tuple table initialization
         */
-       winstate->first_part_slot = ExecInitExtraTupleSlot(estate, scanDesc);
-       winstate->agg_row_slot = ExecInitExtraTupleSlot(estate, scanDesc);
-       winstate->temp_slot_1 = ExecInitExtraTupleSlot(estate, scanDesc);
-       winstate->temp_slot_2 = ExecInitExtraTupleSlot(estate, scanDesc);
+       winstate->first_part_slot = ExecInitExtraTupleSlot(estate, scanDesc,
+                                                                                                          &TTSOpsMinimalTuple);
+       winstate->agg_row_slot = ExecInitExtraTupleSlot(estate, scanDesc,
+                                                                                                       &TTSOpsMinimalTuple);
+       winstate->temp_slot_1 = ExecInitExtraTupleSlot(estate, scanDesc,
+                                                                                                  &TTSOpsMinimalTuple);
+       winstate->temp_slot_2 = ExecInitExtraTupleSlot(estate, scanDesc,
+                                                                                                  &TTSOpsMinimalTuple);
 
        /*
         * create frame head and tail slots only if needed (must create slots in
@@ -2339,17 +2348,19 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags)
                if (((frameOptions & FRAMEOPTION_START_CURRENT_ROW) &&
                         node->ordNumCols != 0) ||
                        (frameOptions & FRAMEOPTION_START_OFFSET))
-                       winstate->framehead_slot = ExecInitExtraTupleSlot(estate, scanDesc);
+                       winstate->framehead_slot = ExecInitExtraTupleSlot(estate, scanDesc,
+                                                                                                                         &TTSOpsMinimalTuple);
                if (((frameOptions & FRAMEOPTION_END_CURRENT_ROW) &&
                         node->ordNumCols != 0) ||
                        (frameOptions & FRAMEOPTION_END_OFFSET))
-                       winstate->frametail_slot = ExecInitExtraTupleSlot(estate, scanDesc);
+                       winstate->frametail_slot = ExecInitExtraTupleSlot(estate, scanDesc,
+                                                                                                                         &TTSOpsMinimalTuple);
        }
 
        /*
         * Initialize result slot, type and projection.
         */
-       ExecInitResultTupleSlotTL(&winstate->ss.ps);
+       ExecInitResultTupleSlotTL(&winstate->ss.ps, &TTSOpsVirtual);
        ExecAssignProjectionInfo(&winstate->ss.ps, NULL);
 
        /* Set up data for comparing tuples */
index 1ce8ae9f026318401fb015f943c0b46483dcbcaf..a432926fe156e0cc7b9952de28dcaab50d540f96 100644 (file)
@@ -160,7 +160,12 @@ ExecInitWorkTableScan(WorkTableScan *node, EState *estate, int eflags)
         * tuple table initialization
         */
        ExecInitResultTypeTL(&scanstate->ss.ps);
-       ExecInitScanTupleSlot(estate, &scanstate->ss, NULL);
+
+       /* signal that return type is not yet known */
+       scanstate->ss.ps.resultopsset = true;
+       scanstate->ss.ps.resultopsfixed = false;
+
+       ExecInitScanTupleSlot(estate, &scanstate->ss, NULL, &TTSOpsMinimalTuple);
 
        /*
         * initialize child expressions
index 0b5e0dd89f5733b4aaa73949bbeb01792ae602e3..be9fd49cd2e0ea89e72abc684916383b8d34a855 100644 (file)
@@ -1275,7 +1275,7 @@ check_default_partition_contents(Relation parent, Relation default_rel,
                econtext = GetPerTupleExprContext(estate);
                snapshot = RegisterSnapshot(GetLatestSnapshot());
                scan = heap_beginscan(part_rel, snapshot, 0, NULL);
-               tupslot = MakeSingleTupleTableSlot(tupdesc);
+               tupslot = MakeSingleTupleTableSlot(tupdesc, &TTSOpsHeapTuple);
 
                /*
                 * Switch to per-tuple memory context and reset it for each tuple
index 6e420d893cf70965d0cdf84dd923dc1901c7af62..9e682331d2f8e89e9378842bf252b9746a1a9b61 100644 (file)
@@ -685,7 +685,7 @@ fetch_remote_table_info(char *nspname, char *relname,
                                (errmsg("could not fetch table info for table \"%s.%s\" from publisher: %s",
                                                nspname, relname, res->err)));
 
-       slot = MakeSingleTupleTableSlot(res->tupledesc);
+       slot = MakeSingleTupleTableSlot(res->tupledesc, &TTSOpsMinimalTuple);
        if (!tuplestore_gettupleslot(res->tuplestore, true, false, slot))
                ereport(ERROR,
                                (errmsg("table \"%s.%s\" not found on publisher",
@@ -727,7 +727,7 @@ fetch_remote_table_info(char *nspname, char *relname,
        lrel->attkeys = NULL;
 
        natt = 0;
-       slot = MakeSingleTupleTableSlot(res->tupledesc);
+       slot = MakeSingleTupleTableSlot(res->tupledesc, &TTSOpsMinimalTuple);
        while (tuplestore_gettupleslot(res->tuplestore, true, false, slot))
        {
                lrel->attnames[natt] =
index 277da69fa6c1e3e6787ff65723533305b4aef52c..3cd1e0d728e2a07922d52bcfdbe7da0144f2daac 100644 (file)
@@ -213,7 +213,8 @@ create_estate_for_relation(LogicalRepRelMapEntry *rel)
 
        /* Triggers might need a slot */
        if (resultRelInfo->ri_TrigDesc)
-               estate->es_trig_tuple_slot = ExecInitExtraTupleSlot(estate, NULL);
+               estate->es_trig_tuple_slot = ExecInitExtraTupleSlot(estate, NULL,
+                                                                                                                       &TTSOpsVirtual);
 
        /* Prepare to catch AFTER triggers. */
        AfterTriggerBeginQuery();
@@ -609,7 +610,8 @@ apply_handle_insert(StringInfo s)
        /* Initialize the executor state. */
        estate = create_estate_for_relation(rel);
        remoteslot = ExecInitExtraTupleSlot(estate,
-                                                                               RelationGetDescr(rel->localrel));
+                                                                               RelationGetDescr(rel->localrel),
+                                                                               &TTSOpsHeapTuple);
 
        /* Input functions may need an active snapshot, so get one */
        PushActiveSnapshot(GetTransactionSnapshot());
@@ -715,9 +717,11 @@ apply_handle_update(StringInfo s)
        /* Initialize the executor state. */
        estate = create_estate_for_relation(rel);
        remoteslot = ExecInitExtraTupleSlot(estate,
-                                                                               RelationGetDescr(rel->localrel));
+                                                                               RelationGetDescr(rel->localrel),
+                                                                               &TTSOpsHeapTuple);
        localslot = ExecInitExtraTupleSlot(estate,
-                                                                          RelationGetDescr(rel->localrel));
+                                                                          RelationGetDescr(rel->localrel),
+                                                                          &TTSOpsHeapTuple);
        EvalPlanQualInit(&epqstate, estate, NULL, NIL, -1);
 
        PushActiveSnapshot(GetTransactionSnapshot());
@@ -756,7 +760,7 @@ apply_handle_update(StringInfo s)
        {
                /* Process and store remote tuple in the slot */
                oldctx = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
-               ExecStoreHeapTuple(localslot->tts_tuple, remoteslot, false);
+               ExecCopySlot(remoteslot, localslot);
                slot_modify_cstrings(remoteslot, rel, newtup.values, newtup.changed);
                MemoryContextSwitchTo(oldctx);
 
@@ -833,9 +837,11 @@ apply_handle_delete(StringInfo s)
        /* Initialize the executor state. */
        estate = create_estate_for_relation(rel);
        remoteslot = ExecInitExtraTupleSlot(estate,
-                                                                               RelationGetDescr(rel->localrel));
+                                                                               RelationGetDescr(rel->localrel),
+                                                                               &TTSOpsVirtual);
        localslot = ExecInitExtraTupleSlot(estate,
-                                                                          RelationGetDescr(rel->localrel));
+                                                                          RelationGetDescr(rel->localrel),
+                                                                          &TTSOpsHeapTuple);
        EvalPlanQualInit(&epqstate, estate, NULL, NIL, -1);
 
        PushActiveSnapshot(GetTransactionSnapshot());
index 2683385ca6e0ac4c0d38e50439c9e7a5ea3db5b0..39337d2f1f8d8836f83675106af4ab628653ae3b 100644 (file)
@@ -403,7 +403,7 @@ IdentifySystem(void)
                                                          TEXTOID, -1, 0);
 
        /* prepare for projection of tuples */
-       tstate = begin_tup_output_tupdesc(dest, tupdesc);
+       tstate = begin_tup_output_tupdesc(dest, tupdesc, &TTSOpsVirtual);
 
        /* column 1: system identifier */
        values[0] = CStringGetTextDatum(sysid);
@@ -735,7 +735,7 @@ StartReplication(StartReplicationCmd *cmd)
                                                                  TEXTOID, -1, 0);
 
                /* prepare for projection of tuple */
-               tstate = begin_tup_output_tupdesc(dest, tupdesc);
+               tstate = begin_tup_output_tupdesc(dest, tupdesc, &TTSOpsVirtual);
 
                values[0] = Int64GetDatum((int64) sendTimeLineNextTLI);
                values[1] = CStringGetTextDatum(startpos_str);
@@ -1007,7 +1007,7 @@ CreateReplicationSlot(CreateReplicationSlotCmd *cmd)
                                                          TEXTOID, -1, 0);
 
        /* prepare for projection of tuples */
-       tstate = begin_tup_output_tupdesc(dest, tupdesc);
+       tstate = begin_tup_output_tupdesc(dest, tupdesc, &TTSOpsVirtual);
 
        /* slot_name */
        slot_name = NameStr(MyReplicationSlot->data.name);
index 66cc5c35c68ce49cf479239f4d54f5461b614809..b44438bf088d8a4de1ea82b6a66fbf7684ce5e81 100644 (file)
@@ -1071,7 +1071,7 @@ RunFromStore(Portal portal, ScanDirection direction, uint64 count,
        uint64          current_tuple_count = 0;
        TupleTableSlot *slot;
 
-       slot = MakeSingleTupleTableSlot(portal->tupDesc);
+       slot = MakeSingleTupleTableSlot(portal->tupDesc, &TTSOpsMinimalTuple);
 
        dest->rStartup(dest, CMD_SELECT, portal->tupDesc);
 
index be9422dcfb68ba06cf88dbaaa6b63ffd6efd974b..8871aed9045a9fa57fb97cad35fbef550bc107ba 100644 (file)
@@ -239,7 +239,8 @@ ordered_set_startup(FunctionCallInfo fcinfo, bool use_tuples)
                        }
 
                        /* Create slot we'll use to store/retrieve rows */
-                       qstate->tupslot = MakeSingleTupleTableSlot(qstate->tupdesc);
+                       qstate->tupslot = MakeSingleTupleTableSlot(qstate->tupdesc,
+                                                                                                          &TTSOpsMinimalTuple);
                }
                else
                {
@@ -1375,7 +1376,8 @@ hypothetical_dense_rank_final(PG_FUNCTION_ARGS)
         * previous row available for comparisons.  This is accomplished by
         * swapping the slot pointer variables after each row.
         */
-       extraslot = MakeSingleTupleTableSlot(osastate->qstate->tupdesc);
+       extraslot = MakeSingleTupleTableSlot(osastate->qstate->tupdesc,
+                                                                                &TTSOpsMinimalTuple);
        slot2 = extraslot;
 
        /* iterate till we find the hypothetical row */
index e0ece74bb9284421d97c8f8b31044fd00ea4081e..dbbbcc979b451f9795b51624567ecc678e9ab407 100644 (file)
@@ -5534,7 +5534,8 @@ get_actual_variable_range(PlannerInfo *root, VariableStatData *vardata,
                        indexInfo = BuildIndexInfo(indexRel);
 
                        /* some other stuff */
-                       slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRel));
+                       slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRel),
+                                                                                       &TTSOpsHeapTuple);
                        econtext->ecxt_scantuple = slot;
                        get_typlenbyval(vardata->atttype, &typLen, &typByVal);
                        InitNonVacuumableSnapshot(SnapshotNonVacuumable, RecentGlobalXmin);
index 0327b295da8f3cdab135434df8ff85fc8b72df1b..f9074215a2d6ea7ba528ddb8980cb0cac3b10bbd 100644 (file)
@@ -8262,7 +8262,7 @@ ShowGUCConfigOption(const char *name, DestReceiver *dest)
                                                          TEXTOID, -1, 0);
 
        /* prepare for projection of tuples */
-       tstate = begin_tup_output_tupdesc(dest, tupdesc);
+       tstate = begin_tup_output_tupdesc(dest, tupdesc, &TTSOpsVirtual);
 
        /* Send it */
        do_text_output_oneline(tstate, value);
@@ -8292,7 +8292,7 @@ ShowAllGUCConfig(DestReceiver *dest)
                                                          TEXTOID, -1, 0);
 
        /* prepare for projection of tuples */
-       tstate = begin_tup_output_tupdesc(dest, tupdesc);
+       tstate = begin_tup_output_tupdesc(dest, tupdesc, &TTSOpsVirtual);
 
        for (i = 0; i < num_guc_variables; i++)
        {
index 5909404e1e5548a9b3352a7e90ee266ea4421813..ee7fd83c02c9ff05512bdc19cadcc2dccb679a06 100644 (file)
@@ -933,7 +933,7 @@ tuplesort_begin_cluster(TupleDesc tupDesc,
                 * scantuple has to point to that slot, too.
                 */
                state->estate = CreateExecutorState();
-               slot = MakeSingleTupleTableSlot(tupDesc);
+               slot = MakeSingleTupleTableSlot(tupDesc, &TTSOpsVirtual);
                econtext = GetPerTupleExprContext(state->estate);
                econtext->ecxt_scantuple = slot;
        }
index 84412657845efafdbfe3adedea42b57d95e2bc17..14c4e3ae2fa2f058604e24a1ae120778440c7164 100644 (file)
@@ -249,6 +249,7 @@ extern List *ExecInitExprList(List *nodes, PlanState *parent);
 extern ExprState *ExecBuildAggTrans(AggState *aggstate, struct AggStatePerPhaseData *phase,
                                  bool doSort, bool doHash);
 extern ExprState *ExecBuildGroupingEqual(TupleDesc ldesc, TupleDesc rdesc,
+                                          const TupleTableSlotOps *lops, const TupleTableSlotOps *rops,
                                           int numCols,
                                           AttrNumber *keyColIdx,
                                           Oid *eqfunctions,
@@ -430,13 +431,18 @@ extern void ExecScanReScan(ScanState *node);
  * prototypes from functions in execTuples.c
  */
 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 void ExecInitResultSlot(PlanState *planstate,
+                                                          const TupleTableSlotOps *tts_ops);
+extern void ExecInitResultTupleSlotTL(PlanState *planstate,
+                                                                         const TupleTableSlotOps *tts_ops);
+extern void ExecInitScanTupleSlot(EState *estate, ScanState *scanstate,
+                                                                 TupleDesc tupleDesc,
+                                                                 const TupleTableSlotOps *tts_ops);
 extern TupleTableSlot *ExecInitExtraTupleSlot(EState *estate,
-                                          TupleDesc tupleDesc);
-extern TupleTableSlot *ExecInitNullTupleSlot(EState *estate,
-                                         TupleDesc tupType);
+                                          TupleDesc tupledesc,
+                                          const TupleTableSlotOps *tts_ops);
+extern TupleTableSlot *ExecInitNullTupleSlot(EState *estate, TupleDesc tupType,
+                                         const TupleTableSlotOps *tts_ops);
 extern TupleDesc ExecTypeFromTL(List *targetList, bool hasoid);
 extern TupleDesc ExecCleanTypeFromTL(List *targetList, bool hasoid);
 extern TupleDesc ExecTypeFromExprList(List *exprList);
@@ -450,7 +456,8 @@ typedef struct TupOutputState
 } TupOutputState;
 
 extern TupOutputState *begin_tup_output_tupdesc(DestReceiver *dest,
-                                                TupleDesc tupdesc);
+                                                TupleDesc tupdesc,
+                                                const TupleTableSlotOps *tts_ops);
 extern void do_tup_output(TupOutputState *tstate, Datum *values, bool *isnull);
 extern void do_text_output_multiline(TupOutputState *tstate, const char *txt);
 extern void end_tup_output(TupOutputState *tstate);
@@ -504,13 +511,18 @@ extern ExprContext *MakePerTupleExprContext(EState *estate);
 
 extern void ExecAssignExprContext(EState *estate, PlanState *planstate);
 extern TupleDesc ExecGetResultType(PlanState *planstate);
+extern TupleTableSlot ExecGetResultSlot(PlanState *planstate);
+extern const TupleTableSlotOps *ExecGetResultSlotOps(PlanState *planstate,
+                                                                                                        bool *isfixed);
 extern void ExecAssignProjectionInfo(PlanState *planstate,
                                                 TupleDesc inputDesc);
 extern void ExecConditionalAssignProjectionInfo(PlanState *planstate,
                                                                        TupleDesc inputDesc, Index varno);
 extern void ExecFreeExprContext(PlanState *planstate);
 extern void ExecAssignScanType(ScanState *scanstate, TupleDesc tupDesc);
-extern void ExecCreateScanSlotFromOuterPlan(EState *estate, ScanState *scanstate);
+extern void ExecCreateScanSlotFromOuterPlan(EState *estate,
+                                                               ScanState *scanstate,
+                                                               const TupleTableSlotOps *tts_ops);
 
 extern bool ExecRelationIsTargetRelation(EState *estate, Index scanrelid);
 
index 8bfa73c30ea2d3df1ac8e4e8c42bcbf7ff5e46e6..86e47c56af2aaea3c767cfe3576b071fe148b3ad 100644 (file)
 #define                        TTS_FLAG_FIXED          (1 << 5)
 #define TTS_FIXED(slot) (((slot)->tts_flags & TTS_FLAG_FIXED) != 0)
 
+struct TupleTableSlotOps;
+typedef struct TupleTableSlotOps TupleTableSlotOps;
+
 typedef struct TupleTableSlot
 {
        NodeTag         type;
@@ -141,20 +144,35 @@ typedef struct TupleTableSlot
        AttrNumber      tts_nvalid;             /* # of valid values in tts_values */
 #define FIELDNO_TUPLETABLESLOT_TUPLE 3
        HeapTuple       tts_tuple;              /* physical tuple, or NULL if virtual */
-#define FIELDNO_TUPLETABLESLOT_TUPLEDESCRIPTOR 4
+       const TupleTableSlotOps *const tts_ops; /* implementation of slot */
+#define FIELDNO_TUPLETABLESLOT_TUPLEDESCRIPTOR 5
        TupleDesc       tts_tupleDescriptor;    /* slot's tuple descriptor */
        MemoryContext tts_mcxt;         /* slot itself is in this context */
        Buffer          tts_buffer;             /* tuple's buffer, or InvalidBuffer */
-#define FIELDNO_TUPLETABLESLOT_OFF 7
+#define FIELDNO_TUPLETABLESLOT_OFF 8
        uint32          tts_off;                /* saved state for slot_deform_tuple */
-#define FIELDNO_TUPLETABLESLOT_VALUES 8
+#define FIELDNO_TUPLETABLESLOT_VALUES 9
        Datum      *tts_values;         /* current per-attribute values */
-#define FIELDNO_TUPLETABLESLOT_ISNULL 9
+#define FIELDNO_TUPLETABLESLOT_ISNULL 10
        bool       *tts_isnull;         /* current per-attribute isnull flags */
        MinimalTuple tts_mintuple;      /* minimal tuple, or NULL if none */
        HeapTupleData tts_minhdr;       /* workspace for minimal-tuple-only case */
 } TupleTableSlot;
 
+/* routines for a TupleTableSlot implementation */
+struct TupleTableSlotOps
+{
+};
+
+/*
+ * Predefined TupleTableSlotOps for various types of TupleTableSlotOps. The
+ * same are used to identify the type of a given slot.
+ */
+extern PGDLLIMPORT const TupleTableSlotOps TTSOpsVirtual;
+extern PGDLLIMPORT const TupleTableSlotOps TTSOpsHeapTuple;
+extern PGDLLIMPORT const TupleTableSlotOps TTSOpsMinimalTuple;
+extern PGDLLIMPORT const TupleTableSlotOps TTSOpsBufferTuple;
+
 #define TTS_HAS_PHYSICAL_TUPLE(slot)  \
        ((slot)->tts_tuple != NULL && (slot)->tts_tuple != &((slot)->tts_minhdr))
 
@@ -165,10 +183,13 @@ typedef struct TupleTableSlot
        ((slot) == NULL || TTS_EMPTY(slot))
 
 /* in executor/execTuples.c */
-extern TupleTableSlot *MakeTupleTableSlot(TupleDesc desc);
-extern TupleTableSlot *ExecAllocTableSlot(List **tupleTable, TupleDesc desc);
+extern TupleTableSlot *MakeTupleTableSlot(TupleDesc tupleDesc,
+                                  const TupleTableSlotOps *tts_ops);
+extern TupleTableSlot *ExecAllocTableSlot(List **tupleTable, TupleDesc desc,
+                                  const TupleTableSlotOps *tts_ops);
 extern void ExecResetTupleTable(List *tupleTable, bool shouldFree);
-extern TupleTableSlot *MakeSingleTupleTableSlot(TupleDesc tupdesc);
+extern TupleTableSlot *MakeSingleTupleTableSlot(TupleDesc tupdesc,
+                                                const TupleTableSlotOps *tts_ops);
 extern void ExecDropSingleTupleTableSlot(TupleTableSlot *slot);
 extern void ExecSetSlotDescriptor(TupleTableSlot *slot, TupleDesc tupdesc);
 extern TupleTableSlot *ExecStoreHeapTuple(HeapTuple tuple,
index 18544566f70f17fd1187184e4c44591dc12118ca..63c871e6d03f7d95b8f593daf7166b0142fe2cf7 100644 (file)
@@ -977,6 +977,42 @@ typedef struct PlanState
         * descriptor, without encoding knowledge about all executor nodes.
         */
        TupleDesc       scandesc;
+
+       /*
+        * Define the slot types for inner, outer and scanslots for expression
+        * contexts with this state as a parent.  If *opsset is set, then
+        * *opsfixed indicates whether *ops is guaranteed to be the type of slot
+        * used. That means that every slot in the corresponding
+        * ExprContext.ecxt_*tuple will point to a slot of that type, while
+        * evaluating the expression.  If *opsfixed is false, but *ops is set,
+        * that indicates the most likely type of slot.
+        *
+        * The scan* fields are set by ExecInitScanTupleSlot(). If that's not
+        * called, nodes can initialize the fields themselves.
+        *
+        * If outer/inneropsset is false, the information is inferred on-demand
+        * using ExecGetResultSlotOps() on ->righttree/lefttree, using the
+        * corresponding node's resultops* fields.
+        *
+        * The result* fields are automatically set when ExecInitResultSlot is
+        * used (be it directly or when the slot is created by
+        * ExecAssignScanProjectionInfo() /
+        * ExecConditionalAssignProjectionInfo()).  If no projection is necessary
+        * ExecConditionalAssignProjectionInfo() defaults those fields to the scan
+        * operations.
+        */
+       const TupleTableSlotOps *scanops;
+       const TupleTableSlotOps *outerops;
+       const TupleTableSlotOps *innerops;
+       const TupleTableSlotOps *resultops;
+       bool scanopsfixed;
+       bool outeropsfixed;
+       bool inneropsfixed;
+       bool resultopsfixed;
+       bool scanopsset;
+       bool outeropsset;
+       bool inneropsset;
+       bool resultopsset;
 } PlanState;
 
 /* ----------------
@@ -1064,6 +1100,8 @@ typedef struct ModifyTableState
        PlanState **mt_plans;           /* subplans (one per target rel) */
        int                     mt_nplans;              /* number of plans in the array */
        int                     mt_whichplan;   /* which one is being executed (0..n-1) */
+       TupleTableSlot** mt_scans;      /* input tuple corresponding to underlying
+                                                                  plans */
        ResultRelInfo *resultRelInfo;   /* per-subplan target relations */
        ResultRelInfo *rootResultRelInfo;       /* root target relation (partitioned
                                                                                 * table root) */
@@ -1329,6 +1367,7 @@ typedef struct IndexScanState
        bool       *iss_OrderByTypByVals;
        int16      *iss_OrderByTypLens;
        Size            iss_PscanLen;
+       TupleTableSlot *iss_ReorderQueueSlot;
 } IndexScanState;
 
 /* ----------------