aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor')
-rw-r--r--src/backend/executor/execExpr.c4
-rw-r--r--src/backend/executor/execGrouping.c8
-rw-r--r--src/backend/executor/execIndexing.c3
-rw-r--r--src/backend/executor/execJunk.c4
-rw-r--r--src/backend/executor/execMain.c12
-rw-r--r--src/backend/executor/execPartition.c8
-rw-r--r--src/backend/executor/execSRF.c3
-rw-r--r--src/backend/executor/execTuples.c67
-rw-r--r--src/backend/executor/execUtils.c47
-rw-r--r--src/backend/executor/functions.c24
-rw-r--r--src/backend/executor/nodeAgg.c17
-rw-r--r--src/backend/executor/nodeAppend.c6
-rw-r--r--src/backend/executor/nodeBitmapHeapscan.c3
-rw-r--r--src/backend/executor/nodeCtescan.c3
-rw-r--r--src/backend/executor/nodeCustom.c7
-rw-r--r--src/backend/executor/nodeForeignscan.c10
-rw-r--r--src/backend/executor/nodeFunctionscan.c6
-rw-r--r--src/backend/executor/nodeGather.c8
-rw-r--r--src/backend/executor/nodeGatherMerge.c10
-rw-r--r--src/backend/executor/nodeGroup.c6
-rw-r--r--src/backend/executor/nodeHash.c2
-rw-r--r--src/backend/executor/nodeHashjoin.c15
-rw-r--r--src/backend/executor/nodeIndexonlyscan.c2
-rw-r--r--src/backend/executor/nodeIndexscan.c21
-rw-r--r--src/backend/executor/nodeLimit.c4
-rw-r--r--src/backend/executor/nodeLockRows.c5
-rw-r--r--src/backend/executor/nodeMaterial.c10
-rw-r--r--src/backend/executor/nodeMergeAppend.c6
-rw-r--r--src/backend/executor/nodeMergejoin.c15
-rw-r--r--src/backend/executor/nodeModifyTable.c28
-rw-r--r--src/backend/executor/nodeNamedtuplestorescan.c3
-rw-r--r--src/backend/executor/nodeNestloop.c5
-rw-r--r--src/backend/executor/nodeProjectSet.c2
-rw-r--r--src/backend/executor/nodeResult.c2
-rw-r--r--src/backend/executor/nodeSamplescan.c3
-rw-r--r--src/backend/executor/nodeSeqscan.c3
-rw-r--r--src/backend/executor/nodeSetOp.c4
-rw-r--r--src/backend/executor/nodeSort.c4
-rw-r--r--src/backend/executor/nodeSubplan.c5
-rw-r--r--src/backend/executor/nodeSubqueryscan.c13
-rw-r--r--src/backend/executor/nodeTableFuncscan.c3
-rw-r--r--src/backend/executor/nodeTidscan.c3
-rw-r--r--src/backend/executor/nodeUnique.c2
-rw-r--r--src/backend/executor/nodeValuesscan.c2
-rw-r--r--src/backend/executor/nodeWindowAgg.c27
-rw-r--r--src/backend/executor/nodeWorktablescan.c7
46 files changed, 330 insertions, 122 deletions
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index 885da18306a..cd5ee91cd43 100644
--- a/src/backend/executor/execExpr.c
+++ b/src/backend/executor/execExpr.c
@@ -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,
diff --git a/src/backend/executor/execGrouping.c b/src/backend/executor/execGrouping.c
index c4d0e040587..abce1e95cb6 100644
--- a/src/backend/executor/execGrouping.c
+++ b/src/backend/executor/execGrouping.c
@@ -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);
diff --git a/src/backend/executor/execIndexing.c b/src/backend/executor/execIndexing.c
index 9927ad70e66..8b35bb458de 100644
--- a/src/backend/executor/execIndexing.c
+++ b/src/backend/executor/execIndexing.c
@@ -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;
diff --git a/src/backend/executor/execJunk.c b/src/backend/executor/execJunk.c
index 57d74e57c1a..26558282e9c 100644
--- a/src/backend/executor/execJunk.c
+++ b/src/backend/executor/execJunk.c
@@ -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
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index d10e533fd16..74398eb4643 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -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);
diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c
index 45fc75937ab..e11fe687121 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -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"));
diff --git a/src/backend/executor/execSRF.c b/src/backend/executor/execSRF.c
index 3bffb0ea71f..248283f2543 100644
--- a/src/backend/executor/execSRF.c
+++ b/src/backend/executor/execSRF.c
@@ -873,7 +873,8 @@ ExecPrepareTuplestoreResult(SetExprState *sexpr,
slotDesc = NULL; /* keep compiler quiet */
}
- sexpr->funcResultSlot = MakeSingleTupleTableSlot(slotDesc);
+ sexpr->funcResultSlot = MakeSingleTupleTableSlot(slotDesc,
+ &TTSOpsMinimalTuple);
MemoryContextSwitchTo(oldcontext);
}
diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c
index 391db672d1d..2cd7e5c8669 100644
--- a/src/backend/executor/execTuples.c
+++ b/src/backend/executor/execTuples.c
@@ -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);
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index f9e7bb479f1..f39be12c54d 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -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);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c
index f4dd5732198..ae5c7c5490b 100644
--- a/src/backend/executor/functions.c
+++ b/src/backend/executor/functions.c
@@ -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;
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index 85f1ec7140f..20d6d8e9cbb 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -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 */
diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c
index 94a17c7c67c..8c4abe12882 100644
--- a/src/backend/executor/nodeAppend.c
+++ b/src/backend/executor/nodeAppend.c
@@ -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 *));
diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c
index c153d74f411..1c27bfc412c 100644
--- a/src/backend/executor/nodeBitmapHeapscan.c
+++ b/src/backend/executor/nodeBitmapHeapscan.c
@@ -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);
/*
diff --git a/src/backend/executor/nodeCtescan.c b/src/backend/executor/nodeCtescan.c
index 017b8772775..133aaf2d3b7 100644
--- a/src/backend/executor/nodeCtescan.c
+++ b/src/backend/executor/nodeCtescan.c
@@ -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.
diff --git a/src/backend/executor/nodeCustom.c b/src/backend/executor/nodeCustom.c
index ab3e34790e8..a2e67074a87 100644
--- a/src/backend/executor/nodeCustom.c
+++ b/src/backend/executor/nodeCustom.c
@@ -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 */
diff --git a/src/backend/executor/nodeForeignscan.c b/src/backend/executor/nodeForeignscan.c
index f7eef32f6fe..a2ab2d265b3 100644
--- a/src/backend/executor/nodeForeignscan.c
+++ b/src/backend/executor/nodeForeignscan.c
@@ -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.
*/
diff --git a/src/backend/executor/nodeFunctionscan.c b/src/backend/executor/nodeFunctionscan.c
index 0596adbb2f1..b6a1fa14560 100644
--- a/src/backend/executor/nodeFunctionscan.c
+++ b/src/backend/executor/nodeFunctionscan.c
@@ -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.
diff --git a/src/backend/executor/nodeGather.c b/src/backend/executor/nodeGather.c
index afddb0a0394..e45e07f0a1a 100644
--- a/src/backend/executor/nodeGather.c
+++ b/src/backend/executor/nodeGather.c
@@ -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
diff --git a/src/backend/executor/nodeGatherMerge.c b/src/backend/executor/nodeGatherMerge.c
index 7ae067f9ebf..651565123be 100644
--- a/src/backend/executor/nodeGatherMerge.c
+++ b/src/backend/executor/nodeGatherMerge.c
@@ -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 */
diff --git a/src/backend/executor/nodeGroup.c b/src/backend/executor/nodeGroup.c
index 9c1e51bc954..58e0b10cd16 100644
--- a/src/backend/executor/nodeGroup.c
+++ b/src/backend/executor/nodeGroup.c
@@ -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);
/*
diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c
index 5a9f1ea3c55..ba2f6686cf6 100644
--- a/src/backend/executor/nodeHash.c
+++ b/src/backend/executor/nodeHash.c
@@ -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;
/*
diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c
index d6a6ef770dd..c78b92d8a60 100644
--- a/src/backend/executor/nodeHashjoin.c
+++ b/src/backend/executor/nodeHashjoin.c
@@ -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",
diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c
index 865a056c027..4e5e52cec3b 100644
--- a/src/backend/executor/nodeIndexonlyscan.c
+++ b/src/backend/executor/nodeIndexonlyscan.c
@@ -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
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index 8593c0e3050..479cbf9df4f 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -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);
}
/*
diff --git a/src/backend/executor/nodeLimit.c b/src/backend/executor/nodeLimit.c
index f0b68191400..6792f9e86c7 100644
--- a/src/backend/executor/nodeLimit.c
+++ b/src/backend/executor/nodeLimit.c
@@ -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
diff --git a/src/backend/executor/nodeLockRows.c b/src/backend/executor/nodeLockRows.c
index 961798cecb3..7887388b9e9 100644
--- a/src/backend/executor/nodeLockRows.c
+++ b/src/backend/executor/nodeLockRows.c
@@ -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
diff --git a/src/backend/executor/nodeMaterial.c b/src/backend/executor/nodeMaterial.c
index 4ede428f908..657814cd0db 100644
--- a/src/backend/executor/nodeMaterial.c
+++ b/src/backend/executor/nodeMaterial.c
@@ -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;
}
diff --git a/src/backend/executor/nodeMergeAppend.c b/src/backend/executor/nodeMergeAppend.c
index dbed667d164..188e76b60cd 100644
--- a/src/backend/executor/nodeMergeAppend.c
+++ b/src/backend/executor/nodeMergeAppend.c
@@ -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
diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c
index 9c978313318..1c90291d127 100644
--- a/src/backend/executor/nodeMergejoin.c
+++ b/src/backend/executor/nodeMergejoin.c
@@ -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
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index a3ca336f2ac..bb344a7070a 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -2056,6 +2056,15 @@ ExecModifyTable(PlanState *pstate)
}
/*
+ * 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
diff --git a/src/backend/executor/nodeNamedtuplestorescan.c b/src/backend/executor/nodeNamedtuplestorescan.c
index cf1b7b4f872..cd8a1fceac5 100644
--- a/src/backend/executor/nodeNamedtuplestorescan.c
+++ b/src/backend/executor/nodeNamedtuplestorescan.c
@@ -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.
diff --git a/src/backend/executor/nodeNestloop.c b/src/backend/executor/nodeNestloop.c
index 8dbec685eb1..0cb6f9dd4cd 100644
--- a/src/backend/executor/nodeNestloop.c
+++ b/src/backend/executor/nodeNestloop.c
@@ -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",
diff --git a/src/backend/executor/nodeProjectSet.c b/src/backend/executor/nodeProjectSet.c
index e4dd4142177..06a7da8f77e 100644
--- a/src/backend/executor/nodeProjectSet.c
+++ b/src/backend/executor/nodeProjectSet.c
@@ -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);
diff --git a/src/backend/executor/nodeResult.c b/src/backend/executor/nodeResult.c
index 2bbb2e78848..63428c7ffe0 100644
--- a/src/backend/executor/nodeResult.c
+++ b/src/backend/executor/nodeResult.c
@@ -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);
/*
diff --git a/src/backend/executor/nodeSamplescan.c b/src/backend/executor/nodeSamplescan.c
index cfa26535d7b..55e7bd2f6cf 100644
--- a/src/backend/executor/nodeSamplescan.c
+++ b/src/backend/executor/nodeSamplescan.c
@@ -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.
diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c
index b4bea67610f..307ad9ccd53 100644
--- a/src/backend/executor/nodeSeqscan.c
+++ b/src/backend/executor/nodeSeqscan.c
@@ -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.
diff --git a/src/backend/executor/nodeSetOp.c b/src/backend/executor/nodeSetOp.c
index 46bf77775c4..44c43e99a02 100644
--- a/src/backend/executor/nodeSetOp.c
+++ b/src/backend/executor/nodeSetOp.c
@@ -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;
/*
diff --git a/src/backend/executor/nodeSort.c b/src/backend/executor/nodeSort.c
index 5492cd45579..750292b1014 100644
--- a/src/backend/executor/nodeSort.c
+++ b/src/backend/executor/nodeSort.c
@@ -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",
diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c
index 63de981034d..b42e60576e3 100644
--- a/src/backend/executor/nodeSubplan.c
+++ b/src/backend/executor/nodeSubplan.c
@@ -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,
diff --git a/src/backend/executor/nodeSubqueryscan.c b/src/backend/executor/nodeSubqueryscan.c
index b84c6892d50..c9058ab0e94 100644
--- a/src/backend/executor/nodeSubqueryscan.c
+++ b/src/backend/executor/nodeSubqueryscan.c
@@ -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.
diff --git a/src/backend/executor/nodeTableFuncscan.c b/src/backend/executor/nodeTableFuncscan.c
index b0c94d7e063..a79e4cb2cf5 100644
--- a/src/backend/executor/nodeTableFuncscan.c
+++ b/src/backend/executor/nodeTableFuncscan.c
@@ -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.
diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c
index bc859e3d516..939ece2faa1 100644
--- a/src/backend/executor/nodeTidscan.c
+++ b/src/backend/executor/nodeTidscan.c
@@ -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.
diff --git a/src/backend/executor/nodeUnique.c b/src/backend/executor/nodeUnique.c
index c791f89b48c..c5e4232e68c 100644
--- a/src/backend/executor/nodeUnique.c
+++ b/src/backend/executor/nodeUnique.c
@@ -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;
/*
diff --git a/src/backend/executor/nodeValuesscan.c b/src/backend/executor/nodeValuesscan.c
index fa49d0470fc..6351cdac27a 100644
--- a/src/backend/executor/nodeValuesscan.c
+++ b/src/backend/executor/nodeValuesscan.c
@@ -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.
diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c
index 6e597e82856..298e3707450 100644
--- a/src/backend/executor/nodeWindowAgg.c
+++ b/src/backend/executor/nodeWindowAgg.c
@@ -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 */
diff --git a/src/backend/executor/nodeWorktablescan.c b/src/backend/executor/nodeWorktablescan.c
index 1ce8ae9f026..a432926fe15 100644
--- a/src/backend/executor/nodeWorktablescan.c
+++ b/src/backend/executor/nodeWorktablescan.c
@@ -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