diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index b3933df9af..d5883c98d1 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -2444,10 +2444,9 @@ CopyFrom(CopyState cstate) estate->es_range_table = cstate->range_table; /* Set up a tuple slot too */ - myslot = ExecInitExtraTupleSlot(estate); - ExecSetSlotDescriptor(myslot, tupDesc); + myslot = ExecInitExtraTupleSlot(estate, tupDesc); /* Triggers might need a slot as well */ - estate->es_trig_tuple_slot = ExecInitExtraTupleSlot(estate); + estate->es_trig_tuple_slot = ExecInitExtraTupleSlot(estate, NULL); /* Prepare to catch AFTER triggers. */ AfterTriggerBeginQuery(); diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 160d941c00..fffc0095a7 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -3251,7 +3251,8 @@ TriggerEnabled(EState *estate, ResultRelInfo *relinfo, if (estate->es_trig_oldtup_slot == NULL) { oldContext = MemoryContextSwitchTo(estate->es_query_cxt); - estate->es_trig_oldtup_slot = ExecInitExtraTupleSlot(estate); + estate->es_trig_oldtup_slot = + ExecInitExtraTupleSlot(estate, NULL); MemoryContextSwitchTo(oldContext); } oldslot = estate->es_trig_oldtup_slot; @@ -3264,7 +3265,8 @@ TriggerEnabled(EState *estate, ResultRelInfo *relinfo, if (estate->es_trig_newtup_slot == NULL) { oldContext = MemoryContextSwitchTo(estate->es_query_cxt); - estate->es_trig_newtup_slot = ExecInitExtraTupleSlot(estate); + estate->es_trig_newtup_slot = + ExecInitExtraTupleSlot(estate, NULL); MemoryContextSwitchTo(oldContext); } newslot = estate->es_trig_newtup_slot; diff --git a/src/backend/executor/README b/src/backend/executor/README index b3e74aa1a5..0d7cd552eb 100644 --- a/src/backend/executor/README +++ b/src/backend/executor/README @@ -243,6 +243,8 @@ This is a sketch of control flow for full query processing: switch to per-query context to run ExecInitNode AfterTriggerBeginQuery ExecInitNode --- recursively scans plan tree + ExecInitNode + recurse into subsidiary nodes CreateExprContext creates per-tuple context ExecInitExpr diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c index 463e185a9a..db5fcafbfe 100644 --- a/src/backend/executor/execExpr.c +++ b/src/backend/executor/execExpr.c @@ -2415,7 +2415,7 @@ ExecInitWholeRowVar(ExprEvalStep *scratch, Var *variable, ExprState *state) scratch->d.wholerow.junkFilter = ExecInitJunkFilter(subplan->plan->targetlist, ExecGetResultType(subplan)->tdhasoid, - ExecInitExtraTupleSlot(parent->state)); + ExecInitExtraTupleSlot(parent->state, NULL)); } } } diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 5d3e923cca..91ba939bdc 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -1073,7 +1073,7 @@ InitPlan(QueryDesc *queryDesc, int eflags) j = ExecInitJunkFilter(planstate->plan->targetlist, tupType->tdhasoid, - ExecInitExtraTupleSlot(estate)); + ExecInitExtraTupleSlot(estate, NULL)); estate->es_junkFilter = j; /* Want to return the cleaned tuple type */ diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c index 4048c3ebc6..00523ce250 100644 --- a/src/backend/executor/execPartition.c +++ b/src/backend/executor/execPartition.c @@ -93,7 +93,7 @@ ExecSetupPartitionTupleRouting(ModifyTableState *mtstate, * We need an additional tuple slot for storing transient tuples that * are converted to the root table descriptor. */ - proute->root_tuple_slot = MakeTupleTableSlot(); + proute->root_tuple_slot = MakeTupleTableSlot(NULL); } else { @@ -112,7 +112,7 @@ ExecSetupPartitionTupleRouting(ModifyTableState *mtstate, * (such as ModifyTableState) and released when the node finishes * processing. */ - proute->partition_tuple_slot = MakeTupleTableSlot(); + proute->partition_tuple_slot = MakeTupleTableSlot(NULL); i = 0; foreach(cell, leaf_parts) diff --git a/src/backend/executor/execScan.c b/src/backend/executor/execScan.c index bf4f603fd3..caf91730ce 100644 --- a/src/backend/executor/execScan.c +++ b/src/backend/executor/execScan.c @@ -229,7 +229,7 @@ ExecScan(ScanState *node, * the scan node, because the planner will preferentially generate a matching * tlist. * - * ExecAssignScanType must have been called already. + * The scan slot's descriptor must have been set already. */ void ExecAssignScanProjectionInfo(ScanState *node) diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c index 5df89e419c..c46d65cf93 100644 --- a/src/backend/executor/execTuples.c +++ b/src/backend/executor/execTuples.c @@ -58,7 +58,7 @@ * At ExecutorStart() * ---------------- * - ExecInitSeqScan() calls ExecInitScanTupleSlot() and - * ExecInitResultTupleSlot() to construct TupleTableSlots + * ExecInitResultTupleSlotTL() to construct TupleTableSlots * for the tuples returned by the access methods and the * tuples resulting from performing target list projections. * @@ -104,19 +104,36 @@ static TupleDesc ExecTypeFromTLInternal(List *targetList, /* -------------------------------- * MakeTupleTableSlot * - * Basic routine to make an empty TupleTableSlot. + * Basic routine to make an empty TupleTableSlot. If tupleDesc is + * specified the slot's descriptor is fixed for it's lifetime, gaining + * some efficiency. If that's undesirable, pass NULL. * -------------------------------- */ TupleTableSlot * -MakeTupleTableSlot(void) +MakeTupleTableSlot(TupleDesc tupleDesc) { - TupleTableSlot *slot = makeNode(TupleTableSlot); + Size sz; + TupleTableSlot *slot; + /* + * When a fixed descriptor is specified, we can reduce overhead by + * allocating the entire slot in one go. + */ + if (tupleDesc) + sz = MAXALIGN(sizeof(TupleTableSlot)) + + MAXALIGN(tupleDesc->natts * sizeof(Datum)) + + MAXALIGN(tupleDesc->natts * sizeof(bool)); + else + sz = sizeof(TupleTableSlot); + + slot = palloc0(sz); + slot->type = T_TupleTableSlot; slot->tts_isempty = true; slot->tts_shouldFree = false; slot->tts_shouldFreeMin = false; slot->tts_tuple = NULL; - slot->tts_tupleDescriptor = NULL; + slot->tts_fixedTupleDescriptor = tupleDesc != NULL; + slot->tts_tupleDescriptor = tupleDesc; slot->tts_mcxt = CurrentMemoryContext; slot->tts_buffer = InvalidBuffer; slot->tts_nvalid = 0; @@ -124,6 +141,19 @@ MakeTupleTableSlot(void) slot->tts_isnull = NULL; slot->tts_mintuple = NULL; + if (tupleDesc != NULL) + { + slot->tts_values = (Datum *) + (((char *) slot) + + MAXALIGN(sizeof(TupleTableSlot))); + slot->tts_isnull = (bool *) + (((char *) slot) + + MAXALIGN(sizeof(TupleTableSlot)) + + MAXALIGN(tupleDesc->natts * sizeof(Datum))); + + PinTupleDesc(tupleDesc); + } + return slot; } @@ -134,9 +164,9 @@ MakeTupleTableSlot(void) * -------------------------------- */ TupleTableSlot * -ExecAllocTableSlot(List **tupleTable) +ExecAllocTableSlot(List **tupleTable, TupleDesc desc) { - TupleTableSlot *slot = MakeTupleTableSlot(); + TupleTableSlot *slot = MakeTupleTableSlot(desc); *tupleTable = lappend(*tupleTable, slot); @@ -173,10 +203,13 @@ ExecResetTupleTable(List *tupleTable, /* tuple table */ /* If shouldFree, release memory occupied by the slot itself */ if (shouldFree) { - if (slot->tts_values) - pfree(slot->tts_values); - if (slot->tts_isnull) - pfree(slot->tts_isnull); + if (!slot->tts_fixedTupleDescriptor) + { + if (slot->tts_values) + pfree(slot->tts_values); + if (slot->tts_isnull) + pfree(slot->tts_isnull); + } pfree(slot); } } @@ -198,9 +231,7 @@ ExecResetTupleTable(List *tupleTable, /* tuple table */ TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc) { - TupleTableSlot *slot = MakeTupleTableSlot(); - - ExecSetSlotDescriptor(slot, tupdesc); + TupleTableSlot *slot = MakeTupleTableSlot(tupdesc); return slot; } @@ -220,10 +251,13 @@ ExecDropSingleTupleTableSlot(TupleTableSlot *slot) ExecClearTuple(slot); if (slot->tts_tupleDescriptor) ReleaseTupleDesc(slot->tts_tupleDescriptor); - if (slot->tts_values) - pfree(slot->tts_values); - if (slot->tts_isnull) - pfree(slot->tts_isnull); + if (!slot->tts_fixedTupleDescriptor) + { + if (slot->tts_values) + pfree(slot->tts_values); + if (slot->tts_isnull) + pfree(slot->tts_isnull); + } pfree(slot); } @@ -247,6 +281,8 @@ void ExecSetSlotDescriptor(TupleTableSlot *slot, /* slot to change */ TupleDesc tupdesc) /* new tuple descriptor */ { + Assert(!slot->tts_fixedTupleDescriptor); + /* For safety, make sure slot is empty before changing it */ ExecClearTuple(slot); @@ -816,7 +852,7 @@ ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot) */ /* -------------------------------- - * ExecInit{Result,Scan,Extra}TupleSlot + * ExecInit{Result,Scan,Extra}TupleSlot[TL] * * These are convenience routines to initialize the specified slot * in nodes inheriting the appropriate state. ExecInitExtraTupleSlot @@ -825,13 +861,30 @@ ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot) */ /* ---------------- - * ExecInitResultTupleSlot + * ExecInitResultTupleSlotTL + * + * Initialize result tuple slot, using the plan node's targetlist. * ---------------- */ void -ExecInitResultTupleSlot(EState *estate, PlanState *planstate) +ExecInitResultTupleSlotTL(EState *estate, PlanState *planstate) { - planstate->ps_ResultTupleSlot = ExecAllocTableSlot(&estate->es_tupleTable); + bool hasoid; + TupleDesc tupDesc; + + if (ExecContextForcesOids(planstate, &hasoid)) + { + /* context forces OID choice; hasoid is now set correctly */ + } + else + { + /* given free choice, don't leave space for OIDs in result tuples */ + hasoid = false; + } + + tupDesc = ExecTypeFromTL(planstate->plan->targetlist, hasoid); + + planstate->ps_ResultTupleSlot = ExecAllocTableSlot(&estate->es_tupleTable, tupDesc); } /* ---------------- @@ -839,19 +892,24 @@ ExecInitResultTupleSlot(EState *estate, PlanState *planstate) * ---------------- */ void -ExecInitScanTupleSlot(EState *estate, ScanState *scanstate) +ExecInitScanTupleSlot(EState *estate, ScanState *scanstate, TupleDesc tupledesc) { - scanstate->ss_ScanTupleSlot = ExecAllocTableSlot(&estate->es_tupleTable); + scanstate->ss_ScanTupleSlot = ExecAllocTableSlot(&estate->es_tupleTable, + tupledesc); } /* ---------------- * ExecInitExtraTupleSlot + * + * Return a newly created slot. If tupledesc is non-NULL the slot will have + * that as its fixed tupledesc. Otherwise the caller needs to use + * ExecSetSlotDescriptor() to set the descriptor before use. * ---------------- */ TupleTableSlot * -ExecInitExtraTupleSlot(EState *estate) +ExecInitExtraTupleSlot(EState *estate, TupleDesc tupledesc) { - return ExecAllocTableSlot(&estate->es_tupleTable); + return ExecAllocTableSlot(&estate->es_tupleTable, tupledesc); } /* ---------------- @@ -865,9 +923,7 @@ ExecInitExtraTupleSlot(EState *estate) TupleTableSlot * ExecInitNullTupleSlot(EState *estate, TupleDesc tupType) { - TupleTableSlot *slot = ExecInitExtraTupleSlot(estate); - - ExecSetSlotDescriptor(slot, tupType); + TupleTableSlot *slot = ExecInitExtraTupleSlot(estate, tupType); return ExecStoreAllNullTuple(slot); } diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c index 50b6edce63..a8ae37ebc8 100644 --- a/src/backend/executor/execUtils.c +++ b/src/backend/executor/execUtils.c @@ -22,7 +22,6 @@ * ReScanExprContext * * ExecAssignExprContext Common code for plan node init routines. - * ExecAssignResultType * etc * * ExecOpenScanRelation Common code for scan node init routines. @@ -428,47 +427,6 @@ ExecAssignExprContext(EState *estate, PlanState *planstate) planstate->ps_ExprContext = CreateExprContext(estate); } -/* ---------------- - * ExecAssignResultType - * ---------------- - */ -void -ExecAssignResultType(PlanState *planstate, TupleDesc tupDesc) -{ - TupleTableSlot *slot = planstate->ps_ResultTupleSlot; - - ExecSetSlotDescriptor(slot, tupDesc); -} - -/* ---------------- - * ExecAssignResultTypeFromTL - * ---------------- - */ -void -ExecAssignResultTypeFromTL(PlanState *planstate) -{ - bool hasoid; - TupleDesc tupDesc; - - if (ExecContextForcesOids(planstate, &hasoid)) - { - /* context forces OID choice; hasoid is now set correctly */ - } - else - { - /* given free choice, don't leave space for OIDs in result tuples */ - hasoid = false; - } - - /* - * ExecTypeFromTL needs the parse-time representation of the tlist, not a - * list of ExprStates. This is good because some plan nodes don't bother - * to set up planstate->targetlist ... - */ - tupDesc = ExecTypeFromTL(planstate->plan->targetlist, hasoid); - ExecAssignResultType(planstate, tupDesc); -} - /* ---------------- * ExecGetResultType * ---------------- @@ -609,13 +567,9 @@ ExecFreeExprContext(PlanState *planstate) planstate->ps_ExprContext = NULL; } + /* ---------------------------------------------------------------- - * the following scan type support functions are for - * those nodes which are stubborn and return tuples in - * their Scan tuple slot instead of their Result tuple - * slot.. luck fur us, these nodes do not do projections - * so we don't have to worry about getting the ProjectionInfo - * right for them... -cim 6/3/91 + * Scan node support * ---------------------------------------------------------------- */ @@ -632,11 +586,11 @@ ExecAssignScanType(ScanState *scanstate, TupleDesc tupDesc) } /* ---------------- - * ExecAssignScanTypeFromOuterPlan + * ExecCreateSlotFromOuterPlan * ---------------- */ void -ExecAssignScanTypeFromOuterPlan(ScanState *scanstate) +ExecCreateScanSlotFromOuterPlan(EState *estate, ScanState *scanstate) { PlanState *outerPlan; TupleDesc tupDesc; @@ -644,15 +598,9 @@ ExecAssignScanTypeFromOuterPlan(ScanState *scanstate) outerPlan = outerPlanState(scanstate); tupDesc = ExecGetResultType(outerPlan); - ExecAssignScanType(scanstate, tupDesc); + ExecInitScanTupleSlot(estate, scanstate, tupDesc); } - -/* ---------------------------------------------------------------- - * Scan node support - * ---------------------------------------------------------------- - */ - /* ---------------------------------------------------------------- * ExecRelationIsTargetRelation * diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c index e74b3a9391..1b1334006f 100644 --- a/src/backend/executor/nodeAgg.c +++ b/src/backend/executor/nodeAgg.c @@ -1402,8 +1402,8 @@ find_hash_columns(AggState *aggstate) perhash->aggnode->grpOperators, &perhash->eqfuncoids, &perhash->hashfunctions); - perhash->hashslot = ExecAllocTableSlot(&estate->es_tupleTable); - ExecSetSlotDescriptor(perhash->hashslot, hashDesc); + perhash->hashslot = + ExecAllocTableSlot(&estate->es_tupleTable, hashDesc); list_free(hashTlist); bms_free(colnos); @@ -2199,13 +2199,29 @@ ExecInitAgg(Agg *node, EState *estate, int eflags) ExecAssignExprContext(estate, &aggstate->ss.ps); /* - * tuple table initialization. + * Initialize child nodes. * - * For hashtables, we create some additional slots below. + * If we are doing a hashed aggregation then the child plan does not need + * to handle REWIND efficiently; see ExecReScanAgg. */ - ExecInitScanTupleSlot(estate, &aggstate->ss); - ExecInitResultTupleSlot(estate, &aggstate->ss.ps); - aggstate->sort_slot = ExecInitExtraTupleSlot(estate); + if (node->aggstrategy == AGG_HASHED) + eflags &= ~EXEC_FLAG_REWIND; + outerPlan = outerPlan(node); + outerPlanState(aggstate) = ExecInitNode(outerPlan, estate, eflags); + + /* + * initialize source tuple type. + */ + ExecCreateScanSlotFromOuterPlan(estate, &aggstate->ss); + scanDesc = aggstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor; + if (node->chain) + aggstate->sort_slot = ExecInitExtraTupleSlot(estate, scanDesc); + + /* + * Initialize result type, slot and projection. + */ + ExecInitResultTupleSlotTL(estate, &aggstate->ss.ps); + ExecAssignProjectionInfo(&aggstate->ss.ps, NULL); /* * initialize child expressions @@ -2223,31 +2239,6 @@ ExecInitAgg(Agg *node, EState *estate, int eflags) aggstate->ss.ps.qual = ExecInitQual(node->plan.qual, (PlanState *) aggstate); - /* - * Initialize child nodes. - * - * If we are doing a hashed aggregation then the child plan does not need - * to handle REWIND efficiently; see ExecReScanAgg. - */ - if (node->aggstrategy == AGG_HASHED) - eflags &= ~EXEC_FLAG_REWIND; - outerPlan = outerPlan(node); - outerPlanState(aggstate) = ExecInitNode(outerPlan, estate, eflags); - - /* - * initialize source tuple type. - */ - ExecAssignScanTypeFromOuterPlan(&aggstate->ss); - scanDesc = aggstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor; - if (node->chain) - ExecSetSlotDescriptor(aggstate->sort_slot, scanDesc); - - /* - * Initialize result tuple type and projection info. - */ - ExecAssignResultTypeFromTL(&aggstate->ss.ps); - ExecAssignProjectionInfo(&aggstate->ss.ps, NULL); - /* * We should now have found all Aggrefs in the targetlist and quals. */ @@ -3071,8 +3062,8 @@ build_pertrans_for_aggref(AggStatePerTrans pertrans, if (numSortCols > 0 || aggref->aggfilter) { pertrans->sortdesc = ExecTypeFromTL(aggref->args, false); - pertrans->sortslot = ExecInitExtraTupleSlot(estate); - ExecSetSlotDescriptor(pertrans->sortslot, pertrans->sortdesc); + pertrans->sortslot = + ExecInitExtraTupleSlot(estate, pertrans->sortdesc); } if (numSortCols > 0) @@ -3093,9 +3084,8 @@ build_pertrans_for_aggref(AggStatePerTrans pertrans, else if (numDistinctCols > 0) { /* we will need an extra slot to store prior values */ - pertrans->uniqslot = ExecInitExtraTupleSlot(estate); - ExecSetSlotDescriptor(pertrans->uniqslot, - pertrans->sortdesc); + pertrans->uniqslot = + ExecInitExtraTupleSlot(estate, pertrans->sortdesc); } /* Extract the sort information for use later */ diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c index 264d8fea8d..7a3dd2ee2d 100644 --- a/src/backend/executor/nodeAppend.c +++ b/src/backend/executor/nodeAppend.c @@ -129,17 +129,9 @@ ExecInitAppend(Append *node, EState *estate, int eflags) appendstate->as_nplans = nplans; /* - * Miscellaneous initialization - * - * Append plans don't have expression contexts because they never call - * ExecQual or ExecProject. + * Initialize result tuple type and slot. */ - - /* - * append nodes still have Result slots, which hold pointers to tuples, so - * we have to initialize them. - */ - ExecInitResultTupleSlot(estate, &appendstate->ps); + ExecInitResultTupleSlotTL(estate, &appendstate->ps); /* * call ExecInitNode on each of the plans to be executed and save the @@ -155,9 +147,11 @@ ExecInitAppend(Append *node, EState *estate, int eflags) } /* - * initialize output tuple type + * Miscellaneous initialization + * + * Append plans don't have expression contexts because they never call + * ExecQual or ExecProject. */ - ExecAssignResultTypeFromTL(&appendstate->ps); appendstate->ps.ps_ProjInfo = NULL; /* diff --git a/src/backend/executor/nodeBitmapAnd.c b/src/backend/executor/nodeBitmapAnd.c index 913046c987..23d0d94326 100644 --- a/src/backend/executor/nodeBitmapAnd.c +++ b/src/backend/executor/nodeBitmapAnd.c @@ -80,13 +80,6 @@ ExecInitBitmapAnd(BitmapAnd *node, EState *estate, int eflags) bitmapandstate->bitmapplans = bitmapplanstates; bitmapandstate->nplans = nplans; - /* - * Miscellaneous initialization - * - * BitmapAnd plans don't have expression contexts because they never call - * ExecQual or ExecProject. They don't need any tuple slots either. - */ - /* * call ExecInitNode on each of the plans to be executed and save the * results into the array "bitmapplanstates". @@ -99,6 +92,13 @@ ExecInitBitmapAnd(BitmapAnd *node, EState *estate, int eflags) i++; } + /* + * Miscellaneous initialization + * + * BitmapAnd plans don't have expression contexts because they never call + * ExecQual or ExecProject. They don't need any tuple slots either. + */ + return bitmapandstate; } diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c index fa65d4efbe..3e1c9e0714 100644 --- a/src/backend/executor/nodeBitmapHeapscan.c +++ b/src/backend/executor/nodeBitmapHeapscan.c @@ -906,6 +906,33 @@ ExecInitBitmapHeapScan(BitmapHeapScan *node, EState *estate, int eflags) */ ExecAssignExprContext(estate, &scanstate->ss.ps); + /* + * open the base relation and acquire appropriate lock on it. + */ + currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags); + + /* + * initialize child nodes + * + * We do this after ExecOpenScanRelation because the child nodes will open + * indexscans on our relation's indexes, and we want to be sure we have + * acquired a lock on the relation first. + */ + outerPlanState(scanstate) = ExecInitNode(outerPlan(node), estate, eflags); + + /* + * get the scan type from the relation descriptor. + */ + ExecInitScanTupleSlot(estate, &scanstate->ss, + RelationGetDescr(currentRelation)); + + + /* + * Initialize result slot, type and projection. + */ + ExecInitResultTupleSlotTL(estate, &scanstate->ss.ps); + ExecAssignScanProjectionInfo(&scanstate->ss); + /* * initialize child expressions */ @@ -914,17 +941,6 @@ ExecInitBitmapHeapScan(BitmapHeapScan *node, EState *estate, int eflags) scanstate->bitmapqualorig = ExecInitQual(node->bitmapqualorig, (PlanState *) scanstate); - /* - * tuple table initialization - */ - ExecInitResultTupleSlot(estate, &scanstate->ss.ps); - ExecInitScanTupleSlot(estate, &scanstate->ss); - - /* - * open the base relation and acquire appropriate lock on it. - */ - currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags); - /* * Determine the maximum for prefetch_target. If the tablespace has a * specific IO concurrency set, use that to compute the corresponding @@ -952,26 +968,6 @@ ExecInitBitmapHeapScan(BitmapHeapScan *node, EState *estate, int eflags) 0, NULL); - /* - * get the scan type from the relation descriptor. - */ - ExecAssignScanType(&scanstate->ss, RelationGetDescr(currentRelation)); - - /* - * Initialize result tuple type and projection info. - */ - ExecAssignResultTypeFromTL(&scanstate->ss.ps); - ExecAssignScanProjectionInfo(&scanstate->ss); - - /* - * initialize child nodes - * - * We do this last because the child nodes will open indexscans on our - * relation's indexes, and we want to be sure we have acquired a lock on - * the relation first. - */ - outerPlanState(scanstate) = ExecInitNode(outerPlan(node), estate, eflags); - /* * all done. */ diff --git a/src/backend/executor/nodeBitmapIndexscan.c b/src/backend/executor/nodeBitmapIndexscan.c index bb5e4da187..d04f4901b4 100644 --- a/src/backend/executor/nodeBitmapIndexscan.c +++ b/src/backend/executor/nodeBitmapIndexscan.c @@ -226,6 +226,15 @@ ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate, int eflags) /* normally we don't make the result bitmap till runtime */ indexstate->biss_result = NULL; + /* + * We do not open or lock the base relation here. We assume that an + * ancestor BitmapHeapScan node is holding AccessShareLock (or better) on + * the heap relation throughout the execution of the plan tree. + */ + + indexstate->ss.ss_currentRelation = NULL; + indexstate->ss.ss_currentScanDesc = NULL; + /* * Miscellaneous initialization * @@ -242,15 +251,6 @@ ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate, int eflags) * sub-parts corresponding to runtime keys (see below). */ - /* - * We do not open or lock the base relation here. We assume that an - * ancestor BitmapHeapScan node is holding AccessShareLock (or better) on - * the heap relation throughout the execution of the plan tree. - */ - - indexstate->ss.ss_currentRelation = NULL; - indexstate->ss.ss_currentScanDesc = NULL; - /* * If we are just doing EXPLAIN (ie, aren't going to run the plan), stop * here. This allows an index-advisor plugin to EXPLAIN a plan containing diff --git a/src/backend/executor/nodeBitmapOr.c b/src/backend/executor/nodeBitmapOr.c index 8047549f7d..3f0a0a0544 100644 --- a/src/backend/executor/nodeBitmapOr.c +++ b/src/backend/executor/nodeBitmapOr.c @@ -81,13 +81,6 @@ ExecInitBitmapOr(BitmapOr *node, EState *estate, int eflags) bitmaporstate->bitmapplans = bitmapplanstates; bitmaporstate->nplans = nplans; - /* - * Miscellaneous initialization - * - * BitmapOr plans don't have expression contexts because they never call - * ExecQual or ExecProject. They don't need any tuple slots either. - */ - /* * call ExecInitNode on each of the plans to be executed and save the * results into the array "bitmapplanstates". @@ -100,6 +93,13 @@ ExecInitBitmapOr(BitmapOr *node, EState *estate, int eflags) i++; } + /* + * Miscellaneous initialization + * + * BitmapOr plans don't have expression contexts because they never call + * ExecQual or ExecProject. They don't need any tuple slots either. + */ + return bitmaporstate; } diff --git a/src/backend/executor/nodeCtescan.c b/src/backend/executor/nodeCtescan.c index ec6d75cbd4..218619c760 100644 --- a/src/backend/executor/nodeCtescan.c +++ b/src/backend/executor/nodeCtescan.c @@ -242,31 +242,25 @@ ExecInitCteScan(CteScan *node, EState *estate, int eflags) */ ExecAssignExprContext(estate, &scanstate->ss.ps); + /* + * The scan tuple type (ie, the rowtype we expect to find in the work + * table) is the same as the result rowtype of the CTE query. + */ + ExecInitScanTupleSlot(estate, &scanstate->ss, + ExecGetResultType(scanstate->cteplanstate)); + + /* + * Initialize result slot, type and projection. + */ + ExecInitResultTupleSlotTL(estate, &scanstate->ss.ps); + ExecAssignScanProjectionInfo(&scanstate->ss); + /* * initialize child expressions */ scanstate->ss.ps.qual = ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate); - /* - * tuple table initialization - */ - ExecInitResultTupleSlot(estate, &scanstate->ss.ps); - ExecInitScanTupleSlot(estate, &scanstate->ss); - - /* - * The scan tuple type (ie, the rowtype we expect to find in the work - * table) is the same as the result rowtype of the CTE query. - */ - ExecAssignScanType(&scanstate->ss, - ExecGetResultType(scanstate->cteplanstate)); - - /* - * Initialize result tuple type and projection info. - */ - ExecAssignResultTypeFromTL(&scanstate->ss.ps); - ExecAssignScanProjectionInfo(&scanstate->ss); - return scanstate; } diff --git a/src/backend/executor/nodeCustom.c b/src/backend/executor/nodeCustom.c index 936a2221f5..b816e0b31d 100644 --- a/src/backend/executor/nodeCustom.c +++ b/src/backend/executor/nodeCustom.c @@ -54,14 +54,6 @@ ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags) /* create expression context for node */ ExecAssignExprContext(estate, &css->ss.ps); - /* initialize child expressions */ - css->ss.ps.qual = - ExecInitQual(cscan->scan.plan.qual, (PlanState *) css); - - /* tuple table initialization */ - ExecInitScanTupleSlot(estate, &css->ss); - ExecInitResultTupleSlot(estate, &css->ss.ps); - /* * open the base relation, if any, and acquire an appropriate lock on it */ @@ -81,23 +73,27 @@ ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags) TupleDesc scan_tupdesc; scan_tupdesc = ExecTypeFromTL(cscan->custom_scan_tlist, false); - ExecAssignScanType(&css->ss, scan_tupdesc); + ExecInitScanTupleSlot(estate, &css->ss, scan_tupdesc); /* Node's targetlist will contain Vars with varno = INDEX_VAR */ tlistvarno = INDEX_VAR; } else { - ExecAssignScanType(&css->ss, RelationGetDescr(scan_rel)); + ExecInitScanTupleSlot(estate, &css->ss, RelationGetDescr(scan_rel)); /* Node's targetlist will contain Vars with varno = scanrelid */ tlistvarno = scanrelid; } /* - * Initialize result tuple type and projection info. + * Initialize result slot, type and projection. */ - ExecAssignResultTypeFromTL(&css->ss.ps); + ExecInitResultTupleSlotTL(estate, &css->ss.ps); ExecAssignScanProjectionInfoWithVarno(&css->ss, tlistvarno); + /* initialize child expressions */ + css->ss.ps.qual = + ExecInitQual(cscan->scan.plan.qual, (PlanState *) css); + /* * The callback of custom-scan provider applies the final initialization * of the custom-scan-state node according to its logic. diff --git a/src/backend/executor/nodeForeignscan.c b/src/backend/executor/nodeForeignscan.c index 59865f5cca..0084234b35 100644 --- a/src/backend/executor/nodeForeignscan.c +++ b/src/backend/executor/nodeForeignscan.c @@ -155,20 +155,6 @@ ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags) */ ExecAssignExprContext(estate, &scanstate->ss.ps); - /* - * initialize child expressions - */ - scanstate->ss.ps.qual = - ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate); - scanstate->fdw_recheck_quals = - ExecInitQual(node->fdw_recheck_quals, (PlanState *) scanstate); - - /* - * tuple table initialization - */ - ExecInitResultTupleSlot(estate, &scanstate->ss.ps); - ExecInitScanTupleSlot(estate, &scanstate->ss); - /* * open the base relation, if any, and acquire an appropriate lock on it; * also acquire function pointers from the FDW's handler @@ -194,23 +180,31 @@ ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags) TupleDesc scan_tupdesc; scan_tupdesc = ExecTypeFromTL(node->fdw_scan_tlist, false); - ExecAssignScanType(&scanstate->ss, scan_tupdesc); + ExecInitScanTupleSlot(estate, &scanstate->ss, scan_tupdesc); /* Node's targetlist will contain Vars with varno = INDEX_VAR */ tlistvarno = INDEX_VAR; } else { - ExecAssignScanType(&scanstate->ss, RelationGetDescr(currentRelation)); + ExecInitScanTupleSlot(estate, &scanstate->ss, RelationGetDescr(currentRelation)); /* Node's targetlist will contain Vars with varno = scanrelid */ tlistvarno = scanrelid; } /* - * Initialize result tuple type and projection info. + * Initialize result slot, type and projection. */ - ExecAssignResultTypeFromTL(&scanstate->ss.ps); + ExecInitResultTupleSlotTL(estate, &scanstate->ss.ps); ExecAssignScanProjectionInfoWithVarno(&scanstate->ss, tlistvarno); + /* + * initialize child expressions + */ + scanstate->ss.ps.qual = + ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate); + scanstate->fdw_recheck_quals = + ExecInitQual(node->fdw_recheck_quals, (PlanState *) scanstate); + /* * Initialize FDW-related state. */ diff --git a/src/backend/executor/nodeFunctionscan.c b/src/backend/executor/nodeFunctionscan.c index 69f8d3e814..fb7c9f6787 100644 --- a/src/backend/executor/nodeFunctionscan.c +++ b/src/backend/executor/nodeFunctionscan.c @@ -334,18 +334,6 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags) */ ExecAssignExprContext(estate, &scanstate->ss.ps); - /* - * tuple table initialization - */ - ExecInitResultTupleSlot(estate, &scanstate->ss.ps); - ExecInitScanTupleSlot(estate, &scanstate->ss); - - /* - * initialize child expressions - */ - scanstate->ss.ps.qual = - ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate); - scanstate->funcstates = palloc(nfuncs * sizeof(FunctionScanPerFuncState)); natts = 0; @@ -436,8 +424,7 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags) */ if (!scanstate->simple) { - fs->func_slot = ExecInitExtraTupleSlot(estate); - ExecSetSlotDescriptor(fs->func_slot, fs->tupdesc); + fs->func_slot = ExecInitExtraTupleSlot(estate, fs->tupdesc); } else fs->func_slot = NULL; @@ -492,14 +479,23 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags) Assert(attno == natts); } - ExecAssignScanType(&scanstate->ss, scan_tupdesc); + /* + * Initialize scan slot and type. + */ + ExecInitScanTupleSlot(estate, &scanstate->ss, scan_tupdesc); /* - * Initialize result tuple type and projection info. + * Initialize result slot, type and projection. */ - ExecAssignResultTypeFromTL(&scanstate->ss.ps); + ExecInitResultTupleSlotTL(estate, &scanstate->ss.ps); ExecAssignScanProjectionInfo(&scanstate->ss); + /* + * initialize child expressions + */ + scanstate->ss.ps.qual = + ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate); + /* * Create a memory context that ExecMakeTableFunctionResult can use to * evaluate function arguments in. We can't use the per-tuple context for diff --git a/src/backend/executor/nodeGather.c b/src/backend/executor/nodeGather.c index 58eadd45b8..eaf7d2d563 100644 --- a/src/backend/executor/nodeGather.c +++ b/src/backend/executor/nodeGather.c @@ -59,7 +59,6 @@ ExecInitGather(Gather *node, EState *estate, int eflags) { GatherState *gatherstate; Plan *outerNode; - bool hasoid; TupleDesc tupDesc; /* Gather node doesn't have innerPlan node. */ @@ -85,37 +84,29 @@ ExecInitGather(Gather *node, EState *estate, int eflags) */ ExecAssignExprContext(estate, &gatherstate->ps); - /* - * Gather doesn't support checking a qual (it's always more efficient to - * do it in the child node). - */ - Assert(!node->plan.qual); - - /* - * tuple table initialization - */ - gatherstate->funnel_slot = ExecInitExtraTupleSlot(estate); - ExecInitResultTupleSlot(estate, &gatherstate->ps); - /* * now initialize outer plan */ outerNode = outerPlan(node); outerPlanState(gatherstate) = ExecInitNode(outerNode, estate, eflags); + tupDesc = ExecGetResultType(outerPlanState(gatherstate)); + + /* + * Initialize result slot, type and projection. + */ + ExecInitResultTupleSlotTL(estate, &gatherstate->ps); + ExecConditionalAssignProjectionInfo(&gatherstate->ps, tupDesc, OUTER_VAR); /* * Initialize funnel slot to same tuple descriptor as outer plan. */ - if (!ExecContextForcesOids(outerPlanState(gatherstate), &hasoid)) - hasoid = false; - tupDesc = ExecTypeFromTL(outerNode->targetlist, hasoid); - ExecSetSlotDescriptor(gatherstate->funnel_slot, tupDesc); + gatherstate->funnel_slot = ExecInitExtraTupleSlot(estate, tupDesc); /* - * Initialize result tuple type and projection info. + * Gather doesn't support checking a qual (it's always more efficient to + * do it in the child node). */ - ExecAssignResultTypeFromTL(&gatherstate->ps); - ExecConditionalAssignProjectionInfo(&gatherstate->ps, tupDesc, OUTER_VAR); + Assert(!node->plan.qual); return gatherstate; } diff --git a/src/backend/executor/nodeGatherMerge.c b/src/backend/executor/nodeGatherMerge.c index 6858c91e8c..83221cdbae 100644 --- a/src/backend/executor/nodeGatherMerge.c +++ b/src/backend/executor/nodeGatherMerge.c @@ -73,7 +73,6 @@ ExecInitGatherMerge(GatherMerge *node, EState *estate, int eflags) { GatherMergeState *gm_state; Plan *outerNode; - bool hasoid; TupleDesc tupDesc; /* Gather merge node doesn't have innerPlan node. */ @@ -104,11 +103,6 @@ ExecInitGatherMerge(GatherMerge *node, EState *estate, int eflags) */ Assert(!node->plan.qual); - /* - * tuple table initialization - */ - ExecInitResultTupleSlot(estate, &gm_state->ps); - /* * now initialize outer plan */ @@ -119,15 +113,13 @@ ExecInitGatherMerge(GatherMerge *node, EState *estate, int eflags) * Store the tuple descriptor into gather merge state, so we can use it * while initializing the gather merge slots. */ - if (!ExecContextForcesOids(outerPlanState(gm_state), &hasoid)) - hasoid = false; - tupDesc = ExecTypeFromTL(outerNode->targetlist, hasoid); + tupDesc = ExecGetResultType(outerPlanState(gm_state)); gm_state->tupDesc = tupDesc; /* - * Initialize result tuple type and projection info. + * Initialize result slot, type and projection. */ - ExecAssignResultTypeFromTL(&gm_state->ps); + ExecInitResultTupleSlotTL(estate, &gm_state->ps); ExecConditionalAssignProjectionInfo(&gm_state->ps, tupDesc, OUTER_VAR); /* @@ -410,9 +402,8 @@ gather_merge_setup(GatherMergeState *gm_state) (HeapTuple *) palloc0(sizeof(HeapTuple) * MAX_TUPLE_STORE); /* Initialize tuple slot for worker */ - gm_state->gm_slots[i + 1] = ExecInitExtraTupleSlot(gm_state->ps.state); - ExecSetSlotDescriptor(gm_state->gm_slots[i + 1], - gm_state->tupDesc); + gm_state->gm_slots[i + 1] = + ExecInitExtraTupleSlot(gm_state->ps.state, gm_state->tupDesc); } /* Allocate the resources for the merge */ diff --git a/src/backend/executor/nodeGroup.c b/src/backend/executor/nodeGroup.c index 8f7bf459ef..c6efd64d00 100644 --- a/src/backend/executor/nodeGroup.c +++ b/src/backend/executor/nodeGroup.c @@ -182,10 +182,20 @@ ExecInitGroup(Group *node, EState *estate, int eflags) ExecAssignExprContext(estate, &grpstate->ss.ps); /* - * tuple table initialization + * initialize child nodes */ - ExecInitScanTupleSlot(estate, &grpstate->ss); - ExecInitResultTupleSlot(estate, &grpstate->ss.ps); + outerPlanState(grpstate) = ExecInitNode(outerPlan(node), estate, eflags); + + /* + * Initialize scan slot and type. + */ + ExecCreateScanSlotFromOuterPlan(estate, &grpstate->ss); + + /* + * Initialize result slot, type and projection. + */ + ExecInitResultTupleSlotTL(estate, &grpstate->ss.ps); + ExecAssignProjectionInfo(&grpstate->ss.ps, NULL); /* * initialize child expressions @@ -193,22 +203,6 @@ ExecInitGroup(Group *node, EState *estate, int eflags) grpstate->ss.ps.qual = ExecInitQual(node->plan.qual, (PlanState *) grpstate); - /* - * initialize child nodes - */ - outerPlanState(grpstate) = ExecInitNode(outerPlan(node), estate, eflags); - - /* - * initialize tuple type. - */ - ExecAssignScanTypeFromOuterPlan(&grpstate->ss); - - /* - * Initialize result tuple type and projection info. - */ - ExecAssignResultTypeFromTL(&grpstate->ss.ps); - ExecAssignProjectionInfo(&grpstate->ss.ps, NULL); - /* * Precompute fmgr lookup data for inner loop */ diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c index b10f847452..06bb44b163 100644 --- a/src/backend/executor/nodeHash.c +++ b/src/backend/executor/nodeHash.c @@ -374,9 +374,16 @@ ExecInitHash(Hash *node, EState *estate, int eflags) ExecAssignExprContext(estate, &hashstate->ps); /* - * initialize our result slot + * initialize child nodes */ - ExecInitResultTupleSlot(estate, &hashstate->ps); + outerPlanState(hashstate) = ExecInitNode(outerPlan(node), estate, eflags); + + /* + * initialize our result slot and type. No need to build projection + * because this node doesn't do projections. + */ + ExecInitResultTupleSlotTL(estate, &hashstate->ps); + hashstate->ps.ps_ProjInfo = NULL; /* * initialize child expressions @@ -384,18 +391,6 @@ ExecInitHash(Hash *node, EState *estate, int eflags) hashstate->ps.qual = ExecInitQual(node->plan.qual, (PlanState *) hashstate); - /* - * initialize child nodes - */ - outerPlanState(hashstate) = ExecInitNode(outerPlan(node), estate, eflags); - - /* - * initialize tuple type. no need to initialize projection info because - * this node doesn't do projections - */ - ExecAssignResultTypeFromTL(&hashstate->ps); - hashstate->ps.ps_ProjInfo = NULL; - return hashstate; } diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c index 03d78042fa..ab91eb2527 100644 --- a/src/backend/executor/nodeHashjoin.c +++ b/src/backend/executor/nodeHashjoin.c @@ -596,6 +596,7 @@ ExecInitHashJoin(HashJoin *node, EState *estate, int eflags) List *lclauses; List *rclauses; List *hoperators; + TupleDesc outerDesc, innerDesc; ListCell *l; /* check for unsupported flags */ @@ -614,6 +615,7 @@ ExecInitHashJoin(HashJoin *node, EState *estate, int eflags) * managed to launch a parallel query. */ hjstate->js.ps.ExecProcNode = ExecHashJoin; + hjstate->js.jointype = node->join.jointype; /* * Miscellaneous initialization @@ -622,17 +624,6 @@ ExecInitHashJoin(HashJoin *node, EState *estate, int eflags) */ ExecAssignExprContext(estate, &hjstate->js.ps); - /* - * initialize child expressions - */ - hjstate->js.ps.qual = - ExecInitQual(node->join.plan.qual, (PlanState *) hjstate); - hjstate->js.jointype = node->join.jointype; - hjstate->js.joinqual = - ExecInitQual(node->join.joinqual, (PlanState *) hjstate); - hjstate->hashclauses = - ExecInitQual(node->hashclauses, (PlanState *) hjstate); - /* * initialize child nodes * @@ -644,13 +635,20 @@ ExecInitHashJoin(HashJoin *node, EState *estate, int eflags) hashNode = (Hash *) innerPlan(node); outerPlanState(hjstate) = ExecInitNode(outerNode, estate, eflags); + outerDesc = ExecGetResultType(outerPlanState(hjstate)); innerPlanState(hjstate) = ExecInitNode((Plan *) hashNode, estate, eflags); + innerDesc = ExecGetResultType(innerPlanState(hjstate)); + + /* + * Initialize result slot, type and projection. + */ + ExecInitResultTupleSlotTL(estate, &hjstate->js.ps); + ExecAssignProjectionInfo(&hjstate->js.ps, NULL); /* * tuple table initialization */ - ExecInitResultTupleSlot(estate, &hjstate->js.ps); - hjstate->hj_OuterTupleSlot = ExecInitExtraTupleSlot(estate); + hjstate->hj_OuterTupleSlot = ExecInitExtraTupleSlot(estate, outerDesc); /* * detect whether we need only consider the first matching inner tuple @@ -667,21 +665,17 @@ ExecInitHashJoin(HashJoin *node, EState *estate, int eflags) case JOIN_LEFT: case JOIN_ANTI: hjstate->hj_NullInnerTupleSlot = - ExecInitNullTupleSlot(estate, - ExecGetResultType(innerPlanState(hjstate))); + ExecInitNullTupleSlot(estate, innerDesc); break; case JOIN_RIGHT: hjstate->hj_NullOuterTupleSlot = - ExecInitNullTupleSlot(estate, - ExecGetResultType(outerPlanState(hjstate))); + ExecInitNullTupleSlot(estate, outerDesc); break; case JOIN_FULL: hjstate->hj_NullOuterTupleSlot = - ExecInitNullTupleSlot(estate, - ExecGetResultType(outerPlanState(hjstate))); + ExecInitNullTupleSlot(estate, outerDesc); hjstate->hj_NullInnerTupleSlot = - ExecInitNullTupleSlot(estate, - ExecGetResultType(innerPlanState(hjstate))); + ExecInitNullTupleSlot(estate, innerDesc); break; default: elog(ERROR, "unrecognized join type: %d", @@ -703,13 +697,14 @@ ExecInitHashJoin(HashJoin *node, EState *estate, int eflags) } /* - * initialize tuple type and projection info + * initialize child expressions */ - ExecAssignResultTypeFromTL(&hjstate->js.ps); - ExecAssignProjectionInfo(&hjstate->js.ps, NULL); - - ExecSetSlotDescriptor(hjstate->hj_OuterTupleSlot, - ExecGetResultType(outerPlanState(hjstate))); + hjstate->js.ps.qual = + ExecInitQual(node->join.plan.qual, (PlanState *) hjstate); + hjstate->js.joinqual = + ExecInitQual(node->join.joinqual, (PlanState *) hjstate); + hjstate->hashclauses = + ExecInitQual(node->hashclauses, (PlanState *) hjstate); /* * initialize hash-specific info diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c index 8ffcc52bea..ddc0ae9061 100644 --- a/src/backend/executor/nodeIndexonlyscan.c +++ b/src/backend/executor/nodeIndexonlyscan.c @@ -518,23 +518,6 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags) */ ExecAssignExprContext(estate, &indexstate->ss.ps); - /* - * initialize child expressions - * - * Note: we don't initialize all of the indexorderby expression, only the - * sub-parts corresponding to runtime keys (see below). - */ - indexstate->ss.ps.qual = - ExecInitQual(node->scan.plan.qual, (PlanState *) indexstate); - indexstate->indexqual = - ExecInitQual(node->indexqual, (PlanState *) indexstate); - - /* - * tuple table initialization - */ - ExecInitResultTupleSlot(estate, &indexstate->ss.ps); - ExecInitScanTupleSlot(estate, &indexstate->ss); - /* * open the base relation and acquire appropriate lock on it. */ @@ -551,16 +534,27 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags) * suitable data anyway.) */ tupDesc = ExecTypeFromTL(node->indextlist, false); - ExecAssignScanType(&indexstate->ss, tupDesc); + ExecInitScanTupleSlot(estate, &indexstate->ss, tupDesc); /* - * Initialize result tuple type and projection info. The node's + * Initialize result slot, type and projection info. The node's * targetlist will contain Vars with varno = INDEX_VAR, referencing the * scan tuple. */ - ExecAssignResultTypeFromTL(&indexstate->ss.ps); + ExecInitResultTupleSlotTL(estate, &indexstate->ss.ps); ExecAssignScanProjectionInfoWithVarno(&indexstate->ss, INDEX_VAR); + /* + * initialize child expressions + * + * Note: we don't initialize all of the indexorderby expression, only the + * sub-parts corresponding to runtime keys (see below). + */ + indexstate->ss.ps.qual = + ExecInitQual(node->scan.plan.qual, (PlanState *) indexstate); + indexstate->indexqual = + ExecInitQual(node->indexqual, (PlanState *) indexstate); + /* * If we are just doing EXPLAIN (ie, aren't going to run the plan), stop * here. This allows an index-advisor plugin to EXPLAIN a plan containing diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c index b8b961add4..01c9de88f4 100644 --- a/src/backend/executor/nodeIndexscan.c +++ b/src/backend/executor/nodeIndexscan.c @@ -940,6 +940,26 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags) */ ExecAssignExprContext(estate, &indexstate->ss.ps); + /* + * open the base relation and acquire appropriate lock on it. + */ + currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags); + + indexstate->ss.ss_currentRelation = currentRelation; + indexstate->ss.ss_currentScanDesc = NULL; /* no heap scan here */ + + /* + * get the scan type from the relation descriptor. + */ + ExecInitScanTupleSlot(estate, &indexstate->ss, + RelationGetDescr(currentRelation)); + + /* + * Initialize result slot, type and projection. + */ + ExecInitResultTupleSlotTL(estate, &indexstate->ss.ps); + ExecAssignScanProjectionInfo(&indexstate->ss); + /* * initialize child expressions * @@ -957,31 +977,6 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags) indexstate->indexorderbyorig = ExecInitExprList(node->indexorderbyorig, (PlanState *) indexstate); - /* - * tuple table initialization - */ - ExecInitResultTupleSlot(estate, &indexstate->ss.ps); - ExecInitScanTupleSlot(estate, &indexstate->ss); - - /* - * open the base relation and acquire appropriate lock on it. - */ - currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags); - - indexstate->ss.ss_currentRelation = currentRelation; - indexstate->ss.ss_currentScanDesc = NULL; /* no heap scan here */ - - /* - * get the scan type from the relation descriptor. - */ - ExecAssignScanType(&indexstate->ss, RelationGetDescr(currentRelation)); - - /* - * Initialize result tuple type and projection info. - */ - ExecAssignResultTypeFromTL(&indexstate->ss.ps); - ExecAssignScanProjectionInfo(&indexstate->ss); - /* * If we are just doing EXPLAIN (ie, aren't going to run the plan), stop * here. This allows an index-advisor plugin to EXPLAIN a plan containing diff --git a/src/backend/executor/nodeLimit.c b/src/backend/executor/nodeLimit.c index 29d2deac23..56d98b4490 100644 --- a/src/backend/executor/nodeLimit.c +++ b/src/backend/executor/nodeLimit.c @@ -353,6 +353,12 @@ ExecInitLimit(Limit *node, EState *estate, int eflags) */ ExecAssignExprContext(estate, &limitstate->ps); + /* + * initialize outer plan + */ + outerPlan = outerPlan(node); + outerPlanState(limitstate) = ExecInitNode(outerPlan, estate, eflags); + /* * initialize child expressions */ @@ -362,21 +368,15 @@ ExecInitLimit(Limit *node, EState *estate, int eflags) (PlanState *) limitstate); /* - * Tuple table initialization (XXX not actually used...) + * Initialize result slot and type. (XXX not actually used, but upper + * nodes access it to get this node's result tupledesc...) */ - ExecInitResultTupleSlot(estate, &limitstate->ps); - - /* - * then initialize outer plan - */ - outerPlan = outerPlan(node); - outerPlanState(limitstate) = ExecInitNode(outerPlan, estate, eflags); + ExecInitResultTupleSlotTL(estate, &limitstate->ps); /* * limit nodes do no projections, so initialize projection info for this * node appropriately */ - ExecAssignResultTypeFromTL(&limitstate->ps); limitstate->ps.ps_ProjInfo = NULL; return limitstate; diff --git a/src/backend/executor/nodeLockRows.c b/src/backend/executor/nodeLockRows.c index 7961b4be6a..b39ccf7dc1 100644 --- a/src/backend/executor/nodeLockRows.c +++ b/src/backend/executor/nodeLockRows.c @@ -370,13 +370,15 @@ ExecInitLockRows(LockRows *node, EState *estate, int eflags) /* * Miscellaneous initialization * - * LockRows nodes never call ExecQual or ExecProject. + * LockRows nodes never call ExecQual or ExecProject, therefore no + * ExprContext is needed. */ /* - * Tuple table initialization (XXX not actually used...) + * Tuple table initialization (XXX not actually used, but upper nodes + * access it to get this node's result tupledesc...) */ - ExecInitResultTupleSlot(estate, &lrstate->ps); + ExecInitResultTupleSlotTL(estate, &lrstate->ps); /* * then initialize outer plan @@ -387,7 +389,6 @@ ExecInitLockRows(LockRows *node, EState *estate, int eflags) * LockRows nodes do no projections, so initialize projection info for * this node appropriately */ - ExecAssignResultTypeFromTL(&lrstate->ps); lrstate->ps.ps_ProjInfo = NULL; /* diff --git a/src/backend/executor/nodeMaterial.c b/src/backend/executor/nodeMaterial.c index 85afe87c44..8c2e57dbd0 100644 --- a/src/backend/executor/nodeMaterial.c +++ b/src/backend/executor/nodeMaterial.c @@ -206,14 +206,6 @@ ExecInitMaterial(Material *node, EState *estate, int eflags) * ExecQual or ExecProject. */ - /* - * tuple table initialization - * - * material nodes only return tuples from their materialized relation. - */ - ExecInitResultTupleSlot(estate, &matstate->ss.ps); - ExecInitScanTupleSlot(estate, &matstate->ss); - /* * initialize child nodes * @@ -226,13 +218,19 @@ ExecInitMaterial(Material *node, EState *estate, int eflags) outerPlanState(matstate) = ExecInitNode(outerPlan, estate, eflags); /* - * initialize tuple type. no need to initialize projection info because - * this node doesn't do projections. + * Initialize result type and slot. No need to initialize projection info + * because this node doesn't do projections. + * + * material nodes only return tuples from their materialized relation. */ - ExecAssignResultTypeFromTL(&matstate->ss.ps); - ExecAssignScanTypeFromOuterPlan(&matstate->ss); + ExecInitResultTupleSlotTL(estate, &matstate->ss.ps); matstate->ss.ps.ps_ProjInfo = NULL; + /* + * initialize tuple type. + */ + ExecCreateScanSlotFromOuterPlan(estate, &matstate->ss); + return matstate; } diff --git a/src/backend/executor/nodeMergeAppend.c b/src/backend/executor/nodeMergeAppend.c index ab4009c967..118f4ef07d 100644 --- a/src/backend/executor/nodeMergeAppend.c +++ b/src/backend/executor/nodeMergeAppend.c @@ -109,7 +109,7 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags) * MergeAppend nodes do have Result slots, which hold pointers to tuples, * so we have to initialize them. */ - ExecInitResultTupleSlot(estate, &mergestate->ps); + ExecInitResultTupleSlotTL(estate, &mergestate->ps); /* * call ExecInitNode on each of the plans to be executed and save the @@ -124,10 +124,6 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags) i++; } - /* - * initialize output tuple type - */ - ExecAssignResultTypeFromTL(&mergestate->ps); mergestate->ps.ps_ProjInfo = NULL; /* diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c index ec5f82f6a9..f3cbe2f889 100644 --- a/src/backend/executor/nodeMergejoin.c +++ b/src/backend/executor/nodeMergejoin.c @@ -1436,6 +1436,7 @@ MergeJoinState * ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags) { MergeJoinState *mergestate; + TupleDesc outerDesc, innerDesc; /* check for unsupported flags */ Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK))); @@ -1450,6 +1451,8 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags) mergestate->js.ps.plan = (Plan *) node; mergestate->js.ps.state = estate; mergestate->js.ps.ExecProcNode = ExecMergeJoin; + mergestate->js.jointype = node->join.jointype; + mergestate->mj_ConstFalseJoin = false; /* * Miscellaneous initialization @@ -1466,17 +1469,6 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags) mergestate->mj_OuterEContext = CreateExprContext(estate); mergestate->mj_InnerEContext = CreateExprContext(estate); - /* - * initialize child expressions - */ - mergestate->js.ps.qual = - ExecInitQual(node->join.plan.qual, (PlanState *) mergestate); - mergestate->js.jointype = node->join.jointype; - mergestate->js.joinqual = - ExecInitQual(node->join.joinqual, (PlanState *) mergestate); - mergestate->mj_ConstFalseJoin = false; - /* mergeclauses are handled below */ - /* * initialize child nodes * @@ -1488,10 +1480,12 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags) mergestate->mj_SkipMarkRestore = node->skip_mark_restore; outerPlanState(mergestate) = ExecInitNode(outerPlan(node), estate, eflags); + outerDesc = ExecGetResultType(outerPlanState(mergestate)); innerPlanState(mergestate) = ExecInitNode(innerPlan(node), estate, mergestate->mj_SkipMarkRestore ? eflags : (eflags | EXEC_FLAG_MARK)); + innerDesc = ExecGetResultType(innerPlanState(mergestate)); /* * For certain types of inner child nodes, it is advantageous to issue @@ -1514,14 +1508,25 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags) else mergestate->mj_ExtraMarks = false; + /* + * Initialize result slot, type and projection. + */ + ExecInitResultTupleSlotTL(estate, &mergestate->js.ps); + ExecAssignProjectionInfo(&mergestate->js.ps, NULL); + /* * tuple table initialization */ - ExecInitResultTupleSlot(estate, &mergestate->js.ps); + mergestate->mj_MarkedTupleSlot = ExecInitExtraTupleSlot(estate, innerDesc); - mergestate->mj_MarkedTupleSlot = ExecInitExtraTupleSlot(estate); - ExecSetSlotDescriptor(mergestate->mj_MarkedTupleSlot, - ExecGetResultType(innerPlanState(mergestate))); + /* + * initialize child expressions + */ + mergestate->js.ps.qual = + ExecInitQual(node->join.plan.qual, (PlanState *) mergestate); + mergestate->js.joinqual = + ExecInitQual(node->join.joinqual, (PlanState *) mergestate); + /* mergeclauses are handled below */ /* * detect whether we need only consider the first matching inner tuple @@ -1542,15 +1547,13 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags) mergestate->mj_FillOuter = true; mergestate->mj_FillInner = false; mergestate->mj_NullInnerTupleSlot = - ExecInitNullTupleSlot(estate, - ExecGetResultType(innerPlanState(mergestate))); + ExecInitNullTupleSlot(estate, innerDesc); break; case JOIN_RIGHT: mergestate->mj_FillOuter = false; mergestate->mj_FillInner = true; mergestate->mj_NullOuterTupleSlot = - ExecInitNullTupleSlot(estate, - ExecGetResultType(outerPlanState(mergestate))); + ExecInitNullTupleSlot(estate, outerDesc); /* * Can't handle right or full join with non-constant extra @@ -1566,11 +1569,9 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags) mergestate->mj_FillOuter = true; mergestate->mj_FillInner = true; mergestate->mj_NullOuterTupleSlot = - ExecInitNullTupleSlot(estate, - ExecGetResultType(outerPlanState(mergestate))); + ExecInitNullTupleSlot(estate, outerDesc); mergestate->mj_NullInnerTupleSlot = - ExecInitNullTupleSlot(estate, - ExecGetResultType(innerPlanState(mergestate))); + ExecInitNullTupleSlot(estate, innerDesc); /* * Can't handle right or full join with non-constant extra @@ -1587,12 +1588,6 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags) (int) node->join.jointype); } - /* - * initialize tuple type and projection info - */ - ExecAssignResultTypeFromTL(&mergestate->js.ps); - ExecAssignProjectionInfo(&mergestate->js.ps, NULL); - /* * preprocess the merge clauses */ diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index 2a8ecbd830..93c03cfb07 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -2367,8 +2367,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) */ - ExecInitResultTupleSlot(estate, &mtstate->ps); - ExecAssignResultTypeFromTL(&mtstate->ps); + ExecInitResultTupleSlotTL(estate, &mtstate->ps); slot = mtstate->ps.ps_ResultTupleSlot; /* Need an econtext too */ @@ -2435,8 +2434,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) * expects one (maybe should change that?). */ mtstate->ps.plan->targetlist = NIL; - ExecInitResultTupleSlot(estate, &mtstate->ps); - ExecAssignResultTypeFromTL(&mtstate->ps); + ExecInitResultTupleSlotTL(estate, &mtstate->ps); mtstate->ps.ps_ExprContext = NULL; } @@ -2449,6 +2447,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) if (node->onConflictAction == ONCONFLICT_UPDATE) { ExprContext *econtext; + TupleDesc relationDesc; TupleDesc tupDesc; /* insert may only have one plan, inheritance is not expanded */ @@ -2459,26 +2458,26 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) ExecAssignExprContext(estate, &mtstate->ps); econtext = mtstate->ps.ps_ExprContext; + relationDesc = resultRelInfo->ri_RelationDesc->rd_att; /* initialize slot for the existing tuple */ - mtstate->mt_existing = ExecInitExtraTupleSlot(mtstate->ps.state); - ExecSetSlotDescriptor(mtstate->mt_existing, - resultRelInfo->ri_RelationDesc->rd_att); + mtstate->mt_existing = + ExecInitExtraTupleSlot(mtstate->ps.state, relationDesc); /* carried forward solely for the benefit of explain */ mtstate->mt_excludedtlist = node->exclRelTlist; /* create target slot for UPDATE SET projection */ tupDesc = ExecTypeFromTL((List *) node->onConflictSet, - resultRelInfo->ri_RelationDesc->rd_rel->relhasoids); - mtstate->mt_conflproj = ExecInitExtraTupleSlot(mtstate->ps.state); - ExecSetSlotDescriptor(mtstate->mt_conflproj, tupDesc); + relationDesc->tdhasoid); + mtstate->mt_conflproj = + ExecInitExtraTupleSlot(mtstate->ps.state, tupDesc); /* build UPDATE SET projection state */ resultRelInfo->ri_onConflictSetProj = ExecBuildProjectionInfo(node->onConflictSet, econtext, mtstate->mt_conflproj, &mtstate->ps, - resultRelInfo->ri_RelationDesc->rd_att); + relationDesc); /* build DO UPDATE WHERE clause expression */ if (node->onConflictWhere) @@ -2583,7 +2582,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) j = ExecInitJunkFilter(subplan->targetlist, resultRelInfo->ri_RelationDesc->rd_att->tdhasoid, - ExecInitExtraTupleSlot(estate)); + ExecInitExtraTupleSlot(estate, NULL)); if (operation == CMD_UPDATE || operation == CMD_DELETE) { @@ -2633,7 +2632,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) * we keep it in the estate. */ if (estate->es_trig_tuple_slot == NULL) - estate->es_trig_tuple_slot = ExecInitExtraTupleSlot(estate); + estate->es_trig_tuple_slot = ExecInitExtraTupleSlot(estate, NULL); /* * 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 c3b28176e4..4d898b1f83 100644 --- a/src/backend/executor/nodeNamedtuplestorescan.c +++ b/src/backend/executor/nodeNamedtuplestorescan.c @@ -132,6 +132,13 @@ ExecInitNamedTuplestoreScan(NamedTuplestoreScan *node, EState *estate, int eflag */ ExecAssignExprContext(estate, &scanstate->ss.ps); + /* + * Tuple table and result type initialization. The scan tuple type is + * specified for the tuplestore. + */ + ExecInitResultTupleSlotTL(estate, &scanstate->ss.ps); + ExecInitScanTupleSlot(estate, &scanstate->ss, scanstate->tupdesc); + /* * initialize child expressions */ @@ -139,20 +146,8 @@ ExecInitNamedTuplestoreScan(NamedTuplestoreScan *node, EState *estate, int eflag ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate); /* - * tuple table initialization + * Initialize projection. */ - ExecInitResultTupleSlot(estate, &scanstate->ss.ps); - ExecInitScanTupleSlot(estate, &scanstate->ss); - - /* - * The scan tuple type is specified for the tuplestore. - */ - ExecAssignScanType(&scanstate->ss, scanstate->tupdesc); - - /* - * Initialize result tuple type and projection info. - */ - ExecAssignResultTypeFromTL(&scanstate->ss.ps); ExecAssignScanProjectionInfo(&scanstate->ss); return scanstate; diff --git a/src/backend/executor/nodeNestloop.c b/src/backend/executor/nodeNestloop.c index 9b4f8cc432..9ae9863226 100644 --- a/src/backend/executor/nodeNestloop.c +++ b/src/backend/executor/nodeNestloop.c @@ -285,15 +285,6 @@ ExecInitNestLoop(NestLoop *node, EState *estate, int eflags) */ ExecAssignExprContext(estate, &nlstate->js.ps); - /* - * initialize child expressions - */ - nlstate->js.ps.qual = - ExecInitQual(node->join.plan.qual, (PlanState *) nlstate); - nlstate->js.jointype = node->join.jointype; - nlstate->js.joinqual = - ExecInitQual(node->join.joinqual, (PlanState *) nlstate); - /* * initialize child nodes * @@ -311,9 +302,19 @@ ExecInitNestLoop(NestLoop *node, EState *estate, int eflags) innerPlanState(nlstate) = ExecInitNode(innerPlan(node), estate, eflags); /* - * tuple table initialization + * Initialize result slot, type and projection. */ - ExecInitResultTupleSlot(estate, &nlstate->js.ps); + ExecInitResultTupleSlotTL(estate, &nlstate->js.ps); + ExecAssignProjectionInfo(&nlstate->js.ps, NULL); + + /* + * initialize child expressions + */ + nlstate->js.ps.qual = + ExecInitQual(node->join.plan.qual, (PlanState *) nlstate); + nlstate->js.jointype = node->join.jointype; + nlstate->js.joinqual = + ExecInitQual(node->join.joinqual, (PlanState *) nlstate); /* * detect whether we need only consider the first matching inner tuple @@ -338,12 +339,6 @@ ExecInitNestLoop(NestLoop *node, EState *estate, int eflags) (int) node->join.jointype); } - /* - * initialize tuple type and projection info - */ - ExecAssignResultTypeFromTL(&nlstate->js.ps); - ExecAssignProjectionInfo(&nlstate->js.ps, NULL); - /* * finally, wipe the current outer tuple clean. */ diff --git a/src/backend/executor/nodeProjectSet.c b/src/backend/executor/nodeProjectSet.c index 3b79993ade..6d6ed38cee 100644 --- a/src/backend/executor/nodeProjectSet.c +++ b/src/backend/executor/nodeProjectSet.c @@ -243,14 +243,6 @@ ExecInitProjectSet(ProjectSet *node, EState *estate, int eflags) */ ExecAssignExprContext(estate, &state->ps); - /* - * tuple table initialization - */ - ExecInitResultTupleSlot(estate, &state->ps); - - /* We don't support any qual on ProjectSet nodes */ - Assert(node->plan.qual == NIL); - /* * initialize child nodes */ @@ -262,9 +254,9 @@ ExecInitProjectSet(ProjectSet *node, EState *estate, int eflags) Assert(innerPlan(node) == NULL); /* - * initialize tuple type and projection info + * tuple table and result type initialization */ - ExecAssignResultTypeFromTL(&state->ps); + ExecInitResultTupleSlotTL(estate, &state->ps); /* Create workspace for per-tlist-entry expr state & SRF-is-done state */ state->nelems = list_length(node->plan.targetlist); @@ -301,6 +293,8 @@ ExecInitProjectSet(ProjectSet *node, EState *estate, int eflags) off++; } + /* We don't support any qual on ProjectSet nodes */ + Assert(node->plan.qual == NIL); /* * Create a memory context that ExecMakeFunctionResult can use to evaluate diff --git a/src/backend/executor/nodeRecursiveunion.c b/src/backend/executor/nodeRecursiveunion.c index ba48a69a3b..6b3ea5afb3 100644 --- a/src/backend/executor/nodeRecursiveunion.c +++ b/src/backend/executor/nodeRecursiveunion.c @@ -229,14 +229,13 @@ ExecInitRecursiveUnion(RecursiveUnion *node, EState *estate, int eflags) * RecursiveUnion nodes still have Result slots, which hold pointers to * tuples, so we have to initialize them. */ - ExecInitResultTupleSlot(estate, &rustate->ps); + ExecInitResultTupleSlotTL(estate, &rustate->ps); /* - * Initialize result tuple type and projection info. (Note: we have to - * set up the result type before initializing child nodes, because - * nodeWorktablescan.c expects it to be valid.) + * Initialize result tuple type. (Note: we have to set up the result type + * before initializing child nodes, because nodeWorktablescan.c expects it + * to be valid.) */ - ExecAssignResultTypeFromTL(&rustate->ps); rustate->ps.ps_ProjInfo = NULL; /* diff --git a/src/backend/executor/nodeResult.c b/src/backend/executor/nodeResult.c index 5860d9c1ce..e4418a29bb 100644 --- a/src/backend/executor/nodeResult.c +++ b/src/backend/executor/nodeResult.c @@ -204,19 +204,6 @@ ExecInitResult(Result *node, EState *estate, int eflags) */ ExecAssignExprContext(estate, &resstate->ps); - /* - * tuple table initialization - */ - ExecInitResultTupleSlot(estate, &resstate->ps); - - /* - * initialize child expressions - */ - resstate->ps.qual = - ExecInitQual(node->plan.qual, (PlanState *) resstate); - resstate->resconstantqual = - ExecInitQual((List *) node->resconstantqual, (PlanState *) resstate); - /* * initialize child nodes */ @@ -228,11 +215,19 @@ ExecInitResult(Result *node, EState *estate, int eflags) Assert(innerPlan(node) == NULL); /* - * initialize tuple type and projection info + * Initialize result slot, type and projection. */ - ExecAssignResultTypeFromTL(&resstate->ps); + ExecInitResultTupleSlotTL(estate, &resstate->ps); ExecAssignProjectionInfo(&resstate->ps, NULL); + /* + * initialize child expressions + */ + resstate->ps.qual = + ExecInitQual(node->plan.qual, (PlanState *) resstate); + resstate->resconstantqual = + ExecInitQual((List *) node->resconstantqual, (PlanState *) resstate); + return resstate; } diff --git a/src/backend/executor/nodeSamplescan.c b/src/backend/executor/nodeSamplescan.c index e88cd18737..872d6e5735 100644 --- a/src/backend/executor/nodeSamplescan.c +++ b/src/backend/executor/nodeSamplescan.c @@ -26,7 +26,6 @@ #include "utils/rel.h" #include "utils/tqual.h" -static void InitScanRelation(SampleScanState *node, EState *estate, int eflags); static TupleTableSlot *SampleNext(SampleScanState *node); static void tablesample_init(SampleScanState *scanstate); static HeapTuple tablesample_getnext(SampleScanState *scanstate); @@ -106,35 +105,6 @@ ExecSampleScan(PlanState *pstate) (ExecScanRecheckMtd) SampleRecheck); } -/* ---------------------------------------------------------------- - * InitScanRelation - * - * Set up to access the scan relation. - * ---------------------------------------------------------------- - */ -static void -InitScanRelation(SampleScanState *node, EState *estate, int eflags) -{ - Relation currentRelation; - - /* - * get the relation object id from the relid'th entry in the range table, - * open that relation and acquire appropriate lock on it. - */ - currentRelation = ExecOpenScanRelation(estate, - ((SampleScan *) node->ss.ps.plan)->scan.scanrelid, - eflags); - - node->ss.ss_currentRelation = currentRelation; - - /* we won't set up the HeapScanDesc till later */ - node->ss.ss_currentScanDesc = NULL; - - /* and report the scan tuple slot's rowtype */ - ExecAssignScanType(&node->ss, RelationGetDescr(currentRelation)); -} - - /* ---------------------------------------------------------------- * ExecInitSampleScan * ---------------------------------------------------------------- @@ -164,6 +134,31 @@ ExecInitSampleScan(SampleScan *node, EState *estate, int eflags) */ ExecAssignExprContext(estate, &scanstate->ss.ps); + /* + * Initialize scan relation. + * + * Get the relation object id from the relid'th entry in the range table, + * open that relation and acquire appropriate lock on it. + */ + scanstate->ss.ss_currentRelation = + ExecOpenScanRelation(estate, + node->scan.scanrelid, + eflags); + + /* we won't set up the HeapScanDesc till later */ + scanstate->ss.ss_currentScanDesc = NULL; + + /* and create slot with appropriate rowtype */ + ExecInitScanTupleSlot(estate, &scanstate->ss, + RelationGetDescr(scanstate->ss.ss_currentRelation)); + + /* + * Initialize result slot, type and projection. + * tuple table and result tuple initialization + */ + ExecInitResultTupleSlotTL(estate, &scanstate->ss.ps); + ExecAssignScanProjectionInfo(&scanstate->ss); + /* * initialize child expressions */ @@ -174,23 +169,6 @@ ExecInitSampleScan(SampleScan *node, EState *estate, int eflags) scanstate->repeatable = ExecInitExpr(tsc->repeatable, (PlanState *) scanstate); - /* - * tuple table initialization - */ - ExecInitResultTupleSlot(estate, &scanstate->ss.ps); - ExecInitScanTupleSlot(estate, &scanstate->ss); - - /* - * initialize scan relation - */ - InitScanRelation(scanstate, estate, eflags); - - /* - * Initialize result tuple type and projection info. - */ - ExecAssignResultTypeFromTL(&scanstate->ss.ps); - ExecAssignScanProjectionInfo(&scanstate->ss); - /* * If we don't have a REPEATABLE clause, select a random seed. We want to * do this just once, since the seed shouldn't change over rescans. diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c index 58631378d5..9db368922a 100644 --- a/src/backend/executor/nodeSeqscan.c +++ b/src/backend/executor/nodeSeqscan.c @@ -32,7 +32,6 @@ #include "executor/nodeSeqscan.h" #include "utils/rel.h" -static void InitScanRelation(SeqScanState *node, EState *estate, int eflags); static TupleTableSlot *SeqNext(SeqScanState *node); /* ---------------------------------------------------------------- @@ -132,31 +131,6 @@ ExecSeqScan(PlanState *pstate) (ExecScanRecheckMtd) SeqRecheck); } -/* ---------------------------------------------------------------- - * InitScanRelation - * - * Set up to access the scan relation. - * ---------------------------------------------------------------- - */ -static void -InitScanRelation(SeqScanState *node, EState *estate, int eflags) -{ - Relation currentRelation; - - /* - * get the relation object id from the relid'th entry in the range table, - * open that relation and acquire appropriate lock on it. - */ - currentRelation = ExecOpenScanRelation(estate, - ((SeqScan *) node->ss.ps.plan)->scanrelid, - eflags); - - node->ss.ss_currentRelation = currentRelation; - - /* and report the scan tuple slot's rowtype */ - ExecAssignScanType(&node->ss, RelationGetDescr(currentRelation)); -} - /* ---------------------------------------------------------------- * ExecInitSeqScan @@ -189,29 +163,33 @@ ExecInitSeqScan(SeqScan *node, EState *estate, int eflags) */ ExecAssignExprContext(estate, &scanstate->ss.ps); + /* + * Initialize scan relation. + * + * Get the relation object id from the relid'th entry in the range table, + * open that relation and acquire appropriate lock on it. + */ + scanstate->ss.ss_currentRelation = + ExecOpenScanRelation(estate, + node->scanrelid, + eflags); + + /* and create slot with the appropriate rowtype */ + ExecInitScanTupleSlot(estate, &scanstate->ss, + RelationGetDescr(scanstate->ss.ss_currentRelation)); + + /* + * Initialize result slot, type and projection. + */ + ExecInitResultTupleSlotTL(estate, &scanstate->ss.ps); + ExecAssignScanProjectionInfo(&scanstate->ss); + /* * initialize child expressions */ scanstate->ss.ps.qual = ExecInitQual(node->plan.qual, (PlanState *) scanstate); - /* - * tuple table initialization - */ - ExecInitResultTupleSlot(estate, &scanstate->ss.ps); - ExecInitScanTupleSlot(estate, &scanstate->ss); - - /* - * initialize scan relation - */ - InitScanRelation(scanstate, estate, eflags); - - /* - * Initialize result tuple type and projection info. - */ - ExecAssignResultTypeFromTL(&scanstate->ss.ps); - ExecAssignScanProjectionInfo(&scanstate->ss); - return scanstate; } diff --git a/src/backend/executor/nodeSetOp.c b/src/backend/executor/nodeSetOp.c index eb5449fc3e..3fa4a5fcc6 100644 --- a/src/backend/executor/nodeSetOp.c +++ b/src/backend/executor/nodeSetOp.c @@ -518,11 +518,6 @@ ExecInitSetOp(SetOp *node, EState *estate, int eflags) "SetOp hash table", ALLOCSET_DEFAULT_SIZES); - /* - * Tuple table initialization - */ - ExecInitResultTupleSlot(estate, &setopstate->ps); - /* * initialize child nodes * @@ -535,10 +530,10 @@ ExecInitSetOp(SetOp *node, EState *estate, int eflags) outerDesc = ExecGetResultType(outerPlanState(setopstate)); /* - * setop nodes do no projections, so initialize projection info for this - * node appropriately + * Initialize result slot and type. Setop nodes do no projections, so + * initialize projection info for this node appropriately. */ - ExecAssignResultTypeFromTL(&setopstate->ps); + ExecInitResultTupleSlotTL(estate, &setopstate->ps); setopstate->ps.ps_ProjInfo = NULL; /* diff --git a/src/backend/executor/nodeSort.c b/src/backend/executor/nodeSort.c index d61c859fce..73f16c9aba 100644 --- a/src/backend/executor/nodeSort.c +++ b/src/backend/executor/nodeSort.c @@ -198,14 +198,6 @@ ExecInitSort(Sort *node, EState *estate, int eflags) * ExecQual or ExecProject. */ - /* - * tuple table initialization - * - * sort nodes only return scan tuples from their sorted relation. - */ - ExecInitResultTupleSlot(estate, &sortstate->ss.ps); - ExecInitScanTupleSlot(estate, &sortstate->ss); - /* * initialize child nodes * @@ -217,11 +209,15 @@ ExecInitSort(Sort *node, EState *estate, int eflags) outerPlanState(sortstate) = ExecInitNode(outerPlan(node), estate, eflags); /* - * initialize tuple type. no need to initialize projection info because + * Initialize scan slot and type. + */ + ExecCreateScanSlotFromOuterPlan(estate, &sortstate->ss); + + /* + * Initialize return slot and type. No need to initialize projection info because * this node doesn't do projections. */ - ExecAssignResultTypeFromTL(&sortstate->ss.ps); - ExecAssignScanTypeFromOuterPlan(&sortstate->ss); + ExecInitResultTupleSlotTL(estate, &sortstate->ss.ps); 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 4927e21217..d5411500a2 100644 --- a/src/backend/executor/nodeSubplan.c +++ b/src/backend/executor/nodeSubplan.c @@ -957,8 +957,7 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent) * own innerecontext. */ tupDescLeft = ExecTypeFromTL(lefttlist, false); - slot = ExecInitExtraTupleSlot(estate); - ExecSetSlotDescriptor(slot, tupDescLeft); + slot = ExecInitExtraTupleSlot(estate, tupDescLeft); sstate->projLeft = ExecBuildProjectionInfo(lefttlist, NULL, slot, @@ -966,8 +965,7 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent) NULL); sstate->descRight = tupDescRight = ExecTypeFromTL(righttlist, false); - slot = ExecInitExtraTupleSlot(estate); - ExecSetSlotDescriptor(slot, tupDescRight); + slot = ExecInitExtraTupleSlot(estate, tupDescRight); sstate->projRight = ExecBuildProjectionInfo(righttlist, sstate->innerecontext, slot, diff --git a/src/backend/executor/nodeSubqueryscan.c b/src/backend/executor/nodeSubqueryscan.c index 715a5b6a84..fa61884785 100644 --- a/src/backend/executor/nodeSubqueryscan.c +++ b/src/backend/executor/nodeSubqueryscan.c @@ -120,35 +120,29 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate, int eflags) */ ExecAssignExprContext(estate, &subquerystate->ss.ps); - /* - * initialize child expressions - */ - subquerystate->ss.ps.qual = - ExecInitQual(node->scan.plan.qual, (PlanState *) subquerystate); - - /* - * tuple table initialization - */ - ExecInitResultTupleSlot(estate, &subquerystate->ss.ps); - ExecInitScanTupleSlot(estate, &subquerystate->ss); - /* * initialize subquery */ subquerystate->subplan = ExecInitNode(node->subplan, estate, eflags); /* - * Initialize scan tuple type (needed by ExecAssignScanProjectionInfo) + * Initialize scan slot and type (needed by ExecInitResultTupleSlotTL) */ - ExecAssignScanType(&subquerystate->ss, - ExecGetResultType(subquerystate->subplan)); + ExecInitScanTupleSlot(estate, &subquerystate->ss, + ExecGetResultType(subquerystate->subplan)); /* - * Initialize result tuple type and projection info. + * Initialize result slot, type and projection. */ - ExecAssignResultTypeFromTL(&subquerystate->ss.ps); + ExecInitResultTupleSlotTL(estate, &subquerystate->ss.ps); ExecAssignScanProjectionInfo(&subquerystate->ss); + /* + * initialize child expressions + */ + subquerystate->ss.ps.qual = + ExecInitQual(node->scan.plan.qual, (PlanState *) subquerystate); + return subquerystate; } diff --git a/src/backend/executor/nodeTableFuncscan.c b/src/backend/executor/nodeTableFuncscan.c index 3b609765d4..fed6f2b3a5 100644 --- a/src/backend/executor/nodeTableFuncscan.c +++ b/src/backend/executor/nodeTableFuncscan.c @@ -139,18 +139,6 @@ ExecInitTableFuncScan(TableFuncScan *node, EState *estate, int eflags) */ ExecAssignExprContext(estate, &scanstate->ss.ps); - /* - * initialize child expressions - */ - scanstate->ss.ps.qual = - ExecInitQual(node->scan.plan.qual, &scanstate->ss.ps); - - /* - * tuple table initialization - */ - ExecInitResultTupleSlot(estate, &scanstate->ss.ps); - ExecInitScanTupleSlot(estate, &scanstate->ss); - /* * initialize source tuple type */ @@ -158,15 +146,21 @@ ExecInitTableFuncScan(TableFuncScan *node, EState *estate, int eflags) tf->coltypes, tf->coltypmods, tf->colcollations); - - ExecAssignScanType(&scanstate->ss, tupdesc); + /* and the corresponding scan slot */ + ExecInitScanTupleSlot(estate, &scanstate->ss, tupdesc); /* - * Initialize result tuple type and projection info. + * Initialize result slot, type and projection. */ - ExecAssignResultTypeFromTL(&scanstate->ss.ps); + ExecInitResultTupleSlotTL(estate, &scanstate->ss.ps); ExecAssignScanProjectionInfo(&scanstate->ss); + /* + * initialize child expressions + */ + scanstate->ss.ps.qual = + ExecInitQual(node->scan.plan.qual, &scanstate->ss.ps); + /* Only XMLTABLE is supported currently */ scanstate->routine = &XmlTableRoutine; diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c index f2737bb7ef..e207b1ffb5 100644 --- a/src/backend/executor/nodeTidscan.c +++ b/src/backend/executor/nodeTidscan.c @@ -530,20 +530,6 @@ ExecInitTidScan(TidScan *node, EState *estate, int eflags) */ ExecAssignExprContext(estate, &tidstate->ss.ps); - /* - * initialize child expressions - */ - tidstate->ss.ps.qual = - ExecInitQual(node->scan.plan.qual, (PlanState *) tidstate); - - TidExprListCreate(tidstate); - - /* - * tuple table initialization - */ - ExecInitResultTupleSlot(estate, &tidstate->ss.ps); - ExecInitScanTupleSlot(estate, &tidstate->ss); - /* * mark tid list as not computed yet */ @@ -562,14 +548,23 @@ ExecInitTidScan(TidScan *node, EState *estate, int eflags) /* * get the scan type from the relation descriptor. */ - ExecAssignScanType(&tidstate->ss, RelationGetDescr(currentRelation)); + ExecInitScanTupleSlot(estate, &tidstate->ss, + RelationGetDescr(currentRelation)); /* - * Initialize result tuple type and projection info. + * Initialize result slot, type and projection. */ - ExecAssignResultTypeFromTL(&tidstate->ss.ps); + ExecInitResultTupleSlotTL(estate, &tidstate->ss.ps); ExecAssignScanProjectionInfo(&tidstate->ss); + /* + * initialize child expressions + */ + tidstate->ss.ps.qual = + ExecInitQual(node->scan.plan.qual, (PlanState *) tidstate); + + TidExprListCreate(tidstate); + /* * all done. */ diff --git a/src/backend/executor/nodeUnique.c b/src/backend/executor/nodeUnique.c index 9f823c58e1..05d65330a0 100644 --- a/src/backend/executor/nodeUnique.c +++ b/src/backend/executor/nodeUnique.c @@ -132,21 +132,16 @@ ExecInitUnique(Unique *node, EState *estate, int eflags) */ ExecAssignExprContext(estate, &uniquestate->ps); - /* - * Tuple table initialization - */ - ExecInitResultTupleSlot(estate, &uniquestate->ps); - /* * then initialize outer plan */ outerPlanState(uniquestate) = ExecInitNode(outerPlan(node), estate, eflags); /* - * unique nodes do no projections, so initialize projection info for this - * node appropriately + * Initialize result slot and type. Unique nodes do no projections, so + * initialize projection info for this node appropriately. */ - ExecAssignResultTypeFromTL(&uniquestate->ps); + ExecInitResultTupleSlotTL(estate, &uniquestate->ps); uniquestate->ps.ps_ProjInfo = NULL; /* diff --git a/src/backend/executor/nodeValuesscan.c b/src/backend/executor/nodeValuesscan.c index c3d78b6295..63b7e7ef5b 100644 --- a/src/backend/executor/nodeValuesscan.c +++ b/src/backend/executor/nodeValuesscan.c @@ -248,10 +248,16 @@ ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags) ExecAssignExprContext(estate, planstate); /* - * tuple table initialization + * Get info about values list, initialize scan slot with it. */ - ExecInitResultTupleSlot(estate, &scanstate->ss.ps); - ExecInitScanTupleSlot(estate, &scanstate->ss); + tupdesc = ExecTypeFromExprList((List *) linitial(node->values_lists)); + ExecInitScanTupleSlot(estate, &scanstate->ss, tupdesc); + + /* + * Initialize result slot, type and projection. + */ + ExecInitResultTupleSlotTL(estate, &scanstate->ss.ps); + ExecAssignScanProjectionInfo(&scanstate->ss); /* * initialize child expressions @@ -259,13 +265,6 @@ ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags) scanstate->ss.ps.qual = ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate); - /* - * get info about values list - */ - tupdesc = ExecTypeFromExprList((List *) linitial(node->values_lists)); - - ExecAssignScanType(&scanstate->ss, tupdesc); - /* * Other node-specific setup */ @@ -281,12 +280,6 @@ ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags) scanstate->exprlists[i++] = (List *) lfirst(vtl); } - /* - * Initialize result tuple type and projection info. - */ - ExecAssignResultTypeFromTL(&scanstate->ss.ps); - ExecAssignScanProjectionInfo(&scanstate->ss); - return scanstate; } diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c index 1c807a8292..a56c3e89fd 100644 --- a/src/backend/executor/nodeWindowAgg.c +++ b/src/backend/executor/nodeWindowAgg.c @@ -2287,30 +2287,6 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags) "WindowAgg Aggregates", ALLOCSET_DEFAULT_SIZES); - /* - * tuple table initialization - */ - ExecInitScanTupleSlot(estate, &winstate->ss); - ExecInitResultTupleSlot(estate, &winstate->ss.ps); - winstate->first_part_slot = ExecInitExtraTupleSlot(estate); - winstate->agg_row_slot = ExecInitExtraTupleSlot(estate); - winstate->temp_slot_1 = ExecInitExtraTupleSlot(estate); - winstate->temp_slot_2 = ExecInitExtraTupleSlot(estate); - - /* - * create frame head and tail slots only if needed (must match logic in - * update_frameheadpos and update_frametailpos) - */ - winstate->framehead_slot = winstate->frametail_slot = NULL; - - if (frameOptions & (FRAMEOPTION_RANGE | FRAMEOPTION_GROUPS)) - { - if (!(frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING)) - winstate->framehead_slot = ExecInitExtraTupleSlot(estate); - if (!(frameOptions & FRAMEOPTION_END_UNBOUNDED_FOLLOWING)) - winstate->frametail_slot = ExecInitExtraTupleSlot(estate); - } - /* * WindowAgg nodes never have quals, since they can only occur at the * logical top level of a query (ie, after any WHERE or HAVING filters) @@ -2328,28 +2304,35 @@ 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). */ - ExecAssignScanTypeFromOuterPlan(&winstate->ss); + ExecCreateScanSlotFromOuterPlan(estate, &winstate->ss); scanDesc = winstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor; - ExecSetSlotDescriptor(winstate->first_part_slot, - winstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor); - ExecSetSlotDescriptor(winstate->agg_row_slot, - winstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor); - ExecSetSlotDescriptor(winstate->temp_slot_1, - winstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor); - ExecSetSlotDescriptor(winstate->temp_slot_2, - winstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor); - if (winstate->framehead_slot) - ExecSetSlotDescriptor(winstate->framehead_slot, - winstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor); - if (winstate->frametail_slot) - ExecSetSlotDescriptor(winstate->frametail_slot, - winstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor); + /* + * 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); /* - * Initialize result tuple type and projection info. + * create frame head and tail slots only if needed (must match logic in + * update_frameheadpos and update_frametailpos) */ - ExecAssignResultTypeFromTL(&winstate->ss.ps); + winstate->framehead_slot = winstate->frametail_slot = NULL; + + if (frameOptions & (FRAMEOPTION_RANGE | FRAMEOPTION_GROUPS)) + { + if (!(frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING)) + winstate->framehead_slot = ExecInitExtraTupleSlot(estate, scanDesc); + if (!(frameOptions & FRAMEOPTION_END_UNBOUNDED_FOLLOWING)) + winstate->frametail_slot = ExecInitExtraTupleSlot(estate, scanDesc); + } + + /* + * Initialize result slot, type and projection. + */ + ExecInitResultTupleSlotTL(estate, &winstate->ss.ps); 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 66d2111bd9..2ff9a215b1 100644 --- a/src/backend/executor/nodeWorktablescan.c +++ b/src/backend/executor/nodeWorktablescan.c @@ -156,6 +156,12 @@ ExecInitWorkTableScan(WorkTableScan *node, EState *estate, int eflags) */ ExecAssignExprContext(estate, &scanstate->ss.ps); + /* + * tuple table initialization + */ + ExecInitResultTupleSlotTL(estate, &scanstate->ss.ps); + ExecInitScanTupleSlot(estate, &scanstate->ss, NULL); + /* * initialize child expressions */ @@ -163,15 +169,9 @@ ExecInitWorkTableScan(WorkTableScan *node, EState *estate, int eflags) ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate); /* - * tuple table initialization + * Do not yet initialize projection info, see ExecWorkTableScan() for + * details. */ - ExecInitResultTupleSlot(estate, &scanstate->ss.ps); - ExecInitScanTupleSlot(estate, &scanstate->ss); - - /* - * Initialize result tuple type, but not yet projection info. - */ - ExecAssignResultTypeFromTL(&scanstate->ss.ps); return scanstate; } diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c index 83c69092ae..04985c9f91 100644 --- a/src/backend/replication/logical/worker.c +++ b/src/backend/replication/logical/worker.c @@ -208,7 +208,7 @@ create_estate_for_relation(LogicalRepRelMapEntry *rel) /* Triggers might need a slot */ if (resultRelInfo->ri_TrigDesc) - estate->es_trig_tuple_slot = ExecInitExtraTupleSlot(estate); + estate->es_trig_tuple_slot = ExecInitExtraTupleSlot(estate, NULL); /* Prepare to catch AFTER triggers. */ AfterTriggerBeginQuery(); @@ -585,8 +585,8 @@ apply_handle_insert(StringInfo s) /* Initialize the executor state. */ estate = create_estate_for_relation(rel); - remoteslot = ExecInitExtraTupleSlot(estate); - ExecSetSlotDescriptor(remoteslot, RelationGetDescr(rel->localrel)); + remoteslot = ExecInitExtraTupleSlot(estate, + RelationGetDescr(rel->localrel)); /* Process and store remote tuple in the slot */ oldctx = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate)); @@ -689,10 +689,10 @@ apply_handle_update(StringInfo s) /* Initialize the executor state. */ estate = create_estate_for_relation(rel); - remoteslot = ExecInitExtraTupleSlot(estate); - ExecSetSlotDescriptor(remoteslot, RelationGetDescr(rel->localrel)); - localslot = ExecInitExtraTupleSlot(estate); - ExecSetSlotDescriptor(localslot, RelationGetDescr(rel->localrel)); + remoteslot = ExecInitExtraTupleSlot(estate, + RelationGetDescr(rel->localrel)); + localslot = ExecInitExtraTupleSlot(estate, + RelationGetDescr(rel->localrel)); EvalPlanQualInit(&epqstate, estate, NULL, NIL, -1); PushActiveSnapshot(GetTransactionSnapshot()); @@ -807,10 +807,10 @@ apply_handle_delete(StringInfo s) /* Initialize the executor state. */ estate = create_estate_for_relation(rel); - remoteslot = ExecInitExtraTupleSlot(estate); - ExecSetSlotDescriptor(remoteslot, RelationGetDescr(rel->localrel)); - localslot = ExecInitExtraTupleSlot(estate); - ExecSetSlotDescriptor(localslot, RelationGetDescr(rel->localrel)); + remoteslot = ExecInitExtraTupleSlot(estate, + RelationGetDescr(rel->localrel)); + localslot = ExecInitExtraTupleSlot(estate, + RelationGetDescr(rel->localrel)); EvalPlanQualInit(&epqstate, estate, NULL, NIL, -1); PushActiveSnapshot(GetTransactionSnapshot()); diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index 621e7c3dc4..45a077a949 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -431,9 +431,10 @@ extern void ExecScanReScan(ScanState *node); /* * prototypes from functions in execTuples.c */ -extern void ExecInitResultTupleSlot(EState *estate, PlanState *planstate); -extern void ExecInitScanTupleSlot(EState *estate, ScanState *scanstate); -extern TupleTableSlot *ExecInitExtraTupleSlot(EState *estate); +extern void ExecInitResultTupleSlotTL(EState *estate, PlanState *planstate); +extern void ExecInitScanTupleSlot(EState *estate, ScanState *scanstate, TupleDesc tupleDesc); +extern TupleTableSlot *ExecInitExtraTupleSlot(EState *estate, + TupleDesc tupleDesc); extern TupleTableSlot *ExecInitNullTupleSlot(EState *estate, TupleDesc tupType); extern TupleDesc ExecTypeFromTL(List *targetList, bool hasoid); @@ -502,8 +503,6 @@ extern ExprContext *MakePerTupleExprContext(EState *estate); } while (0) extern void ExecAssignExprContext(EState *estate, PlanState *planstate); -extern void ExecAssignResultType(PlanState *planstate, TupleDesc tupDesc); -extern void ExecAssignResultTypeFromTL(PlanState *planstate); extern TupleDesc ExecGetResultType(PlanState *planstate); extern void ExecAssignProjectionInfo(PlanState *planstate, TupleDesc inputDesc); @@ -511,7 +510,7 @@ extern void ExecConditionalAssignProjectionInfo(PlanState *planstate, TupleDesc inputDesc, Index varno); extern void ExecFreeExprContext(PlanState *planstate); extern void ExecAssignScanType(ScanState *scanstate, TupleDesc tupDesc); -extern void ExecAssignScanTypeFromOuterPlan(ScanState *scanstate); +extern void ExecCreateScanSlotFromOuterPlan(EState *estate, ScanState *scanstate); extern bool ExecRelationIsTargetRelation(EState *estate, Index scanrelid); diff --git a/src/include/executor/tuptable.h b/src/include/executor/tuptable.h index 5b54834d33..8be0d5edc2 100644 --- a/src/include/executor/tuptable.h +++ b/src/include/executor/tuptable.h @@ -127,6 +127,7 @@ typedef struct TupleTableSlot MinimalTuple tts_mintuple; /* minimal tuple, or NULL if none */ HeapTupleData tts_minhdr; /* workspace for minimal-tuple-only case */ long tts_off; /* saved state for slot_deform_tuple */ + bool tts_fixedTupleDescriptor; /* descriptor can't be changed */ } TupleTableSlot; #define TTS_HAS_PHYSICAL_TUPLE(slot) \ @@ -139,8 +140,8 @@ typedef struct TupleTableSlot ((slot) == NULL || (slot)->tts_isempty) /* in executor/execTuples.c */ -extern TupleTableSlot *MakeTupleTableSlot(void); -extern TupleTableSlot *ExecAllocTableSlot(List **tupleTable); +extern TupleTableSlot *MakeTupleTableSlot(TupleDesc desc); +extern TupleTableSlot *ExecAllocTableSlot(List **tupleTable, TupleDesc desc); extern void ExecResetTupleTable(List *tupleTable, bool shouldFree); extern TupleTableSlot *MakeSingleTupleTableSlot(TupleDesc tupdesc); extern void ExecDropSingleTupleTableSlot(TupleTableSlot *slot);