From ddaa761e96cd4b34035edd40f6bc17b953574496 Mon Sep 17 00:00:00 2001 From: Amit Langote Date: Fri, 11 Aug 2023 14:09:29 +0900 Subject: [PATCH v45 1/6] Add support for allowing ExecInitNode to detect CachedPlan invalidation This means ExecInitNode() will check for CachedPlan invalidation at various points (after locking tables, initializing child plans, etc.) and return either a partially initialized planstate node or NULL if no cleanup is necessary. ExecEndNode() subroutines now always check a pointer for nullness before calling cleanup on it. --- contrib/postgres_fdw/postgres_fdw.c | 4 ++++ src/backend/executor/execMain.c | 23 +++++++++++++++++-- src/backend/executor/execPartition.c | 4 ++++ src/backend/executor/execProcnode.c | 12 +++++++++- src/backend/executor/execUtils.c | 2 ++ src/backend/executor/nodeAgg.c | 15 ++++-------- src/backend/executor/nodeAppend.c | 10 +++++--- src/backend/executor/nodeBitmapAnd.c | 7 +++--- src/backend/executor/nodeBitmapHeapscan.c | 19 +++++---------- src/backend/executor/nodeBitmapIndexscan.c | 10 ++------ src/backend/executor/nodeBitmapOr.c | 7 +++--- src/backend/executor/nodeCtescan.c | 12 ---------- src/backend/executor/nodeCustom.c | 16 ++++++------- src/backend/executor/nodeForeignscan.c | 12 ++++------ src/backend/executor/nodeFunctionscan.c | 12 ---------- src/backend/executor/nodeGather.c | 6 ++--- src/backend/executor/nodeGatherMerge.c | 5 ++-- src/backend/executor/nodeGroup.c | 7 ++---- src/backend/executor/nodeHash.c | 7 ++---- src/backend/executor/nodeHashjoin.c | 16 ++++--------- src/backend/executor/nodeIncrementalSort.c | 10 ++------ src/backend/executor/nodeIndexonlyscan.c | 20 ++++------------ src/backend/executor/nodeIndexscan.c | 20 ++++------------ src/backend/executor/nodeLimit.c | 3 ++- src/backend/executor/nodeLockRows.c | 2 ++ src/backend/executor/nodeMaterial.c | 7 ++---- src/backend/executor/nodeMemoize.c | 12 +++------- src/backend/executor/nodeMergeAppend.c | 6 ++++- src/backend/executor/nodeMergejoin.c | 16 ++++--------- src/backend/executor/nodeModifyTable.c | 18 ++++++--------- .../executor/nodeNamedtuplestorescan.c | 11 --------- src/backend/executor/nodeNestloop.c | 15 ++++-------- src/backend/executor/nodeProjectSet.c | 12 ++-------- src/backend/executor/nodeRecursiveunion.c | 10 ++++++-- src/backend/executor/nodeResult.c | 12 ++-------- src/backend/executor/nodeSamplescan.c | 16 +++---------- src/backend/executor/nodeSeqscan.c | 14 ++--------- src/backend/executor/nodeSetOp.c | 6 ++--- src/backend/executor/nodeSort.c | 9 ++------ src/backend/executor/nodeSubqueryscan.c | 14 ++--------- src/backend/executor/nodeTableFuncscan.c | 12 ---------- src/backend/executor/nodeTidrangescan.c | 14 ++--------- src/backend/executor/nodeTidscan.c | 14 ++--------- src/backend/executor/nodeUnique.c | 7 ++---- src/backend/executor/nodeValuesscan.c | 13 ----------- src/backend/executor/nodeWindowAgg.c | 13 ++--------- src/backend/executor/nodeWorktablescan.c | 11 --------- src/include/executor/executor.h | 12 ++++++++++ src/include/nodes/execnodes.h | 2 ++ src/include/utils/plancache.h | 14 +++++++++++ 50 files changed, 191 insertions(+), 360 deletions(-) diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c index c5cada55fb..1edd4c3f17 100644 --- a/contrib/postgres_fdw/postgres_fdw.c +++ b/contrib/postgres_fdw/postgres_fdw.c @@ -2658,7 +2658,11 @@ postgresBeginDirectModify(ForeignScanState *node, int eflags) /* Get info about foreign table. */ rtindex = node->resultRelInfo->ri_RangeTableIndex; if (fsplan->scan.scanrelid == 0) + { dmstate->rel = ExecOpenScanRelation(estate, rtindex, eflags); + if (!ExecPlanStillValid(estate)) + return; + } else dmstate->rel = node->ss.ss_currentRelation; table = GetForeignTable(RelationGetRelid(dmstate->rel)); diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 4c5a7bbf62..1a848b1c20 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -839,7 +839,7 @@ InitPlan(QueryDesc *queryDesc, int eflags) Plan *plan = plannedstmt->planTree; List *rangeTable = plannedstmt->rtable; EState *estate = queryDesc->estate; - PlanState *planstate; + PlanState *planstate = NULL; TupleDesc tupType; ListCell *l; int i; @@ -855,6 +855,7 @@ InitPlan(QueryDesc *queryDesc, int eflags) ExecInitRangeTable(estate, rangeTable, plannedstmt->permInfos); estate->es_plannedstmt = plannedstmt; + estate->es_cachedplan = NULL; /* * Next, build the ExecRowMark array from the PlanRowMark(s), if any. @@ -886,6 +887,8 @@ InitPlan(QueryDesc *queryDesc, int eflags) case ROW_MARK_KEYSHARE: case ROW_MARK_REFERENCE: relation = ExecGetRangeTableRelation(estate, rc->rti); + if (!ExecPlanStillValid(estate)) + goto plan_init_suspended; break; case ROW_MARK_COPY: /* no physical table access is required */ @@ -953,9 +956,10 @@ InitPlan(QueryDesc *queryDesc, int eflags) sp_eflags |= EXEC_FLAG_REWIND; subplanstate = ExecInitNode(subplan, estate, sp_eflags); - estate->es_subplanstates = lappend(estate->es_subplanstates, subplanstate); + if (!ExecPlanStillValid(estate)) + goto plan_init_suspended; i++; } @@ -966,6 +970,8 @@ InitPlan(QueryDesc *queryDesc, int eflags) * processing tuples. */ planstate = ExecInitNode(plan, estate, eflags); + if (!ExecPlanStillValid(estate)) + goto plan_init_suspended; /* * Get the tuple descriptor describing the type of tuples to return. @@ -1008,6 +1014,15 @@ InitPlan(QueryDesc *queryDesc, int eflags) } queryDesc->tupDesc = tupType; + Assert(planstate != NULL); + queryDesc->planstate = planstate; + return; + +plan_init_suspended: + /* + * Plan initialization failed. Mark QueryDesc as such. ExecEndPlan() + * will clean up initialized plan nodes from estate->es_planstate_nodes. + */ queryDesc->planstate = planstate; } @@ -3010,6 +3025,10 @@ EvalPlanQualEnd(EPQState *epqstate) MemoryContext oldcontext; ListCell *l; + /* Nothing to do if EvalPlanQualInit() wasn't done to begin with. */ + if (epqstate->parentestate == NULL) + return; + rtsize = epqstate->parentestate->es_range_table_size; /* diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c index eb8a87fd63..e88455368c 100644 --- a/src/backend/executor/execPartition.c +++ b/src/backend/executor/execPartition.c @@ -1801,6 +1801,8 @@ ExecInitPartitionPruning(PlanState *planstate, /* Create the working data structure for pruning */ prunestate = CreatePartitionPruneState(planstate, pruneinfo); + if (!ExecPlanStillValid(estate)) + return NULL; /* * Perform an initial partition prune pass, if required. @@ -1927,6 +1929,8 @@ CreatePartitionPruneState(PlanState *planstate, PartitionPruneInfo *pruneinfo) * duration of this executor run. */ partrel = ExecGetRangeTableRelation(estate, pinfo->rtindex); + if (!ExecPlanStillValid(estate)) + return NULL; partkey = RelationGetPartitionKey(partrel); partdesc = PartitionDirectoryLookup(estate->es_partition_directory, partrel); diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c index 4d288bc8d4..842c6751c5 100644 --- a/src/backend/executor/execProcnode.c +++ b/src/backend/executor/execProcnode.c @@ -135,7 +135,13 @@ static bool ExecShutdownNode_walker(PlanState *node, void *context); * 'estate' is the shared execution state for the plan tree * 'eflags' is a bitwise OR of flag bits described in executor.h * - * Returns a PlanState node corresponding to the given Plan node. + * Returns a PlanState node corresponding to the given Plan node or NULL. + * + * NULL may be returned either if the input node is NULL or if the plan + * tree that the node is a part of is found to have been invalidated when + * taking a lock on the relation mentioned in the node or in a child + * node. The latter case arises if the plan tree contains inheritance/ + * partition child tables and is from a CachedPlan. * ------------------------------------------------------------------------ */ PlanState * @@ -388,6 +394,10 @@ ExecInitNode(Plan *node, EState *estate, int eflags) break; } + if (!ExecPlanStillValid(estate)) + return result; + + Assert(result != NULL); ExecSetExecProcNode(result, result->ExecProcNode); /* diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c index c06b228858..f4611bdd27 100644 --- a/src/backend/executor/execUtils.c +++ b/src/backend/executor/execUtils.c @@ -848,6 +848,8 @@ ExecInitResultRelation(EState *estate, ResultRelInfo *resultRelInfo, Relation resultRelationDesc; resultRelationDesc = ExecGetRangeTableRelation(estate, rti); + if (!ExecPlanStillValid(estate)) + return; InitResultRelInfo(resultRelInfo, resultRelationDesc, rti, diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c index 468db94fe5..f46c3df199 100644 --- a/src/backend/executor/nodeAgg.c +++ b/src/backend/executor/nodeAgg.c @@ -3150,7 +3150,8 @@ hashagg_reset_spill_state(AggState *aggstate) } /* free batches */ - list_free_deep(aggstate->hash_batches); + if (aggstate->hash_batches) + list_free_deep(aggstate->hash_batches); aggstate->hash_batches = NIL; /* close tape set */ @@ -3304,6 +3305,8 @@ ExecInitAgg(Agg *node, EState *estate, int eflags) eflags &= ~EXEC_FLAG_REWIND; outerPlan = outerPlan(node); outerPlanState(aggstate) = ExecInitNode(outerPlan, estate, eflags); + if (!ExecPlanStillValid(estate)) + return aggstate; /* * initialize source tuple type. @@ -4357,16 +4360,6 @@ ExecEndAgg(AggState *node) if (node->hashcontext) ReScanExprContext(node->hashcontext); - /* - * We don't actually free any ExprContexts here (see comment in - * ExecFreeExprContext), just unlinking the output one from the plan node - * suffices. - */ - ExecFreeExprContext(&node->ss.ps); - - /* clean up tuple table */ - ExecClearTuple(node->ss.ss_ScanTupleSlot); - outerPlan = outerPlanState(node); ExecEndNode(outerPlan); } diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c index 609df6b9e6..5d9fa4bff3 100644 --- a/src/backend/executor/nodeAppend.c +++ b/src/backend/executor/nodeAppend.c @@ -147,6 +147,8 @@ ExecInitAppend(Append *node, EState *estate, int eflags) list_length(node->appendplans), node->part_prune_info, &validsubplans); + if (!ExecPlanStillValid(estate)) + return NULL; appendstate->as_prune_state = prunestate; nplans = bms_num_members(validsubplans); @@ -185,8 +187,9 @@ ExecInitAppend(Append *node, EState *estate, int eflags) appendstate->ps.resultopsset = true; appendstate->ps.resultopsfixed = false; - appendplanstates = (PlanState **) palloc(nplans * - sizeof(PlanState *)); + appendstate->appendplans = appendplanstates = + (PlanState **) palloc0(nplans * sizeof(PlanState *)); + appendstate->as_nplans = nplans; /* * call ExecInitNode on each of the valid plans to be executed and save @@ -221,11 +224,12 @@ ExecInitAppend(Append *node, EState *estate, int eflags) firstvalid = j; appendplanstates[j++] = ExecInitNode(initNode, estate, eflags); + if (!ExecPlanStillValid(estate)) + return appendstate; } appendstate->as_first_partial_plan = firstvalid; appendstate->appendplans = appendplanstates; - appendstate->as_nplans = nplans; /* Initialize async state */ appendstate->as_asyncplans = asyncplans; diff --git a/src/backend/executor/nodeBitmapAnd.c b/src/backend/executor/nodeBitmapAnd.c index 4c5eb2b23b..93e5de0c1a 100644 --- a/src/backend/executor/nodeBitmapAnd.c +++ b/src/backend/executor/nodeBitmapAnd.c @@ -78,7 +78,6 @@ ExecInitBitmapAnd(BitmapAnd *node, EState *estate, int eflags) bitmapandstate->ps.state = estate; bitmapandstate->ps.ExecProcNode = ExecBitmapAnd; bitmapandstate->bitmapplans = bitmapplanstates; - bitmapandstate->nplans = nplans; /* * call ExecInitNode on each of the plans to be executed and save the @@ -88,8 +87,10 @@ ExecInitBitmapAnd(BitmapAnd *node, EState *estate, int eflags) foreach(l, node->bitmapplans) { initNode = (Plan *) lfirst(l); - bitmapplanstates[i] = ExecInitNode(initNode, estate, eflags); - i++; + bitmapplanstates[i++] = ExecInitNode(initNode, estate, eflags); + if (!ExecPlanStillValid(estate)) + return bitmapandstate; + bitmapandstate->nplans = i; } /* diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c index f35df0b8bf..3cdece852c 100644 --- a/src/backend/executor/nodeBitmapHeapscan.c +++ b/src/backend/executor/nodeBitmapHeapscan.c @@ -655,18 +655,6 @@ ExecEndBitmapHeapScan(BitmapHeapScanState *node) */ scanDesc = node->ss.ss_currentScanDesc; - /* - * Free the exprcontext - */ - ExecFreeExprContext(&node->ss.ps); - - /* - * clear out tuple table slots - */ - if (node->ss.ps.ps_ResultTupleSlot) - ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); - ExecClearTuple(node->ss.ss_ScanTupleSlot); - /* * close down subplans */ @@ -693,7 +681,8 @@ ExecEndBitmapHeapScan(BitmapHeapScanState *node) /* * close heap scan */ - table_endscan(scanDesc); + if (scanDesc) + table_endscan(scanDesc); } /* ---------------------------------------------------------------- @@ -763,11 +752,15 @@ ExecInitBitmapHeapScan(BitmapHeapScan *node, EState *estate, int eflags) * open the scan relation */ currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags); + if (!ExecPlanStillValid(estate)) + return scanstate; /* * initialize child nodes */ outerPlanState(scanstate) = ExecInitNode(outerPlan(node), estate, eflags); + if (!ExecPlanStillValid(estate)) + return scanstate; /* * get the scan type from the relation descriptor. diff --git a/src/backend/executor/nodeBitmapIndexscan.c b/src/backend/executor/nodeBitmapIndexscan.c index 83ec9ede89..4200472d02 100644 --- a/src/backend/executor/nodeBitmapIndexscan.c +++ b/src/backend/executor/nodeBitmapIndexscan.c @@ -184,14 +184,6 @@ ExecEndBitmapIndexScan(BitmapIndexScanState *node) indexRelationDesc = node->biss_RelationDesc; indexScanDesc = node->biss_ScanDesc; - /* - * Free the exprcontext ... now dead code, see ExecFreeExprContext - */ -#ifdef NOT_USED - if (node->biss_RuntimeContext) - FreeExprContext(node->biss_RuntimeContext, true); -#endif - /* * close the index relation (no-op if we didn't open it) */ @@ -263,6 +255,8 @@ ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate, int eflags) /* Open the index relation. */ lockmode = exec_rt_fetch(node->scan.scanrelid, estate)->rellockmode; indexstate->biss_RelationDesc = index_open(node->indexid, lockmode); + if (!ExecPlanStillValid(estate)) + return indexstate; /* * Initialize index-specific scan state diff --git a/src/backend/executor/nodeBitmapOr.c b/src/backend/executor/nodeBitmapOr.c index 0bf8af9652..e0e9228e35 100644 --- a/src/backend/executor/nodeBitmapOr.c +++ b/src/backend/executor/nodeBitmapOr.c @@ -79,7 +79,6 @@ ExecInitBitmapOr(BitmapOr *node, EState *estate, int eflags) bitmaporstate->ps.state = estate; bitmaporstate->ps.ExecProcNode = ExecBitmapOr; bitmaporstate->bitmapplans = bitmapplanstates; - bitmaporstate->nplans = nplans; /* * call ExecInitNode on each of the plans to be executed and save the @@ -89,8 +88,10 @@ ExecInitBitmapOr(BitmapOr *node, EState *estate, int eflags) foreach(l, node->bitmapplans) { initNode = (Plan *) lfirst(l); - bitmapplanstates[i] = ExecInitNode(initNode, estate, eflags); - i++; + bitmapplanstates[i++] = ExecInitNode(initNode, estate, eflags); + if (!ExecPlanStillValid(estate)) + return bitmaporstate; + bitmaporstate->nplans = i; } /* diff --git a/src/backend/executor/nodeCtescan.c b/src/backend/executor/nodeCtescan.c index cc4c4243e2..a0c0c4be33 100644 --- a/src/backend/executor/nodeCtescan.c +++ b/src/backend/executor/nodeCtescan.c @@ -287,18 +287,6 @@ ExecInitCteScan(CteScan *node, EState *estate, int eflags) void ExecEndCteScan(CteScanState *node) { - /* - * Free exprcontext - */ - ExecFreeExprContext(&node->ss.ps); - - /* - * clean out the tuple table - */ - if (node->ss.ps.ps_ResultTupleSlot) - ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); - ExecClearTuple(node->ss.ss_ScanTupleSlot); - /* * If I am the leader, free the tuplestore. */ diff --git a/src/backend/executor/nodeCustom.c b/src/backend/executor/nodeCustom.c index bd42c65b29..38061c30b9 100644 --- a/src/backend/executor/nodeCustom.c +++ b/src/backend/executor/nodeCustom.c @@ -61,6 +61,8 @@ ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags) if (scanrelid > 0) { scan_rel = ExecOpenScanRelation(estate, scanrelid, eflags); + if (!ExecPlanStillValid(estate)) + return NULL; css->ss.ss_currentRelation = scan_rel; } @@ -127,15 +129,11 @@ ExecCustomScan(PlanState *pstate) void ExecEndCustomScan(CustomScanState *node) { - Assert(node->methods->EndCustomScan != NULL); - node->methods->EndCustomScan(node); - - /* Free the exprcontext */ - ExecFreeExprContext(&node->ss.ps); - - /* Clean out the tuple table */ - ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); - ExecClearTuple(node->ss.ss_ScanTupleSlot); + if (node->methods) + { + Assert(node->methods->EndCustomScan != NULL); + node->methods->EndCustomScan(node); + } } void diff --git a/src/backend/executor/nodeForeignscan.c b/src/backend/executor/nodeForeignscan.c index c2139acca0..a3705082a9 100644 --- a/src/backend/executor/nodeForeignscan.c +++ b/src/backend/executor/nodeForeignscan.c @@ -173,6 +173,8 @@ ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags) if (scanrelid > 0) { currentRelation = ExecOpenScanRelation(estate, scanrelid, eflags); + if (!ExecPlanStillValid(estate)) + return NULL; scanstate->ss.ss_currentRelation = currentRelation; fdwroutine = GetFdwRoutineForRelation(currentRelation, true); } @@ -264,6 +266,8 @@ ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags) if (outerPlan(node)) outerPlanState(scanstate) = ExecInitNode(outerPlan(node), estate, eflags); + if (!ExecPlanStillValid(estate)) + return scanstate; /* * Tell the FDW to initialize the scan. @@ -312,14 +316,6 @@ ExecEndForeignScan(ForeignScanState *node) /* Shut down any outer plan. */ if (outerPlanState(node)) ExecEndNode(outerPlanState(node)); - - /* Free the exprcontext */ - ExecFreeExprContext(&node->ss.ps); - - /* clean out the tuple table */ - if (node->ss.ps.ps_ResultTupleSlot) - ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); - ExecClearTuple(node->ss.ss_ScanTupleSlot); } /* ---------------------------------------------------------------- diff --git a/src/backend/executor/nodeFunctionscan.c b/src/backend/executor/nodeFunctionscan.c index dd06ef8aee..a49c1a2c85 100644 --- a/src/backend/executor/nodeFunctionscan.c +++ b/src/backend/executor/nodeFunctionscan.c @@ -523,18 +523,6 @@ ExecEndFunctionScan(FunctionScanState *node) { int i; - /* - * Free the exprcontext - */ - ExecFreeExprContext(&node->ss.ps); - - /* - * clean out the tuple table - */ - if (node->ss.ps.ps_ResultTupleSlot) - ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); - ExecClearTuple(node->ss.ss_ScanTupleSlot); - /* * Release slots and tuplestore resources */ diff --git a/src/backend/executor/nodeGather.c b/src/backend/executor/nodeGather.c index 307fc10eea..6b26e03f74 100644 --- a/src/backend/executor/nodeGather.c +++ b/src/backend/executor/nodeGather.c @@ -89,6 +89,9 @@ ExecInitGather(Gather *node, EState *estate, int eflags) */ outerNode = outerPlan(node); outerPlanState(gatherstate) = ExecInitNode(outerNode, estate, eflags); + if (!ExecPlanStillValid(estate)) + return gatherstate; + tupDesc = ExecGetResultType(outerPlanState(gatherstate)); /* @@ -250,9 +253,6 @@ ExecEndGather(GatherState *node) { ExecEndNode(outerPlanState(node)); /* let children clean up first */ ExecShutdownGather(node); - ExecFreeExprContext(&node->ps); - if (node->ps.ps_ResultTupleSlot) - ExecClearTuple(node->ps.ps_ResultTupleSlot); } /* diff --git a/src/backend/executor/nodeGatherMerge.c b/src/backend/executor/nodeGatherMerge.c index 9d5e1a46e9..84412f94bb 100644 --- a/src/backend/executor/nodeGatherMerge.c +++ b/src/backend/executor/nodeGatherMerge.c @@ -108,6 +108,8 @@ ExecInitGatherMerge(GatherMerge *node, EState *estate, int eflags) */ outerNode = outerPlan(node); outerPlanState(gm_state) = ExecInitNode(outerNode, estate, eflags); + if (!ExecPlanStillValid(estate)) + return gm_state; /* * Leader may access ExecProcNode result directly (if @@ -290,9 +292,6 @@ ExecEndGatherMerge(GatherMergeState *node) { ExecEndNode(outerPlanState(node)); /* let children clean up first */ ExecShutdownGatherMerge(node); - ExecFreeExprContext(&node->ps); - if (node->ps.ps_ResultTupleSlot) - ExecClearTuple(node->ps.ps_ResultTupleSlot); } /* ---------------------------------------------------------------- diff --git a/src/backend/executor/nodeGroup.c b/src/backend/executor/nodeGroup.c index 25a1618952..b6068887f6 100644 --- a/src/backend/executor/nodeGroup.c +++ b/src/backend/executor/nodeGroup.c @@ -185,6 +185,8 @@ ExecInitGroup(Group *node, EState *estate, int eflags) * initialize child nodes */ outerPlanState(grpstate) = ExecInitNode(outerPlan(node), estate, eflags); + if (!ExecPlanStillValid(estate)) + return grpstate; /* * Initialize scan slot and type. @@ -228,11 +230,6 @@ ExecEndGroup(GroupState *node) { PlanState *outerPlan; - ExecFreeExprContext(&node->ss.ps); - - /* clean up tuple table */ - ExecClearTuple(node->ss.ss_ScanTupleSlot); - outerPlan = outerPlanState(node); ExecEndNode(outerPlan); } diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c index 8b5c35b82b..030bf0ed43 100644 --- a/src/backend/executor/nodeHash.c +++ b/src/backend/executor/nodeHash.c @@ -386,6 +386,8 @@ ExecInitHash(Hash *node, EState *estate, int eflags) * initialize child nodes */ outerPlanState(hashstate) = ExecInitNode(outerPlan(node), estate, eflags); + if (!ExecPlanStillValid(estate)) + return hashstate; /* * initialize our result slot and type. No need to build projection @@ -415,11 +417,6 @@ ExecEndHash(HashState *node) { PlanState *outerPlan; - /* - * free exprcontext - */ - ExecFreeExprContext(&node->ps); - /* * shut down the subplan */ diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c index 980746128b..49a6ba4276 100644 --- a/src/backend/executor/nodeHashjoin.c +++ b/src/backend/executor/nodeHashjoin.c @@ -752,8 +752,12 @@ ExecInitHashJoin(HashJoin *node, EState *estate, int eflags) hashNode = (Hash *) innerPlan(node); outerPlanState(hjstate) = ExecInitNode(outerNode, estate, eflags); + if (!ExecPlanStillValid(estate)) + return hjstate; outerDesc = ExecGetResultType(outerPlanState(hjstate)); innerPlanState(hjstate) = ExecInitNode((Plan *) hashNode, estate, eflags); + if (!ExecPlanStillValid(estate)) + return hjstate; innerDesc = ExecGetResultType(innerPlanState(hjstate)); /* @@ -867,18 +871,6 @@ ExecEndHashJoin(HashJoinState *node) node->hj_HashTable = NULL; } - /* - * Free the exprcontext - */ - ExecFreeExprContext(&node->js.ps); - - /* - * clean out the tuple table - */ - ExecClearTuple(node->js.ps.ps_ResultTupleSlot); - ExecClearTuple(node->hj_OuterTupleSlot); - ExecClearTuple(node->hj_HashTupleSlot); - /* * clean up subtrees */ diff --git a/src/backend/executor/nodeIncrementalSort.c b/src/backend/executor/nodeIncrementalSort.c index 7683e3341c..6caa1aa306 100644 --- a/src/backend/executor/nodeIncrementalSort.c +++ b/src/backend/executor/nodeIncrementalSort.c @@ -1041,6 +1041,8 @@ ExecInitIncrementalSort(IncrementalSort *node, EState *estate, int eflags) * nodes may be able to do something more useful. */ outerPlanState(incrsortstate) = ExecInitNode(outerPlan(node), estate, eflags); + if (!ExecPlanStillValid(estate)) + return incrsortstate; /* * Initialize scan slot and type. @@ -1079,14 +1081,6 @@ ExecEndIncrementalSort(IncrementalSortState *node) { SO_printf("ExecEndIncrementalSort: shutting down sort node\n"); - /* clean out the scan tuple */ - ExecClearTuple(node->ss.ss_ScanTupleSlot); - /* must drop pointer to sort result tuple */ - ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); - /* must drop standalone tuple slots from outer node */ - ExecDropSingleTupleTableSlot(node->group_pivot); - ExecDropSingleTupleTableSlot(node->transfer_tuple); - /* * Release tuplesort resources. */ diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c index 0b43a9b969..ea7fd89c0c 100644 --- a/src/backend/executor/nodeIndexonlyscan.c +++ b/src/backend/executor/nodeIndexonlyscan.c @@ -380,22 +380,6 @@ ExecEndIndexOnlyScan(IndexOnlyScanState *node) node->ioss_VMBuffer = InvalidBuffer; } - /* - * Free the exprcontext(s) ... now dead code, see ExecFreeExprContext - */ -#ifdef NOT_USED - ExecFreeExprContext(&node->ss.ps); - if (node->ioss_RuntimeContext) - FreeExprContext(node->ioss_RuntimeContext, true); -#endif - - /* - * clear out tuple table slots - */ - if (node->ss.ps.ps_ResultTupleSlot) - ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); - ExecClearTuple(node->ss.ss_ScanTupleSlot); - /* * close the index relation (no-op if we didn't open it) */ @@ -512,6 +496,8 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags) * open the scan relation */ currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags); + if (!ExecPlanStillValid(estate)) + return NULL; indexstate->ss.ss_currentRelation = currentRelation; indexstate->ss.ss_currentScanDesc = NULL; /* no heap scan here */ @@ -565,6 +551,8 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags) /* Open the index relation. */ lockmode = exec_rt_fetch(node->scan.scanrelid, estate)->rellockmode; indexstate->ioss_RelationDesc = index_open(node->indexid, lockmode); + if (!ExecPlanStillValid(estate)) + return NULL; /* * Initialize index-specific scan state diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c index 4540c7781d..906358011a 100644 --- a/src/backend/executor/nodeIndexscan.c +++ b/src/backend/executor/nodeIndexscan.c @@ -794,22 +794,6 @@ ExecEndIndexScan(IndexScanState *node) indexRelationDesc = node->iss_RelationDesc; indexScanDesc = node->iss_ScanDesc; - /* - * Free the exprcontext(s) ... now dead code, see ExecFreeExprContext - */ -#ifdef NOT_USED - ExecFreeExprContext(&node->ss.ps); - if (node->iss_RuntimeContext) - FreeExprContext(node->iss_RuntimeContext, true); -#endif - - /* - * clear out tuple table slots - */ - if (node->ss.ps.ps_ResultTupleSlot) - ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); - ExecClearTuple(node->ss.ss_ScanTupleSlot); - /* * close the index relation (no-op if we didn't open it) */ @@ -925,6 +909,8 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags) * open the scan relation */ currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags); + if (!ExecPlanStillValid(estate)) + return NULL; indexstate->ss.ss_currentRelation = currentRelation; indexstate->ss.ss_currentScanDesc = NULL; /* no heap scan here */ @@ -970,6 +956,8 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags) /* Open the index relation. */ lockmode = exec_rt_fetch(node->scan.scanrelid, estate)->rellockmode; indexstate->iss_RelationDesc = index_open(node->indexid, lockmode); + if (!ExecPlanStillValid(estate)) + return NULL; /* * Initialize index-specific scan state diff --git a/src/backend/executor/nodeLimit.c b/src/backend/executor/nodeLimit.c index 425fbfc405..6760de0f25 100644 --- a/src/backend/executor/nodeLimit.c +++ b/src/backend/executor/nodeLimit.c @@ -476,6 +476,8 @@ ExecInitLimit(Limit *node, EState *estate, int eflags) */ outerPlan = outerPlan(node); outerPlanState(limitstate) = ExecInitNode(outerPlan, estate, eflags); + if (!ExecPlanStillValid(estate)) + return limitstate; /* * initialize child expressions @@ -534,7 +536,6 @@ ExecInitLimit(Limit *node, EState *estate, int eflags) void ExecEndLimit(LimitState *node) { - ExecFreeExprContext(&node->ps); ExecEndNode(outerPlanState(node)); } diff --git a/src/backend/executor/nodeLockRows.c b/src/backend/executor/nodeLockRows.c index e459971d32..2599332f01 100644 --- a/src/backend/executor/nodeLockRows.c +++ b/src/backend/executor/nodeLockRows.c @@ -322,6 +322,8 @@ ExecInitLockRows(LockRows *node, EState *estate, int eflags) * then initialize outer plan */ outerPlanState(lrstate) = ExecInitNode(outerPlan, estate, eflags); + if (!ExecPlanStillValid(estate)) + return lrstate; /* node returns unmodified slots from the outer plan */ lrstate->ps.resultopsset = true; diff --git a/src/backend/executor/nodeMaterial.c b/src/backend/executor/nodeMaterial.c index 09632678b0..b974ebdc8a 100644 --- a/src/backend/executor/nodeMaterial.c +++ b/src/backend/executor/nodeMaterial.c @@ -214,6 +214,8 @@ ExecInitMaterial(Material *node, EState *estate, int eflags) outerPlan = outerPlan(node); outerPlanState(matstate) = ExecInitNode(outerPlan, estate, eflags); + if (!ExecPlanStillValid(estate)) + return matstate; /* * Initialize result type and slot. No need to initialize projection info @@ -239,11 +241,6 @@ ExecInitMaterial(Material *node, EState *estate, int eflags) void ExecEndMaterial(MaterialState *node) { - /* - * clean out the tuple table - */ - ExecClearTuple(node->ss.ss_ScanTupleSlot); - /* * Release tuplestore resources */ diff --git a/src/backend/executor/nodeMemoize.c b/src/backend/executor/nodeMemoize.c index 4f04269e26..d0cdbe1fd7 100644 --- a/src/backend/executor/nodeMemoize.c +++ b/src/backend/executor/nodeMemoize.c @@ -938,6 +938,8 @@ ExecInitMemoize(Memoize *node, EState *estate, int eflags) outerNode = outerPlan(node); outerPlanState(mstate) = ExecInitNode(outerNode, estate, eflags); + if (!ExecPlanStillValid(estate)) + return mstate; /* * Initialize return slot and type. No need to initialize projection info @@ -1043,6 +1045,7 @@ ExecEndMemoize(MemoizeState *node) { #ifdef USE_ASSERT_CHECKING /* Validate the memory accounting code is correct in assert builds. */ + if (node->hashtable) { int count; uint64 mem = 0; @@ -1091,15 +1094,6 @@ ExecEndMemoize(MemoizeState *node) /* Remove the cache context */ MemoryContextDelete(node->tableContext); - ExecClearTuple(node->ss.ss_ScanTupleSlot); - /* must drop pointer to cache result tuple */ - ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); - - /* - * free exprcontext - */ - ExecFreeExprContext(&node->ss.ps); - /* * shut down the subplan */ diff --git a/src/backend/executor/nodeMergeAppend.c b/src/backend/executor/nodeMergeAppend.c index 21b5726e6e..255b05aad3 100644 --- a/src/backend/executor/nodeMergeAppend.c +++ b/src/backend/executor/nodeMergeAppend.c @@ -95,6 +95,8 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags) list_length(node->mergeplans), node->part_prune_info, &validsubplans); + if (!ExecPlanStillValid(estate)) + return NULL; mergestate->ms_prune_state = prunestate; nplans = bms_num_members(validsubplans); @@ -120,7 +122,7 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags) mergestate->ms_prune_state = NULL; } - mergeplanstates = (PlanState **) palloc(nplans * sizeof(PlanState *)); + mergeplanstates = (PlanState **) palloc0(nplans * sizeof(PlanState *)); mergestate->mergeplans = mergeplanstates; mergestate->ms_nplans = nplans; @@ -151,6 +153,8 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags) Plan *initNode = (Plan *) list_nth(node->mergeplans, i); mergeplanstates[j++] = ExecInitNode(initNode, estate, eflags); + if (!ExecPlanStillValid(estate)) + return mergestate; } mergestate->ps.ps_ProjInfo = NULL; diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c index 00f96d045e..e7f4512419 100644 --- a/src/backend/executor/nodeMergejoin.c +++ b/src/backend/executor/nodeMergejoin.c @@ -1490,11 +1490,15 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags) mergestate->mj_SkipMarkRestore = node->skip_mark_restore; outerPlanState(mergestate) = ExecInitNode(outerPlan(node), estate, eflags); + if (!ExecPlanStillValid(estate)) + return mergestate; outerDesc = ExecGetResultType(outerPlanState(mergestate)); innerPlanState(mergestate) = ExecInitNode(innerPlan(node), estate, mergestate->mj_SkipMarkRestore ? eflags : (eflags | EXEC_FLAG_MARK)); + if (!ExecPlanStillValid(estate)) + return mergestate; innerDesc = ExecGetResultType(innerPlanState(mergestate)); /* @@ -1642,18 +1646,6 @@ ExecEndMergeJoin(MergeJoinState *node) { MJ1_printf("ExecEndMergeJoin: %s\n", "ending node processing"); - - /* - * Free the exprcontext - */ - ExecFreeExprContext(&node->js.ps); - - /* - * clean out the tuple table - */ - ExecClearTuple(node->js.ps.ps_ResultTupleSlot); - ExecClearTuple(node->mj_MarkedTupleSlot); - /* * shut down the subplans */ diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index 5005d8c0d1..c28d5058e9 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -3985,6 +3985,9 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) linitial_int(node->resultRelations)); } + if (!ExecPlanStillValid(estate)) + return NULL; + /* set up epqstate with dummy subplan data for the moment */ EvalPlanQualInit(&mtstate->mt_epqstate, estate, NULL, NIL, node->epqParam, node->resultRelations); @@ -4012,6 +4015,8 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) if (resultRelInfo != mtstate->rootResultRelInfo) { ExecInitResultRelation(estate, resultRelInfo, resultRelation); + if (!ExecPlanStillValid(estate)) + return NULL; /* * For child result relations, store the root result relation @@ -4039,6 +4044,8 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) * Now we may initialize the subplan. */ outerPlanState(mtstate) = ExecInitNode(subplan, estate, eflags); + if (!ExecPlanStillValid(estate)) + return mtstate; /* * Do additional per-result-relation initialization. @@ -4446,17 +4453,6 @@ ExecEndModifyTable(ModifyTableState *node) ExecDropSingleTupleTableSlot(node->mt_root_tuple_slot); } - /* - * Free the exprcontext - */ - ExecFreeExprContext(&node->ps); - - /* - * clean out the tuple table - */ - if (node->ps.ps_ResultTupleSlot) - ExecClearTuple(node->ps.ps_ResultTupleSlot); - /* * Terminate EPQ execution if active */ diff --git a/src/backend/executor/nodeNamedtuplestorescan.c b/src/backend/executor/nodeNamedtuplestorescan.c index 46832ad82f..e142ef593b 100644 --- a/src/backend/executor/nodeNamedtuplestorescan.c +++ b/src/backend/executor/nodeNamedtuplestorescan.c @@ -164,17 +164,6 @@ ExecInitNamedTuplestoreScan(NamedTuplestoreScan *node, EState *estate, int eflag void ExecEndNamedTuplestoreScan(NamedTuplestoreScanState *node) { - /* - * Free exprcontext - */ - ExecFreeExprContext(&node->ss.ps); - - /* - * clean out the tuple table - */ - if (node->ss.ps.ps_ResultTupleSlot) - ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); - ExecClearTuple(node->ss.ss_ScanTupleSlot); } /* ---------------------------------------------------------------- diff --git a/src/backend/executor/nodeNestloop.c b/src/backend/executor/nodeNestloop.c index b3d52e69ec..0158a3e592 100644 --- a/src/backend/executor/nodeNestloop.c +++ b/src/backend/executor/nodeNestloop.c @@ -295,11 +295,15 @@ ExecInitNestLoop(NestLoop *node, EState *estate, int eflags) * values. */ outerPlanState(nlstate) = ExecInitNode(outerPlan(node), estate, eflags); + if (!ExecPlanStillValid(estate)) + return nlstate; if (node->nestParams == NIL) eflags |= EXEC_FLAG_REWIND; else eflags &= ~EXEC_FLAG_REWIND; innerPlanState(nlstate) = ExecInitNode(innerPlan(node), estate, eflags); + if (!ExecPlanStillValid(estate)) + return nlstate; /* * Initialize result slot, type and projection. @@ -363,17 +367,6 @@ ExecEndNestLoop(NestLoopState *node) { NL1_printf("ExecEndNestLoop: %s\n", "ending node processing"); - - /* - * Free the exprcontext - */ - ExecFreeExprContext(&node->js.ps); - - /* - * clean out the tuple table - */ - ExecClearTuple(node->js.ps.ps_ResultTupleSlot); - /* * close down subplans */ diff --git a/src/backend/executor/nodeProjectSet.c b/src/backend/executor/nodeProjectSet.c index f6ff3dc44c..1b4774d4f7 100644 --- a/src/backend/executor/nodeProjectSet.c +++ b/src/backend/executor/nodeProjectSet.c @@ -247,6 +247,8 @@ ExecInitProjectSet(ProjectSet *node, EState *estate, int eflags) * initialize child nodes */ outerPlanState(state) = ExecInitNode(outerPlan(node), estate, eflags); + if (!ExecPlanStillValid(estate)) + return state; /* * we don't use inner plan @@ -320,16 +322,6 @@ ExecInitProjectSet(ProjectSet *node, EState *estate, int eflags) void ExecEndProjectSet(ProjectSetState *node) { - /* - * Free the exprcontext - */ - ExecFreeExprContext(&node->ps); - - /* - * clean out the tuple table - */ - ExecClearTuple(node->ps.ps_ResultTupleSlot); - /* * shut down subplans */ diff --git a/src/backend/executor/nodeRecursiveunion.c b/src/backend/executor/nodeRecursiveunion.c index e781003934..ca4f78685d 100644 --- a/src/backend/executor/nodeRecursiveunion.c +++ b/src/backend/executor/nodeRecursiveunion.c @@ -244,7 +244,11 @@ ExecInitRecursiveUnion(RecursiveUnion *node, EState *estate, int eflags) * initialize child nodes */ outerPlanState(rustate) = ExecInitNode(outerPlan(node), estate, eflags); + if (!ExecPlanStillValid(estate)) + return rustate; innerPlanState(rustate) = ExecInitNode(innerPlan(node), estate, eflags); + if (!ExecPlanStillValid(estate)) + return rustate; /* * If hashing, precompute fmgr lookup data for inner loop, and create the @@ -272,8 +276,10 @@ void ExecEndRecursiveUnion(RecursiveUnionState *node) { /* Release tuplestores */ - tuplestore_end(node->working_table); - tuplestore_end(node->intermediate_table); + if (node->working_table) + tuplestore_end(node->working_table); + if (node->intermediate_table) + tuplestore_end(node->intermediate_table); /* free subsidiary stuff including hashtable */ if (node->tempContext) diff --git a/src/backend/executor/nodeResult.c b/src/backend/executor/nodeResult.c index 4219712d30..d4ea101cbe 100644 --- a/src/backend/executor/nodeResult.c +++ b/src/backend/executor/nodeResult.c @@ -208,6 +208,8 @@ ExecInitResult(Result *node, EState *estate, int eflags) * initialize child nodes */ outerPlanState(resstate) = ExecInitNode(outerPlan(node), estate, eflags); + if (!ExecPlanStillValid(estate)) + return resstate; /* * we don't use inner plan @@ -240,16 +242,6 @@ ExecInitResult(Result *node, EState *estate, int eflags) void ExecEndResult(ResultState *node) { - /* - * Free the exprcontext - */ - ExecFreeExprContext(&node->ps); - - /* - * clean out the tuple table - */ - ExecClearTuple(node->ps.ps_ResultTupleSlot); - /* * shut down subplans */ diff --git a/src/backend/executor/nodeSamplescan.c b/src/backend/executor/nodeSamplescan.c index d7e22b1dbb..02a7db96e1 100644 --- a/src/backend/executor/nodeSamplescan.c +++ b/src/backend/executor/nodeSamplescan.c @@ -125,6 +125,8 @@ ExecInitSampleScan(SampleScan *node, EState *estate, int eflags) ExecOpenScanRelation(estate, node->scan.scanrelid, eflags); + if (!ExecPlanStillValid(estate)) + return NULL; /* we won't set up the HeapScanDesc till later */ scanstate->ss.ss_currentScanDesc = NULL; @@ -185,21 +187,9 @@ ExecEndSampleScan(SampleScanState *node) /* * Tell sampling function that we finished the scan. */ - if (node->tsmroutine->EndSampleScan) + if (node->tsmroutine && node->tsmroutine->EndSampleScan) node->tsmroutine->EndSampleScan(node); - /* - * Free the exprcontext - */ - ExecFreeExprContext(&node->ss.ps); - - /* - * clean out the tuple table - */ - if (node->ss.ps.ps_ResultTupleSlot) - ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); - ExecClearTuple(node->ss.ss_ScanTupleSlot); - /* * close heap scan */ diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c index 4da0f28f7b..48e20aa735 100644 --- a/src/backend/executor/nodeSeqscan.c +++ b/src/backend/executor/nodeSeqscan.c @@ -153,6 +153,8 @@ ExecInitSeqScan(SeqScan *node, EState *estate, int eflags) ExecOpenScanRelation(estate, node->scan.scanrelid, eflags); + if (!ExecPlanStillValid(estate)) + return NULL; /* and create slot with the appropriate rowtype */ ExecInitScanTupleSlot(estate, &scanstate->ss, @@ -190,18 +192,6 @@ ExecEndSeqScan(SeqScanState *node) */ scanDesc = node->ss.ss_currentScanDesc; - /* - * Free the exprcontext - */ - ExecFreeExprContext(&node->ss.ps); - - /* - * clean out the tuple table - */ - if (node->ss.ps.ps_ResultTupleSlot) - ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); - ExecClearTuple(node->ss.ss_ScanTupleSlot); - /* * close heap scan */ diff --git a/src/backend/executor/nodeSetOp.c b/src/backend/executor/nodeSetOp.c index 4bc2406b89..7a3a142204 100644 --- a/src/backend/executor/nodeSetOp.c +++ b/src/backend/executor/nodeSetOp.c @@ -528,6 +528,8 @@ ExecInitSetOp(SetOp *node, EState *estate, int eflags) if (node->strategy == SETOP_HASHED) eflags &= ~EXEC_FLAG_REWIND; outerPlanState(setopstate) = ExecInitNode(outerPlan(node), estate, eflags); + if (!ExecPlanStillValid(estate)) + return setopstate; outerDesc = ExecGetResultType(outerPlanState(setopstate)); /* @@ -582,13 +584,9 @@ ExecInitSetOp(SetOp *node, EState *estate, int eflags) void ExecEndSetOp(SetOpState *node) { - /* clean up tuple table */ - ExecClearTuple(node->ps.ps_ResultTupleSlot); - /* free subsidiary stuff including hashtable */ if (node->tableContext) MemoryContextDelete(node->tableContext); - ExecFreeExprContext(&node->ps); ExecEndNode(outerPlanState(node)); } diff --git a/src/backend/executor/nodeSort.c b/src/backend/executor/nodeSort.c index c6c72c6e67..3ebbc46604 100644 --- a/src/backend/executor/nodeSort.c +++ b/src/backend/executor/nodeSort.c @@ -263,6 +263,8 @@ ExecInitSort(Sort *node, EState *estate, int eflags) eflags &= ~(EXEC_FLAG_REWIND | EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK); outerPlanState(sortstate) = ExecInitNode(outerPlan(node), estate, eflags); + if (!ExecPlanStillValid(estate)) + return sortstate; /* * Initialize scan slot and type. @@ -303,13 +305,6 @@ ExecEndSort(SortState *node) SO1_printf("ExecEndSort: %s\n", "shutting down sort node"); - /* - * clean out the tuple table - */ - ExecClearTuple(node->ss.ss_ScanTupleSlot); - /* must drop pointer to sort result tuple */ - ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); - /* * Release tuplesort resources */ diff --git a/src/backend/executor/nodeSubqueryscan.c b/src/backend/executor/nodeSubqueryscan.c index 42471bfc04..3c5c7c2ebb 100644 --- a/src/backend/executor/nodeSubqueryscan.c +++ b/src/backend/executor/nodeSubqueryscan.c @@ -124,6 +124,8 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate, int eflags) * initialize subquery */ subquerystate->subplan = ExecInitNode(node->subplan, estate, eflags); + if (!ExecPlanStillValid(estate)) + return subquerystate; /* * Initialize scan slot and type (needed by ExecAssignScanProjectionInfo) @@ -167,18 +169,6 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate, int eflags) void ExecEndSubqueryScan(SubqueryScanState *node) { - /* - * Free the exprcontext - */ - ExecFreeExprContext(&node->ss.ps); - - /* - * clean out the upper tuple table - */ - if (node->ss.ps.ps_ResultTupleSlot) - ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); - ExecClearTuple(node->ss.ss_ScanTupleSlot); - /* * close down subquery */ diff --git a/src/backend/executor/nodeTableFuncscan.c b/src/backend/executor/nodeTableFuncscan.c index 791cbd2372..a60dcd4943 100644 --- a/src/backend/executor/nodeTableFuncscan.c +++ b/src/backend/executor/nodeTableFuncscan.c @@ -213,18 +213,6 @@ ExecInitTableFuncScan(TableFuncScan *node, EState *estate, int eflags) void ExecEndTableFuncScan(TableFuncScanState *node) { - /* - * Free the exprcontext - */ - ExecFreeExprContext(&node->ss.ps); - - /* - * clean out the tuple table - */ - if (node->ss.ps.ps_ResultTupleSlot) - ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); - ExecClearTuple(node->ss.ss_ScanTupleSlot); - /* * Release tuplestore resources */ diff --git a/src/backend/executor/nodeTidrangescan.c b/src/backend/executor/nodeTidrangescan.c index 2124c55ef5..d337f3d54a 100644 --- a/src/backend/executor/nodeTidrangescan.c +++ b/src/backend/executor/nodeTidrangescan.c @@ -331,18 +331,6 @@ ExecEndTidRangeScan(TidRangeScanState *node) if (scan != NULL) table_endscan(scan); - - /* - * Free the exprcontext - */ - ExecFreeExprContext(&node->ss.ps); - - /* - * clear out tuple table slots - */ - if (node->ss.ps.ps_ResultTupleSlot) - ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); - ExecClearTuple(node->ss.ss_ScanTupleSlot); } /* ---------------------------------------------------------------- @@ -386,6 +374,8 @@ ExecInitTidRangeScan(TidRangeScan *node, EState *estate, int eflags) * open the scan relation */ currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags); + if (!ExecPlanStillValid(estate)) + return NULL; tidrangestate->ss.ss_currentRelation = currentRelation; tidrangestate->ss.ss_currentScanDesc = NULL; /* no table scan here */ diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c index 862bd0330b..9637f354b2 100644 --- a/src/backend/executor/nodeTidscan.c +++ b/src/backend/executor/nodeTidscan.c @@ -472,18 +472,6 @@ ExecEndTidScan(TidScanState *node) { if (node->ss.ss_currentScanDesc) table_endscan(node->ss.ss_currentScanDesc); - - /* - * Free the exprcontext - */ - ExecFreeExprContext(&node->ss.ps); - - /* - * clear out tuple table slots - */ - if (node->ss.ps.ps_ResultTupleSlot) - ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); - ExecClearTuple(node->ss.ss_ScanTupleSlot); } /* ---------------------------------------------------------------- @@ -529,6 +517,8 @@ ExecInitTidScan(TidScan *node, EState *estate, int eflags) * open the scan relation */ currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags); + if (!ExecPlanStillValid(estate)) + return NULL; tidstate->ss.ss_currentRelation = currentRelation; tidstate->ss.ss_currentScanDesc = NULL; /* no heap scan here */ diff --git a/src/backend/executor/nodeUnique.c b/src/backend/executor/nodeUnique.c index 45035d74fa..28630e380e 100644 --- a/src/backend/executor/nodeUnique.c +++ b/src/backend/executor/nodeUnique.c @@ -136,6 +136,8 @@ ExecInitUnique(Unique *node, EState *estate, int eflags) * then initialize outer plan */ outerPlanState(uniquestate) = ExecInitNode(outerPlan(node), estate, eflags); + if (!ExecPlanStillValid(estate)) + return uniquestate; /* * Initialize result slot and type. Unique nodes do no projections, so @@ -168,11 +170,6 @@ ExecInitUnique(Unique *node, EState *estate, int eflags) void ExecEndUnique(UniqueState *node) { - /* clean up tuple table */ - ExecClearTuple(node->ps.ps_ResultTupleSlot); - - ExecFreeExprContext(&node->ps); - ExecEndNode(outerPlanState(node)); } diff --git a/src/backend/executor/nodeValuesscan.c b/src/backend/executor/nodeValuesscan.c index 32ace63017..3f86783ad7 100644 --- a/src/backend/executor/nodeValuesscan.c +++ b/src/backend/executor/nodeValuesscan.c @@ -328,19 +328,6 @@ ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags) void ExecEndValuesScan(ValuesScanState *node) { - /* - * Free both exprcontexts - */ - ExecFreeExprContext(&node->ss.ps); - node->ss.ps.ps_ExprContext = node->rowcontext; - ExecFreeExprContext(&node->ss.ps); - - /* - * clean out the tuple table - */ - if (node->ss.ps.ps_ResultTupleSlot) - ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); - ExecClearTuple(node->ss.ss_ScanTupleSlot); } /* ---------------------------------------------------------------- diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c index 310ac23e3a..a4153be495 100644 --- a/src/backend/executor/nodeWindowAgg.c +++ b/src/backend/executor/nodeWindowAgg.c @@ -2458,6 +2458,8 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags) */ outerPlan = outerPlan(node); outerPlanState(winstate) = ExecInitNode(outerPlan, estate, eflags); + if (!ExecPlanStillValid(estate)) + return winstate; /* * initialize source tuple type (which is also the tuple type that we'll @@ -2691,17 +2693,6 @@ ExecEndWindowAgg(WindowAggState *node) ExecClearTuple(node->agg_row_slot); ExecClearTuple(node->temp_slot_1); ExecClearTuple(node->temp_slot_2); - if (node->framehead_slot) - ExecClearTuple(node->framehead_slot); - if (node->frametail_slot) - ExecClearTuple(node->frametail_slot); - - /* - * Free both the expr contexts. - */ - ExecFreeExprContext(&node->ss.ps); - node->ss.ps.ps_ExprContext = node->tmpcontext; - ExecFreeExprContext(&node->ss.ps); for (i = 0; i < node->numaggs; i++) { diff --git a/src/backend/executor/nodeWorktablescan.c b/src/backend/executor/nodeWorktablescan.c index 0c13448236..cc63ddfeca 100644 --- a/src/backend/executor/nodeWorktablescan.c +++ b/src/backend/executor/nodeWorktablescan.c @@ -190,17 +190,6 @@ ExecInitWorkTableScan(WorkTableScan *node, EState *estate, int eflags) void ExecEndWorkTableScan(WorkTableScanState *node) { - /* - * Free exprcontext - */ - ExecFreeExprContext(&node->ss.ps); - - /* - * clean out the tuple table - */ - if (node->ss.ps.ps_ResultTupleSlot) - ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); - ExecClearTuple(node->ss.ss_ScanTupleSlot); } /* ---------------------------------------------------------------- diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index c677e490d7..8ec636cab8 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -19,6 +19,7 @@ #include "nodes/lockoptions.h" #include "nodes/parsenodes.h" #include "utils/memutils.h" +#include "utils/plancache.h" /* @@ -256,6 +257,17 @@ extern void ExecEndNode(PlanState *node); extern void ExecShutdownNode(PlanState *node); extern void ExecSetTupleBound(int64 tuples_needed, PlanState *child_node); +/* + * Is the cached plan, if any, still valid at this point? That is, not + * invalidated by the incoming invalidation messages that have been processed + * recently. + */ +static inline bool +ExecPlanStillValid(EState *estate) +{ + return estate->es_cachedplan == NULL ? true : + CachedPlanStillValid(estate->es_cachedplan); +} /* ---------------------------------------------------------------- * ExecProcNode diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index cb714f4a19..719a728319 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -623,6 +623,8 @@ typedef struct EState * ExecRowMarks, or NULL if none */ List *es_rteperminfos; /* List of RTEPermissionInfo */ PlannedStmt *es_plannedstmt; /* link to top of plan tree */ + struct CachedPlan *es_cachedplan; /* CachedPlan if plannedstmt is from, + * one or NULL if not */ const char *es_sourceText; /* Source text from QueryDesc */ JunkFilter *es_junkFilter; /* top-level junk filter, if any */ diff --git a/src/include/utils/plancache.h b/src/include/utils/plancache.h index 916e59d9fe..c83a67fea3 100644 --- a/src/include/utils/plancache.h +++ b/src/include/utils/plancache.h @@ -221,6 +221,20 @@ extern CachedPlan *GetCachedPlan(CachedPlanSource *plansource, ParamListInfo boundParams, ResourceOwner owner, QueryEnvironment *queryEnv); + +/* + * CachedPlanStillValid + * Returns if a cached generic plan is still valid + * + * Called by the executor on every relation lock taken when initializing the + * plan tree in the CachedPlan. + */ +static inline bool +CachedPlanStillValid(CachedPlan *cplan) +{ + return cplan->is_valid; +} + extern void ReleaseCachedPlan(CachedPlan *plan, ResourceOwner owner); extern bool CachedPlanAllowsSimpleValidityCheck(CachedPlanSource *plansource, -- 2.35.3