diff options
Diffstat (limited to 'src/backend/executor')
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 |