1 /*-------------------------------------------------------------------------
4 * miscellaneous executor utility routines
6 * Portions Copyright (c) 1996-2004, 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.114 2004/08/29 05:06:42 momjian 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 = SnapshotAny; /* means 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, if necessary) the index relation
687 * If the index AM is not safe for concurrent updates, obtain an
688 * exclusive lock on the index to lock out other updaters as well
689 * as readers (index_beginscan places AccessShareLock). We will
690 * release this lock in ExecCloseIndices.
692 * If the index AM supports concurrent updates, we obtain no lock
693 * here at all, which is a tad weird, but safe since any critical
694 * operation on the index (like deleting it) will acquire
695 * exclusive lock on the parent table. Perhaps someday we should
696 * acquire RowExclusiveLock on the index here?
698 * If there are multiple not-concurrent-safe indexes, all backends
699 * must lock the indexes in the same order or we will get
700 * deadlocks here during concurrent updates. This is guaranteed
701 * by RelationGetIndexList(), which promises to return the index
704 indexDesc = index_open(indexOid);
706 if (!indexDesc->rd_am->amconcurrent)
707 LockRelation(indexDesc, AccessExclusiveLock);
709 /* extract index key information from the index's pg_index info */
710 ii = BuildIndexInfo(indexDesc);
712 relationDescs[i] = indexDesc;
713 indexInfoArray[i] = ii;
717 list_free(indexoidlist);
720 /* ----------------------------------------------------------------
723 * Close the index relations stored in resultRelInfo
724 * ----------------------------------------------------------------
727 ExecCloseIndices(ResultRelInfo *resultRelInfo)
731 RelationPtr indexDescs;
733 numIndices = resultRelInfo->ri_NumIndices;
734 indexDescs = resultRelInfo->ri_IndexRelationDescs;
736 for (i = 0; i < numIndices; i++)
738 if (indexDescs[i] == NULL)
741 /* Drop lock, if one was acquired by ExecOpenIndices */
742 if (!indexDescs[i]->rd_am->amconcurrent)
743 UnlockRelation(indexDescs[i], AccessExclusiveLock);
745 index_close(indexDescs[i]);
749 * XXX should free indexInfo array here too? Currently we assume that
750 * such stuff will be cleaned up automatically in FreeExecutorState.
754 /* ----------------------------------------------------------------
755 * ExecInsertIndexTuples
757 * This routine takes care of inserting index tuples
758 * into all the relations indexing the result relation
759 * when a heap tuple is inserted into the result relation.
760 * Much of this code should be moved into the genam
761 * stuff as it only exists here because the genam stuff
762 * doesn't provide the functionality needed by the
763 * executor.. -cim 9/27/89
764 * ----------------------------------------------------------------
767 ExecInsertIndexTuples(TupleTableSlot *slot,
773 ResultRelInfo *resultRelInfo;
776 RelationPtr relationDescs;
777 Relation heapRelation;
778 TupleDesc heapDescriptor;
779 IndexInfo **indexInfoArray;
780 ExprContext *econtext;
781 Datum datum[INDEX_MAX_KEYS];
782 char nullv[INDEX_MAX_KEYS];
784 heapTuple = slot->val;
787 * Get information from the result relation info structure.
789 resultRelInfo = estate->es_result_relation_info;
790 numIndices = resultRelInfo->ri_NumIndices;
791 relationDescs = resultRelInfo->ri_IndexRelationDescs;
792 indexInfoArray = resultRelInfo->ri_IndexRelationInfo;
793 heapRelation = resultRelInfo->ri_RelationDesc;
794 heapDescriptor = RelationGetDescr(heapRelation);
797 * We will use the EState's per-tuple context for evaluating
798 * predicates and index expressions (creating it if it's not already
801 econtext = GetPerTupleExprContext(estate);
803 /* Arrange for econtext's scan tuple to be the tuple under test */
804 econtext->ecxt_scantuple = slot;
807 * for each index, form and insert the index tuple
809 for (i = 0; i < numIndices; i++)
811 IndexInfo *indexInfo;
812 InsertIndexResult result;
814 if (relationDescs[i] == NULL)
817 indexInfo = indexInfoArray[i];
819 /* Check for partial index */
820 if (indexInfo->ii_Predicate != NIL)
825 * If predicate state not set up yet, create it (in the
826 * estate's per-query context)
828 predicate = indexInfo->ii_PredicateState;
829 if (predicate == NIL)
832 ExecPrepareExpr((Expr *) indexInfo->ii_Predicate,
834 indexInfo->ii_PredicateState = predicate;
837 /* Skip this index-update if the predicate isn't satisfied */
838 if (!ExecQual(predicate, econtext, false))
843 * FormIndexDatum fills in its datum and null parameters with
844 * attribute information taken from the given heap tuple. It also
845 * computes any expressions needed.
847 FormIndexDatum(indexInfo,
855 * The index AM does the rest. Note we suppress unique-index
856 * checks if we are being called from VACUUM, since VACUUM may
857 * need to move dead tuples that have the same keys as live ones.
859 result = index_insert(relationDescs[i], /* index relation */
860 datum, /* array of heaptuple Datums */
861 nullv, /* info on nulls */
862 &(heapTuple->t_self), /* tid of heap tuple */
864 relationDescs[i]->rd_index->indisunique && !is_vacuum);
867 * keep track of index inserts for debugging
877 * UpdateChangedParamSet
878 * Add changed parameters to a plan node's chgParam set
881 UpdateChangedParamSet(PlanState *node, Bitmapset *newchg)
886 * The plan node only depends on params listed in its allParam set.
887 * Don't include anything else into its chgParam set.
889 parmset = bms_intersect(node->plan->allParam, newchg);
892 * Keep node->chgParam == NULL if there's not actually any members;
893 * this allows the simplest possible tests in executor node files.
895 if (!bms_is_empty(parmset))
896 node->chgParam = bms_join(node->chgParam, parmset);
902 * Register a shutdown callback in an ExprContext.
904 * Shutdown callbacks will be called (in reverse order of registration)
905 * when the ExprContext is deleted or rescanned. This provides a hook
906 * for functions called in the context to do any cleanup needed --- it's
907 * particularly useful for functions returning sets. Note that the
908 * callback will *not* be called in the event that execution is aborted
912 RegisterExprContextCallback(ExprContext *econtext,
913 ExprContextCallbackFunction function,
916 ExprContext_CB *ecxt_callback;
918 /* Save the info in appropriate memory context */
919 ecxt_callback = (ExprContext_CB *)
920 MemoryContextAlloc(econtext->ecxt_per_query_memory,
921 sizeof(ExprContext_CB));
923 ecxt_callback->function = function;
924 ecxt_callback->arg = arg;
926 /* link to front of list for appropriate execution order */
927 ecxt_callback->next = econtext->ecxt_callbacks;
928 econtext->ecxt_callbacks = ecxt_callback;
932 * Deregister a shutdown callback in an ExprContext.
934 * Any list entries matching the function and arg will be removed.
935 * This can be used if it's no longer necessary to call the callback.
938 UnregisterExprContextCallback(ExprContext *econtext,
939 ExprContextCallbackFunction function,
942 ExprContext_CB **prev_callback;
943 ExprContext_CB *ecxt_callback;
945 prev_callback = &econtext->ecxt_callbacks;
947 while ((ecxt_callback = *prev_callback) != NULL)
949 if (ecxt_callback->function == function && ecxt_callback->arg == arg)
951 *prev_callback = ecxt_callback->next;
952 pfree(ecxt_callback);
955 prev_callback = &ecxt_callback->next;
960 * Call all the shutdown callbacks registered in an ExprContext.
962 * The callback list is emptied (important in case this is only a rescan
963 * reset, and not deletion of the ExprContext).
966 ShutdownExprContext(ExprContext *econtext)
968 ExprContext_CB *ecxt_callback;
969 MemoryContext oldcontext;
971 /* Fast path in normal case where there's nothing to do. */
972 if (econtext->ecxt_callbacks == NULL)
976 * Call the callbacks in econtext's per-tuple context. This ensures
977 * that any memory they might leak will get cleaned up.
979 oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
982 * Call each callback function in reverse registration order.
984 while ((ecxt_callback = econtext->ecxt_callbacks) != NULL)
986 econtext->ecxt_callbacks = ecxt_callback->next;
987 (*ecxt_callback->function) (ecxt_callback->arg);
988 pfree(ecxt_callback);
991 MemoryContextSwitchTo(oldcontext);