1
/*-------------------------------------------------------------------------
4
* miscellaneous executor utility routines
6
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
7
* Portions Copyright (c) 1994, Regents of the University of California
11
* $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.117 2004-12-31 21:59:45 pgsql Exp $
13
*-------------------------------------------------------------------------
17
* CreateExecutorState Create/delete executor working state
23
* ExecAssignExprContext Common code for plan node init routines.
24
* ExecAssignResultType
28
* ExecCloseIndices | referenced by InitPlan, EndPlan,
29
* ExecInsertIndexTuples / ExecInsert, ExecUpdate
31
* RegisterExprContextCallback Register function shutdown callback
32
* UnregisterExprContextCallback Deregister function shutdown callback
35
* This file has traditionally been the place to stick misc.
36
* executor support stuff that doesn't really go anyplace else.
41
#include "access/genam.h"
42
#include "access/heapam.h"
43
#include "catalog/catname.h"
44
#include "catalog/index.h"
45
#include "catalog/catalog.h"
46
#include "catalog/pg_index.h"
47
#include "executor/execdebug.h"
48
#include "miscadmin.h"
49
#include "utils/builtins.h"
50
#include "utils/fmgroids.h"
51
#include "utils/memutils.h"
52
#include "utils/relcache.h"
53
#include "utils/syscache.h"
56
/* ----------------------------------------------------------------
57
* global counters for number of tuples processed, retrieved,
58
* appended, replaced, deleted.
59
* ----------------------------------------------------------------
66
int NIndexTupleInserted;
67
extern int NIndexTupleProcessed; /* have to be defined in the
68
* access method level so that the
69
* cinterface.a will link ok. */
72
static void ShutdownExprContext(ExprContext *econtext);
75
/* ----------------------------------------------------------------
77
* ----------------------------------------------------------------
80
/* ----------------------------------------------------------------
82
* ----------------------------------------------------------------
93
NIndexTupleProcessed = 0;
97
/* ----------------------------------------------------------------
99
* ----------------------------------------------------------------
103
DisplayTupleCount(FILE *statfp)
105
if (NTupleProcessed > 0)
106
fprintf(statfp, "!\t%d tuple%s processed, ", NTupleProcessed,
107
(NTupleProcessed == 1) ? "" : "s");
110
fprintf(statfp, "!\tno tuples processed.\n");
113
if (NIndexTupleProcessed > 0)
114
fprintf(statfp, "%d indextuple%s processed, ", NIndexTupleProcessed,
115
(NIndexTupleProcessed == 1) ? "" : "s");
116
if (NIndexTupleInserted > 0)
117
fprintf(statfp, "%d indextuple%s inserted, ", NIndexTupleInserted,
118
(NIndexTupleInserted == 1) ? "" : "s");
119
if (NTupleRetrieved > 0)
120
fprintf(statfp, "%d tuple%s retrieved. ", NTupleRetrieved,
121
(NTupleRetrieved == 1) ? "" : "s");
122
if (NTupleAppended > 0)
123
fprintf(statfp, "%d tuple%s appended. ", NTupleAppended,
124
(NTupleAppended == 1) ? "" : "s");
125
if (NTupleDeleted > 0)
126
fprintf(statfp, "%d tuple%s deleted. ", NTupleDeleted,
127
(NTupleDeleted == 1) ? "" : "s");
128
if (NTupleReplaced > 0)
129
fprintf(statfp, "%d tuple%s replaced. ", NTupleReplaced,
130
(NTupleReplaced == 1) ? "" : "s");
131
fprintf(statfp, "\n");
136
/* ----------------------------------------------------------------
137
* Executor state and memory management functions
138
* ----------------------------------------------------------------
142
* CreateExecutorState
144
* Create and initialize an EState node, which is the root of
145
* working storage for an entire Executor invocation.
147
* Principally, this creates the per-query memory context that will be
148
* used to hold all working data that lives till the end of the query.
149
* Note that the per-query context will become a child of the caller's
150
* CurrentMemoryContext.
154
CreateExecutorState(void)
157
MemoryContext qcontext;
158
MemoryContext oldcontext;
161
* Create the per-query context for this Executor run.
163
qcontext = AllocSetContextCreate(CurrentMemoryContext,
165
ALLOCSET_DEFAULT_MINSIZE,
166
ALLOCSET_DEFAULT_INITSIZE,
167
ALLOCSET_DEFAULT_MAXSIZE);
170
* Make the EState node within the per-query context. This way, we
171
* don't need a separate pfree() operation for it at shutdown.
173
oldcontext = MemoryContextSwitchTo(qcontext);
175
estate = makeNode(EState);
178
* Initialize all fields of the Executor State structure
180
estate->es_direction = ForwardScanDirection;
181
estate->es_snapshot = SnapshotNow;
182
estate->es_crosscheck_snapshot = InvalidSnapshot; /* no crosscheck */
183
estate->es_range_table = NIL;
185
estate->es_result_relations = NULL;
186
estate->es_num_result_relations = 0;
187
estate->es_result_relation_info = NULL;
189
estate->es_junkFilter = NULL;
190
estate->es_into_relation_descriptor = NULL;
192
estate->es_param_list_info = NULL;
193
estate->es_param_exec_vals = NULL;
195
estate->es_query_cxt = qcontext;
197
estate->es_tupleTable = NULL;
199
estate->es_processed = 0;
200
estate->es_lastoid = InvalidOid;
201
estate->es_rowMark = NIL;
203
estate->es_instrument = false;
204
estate->es_select_into = false;
205
estate->es_into_oids = false;
207
estate->es_exprcontexts = NIL;
209
estate->es_per_tuple_exprcontext = NULL;
211
estate->es_topPlan = NULL;
212
estate->es_evalPlanQual = NULL;
213
estate->es_evTupleNull = NULL;
214
estate->es_evTuple = NULL;
215
estate->es_useEvalPlan = false;
218
* Return the executor state structure
220
MemoryContextSwitchTo(oldcontext);
228
* Release an EState along with all remaining working storage.
230
* Note: this is not responsible for releasing non-memory resources,
231
* such as open relations or buffer pins. But it will shut down any
232
* still-active ExprContexts within the EState. That is sufficient
233
* cleanup for situations where the EState has only been used for expression
234
* evaluation, and not to run a complete Plan.
236
* This can be called in any memory context ... so long as it's not one
237
* of the ones to be freed.
241
FreeExecutorState(EState *estate)
244
* Shut down and free any remaining ExprContexts. We do this
245
* explicitly to ensure that any remaining shutdown callbacks get
246
* called (since they might need to release resources that aren't
247
* simply memory within the per-query memory context).
249
while (estate->es_exprcontexts)
252
* XXX: seems there ought to be a faster way to implement this
253
* than repeated list_delete(), no?
255
FreeExprContext((ExprContext *) linitial(estate->es_exprcontexts));
256
/* FreeExprContext removed the list link for us */
260
* Free the per-query memory context, thereby releasing all working
261
* memory, including the EState node itself.
263
MemoryContextDelete(estate->es_query_cxt);
269
* Create a context for expression evaluation within an EState.
271
* An executor run may require multiple ExprContexts (we usually make one
272
* for each Plan node, and a separate one for per-output-tuple processing
273
* such as constraint checking). Each ExprContext has its own "per-tuple"
276
* Note we make no assumption about the caller's memory context.
280
CreateExprContext(EState *estate)
282
ExprContext *econtext;
283
MemoryContext oldcontext;
285
/* Create the ExprContext node within the per-query memory context */
286
oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
288
econtext = makeNode(ExprContext);
290
/* Initialize fields of ExprContext */
291
econtext->ecxt_scantuple = NULL;
292
econtext->ecxt_innertuple = NULL;
293
econtext->ecxt_outertuple = NULL;
295
econtext->ecxt_per_query_memory = estate->es_query_cxt;
298
* Create working memory for expression evaluation in this context.
300
econtext->ecxt_per_tuple_memory =
301
AllocSetContextCreate(estate->es_query_cxt,
303
ALLOCSET_DEFAULT_MINSIZE,
304
ALLOCSET_DEFAULT_INITSIZE,
305
ALLOCSET_DEFAULT_MAXSIZE);
307
econtext->ecxt_param_exec_vals = estate->es_param_exec_vals;
308
econtext->ecxt_param_list_info = estate->es_param_list_info;
310
econtext->ecxt_aggvalues = NULL;
311
econtext->ecxt_aggnulls = NULL;
313
econtext->caseValue_datum = (Datum) 0;
314
econtext->caseValue_isNull = true;
316
econtext->domainValue_datum = (Datum) 0;
317
econtext->domainValue_isNull = true;
319
econtext->ecxt_estate = estate;
321
econtext->ecxt_callbacks = NULL;
324
* Link the ExprContext into the EState to ensure it is shut down when
325
* the EState is freed. Because we use lcons(), shutdowns will occur
326
* in reverse order of creation, which may not be essential but can't
329
estate->es_exprcontexts = lcons(econtext, estate->es_exprcontexts);
331
MemoryContextSwitchTo(oldcontext);
339
* Free an expression context, including calling any remaining
340
* shutdown callbacks.
342
* Since we free the temporary context used for expression evaluation,
343
* any previously computed pass-by-reference expression result will go away!
345
* Note we make no assumption about the caller's memory context.
349
FreeExprContext(ExprContext *econtext)
353
/* Call any registered callbacks */
354
ShutdownExprContext(econtext);
355
/* And clean up the memory used */
356
MemoryContextDelete(econtext->ecxt_per_tuple_memory);
357
/* Unlink self from owning EState */
358
estate = econtext->ecxt_estate;
359
estate->es_exprcontexts = list_delete_ptr(estate->es_exprcontexts, econtext);
360
/* And delete the ExprContext node */
367
* Reset an expression context in preparation for a rescan of its
368
* plan node. This requires calling any registered shutdown callbacks,
369
* since any partially complete set-returning-functions must be canceled.
371
* Note we make no assumption about the caller's memory context.
374
ReScanExprContext(ExprContext *econtext)
376
/* Call any registered callbacks */
377
ShutdownExprContext(econtext);
378
/* And clean up the memory used */
379
MemoryContextReset(econtext->ecxt_per_tuple_memory);
383
* Build a per-output-tuple ExprContext for an EState.
385
* This is normally invoked via GetPerTupleExprContext() macro,
389
MakePerTupleExprContext(EState *estate)
391
if (estate->es_per_tuple_exprcontext == NULL)
392
estate->es_per_tuple_exprcontext = CreateExprContext(estate);
394
return estate->es_per_tuple_exprcontext;
398
/* ----------------------------------------------------------------
399
* miscellaneous node-init support functions
401
* Note: all of these are expected to be called with CurrentMemoryContext
402
* equal to the per-query memory context.
403
* ----------------------------------------------------------------
407
* ExecAssignExprContext
409
* This initializes the ps_ExprContext field. It is only necessary
410
* to do this for nodes which use ExecQual or ExecProject
411
* because those routines require an econtext. Other nodes that
412
* don't have to evaluate expressions don't need to do this.
416
ExecAssignExprContext(EState *estate, PlanState *planstate)
418
planstate->ps_ExprContext = CreateExprContext(estate);
422
* ExecAssignResultType
426
ExecAssignResultType(PlanState *planstate,
427
TupleDesc tupDesc, bool shouldFree)
429
TupleTableSlot *slot = planstate->ps_ResultTupleSlot;
431
ExecSetSlotDescriptor(slot, tupDesc, shouldFree);
435
* ExecAssignResultTypeFromOuterPlan
439
ExecAssignResultTypeFromOuterPlan(PlanState *planstate)
441
PlanState *outerPlan;
444
outerPlan = outerPlanState(planstate);
445
tupDesc = ExecGetResultType(outerPlan);
447
ExecAssignResultType(planstate, tupDesc, false);
451
* ExecAssignResultTypeFromTL
455
ExecAssignResultTypeFromTL(PlanState *planstate)
460
if (ExecContextForcesOids(planstate, &hasoid))
462
/* context forces OID choice; hasoid is now set correctly */
466
/* given free choice, don't leave space for OIDs in result tuples */
471
* ExecTypeFromTL needs the parse-time representation of the tlist,
472
* not a list of ExprStates. This is good because some plan nodes
473
* don't bother to set up planstate->targetlist ...
475
tupDesc = ExecTypeFromTL(planstate->plan->targetlist, hasoid);
476
ExecAssignResultType(planstate, tupDesc, true);
484
ExecGetResultType(PlanState *planstate)
486
TupleTableSlot *slot = planstate->ps_ResultTupleSlot;
488
return slot->ttc_tupleDescriptor;
492
* ExecBuildProjectionInfo
494
* Build a ProjectionInfo node for evaluating the given tlist in the given
495
* econtext, and storing the result into the tuple slot. (Caller must have
496
* ensured that tuple slot has a descriptor matching the tlist!) Note that
497
* the given tlist should be a list of ExprState nodes, not Expr nodes.
501
ExecBuildProjectionInfo(List *targetList,
502
ExprContext *econtext,
503
TupleTableSlot *slot)
505
ProjectionInfo *projInfo = makeNode(ProjectionInfo);
508
len = ExecTargetListLength(targetList);
510
projInfo->pi_targetlist = targetList;
511
projInfo->pi_exprContext = econtext;
512
projInfo->pi_slot = slot;
515
projInfo->pi_tupValues = (Datum *) palloc(len * sizeof(Datum));
516
projInfo->pi_tupNulls = (char *) palloc(len * sizeof(char));
517
projInfo->pi_itemIsDone = (ExprDoneCond *) palloc(len * sizeof(ExprDoneCond));
524
* ExecAssignProjectionInfo
526
* forms the projection information from the node's targetlist
530
ExecAssignProjectionInfo(PlanState *planstate)
532
planstate->ps_ProjInfo =
533
ExecBuildProjectionInfo(planstate->targetlist,
534
planstate->ps_ExprContext,
535
planstate->ps_ResultTupleSlot);
540
* ExecFreeExprContext
542
* A plan node's ExprContext should be freed explicitly during ExecEndNode
543
* because there may be shutdown callbacks to call. (Other resources made
544
* by the above routines, such as projection info, don't need to be freed
545
* explicitly because they're just memory in the per-query memory context.)
549
ExecFreeExprContext(PlanState *planstate)
551
ExprContext *econtext;
554
* get expression context. if NULL then this node has none so we just
557
econtext = planstate->ps_ExprContext;
558
if (econtext == NULL)
561
FreeExprContext(econtext);
563
planstate->ps_ExprContext = NULL;
566
/* ----------------------------------------------------------------
567
* the following scan type support functions are for
568
* those nodes which are stubborn and return tuples in
569
* their Scan tuple slot instead of their Result tuple
570
* slot.. luck fur us, these nodes do not do projections
571
* so we don't have to worry about getting the ProjectionInfo
572
* right for them... -cim 6/3/91
573
* ----------------------------------------------------------------
581
ExecGetScanType(ScanState *scanstate)
583
TupleTableSlot *slot = scanstate->ss_ScanTupleSlot;
585
return slot->ttc_tupleDescriptor;
593
ExecAssignScanType(ScanState *scanstate,
594
TupleDesc tupDesc, bool shouldFree)
596
TupleTableSlot *slot = scanstate->ss_ScanTupleSlot;
598
ExecSetSlotDescriptor(slot, tupDesc, shouldFree);
602
* ExecAssignScanTypeFromOuterPlan
606
ExecAssignScanTypeFromOuterPlan(ScanState *scanstate)
608
PlanState *outerPlan;
611
outerPlan = outerPlanState(scanstate);
612
tupDesc = ExecGetResultType(outerPlan);
614
ExecAssignScanType(scanstate, tupDesc, false);
618
/* ----------------------------------------------------------------
619
* ExecInsertIndexTuples support
620
* ----------------------------------------------------------------
623
/* ----------------------------------------------------------------
626
* Find the indices associated with a result relation, open them,
627
* and save information about them in the result ResultRelInfo.
629
* At entry, caller has already opened and locked
630
* resultRelInfo->ri_RelationDesc.
632
* This used to be horribly ugly code, and slow too because it
633
* did a sequential scan of pg_index. Now we rely on the relcache
634
* to cache a list of the OIDs of the indices associated with any
635
* specific relation, and we use the pg_index syscache to get the
636
* entries we need from pg_index.
637
* ----------------------------------------------------------------
640
ExecOpenIndices(ResultRelInfo *resultRelInfo)
642
Relation resultRelation = resultRelInfo->ri_RelationDesc;
647
RelationPtr relationDescs;
648
IndexInfo **indexInfoArray;
650
resultRelInfo->ri_NumIndices = 0;
652
/* fast path if no indexes */
653
if (!RelationGetForm(resultRelation)->relhasindex)
657
* Get cached list of index OIDs
659
indexoidlist = RelationGetIndexList(resultRelation);
660
len = list_length(indexoidlist);
665
* allocate space for result arrays
667
relationDescs = (RelationPtr) palloc(len * sizeof(Relation));
668
indexInfoArray = (IndexInfo **) palloc(len * sizeof(IndexInfo *));
670
resultRelInfo->ri_NumIndices = len;
671
resultRelInfo->ri_IndexRelationDescs = relationDescs;
672
resultRelInfo->ri_IndexRelationInfo = indexInfoArray;
675
* For each index, open the index relation and save pg_index info.
678
foreach(l, indexoidlist)
680
Oid indexOid = lfirst_oid(l);
685
* Open and lock the index relation
687
* If the index AM supports concurrent updates, obtain RowExclusiveLock
688
* to signify that we are updating the index. This locks out only
689
* operations that need exclusive access, such as relocating the index
690
* to a new tablespace.
692
* If the index AM is not safe for concurrent updates, obtain an
693
* exclusive lock on the index to lock out other updaters as well
694
* as readers (index_beginscan places AccessShareLock).
696
* If there are multiple not-concurrent-safe indexes, all backends
697
* must lock the indexes in the same order or we will get deadlocks
698
* here. This is guaranteed by RelationGetIndexList(), which promises
699
* to return the index list in OID order.
701
* The locks will be released in ExecCloseIndices.
703
indexDesc = index_open(indexOid);
705
if (indexDesc->rd_am->amconcurrent)
706
LockRelation(indexDesc, RowExclusiveLock);
708
LockRelation(indexDesc, AccessExclusiveLock);
710
/* extract index key information from the index's pg_index info */
711
ii = BuildIndexInfo(indexDesc);
713
relationDescs[i] = indexDesc;
714
indexInfoArray[i] = ii;
718
list_free(indexoidlist);
721
/* ----------------------------------------------------------------
724
* Close the index relations stored in resultRelInfo
725
* ----------------------------------------------------------------
728
ExecCloseIndices(ResultRelInfo *resultRelInfo)
732
RelationPtr indexDescs;
734
numIndices = resultRelInfo->ri_NumIndices;
735
indexDescs = resultRelInfo->ri_IndexRelationDescs;
737
for (i = 0; i < numIndices; i++)
739
if (indexDescs[i] == NULL)
740
continue; /* shouldn't happen? */
742
/* Drop lock acquired by ExecOpenIndices */
743
if (indexDescs[i]->rd_am->amconcurrent)
744
UnlockRelation(indexDescs[i], RowExclusiveLock);
746
UnlockRelation(indexDescs[i], AccessExclusiveLock);
748
index_close(indexDescs[i]);
752
* XXX should free indexInfo array here too? Currently we assume that
753
* such stuff will be cleaned up automatically in FreeExecutorState.
757
/* ----------------------------------------------------------------
758
* ExecInsertIndexTuples
760
* This routine takes care of inserting index tuples
761
* into all the relations indexing the result relation
762
* when a heap tuple is inserted into the result relation.
763
* Much of this code should be moved into the genam
764
* stuff as it only exists here because the genam stuff
765
* doesn't provide the functionality needed by the
766
* executor.. -cim 9/27/89
767
* ----------------------------------------------------------------
770
ExecInsertIndexTuples(TupleTableSlot *slot,
776
ResultRelInfo *resultRelInfo;
779
RelationPtr relationDescs;
780
Relation heapRelation;
781
TupleDesc heapDescriptor;
782
IndexInfo **indexInfoArray;
783
ExprContext *econtext;
784
Datum datum[INDEX_MAX_KEYS];
785
char nullv[INDEX_MAX_KEYS];
787
heapTuple = slot->val;
790
* Get information from the result relation info structure.
792
resultRelInfo = estate->es_result_relation_info;
793
numIndices = resultRelInfo->ri_NumIndices;
794
relationDescs = resultRelInfo->ri_IndexRelationDescs;
795
indexInfoArray = resultRelInfo->ri_IndexRelationInfo;
796
heapRelation = resultRelInfo->ri_RelationDesc;
797
heapDescriptor = RelationGetDescr(heapRelation);
800
* We will use the EState's per-tuple context for evaluating
801
* predicates and index expressions (creating it if it's not already
804
econtext = GetPerTupleExprContext(estate);
806
/* Arrange for econtext's scan tuple to be the tuple under test */
807
econtext->ecxt_scantuple = slot;
810
* for each index, form and insert the index tuple
812
for (i = 0; i < numIndices; i++)
814
IndexInfo *indexInfo;
815
InsertIndexResult result;
817
if (relationDescs[i] == NULL)
820
indexInfo = indexInfoArray[i];
822
/* Check for partial index */
823
if (indexInfo->ii_Predicate != NIL)
828
* If predicate state not set up yet, create it (in the
829
* estate's per-query context)
831
predicate = indexInfo->ii_PredicateState;
832
if (predicate == NIL)
835
ExecPrepareExpr((Expr *) indexInfo->ii_Predicate,
837
indexInfo->ii_PredicateState = predicate;
840
/* Skip this index-update if the predicate isn't satisfied */
841
if (!ExecQual(predicate, econtext, false))
846
* FormIndexDatum fills in its datum and null parameters with
847
* attribute information taken from the given heap tuple. It also
848
* computes any expressions needed.
850
FormIndexDatum(indexInfo,
858
* The index AM does the rest. Note we suppress unique-index
859
* checks if we are being called from VACUUM, since VACUUM may
860
* need to move dead tuples that have the same keys as live ones.
862
result = index_insert(relationDescs[i], /* index relation */
863
datum, /* array of heaptuple Datums */
864
nullv, /* info on nulls */
865
&(heapTuple->t_self), /* tid of heap tuple */
867
relationDescs[i]->rd_index->indisunique && !is_vacuum);
870
* keep track of index inserts for debugging
880
* UpdateChangedParamSet
881
* Add changed parameters to a plan node's chgParam set
884
UpdateChangedParamSet(PlanState *node, Bitmapset *newchg)
889
* The plan node only depends on params listed in its allParam set.
890
* Don't include anything else into its chgParam set.
892
parmset = bms_intersect(node->plan->allParam, newchg);
895
* Keep node->chgParam == NULL if there's not actually any members;
896
* this allows the simplest possible tests in executor node files.
898
if (!bms_is_empty(parmset))
899
node->chgParam = bms_join(node->chgParam, parmset);
905
* Register a shutdown callback in an ExprContext.
907
* Shutdown callbacks will be called (in reverse order of registration)
908
* when the ExprContext is deleted or rescanned. This provides a hook
909
* for functions called in the context to do any cleanup needed --- it's
910
* particularly useful for functions returning sets. Note that the
911
* callback will *not* be called in the event that execution is aborted
915
RegisterExprContextCallback(ExprContext *econtext,
916
ExprContextCallbackFunction function,
919
ExprContext_CB *ecxt_callback;
921
/* Save the info in appropriate memory context */
922
ecxt_callback = (ExprContext_CB *)
923
MemoryContextAlloc(econtext->ecxt_per_query_memory,
924
sizeof(ExprContext_CB));
926
ecxt_callback->function = function;
927
ecxt_callback->arg = arg;
929
/* link to front of list for appropriate execution order */
930
ecxt_callback->next = econtext->ecxt_callbacks;
931
econtext->ecxt_callbacks = ecxt_callback;
935
* Deregister a shutdown callback in an ExprContext.
937
* Any list entries matching the function and arg will be removed.
938
* This can be used if it's no longer necessary to call the callback.
941
UnregisterExprContextCallback(ExprContext *econtext,
942
ExprContextCallbackFunction function,
945
ExprContext_CB **prev_callback;
946
ExprContext_CB *ecxt_callback;
948
prev_callback = &econtext->ecxt_callbacks;
950
while ((ecxt_callback = *prev_callback) != NULL)
952
if (ecxt_callback->function == function && ecxt_callback->arg == arg)
954
*prev_callback = ecxt_callback->next;
955
pfree(ecxt_callback);
958
prev_callback = &ecxt_callback->next;
963
* Call all the shutdown callbacks registered in an ExprContext.
965
* The callback list is emptied (important in case this is only a rescan
966
* reset, and not deletion of the ExprContext).
969
ShutdownExprContext(ExprContext *econtext)
971
ExprContext_CB *ecxt_callback;
972
MemoryContext oldcontext;
974
/* Fast path in normal case where there's nothing to do. */
975
if (econtext->ecxt_callbacks == NULL)
979
* Call the callbacks in econtext's per-tuple context. This ensures
980
* that any memory they might leak will get cleaned up.
982
oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
985
* Call each callback function in reverse registration order.
987
while ((ecxt_callback = econtext->ecxt_callbacks) != NULL)
989
econtext->ecxt_callbacks = ecxt_callback->next;
990
(*ecxt_callback->function) (ecxt_callback->arg);
991
pfree(ecxt_callback);
994
MemoryContextSwitchTo(oldcontext);