List *indexoidlist = RelationGetIndexList(relation);
EState *estate = CreateExecutorState();
ExprContext *econtext = GetPerTupleExprContext(estate);
- TupleTableSlot *slot = MakeSingleTupleTableSlot(RelationGetDescr(relation));
+ TupleTableSlot *slot = MakeSingleTupleTableSlot(RelationGetDescr(relation),
+ &TTSOpsHeapTuple);
bool equals = true;
Datum old_values[INDEX_MAX_KEYS];
bool old_isnull[INDEX_MAX_KEYS];
*/
estate = CreateExecutorState();
econtext = GetPerTupleExprContext(estate);
- slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation));
+ slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation),
+ &TTSOpsHeapTuple);
/* Arrange for econtext's scan tuple to be the tuple under test */
econtext->ecxt_scantuple = slot;
*/
estate = CreateExecutorState();
econtext = GetPerTupleExprContext(estate);
- slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation));
+ slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation),
+ &TTSOpsHeapTuple);
/* Arrange for econtext's scan tuple to be the tuple under test */
econtext->ecxt_scantuple = slot;
*/
estate = CreateExecutorState();
econtext = GetPerTupleExprContext(estate);
- slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation));
+ slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation),
+ &TTSOpsHeapTuple);
/* Arrange for econtext's scan tuple to be the tuple under test */
econtext->ecxt_scantuple = slot;
heapRelation = indstate->ri_RelationDesc;
/* Need a slot to hold the tuple being examined */
- slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation));
+ slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation),
+ &TTSOpsHeapTuple);
ExecStoreHeapTuple(heapTuple, slot, false);
/*
estate = CreateExecutorState();
econtext = GetPerTupleExprContext(estate);
/* Need a slot to hold the current heap tuple, too */
- slot = MakeSingleTupleTableSlot(RelationGetDescr(onerel));
+ slot = MakeSingleTupleTableSlot(RelationGetDescr(onerel),
+ &TTSOpsHeapTuple);
/* Arrange for econtext's scan tuple to be the tuple under test */
econtext->ecxt_scantuple = slot;
/*
* The heap tuple must be put into a slot for FormIndexDatum.
*/
- slot = MakeSingleTupleTableSlot(RelationGetDescr(trigdata->tg_relation));
+ slot = MakeSingleTupleTableSlot(RelationGetDescr(trigdata->tg_relation),
+ &TTSOpsHeapTuple);
ExecStoreHeapTuple(new_row, slot, false);
ExecInitRangeTable(estate, cstate->range_table);
/* Set up a tuple slot too */
- myslot = ExecInitExtraTupleSlot(estate, tupDesc);
+ myslot = ExecInitExtraTupleSlot(estate, tupDesc,
+ &TTSOpsHeapTuple);
/* Triggers might need a slot as well */
- estate->es_trig_tuple_slot = ExecInitExtraTupleSlot(estate, NULL);
+ estate->es_trig_tuple_slot = ExecInitExtraTupleSlot(estate, NULL,
+ &TTSOpsHeapTuple);
/*
* Set up a ModifyTableState so we can let FDW(s) init themselves for
Assert(es->indent == 0);
/* output tuples */
- tstate = begin_tup_output_tupdesc(dest, ExplainResultDesc(stmt));
+ tstate = begin_tup_output_tupdesc(dest, ExplainResultDesc(stmt),
+ &TTSOpsVirtual);
if (es->format == EXPLAIN_FORMAT_TEXT)
do_text_output_multiline(tstate, es->str->data);
else
tupTypmod = HeapTupleHeaderGetTypMod(td);
retdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
- tstate = begin_tup_output_tupdesc(dest, retdesc);
+ tstate = begin_tup_output_tupdesc(dest, retdesc,
+ &TTSOpsHeapTuple);
rettupdata.t_len = HeapTupleHeaderGetDatumLength(td);
ItemPointerSetInvalid(&(rettupdata.t_self));
res->err)));
/* Process tables. */
- slot = MakeSingleTupleTableSlot(res->tupledesc);
+ slot = MakeSingleTupleTableSlot(res->tupledesc, &TTSOpsMinimalTuple);
while (tuplestore_gettupleslot(res->tuplestore, true, false, slot))
{
char *nspname;
* tuples are the same, the tupDescs might not be (consider ADD COLUMN
* without a default).
*/
- oldslot = MakeSingleTupleTableSlot(oldTupDesc);
- newslot = MakeSingleTupleTableSlot(newTupDesc);
+ oldslot = MakeSingleTupleTableSlot(oldTupDesc, &TTSOpsHeapTuple);
+ newslot = MakeSingleTupleTableSlot(newTupDesc, &TTSOpsHeapTuple);
/* Preallocate values/isnull arrays */
i = Max(newTupDesc->natts, oldTupDesc->natts);
econtext = GetPerTupleExprContext(estate);
tupdesc = RelationGetDescr(rel);
- slot = MakeSingleTupleTableSlot(tupdesc);
+ slot = MakeSingleTupleTableSlot(tupdesc, &TTSOpsHeapTuple);
econtext->ecxt_scantuple = slot;
snapshot = RegisterSnapshot(GetLatestSnapshot());
{
oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
estate->es_trig_oldtup_slot =
- ExecInitExtraTupleSlot(estate, NULL);
+ ExecInitExtraTupleSlot(estate, NULL, &TTSOpsHeapTuple);
MemoryContextSwitchTo(oldContext);
}
oldslot = estate->es_trig_oldtup_slot;
{
oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
estate->es_trig_newtup_slot =
- ExecInitExtraTupleSlot(estate, NULL);
+ ExecInitExtraTupleSlot(estate, NULL, &TTSOpsHeapTuple);
MemoryContextSwitchTo(oldContext);
}
newslot = estate->es_trig_newtup_slot;
ExecDropSingleTupleTableSlot(slot1);
ExecDropSingleTupleTableSlot(slot2);
}
- slot1 = MakeSingleTupleTableSlot(rel->rd_att);
- slot2 = MakeSingleTupleTableSlot(rel->rd_att);
+ slot1 = MakeSingleTupleTableSlot(rel->rd_att,
+ &TTSOpsMinimalTuple);
+ slot2 = MakeSingleTupleTableSlot(rel->rd_att,
+ &TTSOpsMinimalTuple);
}
if (trigdesc == NULL) /* should not happen */
elog(ERROR, "relation %u has no triggers",
scratch->d.wholerow.junkFilter =
ExecInitJunkFilter(subplan->plan->targetlist,
ExecGetResultType(subplan)->tdhasoid,
- ExecInitExtraTupleSlot(parent->state, NULL));
+ ExecInitExtraTupleSlot(parent->state, NULL,
+ &TTSOpsVirtual));
}
}
}
*/
ExprState *
ExecBuildGroupingEqual(TupleDesc ldesc, TupleDesc rdesc,
+ const TupleTableSlotOps *lops, const TupleTableSlotOps *rops,
int numCols,
AttrNumber *keyColIdx,
Oid *eqfunctions,
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;
* 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);
* 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;
if (slot)
ExecSetSlotDescriptor(slot, cleanTupType);
else
- slot = MakeSingleTupleTableSlot(cleanTupType);
+ slot = MakeSingleTupleTableSlot(cleanTupType, &TTSOpsVirtual);
/*
* Now calculate the mapping between the original tuple's attributes and
if (slot)
ExecSetSlotDescriptor(slot, cleanTupType);
else
- slot = MakeSingleTupleTableSlot(cleanTupType);
+ slot = MakeSingleTupleTableSlot(cleanTupType, &TTSOpsVirtual);
/*
* Calculate the mapping between the original tuple's attributes and the
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 */
*/
if (map != NULL)
slot = execute_attr_map_slot(map, slot,
- MakeTupleTableSlot(tupdesc));
+ MakeTupleTableSlot(tupdesc, &TTSOpsVirtual));
}
insertedCols = GetInsertedColumns(resultRelInfo, estate);
*/
if (map != NULL)
slot = execute_attr_map_slot(map, slot,
- MakeTupleTableSlot(tupdesc));
+ MakeTupleTableSlot(tupdesc, &TTSOpsVirtual));
}
insertedCols = GetInsertedColumns(resultRelInfo, estate);
*/
if (map != NULL)
slot = execute_attr_map_slot(map, slot,
- MakeTupleTableSlot(tupdesc));
+ MakeTupleTableSlot(tupdesc, &TTSOpsVirtual));
}
insertedCols = GetInsertedColumns(resultRelInfo, estate);
*/
if (map != NULL)
slot = execute_attr_map_slot(map, slot,
- MakeTupleTableSlot(tupdesc));
+ MakeTupleTableSlot(tupdesc, &TTSOpsVirtual));
}
insertedCols = GetInsertedColumns(resultRelInfo, estate);
* 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;
*/
proute->partition_tuple_slots[partidx] =
ExecInitExtraTupleSlot(estate,
- RelationGetDescr(partrel));
+ RelationGetDescr(partrel),
+ &TTSOpsHeapTuple);
}
/*
* 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"));
slotDesc = NULL; /* keep compiler quiet */
}
- sexpr->funcResultSlot = MakeSingleTupleTableSlot(slotDesc);
+ sexpr->funcResultSlot = MakeSingleTupleTableSlot(slotDesc,
+ &TTSOpsMinimalTuple);
MemoryContextSwitchTo(oldcontext);
}
bool hasoid, bool skipjunk);
+const TupleTableSlotOps TTSOpsVirtual;
+const TupleTableSlotOps TTSOpsHeapTuple;
+const TupleTableSlotOps TTSOpsMinimalTuple;
+const TupleTableSlotOps TTSOpsBufferTuple;
+
+
/* ----------------------------------------------------------------
* tuple table create/delete functions
* ----------------------------------------------------------------
* --------------------------------
*/
TupleTableSlot *
-MakeTupleTableSlot(TupleDesc tupleDesc)
+MakeTupleTableSlot(TupleDesc tupleDesc,
+ const TupleTableSlotOps *tts_ops)
{
Size sz;
TupleTableSlot *slot;
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)
* --------------------------------
*/
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);
/* --------------------------------
* 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;
}
* ----------------
*/
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;
}
/* ----------------
* ----------------
*/
void
-ExecInitResultTupleSlotTL(PlanState *planstate)
+ExecInitResultTupleSlotTL(PlanState *planstate,
+ const TupleTableSlotOps *tts_ops)
{
ExecInitResultTypeTL(planstate);
- ExecInitResultSlot(planstate);
+ ExecInitResultSlot(planstate, tts_ops);
}
/* ----------------
* ----------------
*/
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;
}
/* ----------------
* ----------------
*/
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);
}
/* ----------------
* ----------------
*/
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);
}
* 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);
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
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);
}
}
* ----------------
*/
void
-ExecCreateScanSlotFromOuterPlan(EState *estate, ScanState *scanstate)
+ExecCreateScanSlotFromOuterPlan(EState *estate,
+ ScanState *scanstate,
+ const TupleTableSlotOps *tts_ops)
{
PlanState *outerPlan;
TupleDesc tupDesc;
outerPlan = outerPlanState(scanstate);
tupDesc = ExecGetResultType(outerPlan);
- ExecInitScanTupleSlot(estate, scanstate, tupDesc);
+ ExecInitScanTupleSlot(estate, scanstate, tupDesc, tts_ops);
}
/* ----------------------------------------------------------------
/* 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)
{
}
/* 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 */
}
}
* 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);
/* 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;
&perhash->eqfuncoids,
&perhash->hashfunctions);
perhash->hashslot =
- ExecAllocTableSlot(&estate->es_tupleTable, hashDesc);
+ ExecAllocTableSlot(&estate->es_tupleTable, hashDesc,
+ &TTSOpsMinimalTuple);
list_free(hashTlist);
bms_free(colnos);
/*
* 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);
/*
{
pertrans->sortdesc = ExecTypeFromTL(aggref->args, false);
pertrans->sortslot =
- ExecInitExtraTupleSlot(estate, pertrans->sortdesc);
+ ExecInitExtraTupleSlot(estate, pertrans->sortdesc,
+ &TTSOpsMinimalTuple);
}
if (numSortCols > 0)
{
/* 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 */
/*
* 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 *));
* get the scan type from the relation descriptor.
*/
ExecInitScanTupleSlot(estate, &scanstate->ss,
- RelationGetDescr(currentRelation));
+ RelationGetDescr(currentRelation),
+ &TTSOpsBufferTuple);
/*
* 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.
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;
}
/*
* Initialize result slot, type and projection.
*/
- ExecInitResultTupleSlotTL(&css->ss.ps);
+ ExecInitResultTupleSlotTL(&css->ss.ps, &TTSOpsVirtual);
ExecAssignScanProjectionInfoWithVarno(&css->ss, tlistvarno);
/* initialize child expressions */
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;
}
/* 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.
*/
*/
if (!scanstate->simple)
{
- fs->func_slot = ExecInitExtraTupleSlot(estate, fs->tupdesc);
+ fs->func_slot = ExecInitExtraTupleSlot(estate, fs->tupdesc,
+ &TTSOpsMinimalTuple);
}
else
fs->func_slot = NULL;
/*
* Initialize scan slot and type.
*/
- ExecInitScanTupleSlot(estate, &scanstate->ss, scan_tupdesc);
+ ExecInitScanTupleSlot(estate, &scanstate->ss, scan_tupdesc,
+ &TTSOpsMinimalTuple);
/*
* Initialize result slot, type and projection.
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.
*/
/*
* 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
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
*/
/* 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 */
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)));
/*
* 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);
/*
* 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;
/*
TupleDesc outerDesc,
innerDesc;
ListCell *l;
+ const TupleTableSlotOps *ops;
/* check for unsupported flags */
Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
/*
* 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
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",
* 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
scandesc = node->iss_ScanDesc;
econtext = node->ss.ps.ps_ExprContext;
- slot = node->ss.ss_ScanTupleSlot;
-
if (scandesc == NULL)
{
/*
*/
if (!pairingheap_is_empty(node->iss_ReorderQueue))
{
+ slot = node->iss_ReorderQueueSlot;
topmost = (ReorderTuple *) pairingheap_first(node->iss_ReorderQueue);
if (node->iss_ReachedEnd ||
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)
{
* 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);
}
/*
*/
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);
/*
* get the scan type from the relation descriptor.
*/
ExecInitScanTupleSlot(estate, &indexstate->ss,
- RelationGetDescr(currentRelation));
+ RelationGetDescr(currentRelation),
+ &TTSOpsBufferTuple);
/*
* Initialize result type and projection.
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);
}
/*
*/
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
*/
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
if (tuplestorestate)
tuplestore_puttupleslot(tuplestorestate, outerslot);
- /*
- * We can just return the subplan's returned tuple, without copying.
- */
- return outerslot;
+ ExecCopySlot(slot, outerslot);
+ return slot;
}
/*
*
* 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;
}
* 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
MergeJoinState *mergestate;
TupleDesc outerDesc,
innerDesc;
+ const TupleTableSlotOps *innerOps;
/* check for unsupported flags */
Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
/*
* 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
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
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
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.
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)
/* 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 &&
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 */
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;
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 */
j = ExecInitJunkFilter(subplan->targetlist,
resultRelInfo->ri_RelationDesc->rd_att->tdhasoid,
- ExecInitExtraTupleSlot(estate, NULL));
+ ExecInitExtraTupleSlot(estate, NULL,
+ &TTSOpsHeapTuple));
if (operation == CMD_UPDATE || operation == CMD_DELETE)
{
/*
* 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
/*
* The scan tuple type is specified for the tuplestore.
*/
- ExecInitScanTupleSlot(estate, &scanstate->ss, scanstate->tupdesc);
+ ExecInitScanTupleSlot(estate, &scanstate->ss, scanstate->tupdesc,
+ &TTSOpsMinimalTuple);
/*
* Initialize result type and projection.
/*
* Initialize result slot, type and projection.
*/
- ExecInitResultTupleSlotTL(&nlstate->js.ps);
+ ExecInitResultTupleSlotTL(&nlstate->js.ps, &TTSOpsVirtual);
ExecAssignProjectionInfo(&nlstate->js.ps, NULL);
/*
case JOIN_ANTI:
nlstate->nl_NullInnerTupleSlot =
ExecInitNullTupleSlot(estate,
- ExecGetResultType(innerPlanState(nlstate)));
+ ExecGetResultType(innerPlanState(nlstate)),
+ &TTSOpsVirtual);
break;
default:
elog(ERROR, "unrecognized join type: %d",
/*
* 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);
/*
* Initialize result slot, type and projection.
*/
- ExecInitResultTupleSlotTL(&resstate->ps);
+ ExecInitResultTupleSlotTL(&resstate->ps, &TTSOpsVirtual);
ExecAssignProjectionInfo(&resstate->ps, NULL);
/*
/* 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.
/* 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.
* 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;
/*
/*
* 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",
* own innerecontext.
*/
tupDescLeft = ExecTypeFromTL(lefttlist, false);
- slot = ExecInitExtraTupleSlot(estate, tupDescLeft);
+ slot = ExecInitExtraTupleSlot(estate, tupDescLeft, &TTSOpsVirtual);
sstate->projLeft = ExecBuildProjectionInfo(lefttlist,
NULL,
slot,
NULL);
sstate->descRight = tupDescRight = ExecTypeFromTL(righttlist, false);
- slot = ExecInitExtraTupleSlot(estate, tupDescRight);
+ slot = ExecInitExtraTupleSlot(estate, tupDescRight, &TTSOpsVirtual);
sstate->projRight = ExecBuildProjectionInfo(righttlist,
sstate->innerecontext,
slot,
* across-type comparison).
*/
sstate->cur_eq_comp = ExecBuildGroupingEqual(tupDescLeft, tupDescRight,
+ &TTSOpsVirtual, &TTSOpsMinimalTuple,
ncols,
sstate->keyColIdx,
sstate->tab_eq_funcoids,
* 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.
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.
* get the scan type from the relation descriptor.
*/
ExecInitScanTupleSlot(estate, &tidstate->ss,
- RelationGetDescr(currentRelation));
+ RelationGetDescr(currentRelation),
+ &TTSOpsBufferTuple);
/*
* Initialize result type and projection.
* 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;
/*
* 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.
* 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
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 */
* 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
econtext = GetPerTupleExprContext(estate);
snapshot = RegisterSnapshot(GetLatestSnapshot());
scan = heap_beginscan(part_rel, snapshot, 0, NULL);
- tupslot = MakeSingleTupleTableSlot(tupdesc);
+ tupslot = MakeSingleTupleTableSlot(tupdesc, &TTSOpsHeapTuple);
/*
* Switch to per-tuple memory context and reset it for each tuple
(errmsg("could not fetch table info for table \"%s.%s\" from publisher: %s",
nspname, relname, res->err)));
- slot = MakeSingleTupleTableSlot(res->tupledesc);
+ slot = MakeSingleTupleTableSlot(res->tupledesc, &TTSOpsMinimalTuple);
if (!tuplestore_gettupleslot(res->tuplestore, true, false, slot))
ereport(ERROR,
(errmsg("table \"%s.%s\" not found on publisher",
lrel->attkeys = NULL;
natt = 0;
- slot = MakeSingleTupleTableSlot(res->tupledesc);
+ slot = MakeSingleTupleTableSlot(res->tupledesc, &TTSOpsMinimalTuple);
while (tuplestore_gettupleslot(res->tuplestore, true, false, slot))
{
lrel->attnames[natt] =
/* Triggers might need a slot */
if (resultRelInfo->ri_TrigDesc)
- estate->es_trig_tuple_slot = ExecInitExtraTupleSlot(estate, NULL);
+ estate->es_trig_tuple_slot = ExecInitExtraTupleSlot(estate, NULL,
+ &TTSOpsVirtual);
/* Prepare to catch AFTER triggers. */
AfterTriggerBeginQuery();
/* Initialize the executor state. */
estate = create_estate_for_relation(rel);
remoteslot = ExecInitExtraTupleSlot(estate,
- RelationGetDescr(rel->localrel));
+ RelationGetDescr(rel->localrel),
+ &TTSOpsHeapTuple);
/* Input functions may need an active snapshot, so get one */
PushActiveSnapshot(GetTransactionSnapshot());
/* Initialize the executor state. */
estate = create_estate_for_relation(rel);
remoteslot = ExecInitExtraTupleSlot(estate,
- RelationGetDescr(rel->localrel));
+ RelationGetDescr(rel->localrel),
+ &TTSOpsHeapTuple);
localslot = ExecInitExtraTupleSlot(estate,
- RelationGetDescr(rel->localrel));
+ RelationGetDescr(rel->localrel),
+ &TTSOpsHeapTuple);
EvalPlanQualInit(&epqstate, estate, NULL, NIL, -1);
PushActiveSnapshot(GetTransactionSnapshot());
{
/* Process and store remote tuple in the slot */
oldctx = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
- ExecStoreHeapTuple(localslot->tts_tuple, remoteslot, false);
+ ExecCopySlot(remoteslot, localslot);
slot_modify_cstrings(remoteslot, rel, newtup.values, newtup.changed);
MemoryContextSwitchTo(oldctx);
/* Initialize the executor state. */
estate = create_estate_for_relation(rel);
remoteslot = ExecInitExtraTupleSlot(estate,
- RelationGetDescr(rel->localrel));
+ RelationGetDescr(rel->localrel),
+ &TTSOpsVirtual);
localslot = ExecInitExtraTupleSlot(estate,
- RelationGetDescr(rel->localrel));
+ RelationGetDescr(rel->localrel),
+ &TTSOpsHeapTuple);
EvalPlanQualInit(&epqstate, estate, NULL, NIL, -1);
PushActiveSnapshot(GetTransactionSnapshot());
TEXTOID, -1, 0);
/* prepare for projection of tuples */
- tstate = begin_tup_output_tupdesc(dest, tupdesc);
+ tstate = begin_tup_output_tupdesc(dest, tupdesc, &TTSOpsVirtual);
/* column 1: system identifier */
values[0] = CStringGetTextDatum(sysid);
TEXTOID, -1, 0);
/* prepare for projection of tuple */
- tstate = begin_tup_output_tupdesc(dest, tupdesc);
+ tstate = begin_tup_output_tupdesc(dest, tupdesc, &TTSOpsVirtual);
values[0] = Int64GetDatum((int64) sendTimeLineNextTLI);
values[1] = CStringGetTextDatum(startpos_str);
TEXTOID, -1, 0);
/* prepare for projection of tuples */
- tstate = begin_tup_output_tupdesc(dest, tupdesc);
+ tstate = begin_tup_output_tupdesc(dest, tupdesc, &TTSOpsVirtual);
/* slot_name */
slot_name = NameStr(MyReplicationSlot->data.name);
uint64 current_tuple_count = 0;
TupleTableSlot *slot;
- slot = MakeSingleTupleTableSlot(portal->tupDesc);
+ slot = MakeSingleTupleTableSlot(portal->tupDesc, &TTSOpsMinimalTuple);
dest->rStartup(dest, CMD_SELECT, portal->tupDesc);
}
/* Create slot we'll use to store/retrieve rows */
- qstate->tupslot = MakeSingleTupleTableSlot(qstate->tupdesc);
+ qstate->tupslot = MakeSingleTupleTableSlot(qstate->tupdesc,
+ &TTSOpsMinimalTuple);
}
else
{
* previous row available for comparisons. This is accomplished by
* swapping the slot pointer variables after each row.
*/
- extraslot = MakeSingleTupleTableSlot(osastate->qstate->tupdesc);
+ extraslot = MakeSingleTupleTableSlot(osastate->qstate->tupdesc,
+ &TTSOpsMinimalTuple);
slot2 = extraslot;
/* iterate till we find the hypothetical row */
indexInfo = BuildIndexInfo(indexRel);
/* some other stuff */
- slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRel));
+ slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRel),
+ &TTSOpsHeapTuple);
econtext->ecxt_scantuple = slot;
get_typlenbyval(vardata->atttype, &typLen, &typByVal);
InitNonVacuumableSnapshot(SnapshotNonVacuumable, RecentGlobalXmin);
TEXTOID, -1, 0);
/* prepare for projection of tuples */
- tstate = begin_tup_output_tupdesc(dest, tupdesc);
+ tstate = begin_tup_output_tupdesc(dest, tupdesc, &TTSOpsVirtual);
/* Send it */
do_text_output_oneline(tstate, value);
TEXTOID, -1, 0);
/* prepare for projection of tuples */
- tstate = begin_tup_output_tupdesc(dest, tupdesc);
+ tstate = begin_tup_output_tupdesc(dest, tupdesc, &TTSOpsVirtual);
for (i = 0; i < num_guc_variables; i++)
{
* scantuple has to point to that slot, too.
*/
state->estate = CreateExecutorState();
- slot = MakeSingleTupleTableSlot(tupDesc);
+ slot = MakeSingleTupleTableSlot(tupDesc, &TTSOpsVirtual);
econtext = GetPerTupleExprContext(state->estate);
econtext->ecxt_scantuple = slot;
}
extern ExprState *ExecBuildAggTrans(AggState *aggstate, struct AggStatePerPhaseData *phase,
bool doSort, bool doHash);
extern ExprState *ExecBuildGroupingEqual(TupleDesc ldesc, TupleDesc rdesc,
+ const TupleTableSlotOps *lops, const TupleTableSlotOps *rops,
int numCols,
AttrNumber *keyColIdx,
Oid *eqfunctions,
* prototypes from functions in execTuples.c
*/
extern void ExecInitResultTypeTL(PlanState *planstate);
-extern void ExecInitResultSlot(PlanState *planstate);
-extern void ExecInitResultTupleSlotTL(PlanState *planstate);
-extern void ExecInitScanTupleSlot(EState *estate, ScanState *scanstate, TupleDesc tupleDesc);
+extern void ExecInitResultSlot(PlanState *planstate,
+ const TupleTableSlotOps *tts_ops);
+extern void ExecInitResultTupleSlotTL(PlanState *planstate,
+ const TupleTableSlotOps *tts_ops);
+extern void ExecInitScanTupleSlot(EState *estate, ScanState *scanstate,
+ TupleDesc tupleDesc,
+ const TupleTableSlotOps *tts_ops);
extern TupleTableSlot *ExecInitExtraTupleSlot(EState *estate,
- TupleDesc tupleDesc);
-extern TupleTableSlot *ExecInitNullTupleSlot(EState *estate,
- TupleDesc tupType);
+ TupleDesc tupledesc,
+ const TupleTableSlotOps *tts_ops);
+extern TupleTableSlot *ExecInitNullTupleSlot(EState *estate, TupleDesc tupType,
+ const TupleTableSlotOps *tts_ops);
extern TupleDesc ExecTypeFromTL(List *targetList, bool hasoid);
extern TupleDesc ExecCleanTypeFromTL(List *targetList, bool hasoid);
extern TupleDesc ExecTypeFromExprList(List *exprList);
} TupOutputState;
extern TupOutputState *begin_tup_output_tupdesc(DestReceiver *dest,
- TupleDesc tupdesc);
+ TupleDesc tupdesc,
+ const TupleTableSlotOps *tts_ops);
extern void do_tup_output(TupOutputState *tstate, Datum *values, bool *isnull);
extern void do_text_output_multiline(TupOutputState *tstate, const char *txt);
extern void end_tup_output(TupOutputState *tstate);
extern void ExecAssignExprContext(EState *estate, PlanState *planstate);
extern TupleDesc ExecGetResultType(PlanState *planstate);
+extern TupleTableSlot ExecGetResultSlot(PlanState *planstate);
+extern const TupleTableSlotOps *ExecGetResultSlotOps(PlanState *planstate,
+ bool *isfixed);
extern void ExecAssignProjectionInfo(PlanState *planstate,
TupleDesc inputDesc);
extern void ExecConditionalAssignProjectionInfo(PlanState *planstate,
TupleDesc inputDesc, Index varno);
extern void ExecFreeExprContext(PlanState *planstate);
extern void ExecAssignScanType(ScanState *scanstate, TupleDesc tupDesc);
-extern void ExecCreateScanSlotFromOuterPlan(EState *estate, ScanState *scanstate);
+extern void ExecCreateScanSlotFromOuterPlan(EState *estate,
+ ScanState *scanstate,
+ const TupleTableSlotOps *tts_ops);
extern bool ExecRelationIsTargetRelation(EState *estate, Index scanrelid);
#define TTS_FLAG_FIXED (1 << 5)
#define TTS_FIXED(slot) (((slot)->tts_flags & TTS_FLAG_FIXED) != 0)
+struct TupleTableSlotOps;
+typedef struct TupleTableSlotOps TupleTableSlotOps;
+
typedef struct TupleTableSlot
{
NodeTag type;
AttrNumber tts_nvalid; /* # of valid values in tts_values */
#define FIELDNO_TUPLETABLESLOT_TUPLE 3
HeapTuple tts_tuple; /* physical tuple, or NULL if virtual */
-#define FIELDNO_TUPLETABLESLOT_TUPLEDESCRIPTOR 4
+ const TupleTableSlotOps *const tts_ops; /* implementation of slot */
+#define FIELDNO_TUPLETABLESLOT_TUPLEDESCRIPTOR 5
TupleDesc tts_tupleDescriptor; /* slot's tuple descriptor */
MemoryContext tts_mcxt; /* slot itself is in this context */
Buffer tts_buffer; /* tuple's buffer, or InvalidBuffer */
-#define FIELDNO_TUPLETABLESLOT_OFF 7
+#define FIELDNO_TUPLETABLESLOT_OFF 8
uint32 tts_off; /* saved state for slot_deform_tuple */
-#define FIELDNO_TUPLETABLESLOT_VALUES 8
+#define FIELDNO_TUPLETABLESLOT_VALUES 9
Datum *tts_values; /* current per-attribute values */
-#define FIELDNO_TUPLETABLESLOT_ISNULL 9
+#define FIELDNO_TUPLETABLESLOT_ISNULL 10
bool *tts_isnull; /* current per-attribute isnull flags */
MinimalTuple tts_mintuple; /* minimal tuple, or NULL if none */
HeapTupleData tts_minhdr; /* workspace for minimal-tuple-only case */
} TupleTableSlot;
+/* routines for a TupleTableSlot implementation */
+struct TupleTableSlotOps
+{
+};
+
+/*
+ * Predefined TupleTableSlotOps for various types of TupleTableSlotOps. The
+ * same are used to identify the type of a given slot.
+ */
+extern PGDLLIMPORT const TupleTableSlotOps TTSOpsVirtual;
+extern PGDLLIMPORT const TupleTableSlotOps TTSOpsHeapTuple;
+extern PGDLLIMPORT const TupleTableSlotOps TTSOpsMinimalTuple;
+extern PGDLLIMPORT const TupleTableSlotOps TTSOpsBufferTuple;
+
#define TTS_HAS_PHYSICAL_TUPLE(slot) \
((slot)->tts_tuple != NULL && (slot)->tts_tuple != &((slot)->tts_minhdr))
((slot) == NULL || TTS_EMPTY(slot))
/* in executor/execTuples.c */
-extern TupleTableSlot *MakeTupleTableSlot(TupleDesc desc);
-extern TupleTableSlot *ExecAllocTableSlot(List **tupleTable, TupleDesc desc);
+extern TupleTableSlot *MakeTupleTableSlot(TupleDesc tupleDesc,
+ const TupleTableSlotOps *tts_ops);
+extern TupleTableSlot *ExecAllocTableSlot(List **tupleTable, TupleDesc desc,
+ const TupleTableSlotOps *tts_ops);
extern void ExecResetTupleTable(List *tupleTable, bool shouldFree);
-extern TupleTableSlot *MakeSingleTupleTableSlot(TupleDesc tupdesc);
+extern TupleTableSlot *MakeSingleTupleTableSlot(TupleDesc tupdesc,
+ const TupleTableSlotOps *tts_ops);
extern void ExecDropSingleTupleTableSlot(TupleTableSlot *slot);
extern void ExecSetSlotDescriptor(TupleTableSlot *slot, TupleDesc tupdesc);
extern TupleTableSlot *ExecStoreHeapTuple(HeapTuple tuple,
* descriptor, without encoding knowledge about all executor nodes.
*/
TupleDesc scandesc;
+
+ /*
+ * Define the slot types for inner, outer and scanslots for expression
+ * contexts with this state as a parent. If *opsset is set, then
+ * *opsfixed indicates whether *ops is guaranteed to be the type of slot
+ * used. That means that every slot in the corresponding
+ * ExprContext.ecxt_*tuple will point to a slot of that type, while
+ * evaluating the expression. If *opsfixed is false, but *ops is set,
+ * that indicates the most likely type of slot.
+ *
+ * The scan* fields are set by ExecInitScanTupleSlot(). If that's not
+ * called, nodes can initialize the fields themselves.
+ *
+ * If outer/inneropsset is false, the information is inferred on-demand
+ * using ExecGetResultSlotOps() on ->righttree/lefttree, using the
+ * corresponding node's resultops* fields.
+ *
+ * The result* fields are automatically set when ExecInitResultSlot is
+ * used (be it directly or when the slot is created by
+ * ExecAssignScanProjectionInfo() /
+ * ExecConditionalAssignProjectionInfo()). If no projection is necessary
+ * ExecConditionalAssignProjectionInfo() defaults those fields to the scan
+ * operations.
+ */
+ const TupleTableSlotOps *scanops;
+ const TupleTableSlotOps *outerops;
+ const TupleTableSlotOps *innerops;
+ const TupleTableSlotOps *resultops;
+ bool scanopsfixed;
+ bool outeropsfixed;
+ bool inneropsfixed;
+ bool resultopsfixed;
+ bool scanopsset;
+ bool outeropsset;
+ bool inneropsset;
+ bool resultopsset;
} PlanState;
/* ----------------
PlanState **mt_plans; /* subplans (one per target rel) */
int mt_nplans; /* number of plans in the array */
int mt_whichplan; /* which one is being executed (0..n-1) */
+ TupleTableSlot** mt_scans; /* input tuple corresponding to underlying
+ plans */
ResultRelInfo *resultRelInfo; /* per-subplan target relations */
ResultRelInfo *rootResultRelInfo; /* root target relation (partitioned
* table root) */
bool *iss_OrderByTypByVals;
int16 *iss_OrderByTypLens;
Size iss_PscanLen;
+ TupleTableSlot *iss_ReorderQueueSlot;
} IndexScanState;
/* ----------------