Introduce notion of different types of slots (without implementing them).

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
This commit is contained in:
Andres Freund 2018-11-15 22:00:30 -08:00
parent 763f2edd92
commit 1a0586de36
69 changed files with 478 additions and 176 deletions

View File

@ -4503,7 +4503,8 @@ ProjIndexIsUnchanged(Relation relation, HeapTuple oldtup, HeapTuple newtup)
List *indexoidlist = RelationGetIndexList(relation); List *indexoidlist = RelationGetIndexList(relation);
EState *estate = CreateExecutorState(); EState *estate = CreateExecutorState();
ExprContext *econtext = GetPerTupleExprContext(estate); ExprContext *econtext = GetPerTupleExprContext(estate);
TupleTableSlot *slot = MakeSingleTupleTableSlot(RelationGetDescr(relation)); TupleTableSlot *slot = MakeSingleTupleTableSlot(RelationGetDescr(relation),
&TTSOpsHeapTuple);
bool equals = true; bool equals = true;
Datum old_values[INDEX_MAX_KEYS]; Datum old_values[INDEX_MAX_KEYS];
bool old_isnull[INDEX_MAX_KEYS]; bool old_isnull[INDEX_MAX_KEYS];

View File

@ -2510,7 +2510,8 @@ IndexBuildHeapRangeScan(Relation heapRelation,
*/ */
estate = CreateExecutorState(); estate = CreateExecutorState();
econtext = GetPerTupleExprContext(estate); econtext = GetPerTupleExprContext(estate);
slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation)); slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation),
&TTSOpsHeapTuple);
/* Arrange for econtext's scan tuple to be the tuple under test */ /* Arrange for econtext's scan tuple to be the tuple under test */
econtext->ecxt_scantuple = slot; econtext->ecxt_scantuple = slot;
@ -2997,7 +2998,8 @@ IndexCheckExclusion(Relation heapRelation,
*/ */
estate = CreateExecutorState(); estate = CreateExecutorState();
econtext = GetPerTupleExprContext(estate); econtext = GetPerTupleExprContext(estate);
slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation)); slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation),
&TTSOpsHeapTuple);
/* Arrange for econtext's scan tuple to be the tuple under test */ /* Arrange for econtext's scan tuple to be the tuple under test */
econtext->ecxt_scantuple = slot; econtext->ecxt_scantuple = slot;
@ -3315,7 +3317,8 @@ validate_index_heapscan(Relation heapRelation,
*/ */
estate = CreateExecutorState(); estate = CreateExecutorState();
econtext = GetPerTupleExprContext(estate); econtext = GetPerTupleExprContext(estate);
slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation)); slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation),
&TTSOpsHeapTuple);
/* Arrange for econtext's scan tuple to be the tuple under test */ /* Arrange for econtext's scan tuple to be the tuple under test */
econtext->ecxt_scantuple = slot; econtext->ecxt_scantuple = slot;

View File

@ -95,7 +95,8 @@ CatalogIndexInsert(CatalogIndexState indstate, HeapTuple heapTuple)
heapRelation = indstate->ri_RelationDesc; heapRelation = indstate->ri_RelationDesc;
/* Need a slot to hold the tuple being examined */ /* Need a slot to hold the tuple being examined */
slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation)); slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation),
&TTSOpsHeapTuple);
ExecStoreHeapTuple(heapTuple, slot, false); ExecStoreHeapTuple(heapTuple, slot, false);
/* /*

View File

@ -730,7 +730,8 @@ compute_index_stats(Relation onerel, double totalrows,
estate = CreateExecutorState(); estate = CreateExecutorState();
econtext = GetPerTupleExprContext(estate); econtext = GetPerTupleExprContext(estate);
/* Need a slot to hold the current heap tuple, too */ /* 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 */ /* Arrange for econtext's scan tuple to be the tuple under test */
econtext->ecxt_scantuple = slot; econtext->ecxt_scantuple = slot;

View File

@ -122,7 +122,8 @@ unique_key_recheck(PG_FUNCTION_ARGS)
/* /*
* The heap tuple must be put into a slot for FormIndexDatum. * 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); ExecStoreHeapTuple(new_row, slot, false);

View File

@ -2488,9 +2488,11 @@ CopyFrom(CopyState cstate)
ExecInitRangeTable(estate, cstate->range_table); ExecInitRangeTable(estate, cstate->range_table);
/* Set up a tuple slot too */ /* Set up a tuple slot too */
myslot = ExecInitExtraTupleSlot(estate, tupDesc); myslot = ExecInitExtraTupleSlot(estate, tupDesc,
&TTSOpsHeapTuple);
/* Triggers might need a slot as well */ /* 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 * Set up a ModifyTableState so we can let FDW(s) init themselves for

View File

@ -266,7 +266,8 @@ ExplainQuery(ParseState *pstate, ExplainStmt *stmt, const char *queryString,
Assert(es->indent == 0); Assert(es->indent == 0);
/* output tuples */ /* 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) if (es->format == EXPLAIN_FORMAT_TEXT)
do_text_output_multiline(tstate, es->str->data); do_text_output_multiline(tstate, es->str->data);
else else

View File

@ -2347,7 +2347,8 @@ ExecuteCallStmt(CallStmt *stmt, ParamListInfo params, bool atomic, DestReceiver
tupTypmod = HeapTupleHeaderGetTypMod(td); tupTypmod = HeapTupleHeaderGetTypMod(td);
retdesc = lookup_rowtype_tupdesc(tupType, tupTypmod); 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); rettupdata.t_len = HeapTupleHeaderGetDatumLength(td);
ItemPointerSetInvalid(&(rettupdata.t_self)); ItemPointerSetInvalid(&(rettupdata.t_self));

View File

@ -1148,7 +1148,7 @@ fetch_table_list(WalReceiverConn *wrconn, List *publications)
res->err))); res->err)));
/* Process tables. */ /* Process tables. */
slot = MakeSingleTupleTableSlot(res->tupledesc); slot = MakeSingleTupleTableSlot(res->tupledesc, &TTSOpsMinimalTuple);
while (tuplestore_gettupleslot(res->tuplestore, true, false, slot)) while (tuplestore_gettupleslot(res->tuplestore, true, false, slot))
{ {
char *nspname; char *nspname;

View File

@ -4736,8 +4736,8 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
* tuples are the same, the tupDescs might not be (consider ADD COLUMN * tuples are the same, the tupDescs might not be (consider ADD COLUMN
* without a default). * without a default).
*/ */
oldslot = MakeSingleTupleTableSlot(oldTupDesc); oldslot = MakeSingleTupleTableSlot(oldTupDesc, &TTSOpsHeapTuple);
newslot = MakeSingleTupleTableSlot(newTupDesc); newslot = MakeSingleTupleTableSlot(newTupDesc, &TTSOpsHeapTuple);
/* Preallocate values/isnull arrays */ /* Preallocate values/isnull arrays */
i = Max(newTupDesc->natts, oldTupDesc->natts); i = Max(newTupDesc->natts, oldTupDesc->natts);
@ -8527,7 +8527,7 @@ validateCheckConstraint(Relation rel, HeapTuple constrtup)
econtext = GetPerTupleExprContext(estate); econtext = GetPerTupleExprContext(estate);
tupdesc = RelationGetDescr(rel); tupdesc = RelationGetDescr(rel);
slot = MakeSingleTupleTableSlot(tupdesc); slot = MakeSingleTupleTableSlot(tupdesc, &TTSOpsHeapTuple);
econtext->ecxt_scantuple = slot; econtext->ecxt_scantuple = slot;
snapshot = RegisterSnapshot(GetLatestSnapshot()); snapshot = RegisterSnapshot(GetLatestSnapshot());

View File

@ -3525,7 +3525,7 @@ TriggerEnabled(EState *estate, ResultRelInfo *relinfo,
{ {
oldContext = MemoryContextSwitchTo(estate->es_query_cxt); oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
estate->es_trig_oldtup_slot = estate->es_trig_oldtup_slot =
ExecInitExtraTupleSlot(estate, NULL); ExecInitExtraTupleSlot(estate, NULL, &TTSOpsHeapTuple);
MemoryContextSwitchTo(oldContext); MemoryContextSwitchTo(oldContext);
} }
oldslot = estate->es_trig_oldtup_slot; oldslot = estate->es_trig_oldtup_slot;
@ -3539,7 +3539,7 @@ TriggerEnabled(EState *estate, ResultRelInfo *relinfo,
{ {
oldContext = MemoryContextSwitchTo(estate->es_query_cxt); oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
estate->es_trig_newtup_slot = estate->es_trig_newtup_slot =
ExecInitExtraTupleSlot(estate, NULL); ExecInitExtraTupleSlot(estate, NULL, &TTSOpsHeapTuple);
MemoryContextSwitchTo(oldContext); MemoryContextSwitchTo(oldContext);
} }
newslot = estate->es_trig_newtup_slot; newslot = estate->es_trig_newtup_slot;
@ -4546,8 +4546,10 @@ afterTriggerInvokeEvents(AfterTriggerEventList *events,
ExecDropSingleTupleTableSlot(slot1); ExecDropSingleTupleTableSlot(slot1);
ExecDropSingleTupleTableSlot(slot2); ExecDropSingleTupleTableSlot(slot2);
} }
slot1 = MakeSingleTupleTableSlot(rel->rd_att); slot1 = MakeSingleTupleTableSlot(rel->rd_att,
slot2 = MakeSingleTupleTableSlot(rel->rd_att); &TTSOpsMinimalTuple);
slot2 = MakeSingleTupleTableSlot(rel->rd_att,
&TTSOpsMinimalTuple);
} }
if (trigdesc == NULL) /* should not happen */ if (trigdesc == NULL) /* should not happen */
elog(ERROR, "relation %u has no triggers", elog(ERROR, "relation %u has no triggers",

View File

@ -2423,7 +2423,8 @@ ExecInitWholeRowVar(ExprEvalStep *scratch, Var *variable, ExprState *state)
scratch->d.wholerow.junkFilter = scratch->d.wholerow.junkFilter =
ExecInitJunkFilter(subplan->plan->targetlist, ExecInitJunkFilter(subplan->plan->targetlist,
ExecGetResultType(subplan)->tdhasoid, ExecGetResultType(subplan)->tdhasoid,
ExecInitExtraTupleSlot(parent->state, NULL)); ExecInitExtraTupleSlot(parent->state, NULL,
&TTSOpsVirtual));
} }
} }
} }
@ -3214,6 +3215,7 @@ ExecBuildAggTransCall(ExprState *state, AggState *aggstate,
*/ */
ExprState * ExprState *
ExecBuildGroupingEqual(TupleDesc ldesc, TupleDesc rdesc, ExecBuildGroupingEqual(TupleDesc ldesc, TupleDesc rdesc,
const TupleTableSlotOps *lops, const TupleTableSlotOps *rops,
int numCols, int numCols,
AttrNumber *keyColIdx, AttrNumber *keyColIdx,
Oid *eqfunctions, Oid *eqfunctions,

View File

@ -75,7 +75,8 @@ execTuplesMatchPrepare(TupleDesc desc,
eqFunctions[i] = get_opcode(eqOperators[i]); eqFunctions[i] = get_opcode(eqOperators[i]);
/* build actual expression */ /* build actual expression */
expr = ExecBuildGroupingEqual(desc, desc, numCols, keyColIdx, eqFunctions, expr = ExecBuildGroupingEqual(desc, desc, NULL, NULL,
numCols, keyColIdx, eqFunctions,
parent); parent);
return expr; return expr;
@ -202,10 +203,13 @@ BuildTupleHashTable(PlanState *parent,
* We copy the input tuple descriptor just for safety --- we assume all * We copy the input tuple descriptor just for safety --- we assume all
* input tuples will have equivalent descriptors. * input tuples will have equivalent descriptors.
*/ */
hashtable->tableslot = MakeSingleTupleTableSlot(CreateTupleDescCopy(inputDesc)); hashtable->tableslot = MakeSingleTupleTableSlot(CreateTupleDescCopy(inputDesc),
&TTSOpsMinimalTuple);
/* build comparator for all columns */ /* build comparator for all columns */
/* XXX: should we support non-minimal tuples for the inputslot? */
hashtable->tab_eq_func = ExecBuildGroupingEqual(inputDesc, inputDesc, hashtable->tab_eq_func = ExecBuildGroupingEqual(inputDesc, inputDesc,
&TTSOpsMinimalTuple, &TTSOpsMinimalTuple,
numCols, numCols,
keyColIdx, eqfuncoids, keyColIdx, eqfuncoids,
parent); parent);

View 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 * to this slot. Be sure to save and restore caller's value for
* scantuple. * scantuple.
*/ */
existing_slot = MakeSingleTupleTableSlot(RelationGetDescr(heap)); existing_slot = MakeSingleTupleTableSlot(RelationGetDescr(heap),
&TTSOpsHeapTuple);
econtext = GetPerTupleExprContext(estate); econtext = GetPerTupleExprContext(estate);
save_scantuple = econtext->ecxt_scantuple; save_scantuple = econtext->ecxt_scantuple;

View File

@ -78,7 +78,7 @@ ExecInitJunkFilter(List *targetList, bool hasoid, TupleTableSlot *slot)
if (slot) if (slot)
ExecSetSlotDescriptor(slot, cleanTupType); ExecSetSlotDescriptor(slot, cleanTupType);
else else
slot = MakeSingleTupleTableSlot(cleanTupType); slot = MakeSingleTupleTableSlot(cleanTupType, &TTSOpsVirtual);
/* /*
* Now calculate the mapping between the original tuple's attributes and * Now calculate the mapping between the original tuple's attributes and
@ -149,7 +149,7 @@ ExecInitJunkFilterConversion(List *targetList,
if (slot) if (slot)
ExecSetSlotDescriptor(slot, cleanTupType); ExecSetSlotDescriptor(slot, cleanTupType);
else else
slot = MakeSingleTupleTableSlot(cleanTupType); slot = MakeSingleTupleTableSlot(cleanTupType, &TTSOpsVirtual);
/* /*
* Calculate the mapping between the original tuple's attributes and the * Calculate the mapping between the original tuple's attributes and the

View File

@ -1052,10 +1052,12 @@ InitPlan(QueryDesc *queryDesc, int eflags)
if (junk_filter_needed) if (junk_filter_needed)
{ {
JunkFilter *j; JunkFilter *j;
TupleTableSlot *slot;
slot = ExecInitExtraTupleSlot(estate, NULL, &TTSOpsVirtual);
j = ExecInitJunkFilter(planstate->plan->targetlist, j = ExecInitJunkFilter(planstate->plan->targetlist,
tupType->tdhasoid, tupType->tdhasoid,
ExecInitExtraTupleSlot(estate, NULL)); slot);
estate->es_junkFilter = j; estate->es_junkFilter = j;
/* Want to return the cleaned tuple type */ /* Want to return the cleaned tuple type */
@ -1928,7 +1930,7 @@ ExecPartitionCheckEmitError(ResultRelInfo *resultRelInfo,
*/ */
if (map != NULL) if (map != NULL)
slot = execute_attr_map_slot(map, slot, slot = execute_attr_map_slot(map, slot,
MakeTupleTableSlot(tupdesc)); MakeTupleTableSlot(tupdesc, &TTSOpsVirtual));
} }
insertedCols = GetInsertedColumns(resultRelInfo, estate); insertedCols = GetInsertedColumns(resultRelInfo, estate);
@ -2009,7 +2011,7 @@ ExecConstraints(ResultRelInfo *resultRelInfo,
*/ */
if (map != NULL) if (map != NULL)
slot = execute_attr_map_slot(map, slot, slot = execute_attr_map_slot(map, slot,
MakeTupleTableSlot(tupdesc)); MakeTupleTableSlot(tupdesc, &TTSOpsVirtual));
} }
insertedCols = GetInsertedColumns(resultRelInfo, estate); insertedCols = GetInsertedColumns(resultRelInfo, estate);
@ -2059,7 +2061,7 @@ ExecConstraints(ResultRelInfo *resultRelInfo,
*/ */
if (map != NULL) if (map != NULL)
slot = execute_attr_map_slot(map, slot, slot = execute_attr_map_slot(map, slot,
MakeTupleTableSlot(tupdesc)); MakeTupleTableSlot(tupdesc, &TTSOpsVirtual));
} }
insertedCols = GetInsertedColumns(resultRelInfo, estate); insertedCols = GetInsertedColumns(resultRelInfo, estate);
@ -2167,7 +2169,7 @@ ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo,
*/ */
if (map != NULL) if (map != NULL)
slot = execute_attr_map_slot(map, slot, slot = execute_attr_map_slot(map, slot,
MakeTupleTableSlot(tupdesc)); MakeTupleTableSlot(tupdesc, &TTSOpsVirtual));
} }
insertedCols = GetInsertedColumns(resultRelInfo, estate); insertedCols = GetInsertedColumns(resultRelInfo, estate);

View File

@ -144,7 +144,8 @@ ExecSetupPartitionTupleRouting(ModifyTableState *mtstate, Relation rel)
* We need an additional tuple slot for storing transient tuples that * We need an additional tuple slot for storing transient tuples that
* are converted to the root table descriptor. * are converted to the root table descriptor.
*/ */
proute->root_tuple_slot = MakeTupleTableSlot(RelationGetDescr(rel)); proute->root_tuple_slot = MakeTupleTableSlot(RelationGetDescr(rel),
&TTSOpsHeapTuple);
} }
i = 0; i = 0;
@ -740,7 +741,8 @@ ExecInitRoutingInfo(ModifyTableState *mtstate,
*/ */
proute->partition_tuple_slots[partidx] = proute->partition_tuple_slots[partidx] =
ExecInitExtraTupleSlot(estate, 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 * using the correct tuple descriptor when computing its partition key
* for tuple routing. * for tuple routing.
*/ */
pd->tupslot = MakeSingleTupleTableSlot(tupdesc); pd->tupslot = MakeSingleTupleTableSlot(tupdesc, &TTSOpsHeapTuple);
pd->tupmap = convert_tuples_by_name_map_if_req(RelationGetDescr(parent), pd->tupmap = convert_tuples_by_name_map_if_req(RelationGetDescr(parent),
tupdesc, tupdesc,
gettext_noop("could not convert row type")); gettext_noop("could not convert row type"));

View File

@ -873,7 +873,8 @@ ExecPrepareTuplestoreResult(SetExprState *sexpr,
slotDesc = NULL; /* keep compiler quiet */ slotDesc = NULL; /* keep compiler quiet */
} }
sexpr->funcResultSlot = MakeSingleTupleTableSlot(slotDesc); sexpr->funcResultSlot = MakeSingleTupleTableSlot(slotDesc,
&TTSOpsMinimalTuple);
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);
} }

View File

@ -73,6 +73,12 @@ static TupleDesc ExecTypeFromTLInternal(List *targetList,
bool hasoid, bool skipjunk); bool hasoid, bool skipjunk);
const TupleTableSlotOps TTSOpsVirtual;
const TupleTableSlotOps TTSOpsHeapTuple;
const TupleTableSlotOps TTSOpsMinimalTuple;
const TupleTableSlotOps TTSOpsBufferTuple;
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
* tuple table create/delete functions * tuple table create/delete functions
* ---------------------------------------------------------------- * ----------------------------------------------------------------
@ -87,7 +93,8 @@ static TupleDesc ExecTypeFromTLInternal(List *targetList,
* -------------------------------- * --------------------------------
*/ */
TupleTableSlot * TupleTableSlot *
MakeTupleTableSlot(TupleDesc tupleDesc) MakeTupleTableSlot(TupleDesc tupleDesc,
const TupleTableSlotOps *tts_ops)
{ {
Size sz; Size sz;
TupleTableSlot *slot; TupleTableSlot *slot;
@ -104,6 +111,8 @@ MakeTupleTableSlot(TupleDesc tupleDesc)
sz = sizeof(TupleTableSlot); sz = sizeof(TupleTableSlot);
slot = palloc0(sz); 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->type = T_TupleTableSlot;
slot->tts_flags |= TTS_FLAG_EMPTY; slot->tts_flags |= TTS_FLAG_EMPTY;
if (tupleDesc != NULL) if (tupleDesc != NULL)
@ -140,9 +149,10 @@ MakeTupleTableSlot(TupleDesc tupleDesc)
* -------------------------------- * --------------------------------
*/ */
TupleTableSlot * 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); *tupleTable = lappend(*tupleTable, slot);
@ -198,16 +208,17 @@ ExecResetTupleTable(List *tupleTable, /* tuple table */
/* -------------------------------- /* --------------------------------
* MakeSingleTupleTableSlot * MakeSingleTupleTableSlot
* *
* This is a convenience routine for operations that need a * This is a convenience routine for operations that need a standalone
* standalone TupleTableSlot not gotten from the main executor * TupleTableSlot not gotten from the main executor tuple table. It makes
* tuple table. It makes a single slot and initializes it * a single slot of given TupleTableSlotType and initializes it to use the
* to use the given tuple descriptor. * given tuple descriptor.
* -------------------------------- * --------------------------------
*/ */
TupleTableSlot * TupleTableSlot *
MakeSingleTupleTableSlot(TupleDesc tupdesc) MakeSingleTupleTableSlot(TupleDesc tupdesc,
const TupleTableSlotOps *tts_ops)
{ {
TupleTableSlot *slot = MakeTupleTableSlot(tupdesc); TupleTableSlot *slot = MakeTupleTableSlot(tupdesc, tts_ops);
return slot; return slot;
} }
@ -964,13 +975,17 @@ ExecInitResultTypeTL(PlanState *planstate)
* ---------------- * ----------------
*/ */
void void
ExecInitResultSlot(PlanState *planstate) ExecInitResultSlot(PlanState *planstate, const TupleTableSlotOps *tts_ops)
{ {
TupleTableSlot *slot; TupleTableSlot *slot;
slot = ExecAllocTableSlot(&planstate->state->es_tupleTable, slot = ExecAllocTableSlot(&planstate->state->es_tupleTable,
planstate->ps_ResultTupleDesc); planstate->ps_ResultTupleDesc, tts_ops);
planstate->ps_ResultTupleSlot = slot; 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 void
ExecInitResultTupleSlotTL(PlanState *planstate) ExecInitResultTupleSlotTL(PlanState *planstate,
const TupleTableSlotOps *tts_ops)
{ {
ExecInitResultTypeTL(planstate); ExecInitResultTypeTL(planstate);
ExecInitResultSlot(planstate); ExecInitResultSlot(planstate, tts_ops);
} }
/* ---------------- /* ----------------
@ -991,11 +1007,15 @@ ExecInitResultTupleSlotTL(PlanState *planstate)
* ---------------- * ----------------
*/ */
void 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, scanstate->ss_ScanTupleSlot = ExecAllocTableSlot(&estate->es_tupleTable,
tupledesc); tupledesc, tts_ops);
scanstate->ps.scandesc = tupledesc; 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 * 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 * 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); return ExecStoreAllNullTuple(slot);
} }
@ -1547,13 +1570,15 @@ HeapTupleHeaderGetDatum(HeapTupleHeader tuple)
* table function capability. Currently used by EXPLAIN and SHOW ALL. * table function capability. Currently used by EXPLAIN and SHOW ALL.
*/ */
TupOutputState * TupOutputState *
begin_tup_output_tupdesc(DestReceiver *dest, TupleDesc tupdesc) begin_tup_output_tupdesc(DestReceiver *dest,
TupleDesc tupdesc,
const TupleTableSlotOps *tts_ops)
{ {
TupOutputState *tstate; TupOutputState *tstate;
tstate = (TupOutputState *) palloc(sizeof(TupOutputState)); tstate = (TupOutputState *) palloc(sizeof(TupOutputState));
tstate->slot = MakeSingleTupleTableSlot(tupdesc); tstate->slot = MakeSingleTupleTableSlot(tupdesc, tts_ops);
tstate->dest = dest; tstate->dest = dest;
tstate->dest->rStartup(tstate->dest, (int) CMD_SELECT, tupdesc); tstate->dest->rStartup(tstate->dest, (int) CMD_SELECT, tupdesc);

View File

@ -454,6 +454,35 @@ ExecGetResultType(PlanState *planstate)
return planstate->ps_ResultTupleDesc; 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 * ExecAssignProjectionInfo
@ -492,11 +521,21 @@ ExecConditionalAssignProjectionInfo(PlanState *planstate, TupleDesc inputDesc,
planstate->plan->targetlist, planstate->plan->targetlist,
varno, varno,
inputDesc)) inputDesc))
{
planstate->ps_ProjInfo = NULL; planstate->ps_ProjInfo = NULL;
planstate->resultopsset = planstate->scanopsset;
planstate->resultopsfixed = planstate->scanopsfixed;
planstate->resultops = planstate->scanops;
}
else else
{ {
if (!planstate->ps_ResultTupleSlot) if (!planstate->ps_ResultTupleSlot)
ExecInitResultSlot(planstate); {
ExecInitResultSlot(planstate, &TTSOpsVirtual);
planstate->resultops = &TTSOpsVirtual;
planstate->resultopsfixed = true;
planstate->resultopsset = true;
}
ExecAssignProjectionInfo(planstate, inputDesc); ExecAssignProjectionInfo(planstate, inputDesc);
} }
} }
@ -611,7 +650,9 @@ ExecAssignScanType(ScanState *scanstate, TupleDesc tupDesc)
* ---------------- * ----------------
*/ */
void void
ExecCreateScanSlotFromOuterPlan(EState *estate, ScanState *scanstate) ExecCreateScanSlotFromOuterPlan(EState *estate,
ScanState *scanstate,
const TupleTableSlotOps *tts_ops)
{ {
PlanState *outerPlan; PlanState *outerPlan;
TupleDesc tupDesc; TupleDesc tupDesc;
@ -619,7 +660,7 @@ ExecCreateScanSlotFromOuterPlan(EState *estate, ScanState *scanstate)
outerPlan = outerPlanState(scanstate); outerPlan = outerPlanState(scanstate);
tupDesc = ExecGetResultType(outerPlan); tupDesc = ExecGetResultType(outerPlan);
ExecInitScanTupleSlot(estate, scanstate, tupDesc); ExecInitScanTupleSlot(estate, scanstate, tupDesc, tts_ops);
} }
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------

View File

@ -1717,7 +1717,8 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
/* Set up junk filter if needed */ /* Set up junk filter if needed */
if (junkFilter) if (junkFilter)
*junkFilter = ExecInitJunkFilter(tlist, false, NULL); *junkFilter = ExecInitJunkFilter(tlist, false,
MakeSingleTupleTableSlot(NULL, &TTSOpsMinimalTuple));
} }
else if (fn_typtype == TYPTYPE_COMPOSITE || rettype == RECORDOID) 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 */ /* Set up junk filter if needed */
if (junkFilter) if (junkFilter)
*junkFilter = ExecInitJunkFilter(tlist, false, NULL); {
TupleTableSlot *slot =
MakeSingleTupleTableSlot(NULL, &TTSOpsMinimalTuple);
*junkFilter = ExecInitJunkFilter(tlist, false, slot);
}
return false; /* NOT returning whole tuple */ 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. * what the caller expects will happen at runtime.
*/ */
if (junkFilter) if (junkFilter)
*junkFilter = ExecInitJunkFilter(tlist, false, NULL); {
TupleTableSlot *slot;
slot = MakeSingleTupleTableSlot(NULL, &TTSOpsMinimalTuple);
*junkFilter = ExecInitJunkFilter(tlist, false, slot);
}
return true; return true;
} }
Assert(tupdesc); Assert(tupdesc);
@ -1927,9 +1938,14 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
/* Set up junk filter if needed */ /* Set up junk filter if needed */
if (junkFilter) if (junkFilter)
{
TupleTableSlot *slot =
MakeSingleTupleTableSlot(NULL, &TTSOpsMinimalTuple);
*junkFilter = ExecInitJunkFilterConversion(tlist, *junkFilter = ExecInitJunkFilterConversion(tlist,
CreateTupleDescCopy(tupdesc), CreateTupleDescCopy(tupdesc),
NULL); slot);
}
/* Report that we are returning entire tuple result */ /* Report that we are returning entire tuple result */
return true; return true;

View File

@ -1403,7 +1403,8 @@ find_hash_columns(AggState *aggstate)
&perhash->eqfuncoids, &perhash->eqfuncoids,
&perhash->hashfunctions); &perhash->hashfunctions);
perhash->hashslot = perhash->hashslot =
ExecAllocTableSlot(&estate->es_tupleTable, hashDesc); ExecAllocTableSlot(&estate->es_tupleTable, hashDesc,
&TTSOpsMinimalTuple);
list_free(hashTlist); list_free(hashTlist);
bms_free(colnos); bms_free(colnos);
@ -2211,15 +2212,17 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
/* /*
* initialize source tuple type. * initialize source tuple type.
*/ */
ExecCreateScanSlotFromOuterPlan(estate, &aggstate->ss); ExecCreateScanSlotFromOuterPlan(estate, &aggstate->ss,
ExecGetResultSlotOps(outerPlanState(&aggstate->ss), NULL));
scanDesc = aggstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor; scanDesc = aggstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor;
if (node->chain) if (node->chain)
aggstate->sort_slot = ExecInitExtraTupleSlot(estate, scanDesc); aggstate->sort_slot = ExecInitExtraTupleSlot(estate, scanDesc,
&TTSOpsMinimalTuple);
/* /*
* Initialize result type, slot and projection. * Initialize result type, slot and projection.
*/ */
ExecInitResultTupleSlotTL(&aggstate->ss.ps); ExecInitResultTupleSlotTL(&aggstate->ss.ps, &TTSOpsVirtual);
ExecAssignProjectionInfo(&aggstate->ss.ps, NULL); ExecAssignProjectionInfo(&aggstate->ss.ps, NULL);
/* /*
@ -3062,7 +3065,8 @@ build_pertrans_for_aggref(AggStatePerTrans pertrans,
{ {
pertrans->sortdesc = ExecTypeFromTL(aggref->args, false); pertrans->sortdesc = ExecTypeFromTL(aggref->args, false);
pertrans->sortslot = pertrans->sortslot =
ExecInitExtraTupleSlot(estate, pertrans->sortdesc); ExecInitExtraTupleSlot(estate, pertrans->sortdesc,
&TTSOpsMinimalTuple);
} }
if (numSortCols > 0) if (numSortCols > 0)
@ -3084,7 +3088,8 @@ build_pertrans_for_aggref(AggStatePerTrans pertrans,
{ {
/* we will need an extra slot to store prior values */ /* we will need an extra slot to store prior values */
pertrans->uniqslot = pertrans->uniqslot =
ExecInitExtraTupleSlot(estate, pertrans->sortdesc); ExecInitExtraTupleSlot(estate, pertrans->sortdesc,
&TTSOpsMinimalTuple);
} }
/* Extract the sort information for use later */ /* Extract the sort information for use later */

View File

@ -196,7 +196,11 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
/* /*
* Initialize result tuple type and slot. * 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 * appendplanstates = (PlanState **) palloc(nplans *
sizeof(PlanState *)); sizeof(PlanState *));

View File

@ -913,7 +913,8 @@ ExecInitBitmapHeapScan(BitmapHeapScan *node, EState *estate, int eflags)
* get the scan type from the relation descriptor. * get the scan type from the relation descriptor.
*/ */
ExecInitScanTupleSlot(estate, &scanstate->ss, ExecInitScanTupleSlot(estate, &scanstate->ss,
RelationGetDescr(currentRelation)); RelationGetDescr(currentRelation),
&TTSOpsBufferTuple);
/* /*

View File

@ -260,7 +260,8 @@ ExecInitCteScan(CteScan *node, EState *estate, int eflags)
* table) is the same as the result rowtype of the CTE query. * table) is the same as the result rowtype of the CTE query.
*/ */
ExecInitScanTupleSlot(estate, &scanstate->ss, ExecInitScanTupleSlot(estate, &scanstate->ss,
ExecGetResultType(scanstate->cteplanstate)); ExecGetResultType(scanstate->cteplanstate),
&TTSOpsMinimalTuple);
/* /*
* Initialize result type and projection. * Initialize result type and projection.

View File

@ -73,13 +73,14 @@ ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags)
TupleDesc scan_tupdesc; TupleDesc scan_tupdesc;
scan_tupdesc = ExecTypeFromTL(cscan->custom_scan_tlist, false); 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 */ /* Node's targetlist will contain Vars with varno = INDEX_VAR */
tlistvarno = INDEX_VAR; tlistvarno = INDEX_VAR;
} }
else 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 */ /* Node's targetlist will contain Vars with varno = scanrelid */
tlistvarno = scanrelid; tlistvarno = scanrelid;
} }
@ -87,7 +88,7 @@ ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags)
/* /*
* Initialize result slot, type and projection. * Initialize result slot, type and projection.
*/ */
ExecInitResultTupleSlotTL(&css->ss.ps); ExecInitResultTupleSlotTL(&css->ss.ps, &TTSOpsVirtual);
ExecAssignScanProjectionInfoWithVarno(&css->ss, tlistvarno); ExecAssignScanProjectionInfoWithVarno(&css->ss, tlistvarno);
/* initialize child expressions */ /* initialize child expressions */

View File

@ -180,7 +180,8 @@ ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags)
TupleDesc scan_tupdesc; TupleDesc scan_tupdesc;
scan_tupdesc = ExecTypeFromTL(node->fdw_scan_tlist, false); 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 */ /* Node's targetlist will contain Vars with varno = INDEX_VAR */
tlistvarno = 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 */ /* don't trust FDWs to return tuples fulfilling NOT NULL constraints */
scan_tupdesc = CreateTupleDescCopy(RelationGetDescr(currentRelation)); 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 */ /* Node's targetlist will contain Vars with varno = scanrelid */
tlistvarno = 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. * Initialize result slot, type and projection.
*/ */

View File

@ -424,7 +424,8 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags)
*/ */
if (!scanstate->simple) if (!scanstate->simple)
{ {
fs->func_slot = ExecInitExtraTupleSlot(estate, fs->tupdesc); fs->func_slot = ExecInitExtraTupleSlot(estate, fs->tupdesc,
&TTSOpsMinimalTuple);
} }
else else
fs->func_slot = NULL; fs->func_slot = NULL;
@ -482,7 +483,8 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags)
/* /*
* Initialize scan slot and type. * Initialize scan slot and type.
*/ */
ExecInitScanTupleSlot(estate, &scanstate->ss, scan_tupdesc); ExecInitScanTupleSlot(estate, &scanstate->ss, scan_tupdesc,
&TTSOpsMinimalTuple);
/* /*
* Initialize result slot, type and projection. * Initialize result slot, type and projection.

View File

@ -91,6 +91,11 @@ ExecInitGather(Gather *node, EState *estate, int eflags)
outerPlanState(gatherstate) = ExecInitNode(outerNode, estate, eflags); outerPlanState(gatherstate) = ExecInitNode(outerNode, estate, eflags);
tupDesc = ExecGetResultType(outerPlanState(gatherstate)); 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. * 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. * 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 * Gather doesn't support checking a qual (it's always more efficient to

View File

@ -122,6 +122,13 @@ ExecInitGatherMerge(GatherMerge *node, EState *estate, int eflags)
ExecInitResultTypeTL(&gm_state->ps); ExecInitResultTypeTL(&gm_state->ps);
ExecConditionalAssignProjectionInfo(&gm_state->ps, tupDesc, OUTER_VAR); 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 * initialize sort-key information
*/ */
@ -404,7 +411,8 @@ gather_merge_setup(GatherMergeState *gm_state)
/* Initialize tuple slot for worker */ /* Initialize tuple slot for worker */
gm_state->gm_slots[i + 1] = 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 */ /* Allocate the resources for the merge */

View File

@ -162,6 +162,7 @@ GroupState *
ExecInitGroup(Group *node, EState *estate, int eflags) ExecInitGroup(Group *node, EState *estate, int eflags)
{ {
GroupState *grpstate; GroupState *grpstate;
const TupleTableSlotOps *tts_ops;
/* check for unsupported flags */ /* check for unsupported flags */
Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK))); Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
@ -188,12 +189,13 @@ ExecInitGroup(Group *node, EState *estate, int eflags)
/* /*
* Initialize scan slot and type. * 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. * Initialize result slot, type and projection.
*/ */
ExecInitResultTupleSlotTL(&grpstate->ss.ps); ExecInitResultTupleSlotTL(&grpstate->ss.ps, &TTSOpsVirtual);
ExecAssignProjectionInfo(&grpstate->ss.ps, NULL); ExecAssignProjectionInfo(&grpstate->ss.ps, NULL);
/* /*

View File

@ -382,7 +382,7 @@ ExecInitHash(Hash *node, EState *estate, int eflags)
* initialize our result slot and type. No need to build projection * initialize our result slot and type. No need to build projection
* because this node doesn't do projections. * because this node doesn't do projections.
*/ */
ExecInitResultTupleSlotTL(&hashstate->ps); ExecInitResultTupleSlotTL(&hashstate->ps, &TTSOpsMinimalTuple);
hashstate->ps.ps_ProjInfo = NULL; hashstate->ps.ps_ProjInfo = NULL;
/* /*

View File

@ -606,6 +606,7 @@ ExecInitHashJoin(HashJoin *node, EState *estate, int eflags)
TupleDesc outerDesc, TupleDesc outerDesc,
innerDesc; innerDesc;
ListCell *l; ListCell *l;
const TupleTableSlotOps *ops;
/* check for unsupported flags */ /* check for unsupported flags */
Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK))); 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. * Initialize result slot, type and projection.
*/ */
ExecInitResultTupleSlotTL(&hjstate->js.ps); ExecInitResultTupleSlotTL(&hjstate->js.ps, &TTSOpsVirtual);
ExecAssignProjectionInfo(&hjstate->js.ps, NULL); ExecAssignProjectionInfo(&hjstate->js.ps, NULL);
/* /*
* tuple table initialization * 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 * 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_LEFT:
case JOIN_ANTI: case JOIN_ANTI:
hjstate->hj_NullInnerTupleSlot = hjstate->hj_NullInnerTupleSlot =
ExecInitNullTupleSlot(estate, innerDesc); ExecInitNullTupleSlot(estate, innerDesc, &TTSOpsVirtual);
break; break;
case JOIN_RIGHT: case JOIN_RIGHT:
hjstate->hj_NullOuterTupleSlot = hjstate->hj_NullOuterTupleSlot =
ExecInitNullTupleSlot(estate, outerDesc); ExecInitNullTupleSlot(estate, outerDesc, &TTSOpsVirtual);
break; break;
case JOIN_FULL: case JOIN_FULL:
hjstate->hj_NullOuterTupleSlot = hjstate->hj_NullOuterTupleSlot =
ExecInitNullTupleSlot(estate, outerDesc); ExecInitNullTupleSlot(estate, outerDesc, &TTSOpsVirtual);
hjstate->hj_NullInnerTupleSlot = hjstate->hj_NullInnerTupleSlot =
ExecInitNullTupleSlot(estate, innerDesc); ExecInitNullTupleSlot(estate, innerDesc, &TTSOpsVirtual);
break; break;
default: default:
elog(ERROR, "unrecognized join type: %d", elog(ERROR, "unrecognized join type: %d",

View File

@ -527,7 +527,7 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
* suitable data anyway.) * suitable data anyway.)
*/ */
tupDesc = ExecTypeFromTL(node->indextlist, false); 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 * Initialize result type and projection info. The node's targetlist will

View File

@ -208,8 +208,6 @@ IndexNextWithReorder(IndexScanState *node)
scandesc = node->iss_ScanDesc; scandesc = node->iss_ScanDesc;
econtext = node->ss.ps.ps_ExprContext; econtext = node->ss.ps.ps_ExprContext;
slot = node->ss.ss_ScanTupleSlot;
if (scandesc == NULL) if (scandesc == NULL)
{ {
/* /*
@ -245,6 +243,7 @@ IndexNextWithReorder(IndexScanState *node)
*/ */
if (!pairingheap_is_empty(node->iss_ReorderQueue)) if (!pairingheap_is_empty(node->iss_ReorderQueue))
{ {
slot = node->iss_ReorderQueueSlot;
topmost = (ReorderTuple *) pairingheap_first(node->iss_ReorderQueue); topmost = (ReorderTuple *) pairingheap_first(node->iss_ReorderQueue);
if (node->iss_ReachedEnd || if (node->iss_ReachedEnd ||
@ -264,13 +263,15 @@ IndexNextWithReorder(IndexScanState *node)
else if (node->iss_ReachedEnd) else if (node->iss_ReachedEnd)
{ {
/* Queue is empty, and no more tuples from index. We're done. */ /* 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. * Fetch next tuple from the index.
*/ */
next_indextuple: next_indextuple:
slot = node->ss.ss_ScanTupleSlot;
tuple = index_getnext(scandesc, ForwardScanDirection); tuple = index_getnext(scandesc, ForwardScanDirection);
if (!tuple) 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 * if we get here it means the index scan failed so we are at the end of
* the scan.. * 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) if (node->ss.ps.ps_ResultTupleSlot)
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
if (node->iss_ReorderQueueSlot)
ExecClearTuple(node->iss_ReorderQueueSlot);
ExecClearTuple(node->ss.ss_ScanTupleSlot); ExecClearTuple(node->ss.ss_ScanTupleSlot);
/* /*
@ -945,7 +949,8 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
* get the scan type from the relation descriptor. * get the scan type from the relation descriptor.
*/ */
ExecInitScanTupleSlot(estate, &indexstate->ss, ExecInitScanTupleSlot(estate, &indexstate->ss,
RelationGetDescr(currentRelation)); RelationGetDescr(currentRelation),
&TTSOpsBufferTuple);
/* /*
* Initialize result type and projection. * Initialize result type and projection.
@ -1076,9 +1081,13 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
indexstate->iss_OrderByNulls = (bool *) indexstate->iss_OrderByNulls = (bool *)
palloc(numOrderByKeys * sizeof(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->iss_ReorderQueue = pairingheap_allocate(reorderqueue_cmp,
indexstate); indexstate);
indexstate->iss_ReorderQueueSlot =
ExecAllocTableSlot(&estate->es_tupleTable,
RelationGetDescr(currentRelation),
&TTSOpsHeapTuple);
} }
/* /*

View File

@ -380,6 +380,10 @@ ExecInitLimit(Limit *node, EState *estate, int eflags)
*/ */
ExecInitResultTypeTL(&limitstate->ps); 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 * limit nodes do no projections, so initialize projection info for this
* node appropriately * node appropriately

View File

@ -390,6 +390,11 @@ ExecInitLockRows(LockRows *node, EState *estate, int eflags)
*/ */
outerPlanState(lrstate) = ExecInitNode(outerPlan, estate, 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 * LockRows nodes do no projections, so initialize projection info for
* this node appropriately * this node appropriately

View File

@ -146,10 +146,8 @@ ExecMaterial(PlanState *pstate)
if (tuplestorestate) if (tuplestorestate)
tuplestore_puttupleslot(tuplestorestate, outerslot); tuplestore_puttupleslot(tuplestorestate, outerslot);
/* ExecCopySlot(slot, outerslot);
* We can just return the subplan's returned tuple, without copying. return slot;
*/
return outerslot;
} }
/* /*
@ -223,13 +221,13 @@ ExecInitMaterial(Material *node, EState *estate, int eflags)
* *
* material nodes only return tuples from their materialized relation. * material nodes only return tuples from their materialized relation.
*/ */
ExecInitResultTupleSlotTL(&matstate->ss.ps); ExecInitResultTupleSlotTL(&matstate->ss.ps, &TTSOpsMinimalTuple);
matstate->ss.ps.ps_ProjInfo = NULL; matstate->ss.ps.ps_ProjInfo = NULL;
/* /*
* initialize tuple type. * initialize tuple type.
*/ */
ExecCreateScanSlotFromOuterPlan(estate, &matstate->ss); ExecCreateScanSlotFromOuterPlan(estate, &matstate->ss, &TTSOpsMinimalTuple);
return matstate; return matstate;
} }

View File

@ -167,7 +167,11 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
* MergeAppend nodes do have Result slots, which hold pointers to tuples, * MergeAppend nodes do have Result slots, which hold pointers to tuples,
* so we have to initialize them. FIXME * 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 * call ExecInitNode on each of the valid plans to be executed and save

View File

@ -1438,6 +1438,7 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags)
MergeJoinState *mergestate; MergeJoinState *mergestate;
TupleDesc outerDesc, TupleDesc outerDesc,
innerDesc; innerDesc;
const TupleTableSlotOps *innerOps;
/* check for unsupported flags */ /* check for unsupported flags */
Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK))); 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. * Initialize result slot, type and projection.
*/ */
ExecInitResultTupleSlotTL(&mergestate->js.ps); ExecInitResultTupleSlotTL(&mergestate->js.ps, &TTSOpsVirtual);
ExecAssignProjectionInfo(&mergestate->js.ps, NULL); ExecAssignProjectionInfo(&mergestate->js.ps, NULL);
/* /*
* tuple table initialization * tuple table initialization
*/ */
mergestate->mj_MarkedTupleSlot = ExecInitExtraTupleSlot(estate, innerDesc); innerOps = ExecGetResultSlotOps(innerPlanState(mergestate), NULL);
mergestate->mj_MarkedTupleSlot = ExecInitExtraTupleSlot(estate, innerDesc,
innerOps);
/* /*
* initialize child expressions * initialize child expressions
@ -1548,13 +1551,13 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags)
mergestate->mj_FillOuter = true; mergestate->mj_FillOuter = true;
mergestate->mj_FillInner = false; mergestate->mj_FillInner = false;
mergestate->mj_NullInnerTupleSlot = mergestate->mj_NullInnerTupleSlot =
ExecInitNullTupleSlot(estate, innerDesc); ExecInitNullTupleSlot(estate, innerDesc, &TTSOpsVirtual);
break; break;
case JOIN_RIGHT: case JOIN_RIGHT:
mergestate->mj_FillOuter = false; mergestate->mj_FillOuter = false;
mergestate->mj_FillInner = true; mergestate->mj_FillInner = true;
mergestate->mj_NullOuterTupleSlot = mergestate->mj_NullOuterTupleSlot =
ExecInitNullTupleSlot(estate, outerDesc); ExecInitNullTupleSlot(estate, outerDesc, &TTSOpsVirtual);
/* /*
* Can't handle right or full join with non-constant extra * 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_FillOuter = true;
mergestate->mj_FillInner = true; mergestate->mj_FillInner = true;
mergestate->mj_NullOuterTupleSlot = mergestate->mj_NullOuterTupleSlot =
ExecInitNullTupleSlot(estate, outerDesc); ExecInitNullTupleSlot(estate, outerDesc, &TTSOpsVirtual);
mergestate->mj_NullInnerTupleSlot = mergestate->mj_NullInnerTupleSlot =
ExecInitNullTupleSlot(estate, innerDesc); ExecInitNullTupleSlot(estate, innerDesc, &TTSOpsVirtual);
/* /*
* Can't handle right or full join with non-constant extra * Can't handle right or full join with non-constant extra

View File

@ -2055,6 +2055,15 @@ ExecModifyTable(PlanState *pstate)
break; 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 * If resultRelInfo->ri_usesFdwDirectModify is true, all we need to do
* here is compute the RETURNING expressions. * 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->mt_plans = (PlanState **) palloc0(sizeof(PlanState *) * nplans);
mtstate->resultRelInfo = estate->es_result_relations + node->resultRelIndex; 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 modifying a partitioned table, initialize the root table info */
if (node->rootResultRelIndex >= 0) if (node->rootResultRelIndex >= 0)
@ -2304,6 +2314,9 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
/* Now init the plan for this result rel */ /* Now init the plan for this result rel */
estate->es_result_relation_info = resultRelInfo; estate->es_result_relation_info = resultRelInfo;
mtstate->mt_plans[i] = ExecInitNode(subplan, estate, eflags); 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 */ /* Also let FDWs init themselves for foreign-table result rels */
if (!resultRelInfo->ri_usesFdwDirectModify && if (!resultRelInfo->ri_usesFdwDirectModify &&
@ -2403,7 +2416,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
mtstate->ps.plan->targetlist = (List *) linitial(node->returningLists); mtstate->ps.plan->targetlist = (List *) linitial(node->returningLists);
/* Set up a slot for the output of the RETURNING projection(s) */ /* Set up a slot for the output of the RETURNING projection(s) */
ExecInitResultTupleSlotTL(&mtstate->ps); ExecInitResultTupleSlotTL(&mtstate->ps, &TTSOpsVirtual);
slot = mtstate->ps.ps_ResultTupleSlot; slot = mtstate->ps.ps_ResultTupleSlot;
/* Need an econtext too */ /* Need an econtext too */
@ -2472,7 +2485,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
mtstate->mt_existing = mtstate->mt_existing =
ExecInitExtraTupleSlot(mtstate->ps.state, ExecInitExtraTupleSlot(mtstate->ps.state,
mtstate->mt_partition_tuple_routing ? mtstate->mt_partition_tuple_routing ?
NULL : relationDesc); NULL : relationDesc, &TTSOpsBufferTuple);
/* carried forward solely for the benefit of explain */ /* carried forward solely for the benefit of explain */
mtstate->mt_excludedtlist = node->exclRelTlist; mtstate->mt_excludedtlist = node->exclRelTlist;
@ -2494,7 +2507,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
mtstate->mt_conflproj = mtstate->mt_conflproj =
ExecInitExtraTupleSlot(mtstate->ps.state, ExecInitExtraTupleSlot(mtstate->ps.state,
mtstate->mt_partition_tuple_routing ? mtstate->mt_partition_tuple_routing ?
NULL : tupDesc); NULL : tupDesc, &TTSOpsHeapTuple);
resultRelInfo->ri_onConflict->oc_ProjTupdesc = tupDesc; resultRelInfo->ri_onConflict->oc_ProjTupdesc = tupDesc;
/* build UPDATE SET projection state */ /* build UPDATE SET projection state */
@ -2605,7 +2618,8 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
j = ExecInitJunkFilter(subplan->targetlist, j = ExecInitJunkFilter(subplan->targetlist,
resultRelInfo->ri_RelationDesc->rd_att->tdhasoid, resultRelInfo->ri_RelationDesc->rd_att->tdhasoid,
ExecInitExtraTupleSlot(estate, NULL)); ExecInitExtraTupleSlot(estate, NULL,
&TTSOpsHeapTuple));
if (operation == CMD_UPDATE || operation == CMD_DELETE) 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 * 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 * 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) 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 * Lastly, if this is not the primary (canSetTag) ModifyTable node, add it

View File

@ -137,7 +137,8 @@ ExecInitNamedTuplestoreScan(NamedTuplestoreScan *node, EState *estate, int eflag
/* /*
* The scan tuple type is specified for the tuplestore. * 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. * Initialize result type and projection.

View File

@ -304,7 +304,7 @@ ExecInitNestLoop(NestLoop *node, EState *estate, int eflags)
/* /*
* Initialize result slot, type and projection. * Initialize result slot, type and projection.
*/ */
ExecInitResultTupleSlotTL(&nlstate->js.ps); ExecInitResultTupleSlotTL(&nlstate->js.ps, &TTSOpsVirtual);
ExecAssignProjectionInfo(&nlstate->js.ps, NULL); ExecAssignProjectionInfo(&nlstate->js.ps, NULL);
/* /*
@ -332,7 +332,8 @@ ExecInitNestLoop(NestLoop *node, EState *estate, int eflags)
case JOIN_ANTI: case JOIN_ANTI:
nlstate->nl_NullInnerTupleSlot = nlstate->nl_NullInnerTupleSlot =
ExecInitNullTupleSlot(estate, ExecInitNullTupleSlot(estate,
ExecGetResultType(innerPlanState(nlstate))); ExecGetResultType(innerPlanState(nlstate)),
&TTSOpsVirtual);
break; break;
default: default:
elog(ERROR, "unrecognized join type: %d", elog(ERROR, "unrecognized join type: %d",

View File

@ -256,7 +256,7 @@ ExecInitProjectSet(ProjectSet *node, EState *estate, int eflags)
/* /*
* tuple table and result type initialization * 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 */ /* Create workspace for per-tlist-entry expr state & SRF-is-done state */
state->nelems = list_length(node->plan.targetlist); state->nelems = list_length(node->plan.targetlist);

View File

@ -217,7 +217,7 @@ ExecInitResult(Result *node, EState *estate, int eflags)
/* /*
* Initialize result slot, type and projection. * Initialize result slot, type and projection.
*/ */
ExecInitResultTupleSlotTL(&resstate->ps); ExecInitResultTupleSlotTL(&resstate->ps, &TTSOpsVirtual);
ExecAssignProjectionInfo(&resstate->ps, NULL); ExecAssignProjectionInfo(&resstate->ps, NULL);
/* /*

View File

@ -146,7 +146,8 @@ ExecInitSampleScan(SampleScan *node, EState *estate, int eflags)
/* and create slot with appropriate rowtype */ /* and create slot with appropriate rowtype */
ExecInitScanTupleSlot(estate, &scanstate->ss, ExecInitScanTupleSlot(estate, &scanstate->ss,
RelationGetDescr(scanstate->ss.ss_currentRelation)); RelationGetDescr(scanstate->ss.ss_currentRelation),
&TTSOpsBufferTuple);
/* /*
* Initialize result type and projection. * Initialize result type and projection.

View File

@ -172,7 +172,8 @@ ExecInitSeqScan(SeqScan *node, EState *estate, int eflags)
/* and create slot with the appropriate rowtype */ /* and create slot with the appropriate rowtype */
ExecInitScanTupleSlot(estate, &scanstate->ss, ExecInitScanTupleSlot(estate, &scanstate->ss,
RelationGetDescr(scanstate->ss.ss_currentRelation)); RelationGetDescr(scanstate->ss.ss_currentRelation),
&TTSOpsBufferTuple);
/* /*
* Initialize result type and projection. * Initialize result type and projection.

View File

@ -532,7 +532,9 @@ ExecInitSetOp(SetOp *node, EState *estate, int eflags)
* Initialize result slot and type. Setop nodes do no projections, so * Initialize result slot and type. Setop nodes do no projections, so
* initialize projection info for this node appropriately. * initialize projection info for this node appropriately.
*/ */
ExecInitResultTupleSlotTL(&setopstate->ps); ExecInitResultTupleSlotTL(&setopstate->ps,
node->strategy == SETOP_HASHED ?
&TTSOpsMinimalTuple : &TTSOpsHeapTuple);
setopstate->ps.ps_ProjInfo = NULL; setopstate->ps.ps_ProjInfo = NULL;
/* /*

View File

@ -211,13 +211,13 @@ ExecInitSort(Sort *node, EState *estate, int eflags)
/* /*
* Initialize scan slot and type. * 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 * Initialize return slot and type. No need to initialize projection info
* because this node doesn't do projections. * because this node doesn't do projections.
*/ */
ExecInitResultTupleSlotTL(&sortstate->ss.ps); ExecInitResultTupleSlotTL(&sortstate->ss.ps, &TTSOpsMinimalTuple);
sortstate->ss.ps.ps_ProjInfo = NULL; sortstate->ss.ps.ps_ProjInfo = NULL;
SO1_printf("ExecInitSort: %s\n", SO1_printf("ExecInitSort: %s\n",

View File

@ -968,7 +968,7 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
* own innerecontext. * own innerecontext.
*/ */
tupDescLeft = ExecTypeFromTL(lefttlist, false); tupDescLeft = ExecTypeFromTL(lefttlist, false);
slot = ExecInitExtraTupleSlot(estate, tupDescLeft); slot = ExecInitExtraTupleSlot(estate, tupDescLeft, &TTSOpsVirtual);
sstate->projLeft = ExecBuildProjectionInfo(lefttlist, sstate->projLeft = ExecBuildProjectionInfo(lefttlist,
NULL, NULL,
slot, slot,
@ -976,7 +976,7 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
NULL); NULL);
sstate->descRight = tupDescRight = ExecTypeFromTL(righttlist, false); sstate->descRight = tupDescRight = ExecTypeFromTL(righttlist, false);
slot = ExecInitExtraTupleSlot(estate, tupDescRight); slot = ExecInitExtraTupleSlot(estate, tupDescRight, &TTSOpsVirtual);
sstate->projRight = ExecBuildProjectionInfo(righttlist, sstate->projRight = ExecBuildProjectionInfo(righttlist,
sstate->innerecontext, sstate->innerecontext,
slot, slot,
@ -988,6 +988,7 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
* across-type comparison). * across-type comparison).
*/ */
sstate->cur_eq_comp = ExecBuildGroupingEqual(tupDescLeft, tupDescRight, sstate->cur_eq_comp = ExecBuildGroupingEqual(tupDescLeft, tupDescRight,
&TTSOpsVirtual, &TTSOpsMinimalTuple,
ncols, ncols,
sstate->keyColIdx, sstate->keyColIdx,
sstate->tab_eq_funcoids, sstate->tab_eq_funcoids,

View File

@ -129,7 +129,18 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate, int eflags)
* Initialize scan slot and type (needed by ExecAssignScanProjectionInfo) * Initialize scan slot and type (needed by ExecAssignScanProjectionInfo)
*/ */
ExecInitScanTupleSlot(estate, &subquerystate->ss, 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. * Initialize result type and projection.

View File

@ -147,7 +147,8 @@ ExecInitTableFuncScan(TableFuncScan *node, EState *estate, int eflags)
tf->coltypmods, tf->coltypmods,
tf->colcollations); tf->colcollations);
/* and the corresponding scan slot */ /* and the corresponding scan slot */
ExecInitScanTupleSlot(estate, &scanstate->ss, tupdesc); ExecInitScanTupleSlot(estate, &scanstate->ss, tupdesc,
&TTSOpsMinimalTuple);
/* /*
* Initialize result type and projection. * Initialize result type and projection.

View File

@ -543,7 +543,8 @@ ExecInitTidScan(TidScan *node, EState *estate, int eflags)
* get the scan type from the relation descriptor. * get the scan type from the relation descriptor.
*/ */
ExecInitScanTupleSlot(estate, &tidstate->ss, ExecInitScanTupleSlot(estate, &tidstate->ss,
RelationGetDescr(currentRelation)); RelationGetDescr(currentRelation),
&TTSOpsBufferTuple);
/* /*
* Initialize result type and projection. * Initialize result type and projection.

View File

@ -141,7 +141,7 @@ ExecInitUnique(Unique *node, EState *estate, int eflags)
* Initialize result slot and type. Unique nodes do no projections, so * Initialize result slot and type. Unique nodes do no projections, so
* initialize projection info for this node appropriately. * initialize projection info for this node appropriately.
*/ */
ExecInitResultTupleSlotTL(&uniquestate->ps); ExecInitResultTupleSlotTL(&uniquestate->ps, &TTSOpsMinimalTuple);
uniquestate->ps.ps_ProjInfo = NULL; uniquestate->ps.ps_ProjInfo = NULL;
/* /*

View File

@ -261,7 +261,7 @@ ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags)
* Get info about values list, initialize scan slot with it. * Get info about values list, initialize scan slot with it.
*/ */
tupdesc = ExecTypeFromExprList((List *) linitial(node->values_lists)); tupdesc = ExecTypeFromExprList((List *) linitial(node->values_lists));
ExecInitScanTupleSlot(estate, &scanstate->ss, tupdesc); ExecInitScanTupleSlot(estate, &scanstate->ss, tupdesc, &TTSOpsVirtual);
/* /*
* Initialize result type and projection. * Initialize result type and projection.

View 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 * initialize source tuple type (which is also the tuple type that we'll
* store in the tuplestore and use in all our working slots). * 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; 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 * tuple table initialization
*/ */
winstate->first_part_slot = ExecInitExtraTupleSlot(estate, scanDesc); winstate->first_part_slot = ExecInitExtraTupleSlot(estate, scanDesc,
winstate->agg_row_slot = ExecInitExtraTupleSlot(estate, scanDesc); &TTSOpsMinimalTuple);
winstate->temp_slot_1 = ExecInitExtraTupleSlot(estate, scanDesc); winstate->agg_row_slot = ExecInitExtraTupleSlot(estate, scanDesc,
winstate->temp_slot_2 = 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 * 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) && if (((frameOptions & FRAMEOPTION_START_CURRENT_ROW) &&
node->ordNumCols != 0) || node->ordNumCols != 0) ||
(frameOptions & FRAMEOPTION_START_OFFSET)) (frameOptions & FRAMEOPTION_START_OFFSET))
winstate->framehead_slot = ExecInitExtraTupleSlot(estate, scanDesc); winstate->framehead_slot = ExecInitExtraTupleSlot(estate, scanDesc,
&TTSOpsMinimalTuple);
if (((frameOptions & FRAMEOPTION_END_CURRENT_ROW) && if (((frameOptions & FRAMEOPTION_END_CURRENT_ROW) &&
node->ordNumCols != 0) || node->ordNumCols != 0) ||
(frameOptions & FRAMEOPTION_END_OFFSET)) (frameOptions & FRAMEOPTION_END_OFFSET))
winstate->frametail_slot = ExecInitExtraTupleSlot(estate, scanDesc); winstate->frametail_slot = ExecInitExtraTupleSlot(estate, scanDesc,
&TTSOpsMinimalTuple);
} }
/* /*
* Initialize result slot, type and projection. * Initialize result slot, type and projection.
*/ */
ExecInitResultTupleSlotTL(&winstate->ss.ps); ExecInitResultTupleSlotTL(&winstate->ss.ps, &TTSOpsVirtual);
ExecAssignProjectionInfo(&winstate->ss.ps, NULL); ExecAssignProjectionInfo(&winstate->ss.ps, NULL);
/* Set up data for comparing tuples */ /* Set up data for comparing tuples */

View File

@ -160,7 +160,12 @@ ExecInitWorkTableScan(WorkTableScan *node, EState *estate, int eflags)
* tuple table initialization * tuple table initialization
*/ */
ExecInitResultTypeTL(&scanstate->ss.ps); 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 * initialize child expressions

View File

@ -1275,7 +1275,7 @@ check_default_partition_contents(Relation parent, Relation default_rel,
econtext = GetPerTupleExprContext(estate); econtext = GetPerTupleExprContext(estate);
snapshot = RegisterSnapshot(GetLatestSnapshot()); snapshot = RegisterSnapshot(GetLatestSnapshot());
scan = heap_beginscan(part_rel, snapshot, 0, NULL); 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 * Switch to per-tuple memory context and reset it for each tuple

View 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", (errmsg("could not fetch table info for table \"%s.%s\" from publisher: %s",
nspname, relname, res->err))); nspname, relname, res->err)));
slot = MakeSingleTupleTableSlot(res->tupledesc); slot = MakeSingleTupleTableSlot(res->tupledesc, &TTSOpsMinimalTuple);
if (!tuplestore_gettupleslot(res->tuplestore, true, false, slot)) if (!tuplestore_gettupleslot(res->tuplestore, true, false, slot))
ereport(ERROR, ereport(ERROR,
(errmsg("table \"%s.%s\" not found on publisher", (errmsg("table \"%s.%s\" not found on publisher",
@ -727,7 +727,7 @@ fetch_remote_table_info(char *nspname, char *relname,
lrel->attkeys = NULL; lrel->attkeys = NULL;
natt = 0; natt = 0;
slot = MakeSingleTupleTableSlot(res->tupledesc); slot = MakeSingleTupleTableSlot(res->tupledesc, &TTSOpsMinimalTuple);
while (tuplestore_gettupleslot(res->tuplestore, true, false, slot)) while (tuplestore_gettupleslot(res->tuplestore, true, false, slot))
{ {
lrel->attnames[natt] = lrel->attnames[natt] =

View File

@ -213,7 +213,8 @@ create_estate_for_relation(LogicalRepRelMapEntry *rel)
/* Triggers might need a slot */ /* Triggers might need a slot */
if (resultRelInfo->ri_TrigDesc) 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. */ /* Prepare to catch AFTER triggers. */
AfterTriggerBeginQuery(); AfterTriggerBeginQuery();
@ -609,7 +610,8 @@ apply_handle_insert(StringInfo s)
/* Initialize the executor state. */ /* Initialize the executor state. */
estate = create_estate_for_relation(rel); estate = create_estate_for_relation(rel);
remoteslot = ExecInitExtraTupleSlot(estate, remoteslot = ExecInitExtraTupleSlot(estate,
RelationGetDescr(rel->localrel)); RelationGetDescr(rel->localrel),
&TTSOpsHeapTuple);
/* Input functions may need an active snapshot, so get one */ /* Input functions may need an active snapshot, so get one */
PushActiveSnapshot(GetTransactionSnapshot()); PushActiveSnapshot(GetTransactionSnapshot());
@ -715,9 +717,11 @@ apply_handle_update(StringInfo s)
/* Initialize the executor state. */ /* Initialize the executor state. */
estate = create_estate_for_relation(rel); estate = create_estate_for_relation(rel);
remoteslot = ExecInitExtraTupleSlot(estate, remoteslot = ExecInitExtraTupleSlot(estate,
RelationGetDescr(rel->localrel)); RelationGetDescr(rel->localrel),
&TTSOpsHeapTuple);
localslot = ExecInitExtraTupleSlot(estate, localslot = ExecInitExtraTupleSlot(estate,
RelationGetDescr(rel->localrel)); RelationGetDescr(rel->localrel),
&TTSOpsHeapTuple);
EvalPlanQualInit(&epqstate, estate, NULL, NIL, -1); EvalPlanQualInit(&epqstate, estate, NULL, NIL, -1);
PushActiveSnapshot(GetTransactionSnapshot()); PushActiveSnapshot(GetTransactionSnapshot());
@ -756,7 +760,7 @@ apply_handle_update(StringInfo s)
{ {
/* Process and store remote tuple in the slot */ /* Process and store remote tuple in the slot */
oldctx = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate)); oldctx = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
ExecStoreHeapTuple(localslot->tts_tuple, remoteslot, false); ExecCopySlot(remoteslot, localslot);
slot_modify_cstrings(remoteslot, rel, newtup.values, newtup.changed); slot_modify_cstrings(remoteslot, rel, newtup.values, newtup.changed);
MemoryContextSwitchTo(oldctx); MemoryContextSwitchTo(oldctx);
@ -833,9 +837,11 @@ apply_handle_delete(StringInfo s)
/* Initialize the executor state. */ /* Initialize the executor state. */
estate = create_estate_for_relation(rel); estate = create_estate_for_relation(rel);
remoteslot = ExecInitExtraTupleSlot(estate, remoteslot = ExecInitExtraTupleSlot(estate,
RelationGetDescr(rel->localrel)); RelationGetDescr(rel->localrel),
&TTSOpsVirtual);
localslot = ExecInitExtraTupleSlot(estate, localslot = ExecInitExtraTupleSlot(estate,
RelationGetDescr(rel->localrel)); RelationGetDescr(rel->localrel),
&TTSOpsHeapTuple);
EvalPlanQualInit(&epqstate, estate, NULL, NIL, -1); EvalPlanQualInit(&epqstate, estate, NULL, NIL, -1);
PushActiveSnapshot(GetTransactionSnapshot()); PushActiveSnapshot(GetTransactionSnapshot());

View File

@ -403,7 +403,7 @@ IdentifySystem(void)
TEXTOID, -1, 0); TEXTOID, -1, 0);
/* prepare for projection of tuples */ /* prepare for projection of tuples */
tstate = begin_tup_output_tupdesc(dest, tupdesc); tstate = begin_tup_output_tupdesc(dest, tupdesc, &TTSOpsVirtual);
/* column 1: system identifier */ /* column 1: system identifier */
values[0] = CStringGetTextDatum(sysid); values[0] = CStringGetTextDatum(sysid);
@ -735,7 +735,7 @@ StartReplication(StartReplicationCmd *cmd)
TEXTOID, -1, 0); TEXTOID, -1, 0);
/* prepare for projection of tuple */ /* 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[0] = Int64GetDatum((int64) sendTimeLineNextTLI);
values[1] = CStringGetTextDatum(startpos_str); values[1] = CStringGetTextDatum(startpos_str);
@ -1007,7 +1007,7 @@ CreateReplicationSlot(CreateReplicationSlotCmd *cmd)
TEXTOID, -1, 0); TEXTOID, -1, 0);
/* prepare for projection of tuples */ /* prepare for projection of tuples */
tstate = begin_tup_output_tupdesc(dest, tupdesc); tstate = begin_tup_output_tupdesc(dest, tupdesc, &TTSOpsVirtual);
/* slot_name */ /* slot_name */
slot_name = NameStr(MyReplicationSlot->data.name); slot_name = NameStr(MyReplicationSlot->data.name);

View File

@ -1071,7 +1071,7 @@ RunFromStore(Portal portal, ScanDirection direction, uint64 count,
uint64 current_tuple_count = 0; uint64 current_tuple_count = 0;
TupleTableSlot *slot; TupleTableSlot *slot;
slot = MakeSingleTupleTableSlot(portal->tupDesc); slot = MakeSingleTupleTableSlot(portal->tupDesc, &TTSOpsMinimalTuple);
dest->rStartup(dest, CMD_SELECT, portal->tupDesc); dest->rStartup(dest, CMD_SELECT, portal->tupDesc);

View File

@ -239,7 +239,8 @@ ordered_set_startup(FunctionCallInfo fcinfo, bool use_tuples)
} }
/* Create slot we'll use to store/retrieve rows */ /* Create slot we'll use to store/retrieve rows */
qstate->tupslot = MakeSingleTupleTableSlot(qstate->tupdesc); qstate->tupslot = MakeSingleTupleTableSlot(qstate->tupdesc,
&TTSOpsMinimalTuple);
} }
else else
{ {
@ -1375,7 +1376,8 @@ hypothetical_dense_rank_final(PG_FUNCTION_ARGS)
* previous row available for comparisons. This is accomplished by * previous row available for comparisons. This is accomplished by
* swapping the slot pointer variables after each row. * swapping the slot pointer variables after each row.
*/ */
extraslot = MakeSingleTupleTableSlot(osastate->qstate->tupdesc); extraslot = MakeSingleTupleTableSlot(osastate->qstate->tupdesc,
&TTSOpsMinimalTuple);
slot2 = extraslot; slot2 = extraslot;
/* iterate till we find the hypothetical row */ /* iterate till we find the hypothetical row */

View File

@ -5534,7 +5534,8 @@ get_actual_variable_range(PlannerInfo *root, VariableStatData *vardata,
indexInfo = BuildIndexInfo(indexRel); indexInfo = BuildIndexInfo(indexRel);
/* some other stuff */ /* some other stuff */
slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRel)); slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRel),
&TTSOpsHeapTuple);
econtext->ecxt_scantuple = slot; econtext->ecxt_scantuple = slot;
get_typlenbyval(vardata->atttype, &typLen, &typByVal); get_typlenbyval(vardata->atttype, &typLen, &typByVal);
InitNonVacuumableSnapshot(SnapshotNonVacuumable, RecentGlobalXmin); InitNonVacuumableSnapshot(SnapshotNonVacuumable, RecentGlobalXmin);

View File

@ -8262,7 +8262,7 @@ ShowGUCConfigOption(const char *name, DestReceiver *dest)
TEXTOID, -1, 0); TEXTOID, -1, 0);
/* prepare for projection of tuples */ /* prepare for projection of tuples */
tstate = begin_tup_output_tupdesc(dest, tupdesc); tstate = begin_tup_output_tupdesc(dest, tupdesc, &TTSOpsVirtual);
/* Send it */ /* Send it */
do_text_output_oneline(tstate, value); do_text_output_oneline(tstate, value);
@ -8292,7 +8292,7 @@ ShowAllGUCConfig(DestReceiver *dest)
TEXTOID, -1, 0); TEXTOID, -1, 0);
/* prepare for projection of tuples */ /* 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++) for (i = 0; i < num_guc_variables; i++)
{ {

View File

@ -933,7 +933,7 @@ tuplesort_begin_cluster(TupleDesc tupDesc,
* scantuple has to point to that slot, too. * scantuple has to point to that slot, too.
*/ */
state->estate = CreateExecutorState(); state->estate = CreateExecutorState();
slot = MakeSingleTupleTableSlot(tupDesc); slot = MakeSingleTupleTableSlot(tupDesc, &TTSOpsVirtual);
econtext = GetPerTupleExprContext(state->estate); econtext = GetPerTupleExprContext(state->estate);
econtext->ecxt_scantuple = slot; econtext->ecxt_scantuple = slot;
} }

View File

@ -249,6 +249,7 @@ extern List *ExecInitExprList(List *nodes, PlanState *parent);
extern ExprState *ExecBuildAggTrans(AggState *aggstate, struct AggStatePerPhaseData *phase, extern ExprState *ExecBuildAggTrans(AggState *aggstate, struct AggStatePerPhaseData *phase,
bool doSort, bool doHash); bool doSort, bool doHash);
extern ExprState *ExecBuildGroupingEqual(TupleDesc ldesc, TupleDesc rdesc, extern ExprState *ExecBuildGroupingEqual(TupleDesc ldesc, TupleDesc rdesc,
const TupleTableSlotOps *lops, const TupleTableSlotOps *rops,
int numCols, int numCols,
AttrNumber *keyColIdx, AttrNumber *keyColIdx,
Oid *eqfunctions, Oid *eqfunctions,
@ -430,13 +431,18 @@ extern void ExecScanReScan(ScanState *node);
* prototypes from functions in execTuples.c * prototypes from functions in execTuples.c
*/ */
extern void ExecInitResultTypeTL(PlanState *planstate); extern void ExecInitResultTypeTL(PlanState *planstate);
extern void ExecInitResultSlot(PlanState *planstate); extern void ExecInitResultSlot(PlanState *planstate,
extern void ExecInitResultTupleSlotTL(PlanState *planstate); const TupleTableSlotOps *tts_ops);
extern void ExecInitScanTupleSlot(EState *estate, ScanState *scanstate, TupleDesc tupleDesc); 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, extern TupleTableSlot *ExecInitExtraTupleSlot(EState *estate,
TupleDesc tupleDesc); TupleDesc tupledesc,
extern TupleTableSlot *ExecInitNullTupleSlot(EState *estate, const TupleTableSlotOps *tts_ops);
TupleDesc tupType); extern TupleTableSlot *ExecInitNullTupleSlot(EState *estate, TupleDesc tupType,
const TupleTableSlotOps *tts_ops);
extern TupleDesc ExecTypeFromTL(List *targetList, bool hasoid); extern TupleDesc ExecTypeFromTL(List *targetList, bool hasoid);
extern TupleDesc ExecCleanTypeFromTL(List *targetList, bool hasoid); extern TupleDesc ExecCleanTypeFromTL(List *targetList, bool hasoid);
extern TupleDesc ExecTypeFromExprList(List *exprList); extern TupleDesc ExecTypeFromExprList(List *exprList);
@ -450,7 +456,8 @@ typedef struct TupOutputState
} TupOutputState; } TupOutputState;
extern TupOutputState *begin_tup_output_tupdesc(DestReceiver *dest, 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_tup_output(TupOutputState *tstate, Datum *values, bool *isnull);
extern void do_text_output_multiline(TupOutputState *tstate, const char *txt); extern void do_text_output_multiline(TupOutputState *tstate, const char *txt);
extern void end_tup_output(TupOutputState *tstate); extern void end_tup_output(TupOutputState *tstate);
@ -504,13 +511,18 @@ extern ExprContext *MakePerTupleExprContext(EState *estate);
extern void ExecAssignExprContext(EState *estate, PlanState *planstate); extern void ExecAssignExprContext(EState *estate, PlanState *planstate);
extern TupleDesc ExecGetResultType(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, extern void ExecAssignProjectionInfo(PlanState *planstate,
TupleDesc inputDesc); TupleDesc inputDesc);
extern void ExecConditionalAssignProjectionInfo(PlanState *planstate, extern void ExecConditionalAssignProjectionInfo(PlanState *planstate,
TupleDesc inputDesc, Index varno); TupleDesc inputDesc, Index varno);
extern void ExecFreeExprContext(PlanState *planstate); extern void ExecFreeExprContext(PlanState *planstate);
extern void ExecAssignScanType(ScanState *scanstate, TupleDesc tupDesc); 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); extern bool ExecRelationIsTargetRelation(EState *estate, Index scanrelid);

View File

@ -132,6 +132,9 @@
#define TTS_FLAG_FIXED (1 << 5) #define TTS_FLAG_FIXED (1 << 5)
#define TTS_FIXED(slot) (((slot)->tts_flags & TTS_FLAG_FIXED) != 0) #define TTS_FIXED(slot) (((slot)->tts_flags & TTS_FLAG_FIXED) != 0)
struct TupleTableSlotOps;
typedef struct TupleTableSlotOps TupleTableSlotOps;
typedef struct TupleTableSlot typedef struct TupleTableSlot
{ {
NodeTag type; NodeTag type;
@ -141,20 +144,35 @@ typedef struct TupleTableSlot
AttrNumber tts_nvalid; /* # of valid values in tts_values */ AttrNumber tts_nvalid; /* # of valid values in tts_values */
#define FIELDNO_TUPLETABLESLOT_TUPLE 3 #define FIELDNO_TUPLETABLESLOT_TUPLE 3
HeapTuple tts_tuple; /* physical tuple, or NULL if virtual */ 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 */ TupleDesc tts_tupleDescriptor; /* slot's tuple descriptor */
MemoryContext tts_mcxt; /* slot itself is in this context */ MemoryContext tts_mcxt; /* slot itself is in this context */
Buffer tts_buffer; /* tuple's buffer, or InvalidBuffer */ 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 */ 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 */ 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 */ bool *tts_isnull; /* current per-attribute isnull flags */
MinimalTuple tts_mintuple; /* minimal tuple, or NULL if none */ MinimalTuple tts_mintuple; /* minimal tuple, or NULL if none */
HeapTupleData tts_minhdr; /* workspace for minimal-tuple-only case */ HeapTupleData tts_minhdr; /* workspace for minimal-tuple-only case */
} TupleTableSlot; } 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) \ #define TTS_HAS_PHYSICAL_TUPLE(slot) \
((slot)->tts_tuple != NULL && (slot)->tts_tuple != &((slot)->tts_minhdr)) ((slot)->tts_tuple != NULL && (slot)->tts_tuple != &((slot)->tts_minhdr))
@ -165,10 +183,13 @@ typedef struct TupleTableSlot
((slot) == NULL || TTS_EMPTY(slot)) ((slot) == NULL || TTS_EMPTY(slot))
/* in executor/execTuples.c */ /* in executor/execTuples.c */
extern TupleTableSlot *MakeTupleTableSlot(TupleDesc desc); extern TupleTableSlot *MakeTupleTableSlot(TupleDesc tupleDesc,
extern TupleTableSlot *ExecAllocTableSlot(List **tupleTable, TupleDesc desc); const TupleTableSlotOps *tts_ops);
extern TupleTableSlot *ExecAllocTableSlot(List **tupleTable, TupleDesc desc,
const TupleTableSlotOps *tts_ops);
extern void ExecResetTupleTable(List *tupleTable, bool shouldFree); 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 ExecDropSingleTupleTableSlot(TupleTableSlot *slot);
extern void ExecSetSlotDescriptor(TupleTableSlot *slot, TupleDesc tupdesc); extern void ExecSetSlotDescriptor(TupleTableSlot *slot, TupleDesc tupdesc);
extern TupleTableSlot *ExecStoreHeapTuple(HeapTuple tuple, extern TupleTableSlot *ExecStoreHeapTuple(HeapTuple tuple,

View File

@ -977,6 +977,42 @@ typedef struct PlanState
* descriptor, without encoding knowledge about all executor nodes. * descriptor, without encoding knowledge about all executor nodes.
*/ */
TupleDesc scandesc; 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; } PlanState;
/* ---------------- /* ----------------
@ -1064,6 +1100,8 @@ typedef struct ModifyTableState
PlanState **mt_plans; /* subplans (one per target rel) */ PlanState **mt_plans; /* subplans (one per target rel) */
int mt_nplans; /* number of plans in the array */ int mt_nplans; /* number of plans in the array */
int mt_whichplan; /* which one is being executed (0..n-1) */ 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 *resultRelInfo; /* per-subplan target relations */
ResultRelInfo *rootResultRelInfo; /* root target relation (partitioned ResultRelInfo *rootResultRelInfo; /* root target relation (partitioned
* table root) */ * table root) */
@ -1329,6 +1367,7 @@ typedef struct IndexScanState
bool *iss_OrderByTypByVals; bool *iss_OrderByTypByVals;
int16 *iss_OrderByTypLens; int16 *iss_OrderByTypLens;
Size iss_PscanLen; Size iss_PscanLen;
TupleTableSlot *iss_ReorderQueueSlot;
} IndexScanState; } IndexScanState;
/* ---------------- /* ----------------