mirror of
https://github.com/postgres/postgres.git
synced 2025-07-03 20:02:46 +03:00
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:
@ -2423,7 +2423,8 @@ ExecInitWholeRowVar(ExprEvalStep *scratch, Var *variable, ExprState *state)
|
||||
scratch->d.wholerow.junkFilter =
|
||||
ExecInitJunkFilter(subplan->plan->targetlist,
|
||||
ExecGetResultType(subplan)->tdhasoid,
|
||||
ExecInitExtraTupleSlot(parent->state, NULL));
|
||||
ExecInitExtraTupleSlot(parent->state, NULL,
|
||||
&TTSOpsVirtual));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3214,6 +3215,7 @@ ExecBuildAggTransCall(ExprState *state, AggState *aggstate,
|
||||
*/
|
||||
ExprState *
|
||||
ExecBuildGroupingEqual(TupleDesc ldesc, TupleDesc rdesc,
|
||||
const TupleTableSlotOps *lops, const TupleTableSlotOps *rops,
|
||||
int numCols,
|
||||
AttrNumber *keyColIdx,
|
||||
Oid *eqfunctions,
|
||||
|
@ -75,7 +75,8 @@ execTuplesMatchPrepare(TupleDesc desc,
|
||||
eqFunctions[i] = get_opcode(eqOperators[i]);
|
||||
|
||||
/* build actual expression */
|
||||
expr = ExecBuildGroupingEqual(desc, desc, numCols, keyColIdx, eqFunctions,
|
||||
expr = ExecBuildGroupingEqual(desc, desc, NULL, NULL,
|
||||
numCols, keyColIdx, eqFunctions,
|
||||
parent);
|
||||
|
||||
return expr;
|
||||
@ -202,10 +203,13 @@ BuildTupleHashTable(PlanState *parent,
|
||||
* We copy the input tuple descriptor just for safety --- we assume all
|
||||
* input tuples will have equivalent descriptors.
|
||||
*/
|
||||
hashtable->tableslot = MakeSingleTupleTableSlot(CreateTupleDescCopy(inputDesc));
|
||||
hashtable->tableslot = MakeSingleTupleTableSlot(CreateTupleDescCopy(inputDesc),
|
||||
&TTSOpsMinimalTuple);
|
||||
|
||||
/* build comparator for all columns */
|
||||
/* XXX: should we support non-minimal tuples for the inputslot? */
|
||||
hashtable->tab_eq_func = ExecBuildGroupingEqual(inputDesc, inputDesc,
|
||||
&TTSOpsMinimalTuple, &TTSOpsMinimalTuple,
|
||||
numCols,
|
||||
keyColIdx, eqfuncoids,
|
||||
parent);
|
||||
|
@ -706,7 +706,8 @@ check_exclusion_or_unique_constraint(Relation heap, Relation index,
|
||||
* to this slot. Be sure to save and restore caller's value for
|
||||
* scantuple.
|
||||
*/
|
||||
existing_slot = MakeSingleTupleTableSlot(RelationGetDescr(heap));
|
||||
existing_slot = MakeSingleTupleTableSlot(RelationGetDescr(heap),
|
||||
&TTSOpsHeapTuple);
|
||||
|
||||
econtext = GetPerTupleExprContext(estate);
|
||||
save_scantuple = econtext->ecxt_scantuple;
|
||||
|
@ -78,7 +78,7 @@ ExecInitJunkFilter(List *targetList, bool hasoid, TupleTableSlot *slot)
|
||||
if (slot)
|
||||
ExecSetSlotDescriptor(slot, cleanTupType);
|
||||
else
|
||||
slot = MakeSingleTupleTableSlot(cleanTupType);
|
||||
slot = MakeSingleTupleTableSlot(cleanTupType, &TTSOpsVirtual);
|
||||
|
||||
/*
|
||||
* Now calculate the mapping between the original tuple's attributes and
|
||||
@ -149,7 +149,7 @@ ExecInitJunkFilterConversion(List *targetList,
|
||||
if (slot)
|
||||
ExecSetSlotDescriptor(slot, cleanTupType);
|
||||
else
|
||||
slot = MakeSingleTupleTableSlot(cleanTupType);
|
||||
slot = MakeSingleTupleTableSlot(cleanTupType, &TTSOpsVirtual);
|
||||
|
||||
/*
|
||||
* Calculate the mapping between the original tuple's attributes and the
|
||||
|
@ -1052,10 +1052,12 @@ InitPlan(QueryDesc *queryDesc, int eflags)
|
||||
if (junk_filter_needed)
|
||||
{
|
||||
JunkFilter *j;
|
||||
TupleTableSlot *slot;
|
||||
|
||||
slot = ExecInitExtraTupleSlot(estate, NULL, &TTSOpsVirtual);
|
||||
j = ExecInitJunkFilter(planstate->plan->targetlist,
|
||||
tupType->tdhasoid,
|
||||
ExecInitExtraTupleSlot(estate, NULL));
|
||||
slot);
|
||||
estate->es_junkFilter = j;
|
||||
|
||||
/* Want to return the cleaned tuple type */
|
||||
@ -1928,7 +1930,7 @@ ExecPartitionCheckEmitError(ResultRelInfo *resultRelInfo,
|
||||
*/
|
||||
if (map != NULL)
|
||||
slot = execute_attr_map_slot(map, slot,
|
||||
MakeTupleTableSlot(tupdesc));
|
||||
MakeTupleTableSlot(tupdesc, &TTSOpsVirtual));
|
||||
}
|
||||
|
||||
insertedCols = GetInsertedColumns(resultRelInfo, estate);
|
||||
@ -2009,7 +2011,7 @@ ExecConstraints(ResultRelInfo *resultRelInfo,
|
||||
*/
|
||||
if (map != NULL)
|
||||
slot = execute_attr_map_slot(map, slot,
|
||||
MakeTupleTableSlot(tupdesc));
|
||||
MakeTupleTableSlot(tupdesc, &TTSOpsVirtual));
|
||||
}
|
||||
|
||||
insertedCols = GetInsertedColumns(resultRelInfo, estate);
|
||||
@ -2059,7 +2061,7 @@ ExecConstraints(ResultRelInfo *resultRelInfo,
|
||||
*/
|
||||
if (map != NULL)
|
||||
slot = execute_attr_map_slot(map, slot,
|
||||
MakeTupleTableSlot(tupdesc));
|
||||
MakeTupleTableSlot(tupdesc, &TTSOpsVirtual));
|
||||
}
|
||||
|
||||
insertedCols = GetInsertedColumns(resultRelInfo, estate);
|
||||
@ -2167,7 +2169,7 @@ ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo,
|
||||
*/
|
||||
if (map != NULL)
|
||||
slot = execute_attr_map_slot(map, slot,
|
||||
MakeTupleTableSlot(tupdesc));
|
||||
MakeTupleTableSlot(tupdesc, &TTSOpsVirtual));
|
||||
}
|
||||
|
||||
insertedCols = GetInsertedColumns(resultRelInfo, estate);
|
||||
|
@ -144,7 +144,8 @@ ExecSetupPartitionTupleRouting(ModifyTableState *mtstate, Relation rel)
|
||||
* We need an additional tuple slot for storing transient tuples that
|
||||
* are converted to the root table descriptor.
|
||||
*/
|
||||
proute->root_tuple_slot = MakeTupleTableSlot(RelationGetDescr(rel));
|
||||
proute->root_tuple_slot = MakeTupleTableSlot(RelationGetDescr(rel),
|
||||
&TTSOpsHeapTuple);
|
||||
}
|
||||
|
||||
i = 0;
|
||||
@ -740,7 +741,8 @@ ExecInitRoutingInfo(ModifyTableState *mtstate,
|
||||
*/
|
||||
proute->partition_tuple_slots[partidx] =
|
||||
ExecInitExtraTupleSlot(estate,
|
||||
RelationGetDescr(partrel));
|
||||
RelationGetDescr(partrel),
|
||||
&TTSOpsHeapTuple);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -974,7 +976,7 @@ get_partition_dispatch_recurse(Relation rel, Relation parent,
|
||||
* using the correct tuple descriptor when computing its partition key
|
||||
* for tuple routing.
|
||||
*/
|
||||
pd->tupslot = MakeSingleTupleTableSlot(tupdesc);
|
||||
pd->tupslot = MakeSingleTupleTableSlot(tupdesc, &TTSOpsHeapTuple);
|
||||
pd->tupmap = convert_tuples_by_name_map_if_req(RelationGetDescr(parent),
|
||||
tupdesc,
|
||||
gettext_noop("could not convert row type"));
|
||||
|
@ -873,7 +873,8 @@ ExecPrepareTuplestoreResult(SetExprState *sexpr,
|
||||
slotDesc = NULL; /* keep compiler quiet */
|
||||
}
|
||||
|
||||
sexpr->funcResultSlot = MakeSingleTupleTableSlot(slotDesc);
|
||||
sexpr->funcResultSlot = MakeSingleTupleTableSlot(slotDesc,
|
||||
&TTSOpsMinimalTuple);
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
}
|
||||
|
||||
|
@ -73,6 +73,12 @@ static TupleDesc ExecTypeFromTLInternal(List *targetList,
|
||||
bool hasoid, bool skipjunk);
|
||||
|
||||
|
||||
const TupleTableSlotOps TTSOpsVirtual;
|
||||
const TupleTableSlotOps TTSOpsHeapTuple;
|
||||
const TupleTableSlotOps TTSOpsMinimalTuple;
|
||||
const TupleTableSlotOps TTSOpsBufferTuple;
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* tuple table create/delete functions
|
||||
* ----------------------------------------------------------------
|
||||
@ -87,7 +93,8 @@ static TupleDesc ExecTypeFromTLInternal(List *targetList,
|
||||
* --------------------------------
|
||||
*/
|
||||
TupleTableSlot *
|
||||
MakeTupleTableSlot(TupleDesc tupleDesc)
|
||||
MakeTupleTableSlot(TupleDesc tupleDesc,
|
||||
const TupleTableSlotOps *tts_ops)
|
||||
{
|
||||
Size sz;
|
||||
TupleTableSlot *slot;
|
||||
@ -104,6 +111,8 @@ MakeTupleTableSlot(TupleDesc tupleDesc)
|
||||
sz = sizeof(TupleTableSlot);
|
||||
|
||||
slot = palloc0(sz);
|
||||
/* const for optimization purposes, OK to modify at allocation time */
|
||||
*((const TupleTableSlotOps **) &slot->tts_ops) = tts_ops;
|
||||
slot->type = T_TupleTableSlot;
|
||||
slot->tts_flags |= TTS_FLAG_EMPTY;
|
||||
if (tupleDesc != NULL)
|
||||
@ -140,9 +149,10 @@ MakeTupleTableSlot(TupleDesc tupleDesc)
|
||||
* --------------------------------
|
||||
*/
|
||||
TupleTableSlot *
|
||||
ExecAllocTableSlot(List **tupleTable, TupleDesc desc)
|
||||
ExecAllocTableSlot(List **tupleTable, TupleDesc desc,
|
||||
const TupleTableSlotOps *tts_ops)
|
||||
{
|
||||
TupleTableSlot *slot = MakeTupleTableSlot(desc);
|
||||
TupleTableSlot *slot = MakeTupleTableSlot(desc, tts_ops);
|
||||
|
||||
*tupleTable = lappend(*tupleTable, slot);
|
||||
|
||||
@ -198,16 +208,17 @@ ExecResetTupleTable(List *tupleTable, /* tuple table */
|
||||
/* --------------------------------
|
||||
* MakeSingleTupleTableSlot
|
||||
*
|
||||
* This is a convenience routine for operations that need a
|
||||
* standalone TupleTableSlot not gotten from the main executor
|
||||
* tuple table. It makes a single slot and initializes it
|
||||
* to use the given tuple descriptor.
|
||||
* This is a convenience routine for operations that need a standalone
|
||||
* TupleTableSlot not gotten from the main executor tuple table. It makes
|
||||
* a single slot of given TupleTableSlotType and initializes it to use the
|
||||
* given tuple descriptor.
|
||||
* --------------------------------
|
||||
*/
|
||||
TupleTableSlot *
|
||||
MakeSingleTupleTableSlot(TupleDesc tupdesc)
|
||||
MakeSingleTupleTableSlot(TupleDesc tupdesc,
|
||||
const TupleTableSlotOps *tts_ops)
|
||||
{
|
||||
TupleTableSlot *slot = MakeTupleTableSlot(tupdesc);
|
||||
TupleTableSlot *slot = MakeTupleTableSlot(tupdesc, tts_ops);
|
||||
|
||||
return slot;
|
||||
}
|
||||
@ -964,13 +975,17 @@ ExecInitResultTypeTL(PlanState *planstate)
|
||||
* ----------------
|
||||
*/
|
||||
void
|
||||
ExecInitResultSlot(PlanState *planstate)
|
||||
ExecInitResultSlot(PlanState *planstate, const TupleTableSlotOps *tts_ops)
|
||||
{
|
||||
TupleTableSlot *slot;
|
||||
|
||||
slot = ExecAllocTableSlot(&planstate->state->es_tupleTable,
|
||||
planstate->ps_ResultTupleDesc);
|
||||
planstate->ps_ResultTupleDesc, tts_ops);
|
||||
planstate->ps_ResultTupleSlot = slot;
|
||||
|
||||
planstate->resultopsfixed = planstate->ps_ResultTupleDesc != NULL;
|
||||
planstate->resultops = tts_ops;
|
||||
planstate->resultopsset = true;
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
@ -980,10 +995,11 @@ ExecInitResultSlot(PlanState *planstate)
|
||||
* ----------------
|
||||
*/
|
||||
void
|
||||
ExecInitResultTupleSlotTL(PlanState *planstate)
|
||||
ExecInitResultTupleSlotTL(PlanState *planstate,
|
||||
const TupleTableSlotOps *tts_ops)
|
||||
{
|
||||
ExecInitResultTypeTL(planstate);
|
||||
ExecInitResultSlot(planstate);
|
||||
ExecInitResultSlot(planstate, tts_ops);
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
@ -991,11 +1007,15 @@ ExecInitResultTupleSlotTL(PlanState *planstate)
|
||||
* ----------------
|
||||
*/
|
||||
void
|
||||
ExecInitScanTupleSlot(EState *estate, ScanState *scanstate, TupleDesc tupledesc)
|
||||
ExecInitScanTupleSlot(EState *estate, ScanState *scanstate,
|
||||
TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
|
||||
{
|
||||
scanstate->ss_ScanTupleSlot = ExecAllocTableSlot(&estate->es_tupleTable,
|
||||
tupledesc);
|
||||
tupledesc, tts_ops);
|
||||
scanstate->ps.scandesc = tupledesc;
|
||||
scanstate->ps.scanopsfixed = tupledesc != NULL;
|
||||
scanstate->ps.scanops = tts_ops;
|
||||
scanstate->ps.scanopsset = true;
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
@ -1007,9 +1027,11 @@ ExecInitScanTupleSlot(EState *estate, ScanState *scanstate, TupleDesc tupledesc)
|
||||
* ----------------
|
||||
*/
|
||||
TupleTableSlot *
|
||||
ExecInitExtraTupleSlot(EState *estate, TupleDesc tupledesc)
|
||||
ExecInitExtraTupleSlot(EState *estate,
|
||||
TupleDesc tupledesc,
|
||||
const TupleTableSlotOps *tts_ops)
|
||||
{
|
||||
return ExecAllocTableSlot(&estate->es_tupleTable, tupledesc);
|
||||
return ExecAllocTableSlot(&estate->es_tupleTable, tupledesc, tts_ops);
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
@ -1021,9 +1043,10 @@ ExecInitExtraTupleSlot(EState *estate, TupleDesc tupledesc)
|
||||
* ----------------
|
||||
*/
|
||||
TupleTableSlot *
|
||||
ExecInitNullTupleSlot(EState *estate, TupleDesc tupType)
|
||||
ExecInitNullTupleSlot(EState *estate, TupleDesc tupType,
|
||||
const TupleTableSlotOps *tts_ops)
|
||||
{
|
||||
TupleTableSlot *slot = ExecInitExtraTupleSlot(estate, tupType);
|
||||
TupleTableSlot *slot = ExecInitExtraTupleSlot(estate, tupType, tts_ops);
|
||||
|
||||
return ExecStoreAllNullTuple(slot);
|
||||
}
|
||||
@ -1547,13 +1570,15 @@ HeapTupleHeaderGetDatum(HeapTupleHeader tuple)
|
||||
* table function capability. Currently used by EXPLAIN and SHOW ALL.
|
||||
*/
|
||||
TupOutputState *
|
||||
begin_tup_output_tupdesc(DestReceiver *dest, TupleDesc tupdesc)
|
||||
begin_tup_output_tupdesc(DestReceiver *dest,
|
||||
TupleDesc tupdesc,
|
||||
const TupleTableSlotOps *tts_ops)
|
||||
{
|
||||
TupOutputState *tstate;
|
||||
|
||||
tstate = (TupOutputState *) palloc(sizeof(TupOutputState));
|
||||
|
||||
tstate->slot = MakeSingleTupleTableSlot(tupdesc);
|
||||
tstate->slot = MakeSingleTupleTableSlot(tupdesc, tts_ops);
|
||||
tstate->dest = dest;
|
||||
|
||||
tstate->dest->rStartup(tstate->dest, (int) CMD_SELECT, tupdesc);
|
||||
|
@ -454,6 +454,35 @@ ExecGetResultType(PlanState *planstate)
|
||||
return planstate->ps_ResultTupleDesc;
|
||||
}
|
||||
|
||||
/*
|
||||
* ExecGetResultSlotOps - information about node's type of result slot
|
||||
*/
|
||||
const TupleTableSlotOps *
|
||||
ExecGetResultSlotOps(PlanState *planstate, bool *isfixed)
|
||||
{
|
||||
if (planstate->resultopsset && planstate->resultops)
|
||||
{
|
||||
if (isfixed)
|
||||
*isfixed = planstate->resultopsfixed;
|
||||
return planstate->resultops;
|
||||
}
|
||||
|
||||
if (isfixed)
|
||||
{
|
||||
if (planstate->resultopsset)
|
||||
*isfixed = planstate->resultopsfixed;
|
||||
else if (planstate->ps_ResultTupleSlot)
|
||||
*isfixed = TTS_FIXED(planstate->ps_ResultTupleSlot);
|
||||
else
|
||||
*isfixed = false;
|
||||
}
|
||||
|
||||
if (!planstate->ps_ResultTupleSlot)
|
||||
return &TTSOpsVirtual;
|
||||
|
||||
return planstate->ps_ResultTupleSlot->tts_ops;
|
||||
}
|
||||
|
||||
|
||||
/* ----------------
|
||||
* ExecAssignProjectionInfo
|
||||
@ -492,11 +521,21 @@ ExecConditionalAssignProjectionInfo(PlanState *planstate, TupleDesc inputDesc,
|
||||
planstate->plan->targetlist,
|
||||
varno,
|
||||
inputDesc))
|
||||
{
|
||||
planstate->ps_ProjInfo = NULL;
|
||||
planstate->resultopsset = planstate->scanopsset;
|
||||
planstate->resultopsfixed = planstate->scanopsfixed;
|
||||
planstate->resultops = planstate->scanops;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!planstate->ps_ResultTupleSlot)
|
||||
ExecInitResultSlot(planstate);
|
||||
{
|
||||
ExecInitResultSlot(planstate, &TTSOpsVirtual);
|
||||
planstate->resultops = &TTSOpsVirtual;
|
||||
planstate->resultopsfixed = true;
|
||||
planstate->resultopsset = true;
|
||||
}
|
||||
ExecAssignProjectionInfo(planstate, inputDesc);
|
||||
}
|
||||
}
|
||||
@ -611,7 +650,9 @@ ExecAssignScanType(ScanState *scanstate, TupleDesc tupDesc)
|
||||
* ----------------
|
||||
*/
|
||||
void
|
||||
ExecCreateScanSlotFromOuterPlan(EState *estate, ScanState *scanstate)
|
||||
ExecCreateScanSlotFromOuterPlan(EState *estate,
|
||||
ScanState *scanstate,
|
||||
const TupleTableSlotOps *tts_ops)
|
||||
{
|
||||
PlanState *outerPlan;
|
||||
TupleDesc tupDesc;
|
||||
@ -619,7 +660,7 @@ ExecCreateScanSlotFromOuterPlan(EState *estate, ScanState *scanstate)
|
||||
outerPlan = outerPlanState(scanstate);
|
||||
tupDesc = ExecGetResultType(outerPlan);
|
||||
|
||||
ExecInitScanTupleSlot(estate, scanstate, tupDesc);
|
||||
ExecInitScanTupleSlot(estate, scanstate, tupDesc, tts_ops);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
@ -1717,7 +1717,8 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
|
||||
|
||||
/* Set up junk filter if needed */
|
||||
if (junkFilter)
|
||||
*junkFilter = ExecInitJunkFilter(tlist, false, NULL);
|
||||
*junkFilter = ExecInitJunkFilter(tlist, false,
|
||||
MakeSingleTupleTableSlot(NULL, &TTSOpsMinimalTuple));
|
||||
}
|
||||
else if (fn_typtype == TYPTYPE_COMPOSITE || rettype == RECORDOID)
|
||||
{
|
||||
@ -1770,7 +1771,12 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
|
||||
}
|
||||
/* Set up junk filter if needed */
|
||||
if (junkFilter)
|
||||
*junkFilter = ExecInitJunkFilter(tlist, false, NULL);
|
||||
{
|
||||
TupleTableSlot *slot =
|
||||
MakeSingleTupleTableSlot(NULL, &TTSOpsMinimalTuple);
|
||||
|
||||
*junkFilter = ExecInitJunkFilter(tlist, false, slot);
|
||||
}
|
||||
return false; /* NOT returning whole tuple */
|
||||
}
|
||||
}
|
||||
@ -1786,7 +1792,12 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
|
||||
* what the caller expects will happen at runtime.
|
||||
*/
|
||||
if (junkFilter)
|
||||
*junkFilter = ExecInitJunkFilter(tlist, false, NULL);
|
||||
{
|
||||
TupleTableSlot *slot;
|
||||
|
||||
slot = MakeSingleTupleTableSlot(NULL, &TTSOpsMinimalTuple);
|
||||
*junkFilter = ExecInitJunkFilter(tlist, false, slot);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
Assert(tupdesc);
|
||||
@ -1927,9 +1938,14 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
|
||||
|
||||
/* Set up junk filter if needed */
|
||||
if (junkFilter)
|
||||
{
|
||||
TupleTableSlot *slot =
|
||||
MakeSingleTupleTableSlot(NULL, &TTSOpsMinimalTuple);
|
||||
|
||||
*junkFilter = ExecInitJunkFilterConversion(tlist,
|
||||
CreateTupleDescCopy(tupdesc),
|
||||
NULL);
|
||||
slot);
|
||||
}
|
||||
|
||||
/* Report that we are returning entire tuple result */
|
||||
return true;
|
||||
|
@ -1403,7 +1403,8 @@ find_hash_columns(AggState *aggstate)
|
||||
&perhash->eqfuncoids,
|
||||
&perhash->hashfunctions);
|
||||
perhash->hashslot =
|
||||
ExecAllocTableSlot(&estate->es_tupleTable, hashDesc);
|
||||
ExecAllocTableSlot(&estate->es_tupleTable, hashDesc,
|
||||
&TTSOpsMinimalTuple);
|
||||
|
||||
list_free(hashTlist);
|
||||
bms_free(colnos);
|
||||
@ -2211,15 +2212,17 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
|
||||
/*
|
||||
* initialize source tuple type.
|
||||
*/
|
||||
ExecCreateScanSlotFromOuterPlan(estate, &aggstate->ss);
|
||||
ExecCreateScanSlotFromOuterPlan(estate, &aggstate->ss,
|
||||
ExecGetResultSlotOps(outerPlanState(&aggstate->ss), NULL));
|
||||
scanDesc = aggstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor;
|
||||
if (node->chain)
|
||||
aggstate->sort_slot = ExecInitExtraTupleSlot(estate, scanDesc);
|
||||
aggstate->sort_slot = ExecInitExtraTupleSlot(estate, scanDesc,
|
||||
&TTSOpsMinimalTuple);
|
||||
|
||||
/*
|
||||
* Initialize result type, slot and projection.
|
||||
*/
|
||||
ExecInitResultTupleSlotTL(&aggstate->ss.ps);
|
||||
ExecInitResultTupleSlotTL(&aggstate->ss.ps, &TTSOpsVirtual);
|
||||
ExecAssignProjectionInfo(&aggstate->ss.ps, NULL);
|
||||
|
||||
/*
|
||||
@ -3062,7 +3065,8 @@ build_pertrans_for_aggref(AggStatePerTrans pertrans,
|
||||
{
|
||||
pertrans->sortdesc = ExecTypeFromTL(aggref->args, false);
|
||||
pertrans->sortslot =
|
||||
ExecInitExtraTupleSlot(estate, pertrans->sortdesc);
|
||||
ExecInitExtraTupleSlot(estate, pertrans->sortdesc,
|
||||
&TTSOpsMinimalTuple);
|
||||
}
|
||||
|
||||
if (numSortCols > 0)
|
||||
@ -3084,7 +3088,8 @@ build_pertrans_for_aggref(AggStatePerTrans pertrans,
|
||||
{
|
||||
/* we will need an extra slot to store prior values */
|
||||
pertrans->uniqslot =
|
||||
ExecInitExtraTupleSlot(estate, pertrans->sortdesc);
|
||||
ExecInitExtraTupleSlot(estate, pertrans->sortdesc,
|
||||
&TTSOpsMinimalTuple);
|
||||
}
|
||||
|
||||
/* Extract the sort information for use later */
|
||||
|
@ -196,7 +196,11 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
|
||||
/*
|
||||
* Initialize result tuple type and slot.
|
||||
*/
|
||||
ExecInitResultTupleSlotTL(&appendstate->ps);
|
||||
ExecInitResultTupleSlotTL(&appendstate->ps, &TTSOpsVirtual);
|
||||
|
||||
/* node returns slots from each of its subnodes, therefore not fixed */
|
||||
appendstate->ps.resultopsset = true;
|
||||
appendstate->ps.resultopsfixed = false;
|
||||
|
||||
appendplanstates = (PlanState **) palloc(nplans *
|
||||
sizeof(PlanState *));
|
||||
|
@ -913,7 +913,8 @@ ExecInitBitmapHeapScan(BitmapHeapScan *node, EState *estate, int eflags)
|
||||
* get the scan type from the relation descriptor.
|
||||
*/
|
||||
ExecInitScanTupleSlot(estate, &scanstate->ss,
|
||||
RelationGetDescr(currentRelation));
|
||||
RelationGetDescr(currentRelation),
|
||||
&TTSOpsBufferTuple);
|
||||
|
||||
|
||||
/*
|
||||
|
@ -260,7 +260,8 @@ ExecInitCteScan(CteScan *node, EState *estate, int eflags)
|
||||
* table) is the same as the result rowtype of the CTE query.
|
||||
*/
|
||||
ExecInitScanTupleSlot(estate, &scanstate->ss,
|
||||
ExecGetResultType(scanstate->cteplanstate));
|
||||
ExecGetResultType(scanstate->cteplanstate),
|
||||
&TTSOpsMinimalTuple);
|
||||
|
||||
/*
|
||||
* Initialize result type and projection.
|
||||
|
@ -73,13 +73,14 @@ ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags)
|
||||
TupleDesc scan_tupdesc;
|
||||
|
||||
scan_tupdesc = ExecTypeFromTL(cscan->custom_scan_tlist, false);
|
||||
ExecInitScanTupleSlot(estate, &css->ss, scan_tupdesc);
|
||||
ExecInitScanTupleSlot(estate, &css->ss, scan_tupdesc, &TTSOpsVirtual);
|
||||
/* Node's targetlist will contain Vars with varno = INDEX_VAR */
|
||||
tlistvarno = INDEX_VAR;
|
||||
}
|
||||
else
|
||||
{
|
||||
ExecInitScanTupleSlot(estate, &css->ss, RelationGetDescr(scan_rel));
|
||||
ExecInitScanTupleSlot(estate, &css->ss, RelationGetDescr(scan_rel),
|
||||
&TTSOpsVirtual);
|
||||
/* Node's targetlist will contain Vars with varno = scanrelid */
|
||||
tlistvarno = scanrelid;
|
||||
}
|
||||
@ -87,7 +88,7 @@ ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags)
|
||||
/*
|
||||
* Initialize result slot, type and projection.
|
||||
*/
|
||||
ExecInitResultTupleSlotTL(&css->ss.ps);
|
||||
ExecInitResultTupleSlotTL(&css->ss.ps, &TTSOpsVirtual);
|
||||
ExecAssignScanProjectionInfoWithVarno(&css->ss, tlistvarno);
|
||||
|
||||
/* initialize child expressions */
|
||||
|
@ -180,7 +180,8 @@ ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags)
|
||||
TupleDesc scan_tupdesc;
|
||||
|
||||
scan_tupdesc = ExecTypeFromTL(node->fdw_scan_tlist, false);
|
||||
ExecInitScanTupleSlot(estate, &scanstate->ss, scan_tupdesc);
|
||||
ExecInitScanTupleSlot(estate, &scanstate->ss, scan_tupdesc,
|
||||
&TTSOpsHeapTuple);
|
||||
/* Node's targetlist will contain Vars with varno = INDEX_VAR */
|
||||
tlistvarno = INDEX_VAR;
|
||||
}
|
||||
@ -190,11 +191,16 @@ ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags)
|
||||
|
||||
/* don't trust FDWs to return tuples fulfilling NOT NULL constraints */
|
||||
scan_tupdesc = CreateTupleDescCopy(RelationGetDescr(currentRelation));
|
||||
ExecInitScanTupleSlot(estate, &scanstate->ss, scan_tupdesc);
|
||||
ExecInitScanTupleSlot(estate, &scanstate->ss, scan_tupdesc,
|
||||
&TTSOpsHeapTuple);
|
||||
/* Node's targetlist will contain Vars with varno = scanrelid */
|
||||
tlistvarno = scanrelid;
|
||||
}
|
||||
|
||||
/* Don't know what an FDW might return */
|
||||
scanstate->ss.ps.scanopsfixed = false;
|
||||
scanstate->ss.ps.scanopsset = true;
|
||||
|
||||
/*
|
||||
* Initialize result slot, type and projection.
|
||||
*/
|
||||
|
@ -424,7 +424,8 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags)
|
||||
*/
|
||||
if (!scanstate->simple)
|
||||
{
|
||||
fs->func_slot = ExecInitExtraTupleSlot(estate, fs->tupdesc);
|
||||
fs->func_slot = ExecInitExtraTupleSlot(estate, fs->tupdesc,
|
||||
&TTSOpsMinimalTuple);
|
||||
}
|
||||
else
|
||||
fs->func_slot = NULL;
|
||||
@ -482,7 +483,8 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags)
|
||||
/*
|
||||
* Initialize scan slot and type.
|
||||
*/
|
||||
ExecInitScanTupleSlot(estate, &scanstate->ss, scan_tupdesc);
|
||||
ExecInitScanTupleSlot(estate, &scanstate->ss, scan_tupdesc,
|
||||
&TTSOpsMinimalTuple);
|
||||
|
||||
/*
|
||||
* Initialize result slot, type and projection.
|
||||
|
@ -91,6 +91,11 @@ ExecInitGather(Gather *node, EState *estate, int eflags)
|
||||
outerPlanState(gatherstate) = ExecInitNode(outerNode, estate, eflags);
|
||||
tupDesc = ExecGetResultType(outerPlanState(gatherstate));
|
||||
|
||||
/* this node uses tuples from the tuple queue as scan slot */
|
||||
gatherstate->ps.scanops = &TTSOpsHeapTuple;
|
||||
gatherstate->ps.scanopsfixed = true;
|
||||
gatherstate->ps.scanopsset = true;
|
||||
|
||||
/*
|
||||
* Initialize result type and projection.
|
||||
*/
|
||||
@ -100,7 +105,8 @@ ExecInitGather(Gather *node, EState *estate, int eflags)
|
||||
/*
|
||||
* Initialize funnel slot to same tuple descriptor as outer plan.
|
||||
*/
|
||||
gatherstate->funnel_slot = ExecInitExtraTupleSlot(estate, tupDesc);
|
||||
gatherstate->funnel_slot = ExecInitExtraTupleSlot(estate, tupDesc,
|
||||
&TTSOpsHeapTuple);
|
||||
|
||||
/*
|
||||
* Gather doesn't support checking a qual (it's always more efficient to
|
||||
|
@ -122,6 +122,13 @@ ExecInitGatherMerge(GatherMerge *node, EState *estate, int eflags)
|
||||
ExecInitResultTypeTL(&gm_state->ps);
|
||||
ExecConditionalAssignProjectionInfo(&gm_state->ps, tupDesc, OUTER_VAR);
|
||||
|
||||
/* leader accesses ExecProcNode result directly, others go through tuple queue */
|
||||
if (gm_state->ps.ps_ProjInfo == NULL)
|
||||
{
|
||||
gm_state->ps.resultopsset = true;
|
||||
gm_state->ps.resultopsfixed = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* initialize sort-key information
|
||||
*/
|
||||
@ -404,7 +411,8 @@ gather_merge_setup(GatherMergeState *gm_state)
|
||||
|
||||
/* Initialize tuple slot for worker */
|
||||
gm_state->gm_slots[i + 1] =
|
||||
ExecInitExtraTupleSlot(gm_state->ps.state, gm_state->tupDesc);
|
||||
ExecInitExtraTupleSlot(gm_state->ps.state, gm_state->tupDesc,
|
||||
&TTSOpsHeapTuple);
|
||||
}
|
||||
|
||||
/* Allocate the resources for the merge */
|
||||
|
@ -162,6 +162,7 @@ GroupState *
|
||||
ExecInitGroup(Group *node, EState *estate, int eflags)
|
||||
{
|
||||
GroupState *grpstate;
|
||||
const TupleTableSlotOps *tts_ops;
|
||||
|
||||
/* check for unsupported flags */
|
||||
Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
|
||||
@ -188,12 +189,13 @@ ExecInitGroup(Group *node, EState *estate, int eflags)
|
||||
/*
|
||||
* Initialize scan slot and type.
|
||||
*/
|
||||
ExecCreateScanSlotFromOuterPlan(estate, &grpstate->ss);
|
||||
tts_ops = ExecGetResultSlotOps(outerPlanState(&grpstate->ss), NULL);
|
||||
ExecCreateScanSlotFromOuterPlan(estate, &grpstate->ss, tts_ops);
|
||||
|
||||
/*
|
||||
* Initialize result slot, type and projection.
|
||||
*/
|
||||
ExecInitResultTupleSlotTL(&grpstate->ss.ps);
|
||||
ExecInitResultTupleSlotTL(&grpstate->ss.ps, &TTSOpsVirtual);
|
||||
ExecAssignProjectionInfo(&grpstate->ss.ps, NULL);
|
||||
|
||||
/*
|
||||
|
@ -382,7 +382,7 @@ ExecInitHash(Hash *node, EState *estate, int eflags)
|
||||
* initialize our result slot and type. No need to build projection
|
||||
* because this node doesn't do projections.
|
||||
*/
|
||||
ExecInitResultTupleSlotTL(&hashstate->ps);
|
||||
ExecInitResultTupleSlotTL(&hashstate->ps, &TTSOpsMinimalTuple);
|
||||
hashstate->ps.ps_ProjInfo = NULL;
|
||||
|
||||
/*
|
||||
|
@ -606,6 +606,7 @@ ExecInitHashJoin(HashJoin *node, EState *estate, int eflags)
|
||||
TupleDesc outerDesc,
|
||||
innerDesc;
|
||||
ListCell *l;
|
||||
const TupleTableSlotOps *ops;
|
||||
|
||||
/* check for unsupported flags */
|
||||
Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
|
||||
@ -650,13 +651,15 @@ ExecInitHashJoin(HashJoin *node, EState *estate, int eflags)
|
||||
/*
|
||||
* Initialize result slot, type and projection.
|
||||
*/
|
||||
ExecInitResultTupleSlotTL(&hjstate->js.ps);
|
||||
ExecInitResultTupleSlotTL(&hjstate->js.ps, &TTSOpsVirtual);
|
||||
ExecAssignProjectionInfo(&hjstate->js.ps, NULL);
|
||||
|
||||
/*
|
||||
* tuple table initialization
|
||||
*/
|
||||
hjstate->hj_OuterTupleSlot = ExecInitExtraTupleSlot(estate, outerDesc);
|
||||
ops = ExecGetResultSlotOps(outerPlanState(hjstate), NULL);
|
||||
hjstate->hj_OuterTupleSlot = ExecInitExtraTupleSlot(estate, outerDesc,
|
||||
ops);
|
||||
|
||||
/*
|
||||
* detect whether we need only consider the first matching inner tuple
|
||||
@ -673,17 +676,17 @@ ExecInitHashJoin(HashJoin *node, EState *estate, int eflags)
|
||||
case JOIN_LEFT:
|
||||
case JOIN_ANTI:
|
||||
hjstate->hj_NullInnerTupleSlot =
|
||||
ExecInitNullTupleSlot(estate, innerDesc);
|
||||
ExecInitNullTupleSlot(estate, innerDesc, &TTSOpsVirtual);
|
||||
break;
|
||||
case JOIN_RIGHT:
|
||||
hjstate->hj_NullOuterTupleSlot =
|
||||
ExecInitNullTupleSlot(estate, outerDesc);
|
||||
ExecInitNullTupleSlot(estate, outerDesc, &TTSOpsVirtual);
|
||||
break;
|
||||
case JOIN_FULL:
|
||||
hjstate->hj_NullOuterTupleSlot =
|
||||
ExecInitNullTupleSlot(estate, outerDesc);
|
||||
ExecInitNullTupleSlot(estate, outerDesc, &TTSOpsVirtual);
|
||||
hjstate->hj_NullInnerTupleSlot =
|
||||
ExecInitNullTupleSlot(estate, innerDesc);
|
||||
ExecInitNullTupleSlot(estate, innerDesc, &TTSOpsVirtual);
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized join type: %d",
|
||||
|
@ -527,7 +527,7 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
|
||||
* suitable data anyway.)
|
||||
*/
|
||||
tupDesc = ExecTypeFromTL(node->indextlist, false);
|
||||
ExecInitScanTupleSlot(estate, &indexstate->ss, tupDesc);
|
||||
ExecInitScanTupleSlot(estate, &indexstate->ss, tupDesc, &TTSOpsHeapTuple);
|
||||
|
||||
/*
|
||||
* Initialize result type and projection info. The node's targetlist will
|
||||
|
@ -208,8 +208,6 @@ IndexNextWithReorder(IndexScanState *node)
|
||||
|
||||
scandesc = node->iss_ScanDesc;
|
||||
econtext = node->ss.ps.ps_ExprContext;
|
||||
slot = node->ss.ss_ScanTupleSlot;
|
||||
|
||||
if (scandesc == NULL)
|
||||
{
|
||||
/*
|
||||
@ -245,6 +243,7 @@ IndexNextWithReorder(IndexScanState *node)
|
||||
*/
|
||||
if (!pairingheap_is_empty(node->iss_ReorderQueue))
|
||||
{
|
||||
slot = node->iss_ReorderQueueSlot;
|
||||
topmost = (ReorderTuple *) pairingheap_first(node->iss_ReorderQueue);
|
||||
|
||||
if (node->iss_ReachedEnd ||
|
||||
@ -264,13 +263,15 @@ IndexNextWithReorder(IndexScanState *node)
|
||||
else if (node->iss_ReachedEnd)
|
||||
{
|
||||
/* Queue is empty, and no more tuples from index. We're done. */
|
||||
return ExecClearTuple(slot);
|
||||
ExecClearTuple(node->iss_ReorderQueueSlot);
|
||||
return ExecClearTuple(node->ss.ss_ScanTupleSlot);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fetch next tuple from the index.
|
||||
*/
|
||||
next_indextuple:
|
||||
slot = node->ss.ss_ScanTupleSlot;
|
||||
tuple = index_getnext(scandesc, ForwardScanDirection);
|
||||
if (!tuple)
|
||||
{
|
||||
@ -372,7 +373,8 @@ next_indextuple:
|
||||
* if we get here it means the index scan failed so we are at the end of
|
||||
* the scan..
|
||||
*/
|
||||
return ExecClearTuple(slot);
|
||||
ExecClearTuple(node->iss_ReorderQueueSlot);
|
||||
return ExecClearTuple(node->ss.ss_ScanTupleSlot);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -824,6 +826,8 @@ ExecEndIndexScan(IndexScanState *node)
|
||||
*/
|
||||
if (node->ss.ps.ps_ResultTupleSlot)
|
||||
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
|
||||
if (node->iss_ReorderQueueSlot)
|
||||
ExecClearTuple(node->iss_ReorderQueueSlot);
|
||||
ExecClearTuple(node->ss.ss_ScanTupleSlot);
|
||||
|
||||
/*
|
||||
@ -945,7 +949,8 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
|
||||
* get the scan type from the relation descriptor.
|
||||
*/
|
||||
ExecInitScanTupleSlot(estate, &indexstate->ss,
|
||||
RelationGetDescr(currentRelation));
|
||||
RelationGetDescr(currentRelation),
|
||||
&TTSOpsBufferTuple);
|
||||
|
||||
/*
|
||||
* Initialize result type and projection.
|
||||
@ -1076,9 +1081,13 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
|
||||
indexstate->iss_OrderByNulls = (bool *)
|
||||
palloc(numOrderByKeys * sizeof(bool));
|
||||
|
||||
/* and initialize the reorder queue */
|
||||
/* and initialize the reorder queue and the corresponding slot */
|
||||
indexstate->iss_ReorderQueue = pairingheap_allocate(reorderqueue_cmp,
|
||||
indexstate);
|
||||
indexstate->iss_ReorderQueueSlot =
|
||||
ExecAllocTableSlot(&estate->es_tupleTable,
|
||||
RelationGetDescr(currentRelation),
|
||||
&TTSOpsHeapTuple);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -380,6 +380,10 @@ ExecInitLimit(Limit *node, EState *estate, int eflags)
|
||||
*/
|
||||
ExecInitResultTypeTL(&limitstate->ps);
|
||||
|
||||
limitstate->ps.resultopsset = true;
|
||||
limitstate->ps.resultops = ExecGetResultSlotOps(outerPlanState(limitstate),
|
||||
&limitstate->ps.resultopsfixed);
|
||||
|
||||
/*
|
||||
* limit nodes do no projections, so initialize projection info for this
|
||||
* node appropriately
|
||||
|
@ -390,6 +390,11 @@ ExecInitLockRows(LockRows *node, EState *estate, int eflags)
|
||||
*/
|
||||
outerPlanState(lrstate) = ExecInitNode(outerPlan, estate, eflags);
|
||||
|
||||
/* node returns unmodified slots from the outer plan */
|
||||
lrstate->ps.resultopsset = true;
|
||||
lrstate->ps.resultops = ExecGetResultSlotOps(outerPlanState(lrstate),
|
||||
&lrstate->ps.resultopsfixed);
|
||||
|
||||
/*
|
||||
* LockRows nodes do no projections, so initialize projection info for
|
||||
* this node appropriately
|
||||
|
@ -146,10 +146,8 @@ ExecMaterial(PlanState *pstate)
|
||||
if (tuplestorestate)
|
||||
tuplestore_puttupleslot(tuplestorestate, outerslot);
|
||||
|
||||
/*
|
||||
* We can just return the subplan's returned tuple, without copying.
|
||||
*/
|
||||
return outerslot;
|
||||
ExecCopySlot(slot, outerslot);
|
||||
return slot;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -223,13 +221,13 @@ ExecInitMaterial(Material *node, EState *estate, int eflags)
|
||||
*
|
||||
* material nodes only return tuples from their materialized relation.
|
||||
*/
|
||||
ExecInitResultTupleSlotTL(&matstate->ss.ps);
|
||||
ExecInitResultTupleSlotTL(&matstate->ss.ps, &TTSOpsMinimalTuple);
|
||||
matstate->ss.ps.ps_ProjInfo = NULL;
|
||||
|
||||
/*
|
||||
* initialize tuple type.
|
||||
*/
|
||||
ExecCreateScanSlotFromOuterPlan(estate, &matstate->ss);
|
||||
ExecCreateScanSlotFromOuterPlan(estate, &matstate->ss, &TTSOpsMinimalTuple);
|
||||
|
||||
return matstate;
|
||||
}
|
||||
|
@ -167,7 +167,11 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
|
||||
* MergeAppend nodes do have Result slots, which hold pointers to tuples,
|
||||
* so we have to initialize them. FIXME
|
||||
*/
|
||||
ExecInitResultTupleSlotTL(&mergestate->ps);
|
||||
ExecInitResultTupleSlotTL(&mergestate->ps, &TTSOpsVirtual);
|
||||
|
||||
/* node returns slots from each of its subnodes, therefore not fixed */
|
||||
mergestate->ps.resultopsset = true;
|
||||
mergestate->ps.resultopsfixed = false;
|
||||
|
||||
/*
|
||||
* call ExecInitNode on each of the valid plans to be executed and save
|
||||
|
@ -1438,6 +1438,7 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags)
|
||||
MergeJoinState *mergestate;
|
||||
TupleDesc outerDesc,
|
||||
innerDesc;
|
||||
const TupleTableSlotOps *innerOps;
|
||||
|
||||
/* check for unsupported flags */
|
||||
Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
|
||||
@ -1512,13 +1513,15 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags)
|
||||
/*
|
||||
* Initialize result slot, type and projection.
|
||||
*/
|
||||
ExecInitResultTupleSlotTL(&mergestate->js.ps);
|
||||
ExecInitResultTupleSlotTL(&mergestate->js.ps, &TTSOpsVirtual);
|
||||
ExecAssignProjectionInfo(&mergestate->js.ps, NULL);
|
||||
|
||||
/*
|
||||
* tuple table initialization
|
||||
*/
|
||||
mergestate->mj_MarkedTupleSlot = ExecInitExtraTupleSlot(estate, innerDesc);
|
||||
innerOps = ExecGetResultSlotOps(innerPlanState(mergestate), NULL);
|
||||
mergestate->mj_MarkedTupleSlot = ExecInitExtraTupleSlot(estate, innerDesc,
|
||||
innerOps);
|
||||
|
||||
/*
|
||||
* initialize child expressions
|
||||
@ -1548,13 +1551,13 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags)
|
||||
mergestate->mj_FillOuter = true;
|
||||
mergestate->mj_FillInner = false;
|
||||
mergestate->mj_NullInnerTupleSlot =
|
||||
ExecInitNullTupleSlot(estate, innerDesc);
|
||||
ExecInitNullTupleSlot(estate, innerDesc, &TTSOpsVirtual);
|
||||
break;
|
||||
case JOIN_RIGHT:
|
||||
mergestate->mj_FillOuter = false;
|
||||
mergestate->mj_FillInner = true;
|
||||
mergestate->mj_NullOuterTupleSlot =
|
||||
ExecInitNullTupleSlot(estate, outerDesc);
|
||||
ExecInitNullTupleSlot(estate, outerDesc, &TTSOpsVirtual);
|
||||
|
||||
/*
|
||||
* Can't handle right or full join with non-constant extra
|
||||
@ -1570,9 +1573,9 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags)
|
||||
mergestate->mj_FillOuter = true;
|
||||
mergestate->mj_FillInner = true;
|
||||
mergestate->mj_NullOuterTupleSlot =
|
||||
ExecInitNullTupleSlot(estate, outerDesc);
|
||||
ExecInitNullTupleSlot(estate, outerDesc, &TTSOpsVirtual);
|
||||
mergestate->mj_NullInnerTupleSlot =
|
||||
ExecInitNullTupleSlot(estate, innerDesc);
|
||||
ExecInitNullTupleSlot(estate, innerDesc, &TTSOpsVirtual);
|
||||
|
||||
/*
|
||||
* Can't handle right or full join with non-constant extra
|
||||
|
@ -2055,6 +2055,15 @@ ExecModifyTable(PlanState *pstate)
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure input tuple is the right format for the target relation.
|
||||
*/
|
||||
if (node->mt_scans[node->mt_whichplan]->tts_ops != planSlot->tts_ops)
|
||||
{
|
||||
ExecCopySlot(node->mt_scans[node->mt_whichplan], planSlot);
|
||||
planSlot = node->mt_scans[node->mt_whichplan];
|
||||
}
|
||||
|
||||
/*
|
||||
* If resultRelInfo->ri_usesFdwDirectModify is true, all we need to do
|
||||
* here is compute the RETURNING expressions.
|
||||
@ -2238,6 +2247,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
|
||||
|
||||
mtstate->mt_plans = (PlanState **) palloc0(sizeof(PlanState *) * nplans);
|
||||
mtstate->resultRelInfo = estate->es_result_relations + node->resultRelIndex;
|
||||
mtstate->mt_scans = (TupleTableSlot **) palloc0(sizeof(TupleTableSlot *) * nplans);
|
||||
|
||||
/* If modifying a partitioned table, initialize the root table info */
|
||||
if (node->rootResultRelIndex >= 0)
|
||||
@ -2304,6 +2314,9 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
|
||||
/* Now init the plan for this result rel */
|
||||
estate->es_result_relation_info = resultRelInfo;
|
||||
mtstate->mt_plans[i] = ExecInitNode(subplan, estate, eflags);
|
||||
mtstate->mt_scans[i] =
|
||||
ExecInitExtraTupleSlot(mtstate->ps.state, ExecGetResultType(mtstate->mt_plans[i]),
|
||||
&TTSOpsHeapTuple);
|
||||
|
||||
/* Also let FDWs init themselves for foreign-table result rels */
|
||||
if (!resultRelInfo->ri_usesFdwDirectModify &&
|
||||
@ -2403,7 +2416,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
|
||||
mtstate->ps.plan->targetlist = (List *) linitial(node->returningLists);
|
||||
|
||||
/* Set up a slot for the output of the RETURNING projection(s) */
|
||||
ExecInitResultTupleSlotTL(&mtstate->ps);
|
||||
ExecInitResultTupleSlotTL(&mtstate->ps, &TTSOpsVirtual);
|
||||
slot = mtstate->ps.ps_ResultTupleSlot;
|
||||
|
||||
/* Need an econtext too */
|
||||
@ -2472,7 +2485,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
|
||||
mtstate->mt_existing =
|
||||
ExecInitExtraTupleSlot(mtstate->ps.state,
|
||||
mtstate->mt_partition_tuple_routing ?
|
||||
NULL : relationDesc);
|
||||
NULL : relationDesc, &TTSOpsBufferTuple);
|
||||
|
||||
/* carried forward solely for the benefit of explain */
|
||||
mtstate->mt_excludedtlist = node->exclRelTlist;
|
||||
@ -2494,7 +2507,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
|
||||
mtstate->mt_conflproj =
|
||||
ExecInitExtraTupleSlot(mtstate->ps.state,
|
||||
mtstate->mt_partition_tuple_routing ?
|
||||
NULL : tupDesc);
|
||||
NULL : tupDesc, &TTSOpsHeapTuple);
|
||||
resultRelInfo->ri_onConflict->oc_ProjTupdesc = tupDesc;
|
||||
|
||||
/* build UPDATE SET projection state */
|
||||
@ -2605,7 +2618,8 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
|
||||
|
||||
j = ExecInitJunkFilter(subplan->targetlist,
|
||||
resultRelInfo->ri_RelationDesc->rd_att->tdhasoid,
|
||||
ExecInitExtraTupleSlot(estate, NULL));
|
||||
ExecInitExtraTupleSlot(estate, NULL,
|
||||
&TTSOpsHeapTuple));
|
||||
|
||||
if (operation == CMD_UPDATE || operation == CMD_DELETE)
|
||||
{
|
||||
@ -2652,10 +2666,12 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
|
||||
/*
|
||||
* Set up a tuple table slot for use for trigger output tuples. In a plan
|
||||
* containing multiple ModifyTable nodes, all can share one such slot, so
|
||||
* we keep it in the estate.
|
||||
* we keep it in the estate. The tuple being inserted doesn't come from a
|
||||
* buffer.
|
||||
*/
|
||||
if (estate->es_trig_tuple_slot == NULL)
|
||||
estate->es_trig_tuple_slot = ExecInitExtraTupleSlot(estate, NULL);
|
||||
estate->es_trig_tuple_slot = ExecInitExtraTupleSlot(estate, NULL,
|
||||
&TTSOpsHeapTuple);
|
||||
|
||||
/*
|
||||
* Lastly, if this is not the primary (canSetTag) ModifyTable node, add it
|
||||
|
@ -137,7 +137,8 @@ ExecInitNamedTuplestoreScan(NamedTuplestoreScan *node, EState *estate, int eflag
|
||||
/*
|
||||
* The scan tuple type is specified for the tuplestore.
|
||||
*/
|
||||
ExecInitScanTupleSlot(estate, &scanstate->ss, scanstate->tupdesc);
|
||||
ExecInitScanTupleSlot(estate, &scanstate->ss, scanstate->tupdesc,
|
||||
&TTSOpsMinimalTuple);
|
||||
|
||||
/*
|
||||
* Initialize result type and projection.
|
||||
|
@ -304,7 +304,7 @@ ExecInitNestLoop(NestLoop *node, EState *estate, int eflags)
|
||||
/*
|
||||
* Initialize result slot, type and projection.
|
||||
*/
|
||||
ExecInitResultTupleSlotTL(&nlstate->js.ps);
|
||||
ExecInitResultTupleSlotTL(&nlstate->js.ps, &TTSOpsVirtual);
|
||||
ExecAssignProjectionInfo(&nlstate->js.ps, NULL);
|
||||
|
||||
/*
|
||||
@ -332,7 +332,8 @@ ExecInitNestLoop(NestLoop *node, EState *estate, int eflags)
|
||||
case JOIN_ANTI:
|
||||
nlstate->nl_NullInnerTupleSlot =
|
||||
ExecInitNullTupleSlot(estate,
|
||||
ExecGetResultType(innerPlanState(nlstate)));
|
||||
ExecGetResultType(innerPlanState(nlstate)),
|
||||
&TTSOpsVirtual);
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized join type: %d",
|
||||
|
@ -256,7 +256,7 @@ ExecInitProjectSet(ProjectSet *node, EState *estate, int eflags)
|
||||
/*
|
||||
* tuple table and result type initialization
|
||||
*/
|
||||
ExecInitResultTupleSlotTL(&state->ps);
|
||||
ExecInitResultTupleSlotTL(&state->ps, &TTSOpsVirtual);
|
||||
|
||||
/* Create workspace for per-tlist-entry expr state & SRF-is-done state */
|
||||
state->nelems = list_length(node->plan.targetlist);
|
||||
|
@ -217,7 +217,7 @@ ExecInitResult(Result *node, EState *estate, int eflags)
|
||||
/*
|
||||
* Initialize result slot, type and projection.
|
||||
*/
|
||||
ExecInitResultTupleSlotTL(&resstate->ps);
|
||||
ExecInitResultTupleSlotTL(&resstate->ps, &TTSOpsVirtual);
|
||||
ExecAssignProjectionInfo(&resstate->ps, NULL);
|
||||
|
||||
/*
|
||||
|
@ -146,7 +146,8 @@ ExecInitSampleScan(SampleScan *node, EState *estate, int eflags)
|
||||
|
||||
/* and create slot with appropriate rowtype */
|
||||
ExecInitScanTupleSlot(estate, &scanstate->ss,
|
||||
RelationGetDescr(scanstate->ss.ss_currentRelation));
|
||||
RelationGetDescr(scanstate->ss.ss_currentRelation),
|
||||
&TTSOpsBufferTuple);
|
||||
|
||||
/*
|
||||
* Initialize result type and projection.
|
||||
|
@ -172,7 +172,8 @@ ExecInitSeqScan(SeqScan *node, EState *estate, int eflags)
|
||||
|
||||
/* and create slot with the appropriate rowtype */
|
||||
ExecInitScanTupleSlot(estate, &scanstate->ss,
|
||||
RelationGetDescr(scanstate->ss.ss_currentRelation));
|
||||
RelationGetDescr(scanstate->ss.ss_currentRelation),
|
||||
&TTSOpsBufferTuple);
|
||||
|
||||
/*
|
||||
* Initialize result type and projection.
|
||||
|
@ -532,7 +532,9 @@ ExecInitSetOp(SetOp *node, EState *estate, int eflags)
|
||||
* Initialize result slot and type. Setop nodes do no projections, so
|
||||
* initialize projection info for this node appropriately.
|
||||
*/
|
||||
ExecInitResultTupleSlotTL(&setopstate->ps);
|
||||
ExecInitResultTupleSlotTL(&setopstate->ps,
|
||||
node->strategy == SETOP_HASHED ?
|
||||
&TTSOpsMinimalTuple : &TTSOpsHeapTuple);
|
||||
setopstate->ps.ps_ProjInfo = NULL;
|
||||
|
||||
/*
|
||||
|
@ -211,13 +211,13 @@ ExecInitSort(Sort *node, EState *estate, int eflags)
|
||||
/*
|
||||
* Initialize scan slot and type.
|
||||
*/
|
||||
ExecCreateScanSlotFromOuterPlan(estate, &sortstate->ss);
|
||||
ExecCreateScanSlotFromOuterPlan(estate, &sortstate->ss, &TTSOpsVirtual);
|
||||
|
||||
/*
|
||||
* Initialize return slot and type. No need to initialize projection info
|
||||
* because this node doesn't do projections.
|
||||
*/
|
||||
ExecInitResultTupleSlotTL(&sortstate->ss.ps);
|
||||
ExecInitResultTupleSlotTL(&sortstate->ss.ps, &TTSOpsMinimalTuple);
|
||||
sortstate->ss.ps.ps_ProjInfo = NULL;
|
||||
|
||||
SO1_printf("ExecInitSort: %s\n",
|
||||
|
@ -968,7 +968,7 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
|
||||
* own innerecontext.
|
||||
*/
|
||||
tupDescLeft = ExecTypeFromTL(lefttlist, false);
|
||||
slot = ExecInitExtraTupleSlot(estate, tupDescLeft);
|
||||
slot = ExecInitExtraTupleSlot(estate, tupDescLeft, &TTSOpsVirtual);
|
||||
sstate->projLeft = ExecBuildProjectionInfo(lefttlist,
|
||||
NULL,
|
||||
slot,
|
||||
@ -976,7 +976,7 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
|
||||
NULL);
|
||||
|
||||
sstate->descRight = tupDescRight = ExecTypeFromTL(righttlist, false);
|
||||
slot = ExecInitExtraTupleSlot(estate, tupDescRight);
|
||||
slot = ExecInitExtraTupleSlot(estate, tupDescRight, &TTSOpsVirtual);
|
||||
sstate->projRight = ExecBuildProjectionInfo(righttlist,
|
||||
sstate->innerecontext,
|
||||
slot,
|
||||
@ -988,6 +988,7 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
|
||||
* across-type comparison).
|
||||
*/
|
||||
sstate->cur_eq_comp = ExecBuildGroupingEqual(tupDescLeft, tupDescRight,
|
||||
&TTSOpsVirtual, &TTSOpsMinimalTuple,
|
||||
ncols,
|
||||
sstate->keyColIdx,
|
||||
sstate->tab_eq_funcoids,
|
||||
|
@ -129,7 +129,18 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate, int eflags)
|
||||
* Initialize scan slot and type (needed by ExecAssignScanProjectionInfo)
|
||||
*/
|
||||
ExecInitScanTupleSlot(estate, &subquerystate->ss,
|
||||
ExecGetResultType(subquerystate->subplan));
|
||||
ExecGetResultType(subquerystate->subplan),
|
||||
ExecGetResultSlotOps(subquerystate->subplan, NULL));
|
||||
/*
|
||||
* The slot used as the scantuple isn't the slot above (outside of EPQ),
|
||||
* but the one from the node below.
|
||||
*/
|
||||
subquerystate->ss.ps.scanopsset = true;
|
||||
subquerystate->ss.ps.scanops = ExecGetResultSlotOps(subquerystate->subplan,
|
||||
&subquerystate->ss.ps.scanopsfixed);
|
||||
subquerystate->ss.ps.resultopsset = true;
|
||||
subquerystate->ss.ps.resultops = subquerystate->ss.ps.scanops;
|
||||
subquerystate->ss.ps.resultopsfixed = subquerystate->ss.ps.scanopsfixed;
|
||||
|
||||
/*
|
||||
* Initialize result type and projection.
|
||||
|
@ -147,7 +147,8 @@ ExecInitTableFuncScan(TableFuncScan *node, EState *estate, int eflags)
|
||||
tf->coltypmods,
|
||||
tf->colcollations);
|
||||
/* and the corresponding scan slot */
|
||||
ExecInitScanTupleSlot(estate, &scanstate->ss, tupdesc);
|
||||
ExecInitScanTupleSlot(estate, &scanstate->ss, tupdesc,
|
||||
&TTSOpsMinimalTuple);
|
||||
|
||||
/*
|
||||
* Initialize result type and projection.
|
||||
|
@ -543,7 +543,8 @@ ExecInitTidScan(TidScan *node, EState *estate, int eflags)
|
||||
* get the scan type from the relation descriptor.
|
||||
*/
|
||||
ExecInitScanTupleSlot(estate, &tidstate->ss,
|
||||
RelationGetDescr(currentRelation));
|
||||
RelationGetDescr(currentRelation),
|
||||
&TTSOpsBufferTuple);
|
||||
|
||||
/*
|
||||
* Initialize result type and projection.
|
||||
|
@ -141,7 +141,7 @@ ExecInitUnique(Unique *node, EState *estate, int eflags)
|
||||
* Initialize result slot and type. Unique nodes do no projections, so
|
||||
* initialize projection info for this node appropriately.
|
||||
*/
|
||||
ExecInitResultTupleSlotTL(&uniquestate->ps);
|
||||
ExecInitResultTupleSlotTL(&uniquestate->ps, &TTSOpsMinimalTuple);
|
||||
uniquestate->ps.ps_ProjInfo = NULL;
|
||||
|
||||
/*
|
||||
|
@ -261,7 +261,7 @@ ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags)
|
||||
* Get info about values list, initialize scan slot with it.
|
||||
*/
|
||||
tupdesc = ExecTypeFromExprList((List *) linitial(node->values_lists));
|
||||
ExecInitScanTupleSlot(estate, &scanstate->ss, tupdesc);
|
||||
ExecInitScanTupleSlot(estate, &scanstate->ss, tupdesc, &TTSOpsVirtual);
|
||||
|
||||
/*
|
||||
* Initialize result type and projection.
|
||||
|
@ -2316,16 +2316,25 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags)
|
||||
* initialize source tuple type (which is also the tuple type that we'll
|
||||
* store in the tuplestore and use in all our working slots).
|
||||
*/
|
||||
ExecCreateScanSlotFromOuterPlan(estate, &winstate->ss);
|
||||
ExecCreateScanSlotFromOuterPlan(estate, &winstate->ss, &TTSOpsMinimalTuple);
|
||||
scanDesc = winstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor;
|
||||
|
||||
/* the outer tuple isn't the child's tuple, but always a minimal tuple */
|
||||
winstate->ss.ps.outeropsset = true;
|
||||
winstate->ss.ps.outerops = &TTSOpsMinimalTuple;
|
||||
winstate->ss.ps.outeropsfixed = true;
|
||||
|
||||
/*
|
||||
* tuple table initialization
|
||||
*/
|
||||
winstate->first_part_slot = ExecInitExtraTupleSlot(estate, scanDesc);
|
||||
winstate->agg_row_slot = ExecInitExtraTupleSlot(estate, scanDesc);
|
||||
winstate->temp_slot_1 = ExecInitExtraTupleSlot(estate, scanDesc);
|
||||
winstate->temp_slot_2 = ExecInitExtraTupleSlot(estate, scanDesc);
|
||||
winstate->first_part_slot = ExecInitExtraTupleSlot(estate, scanDesc,
|
||||
&TTSOpsMinimalTuple);
|
||||
winstate->agg_row_slot = ExecInitExtraTupleSlot(estate, scanDesc,
|
||||
&TTSOpsMinimalTuple);
|
||||
winstate->temp_slot_1 = ExecInitExtraTupleSlot(estate, scanDesc,
|
||||
&TTSOpsMinimalTuple);
|
||||
winstate->temp_slot_2 = ExecInitExtraTupleSlot(estate, scanDesc,
|
||||
&TTSOpsMinimalTuple);
|
||||
|
||||
/*
|
||||
* create frame head and tail slots only if needed (must create slots in
|
||||
@ -2339,17 +2348,19 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags)
|
||||
if (((frameOptions & FRAMEOPTION_START_CURRENT_ROW) &&
|
||||
node->ordNumCols != 0) ||
|
||||
(frameOptions & FRAMEOPTION_START_OFFSET))
|
||||
winstate->framehead_slot = ExecInitExtraTupleSlot(estate, scanDesc);
|
||||
winstate->framehead_slot = ExecInitExtraTupleSlot(estate, scanDesc,
|
||||
&TTSOpsMinimalTuple);
|
||||
if (((frameOptions & FRAMEOPTION_END_CURRENT_ROW) &&
|
||||
node->ordNumCols != 0) ||
|
||||
(frameOptions & FRAMEOPTION_END_OFFSET))
|
||||
winstate->frametail_slot = ExecInitExtraTupleSlot(estate, scanDesc);
|
||||
winstate->frametail_slot = ExecInitExtraTupleSlot(estate, scanDesc,
|
||||
&TTSOpsMinimalTuple);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize result slot, type and projection.
|
||||
*/
|
||||
ExecInitResultTupleSlotTL(&winstate->ss.ps);
|
||||
ExecInitResultTupleSlotTL(&winstate->ss.ps, &TTSOpsVirtual);
|
||||
ExecAssignProjectionInfo(&winstate->ss.ps, NULL);
|
||||
|
||||
/* Set up data for comparing tuples */
|
||||
|
@ -160,7 +160,12 @@ ExecInitWorkTableScan(WorkTableScan *node, EState *estate, int eflags)
|
||||
* tuple table initialization
|
||||
*/
|
||||
ExecInitResultTypeTL(&scanstate->ss.ps);
|
||||
ExecInitScanTupleSlot(estate, &scanstate->ss, NULL);
|
||||
|
||||
/* signal that return type is not yet known */
|
||||
scanstate->ss.ps.resultopsset = true;
|
||||
scanstate->ss.ps.resultopsfixed = false;
|
||||
|
||||
ExecInitScanTupleSlot(estate, &scanstate->ss, NULL, &TTSOpsMinimalTuple);
|
||||
|
||||
/*
|
||||
* initialize child expressions
|
||||
|
Reference in New Issue
Block a user