OSDN Git Service

Phase 3 of read-only-plans project: ExecInitExpr now builds expression
[pg-rex/syncrep.git] / src / backend / executor / execUtils.c
1 /*-------------------------------------------------------------------------
2  *
3  * execUtils.c
4  *        miscellaneous executor utility routines
5  *
6  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.92 2002/12/13 19:45:52 tgl Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15 /*
16  * INTERFACE ROUTINES
17  *              ExecAssignExprContext   Common code for plan node init routines.
18  *
19  *              ExecOpenIndices                 \
20  *              ExecCloseIndices                 | referenced by InitPlan, EndPlan,
21  *              ExecInsertIndexTuples   /  ExecInsert, ExecUpdate
22  *
23  *              RegisterExprContextCallback    Register function shutdown callback
24  *              UnregisterExprContextCallback  Deregister function shutdown callback
25  *
26  *       NOTES
27  *              This file has traditionally been the place to stick misc.
28  *              executor support stuff that doesn't really go anyplace else.
29  *
30  */
31
32 #include "postgres.h"
33
34 #include "access/genam.h"
35 #include "access/heapam.h"
36 #include "catalog/catname.h"
37 #include "catalog/index.h"
38 #include "catalog/catalog.h"
39 #include "catalog/pg_index.h"
40 #include "executor/execdebug.h"
41 #include "miscadmin.h"
42 #include "utils/builtins.h"
43 #include "utils/fmgroids.h"
44 #include "utils/memutils.h"
45 #include "utils/relcache.h"
46 #include "utils/syscache.h"
47
48
49 /* ----------------------------------------------------------------
50  *              global counters for number of tuples processed, retrieved,
51  *              appended, replaced, deleted.
52  * ----------------------------------------------------------------
53  */
54 int                     NTupleProcessed;
55 int                     NTupleRetrieved;
56 int                     NTupleReplaced;
57 int                     NTupleAppended;
58 int                     NTupleDeleted;
59 int                     NIndexTupleInserted;
60 extern int      NIndexTupleProcessed;           /* have to be defined in the
61                                                                                  * access method level so that the
62                                                                                  * cinterface.a will link ok. */
63
64
65 static void ShutdownExprContext(ExprContext *econtext);
66
67 /* ----------------------------------------------------------------
68  *                                              statistic functions
69  * ----------------------------------------------------------------
70  */
71
72 /* ----------------------------------------------------------------
73  *              ResetTupleCount
74  * ----------------------------------------------------------------
75  */
76 #ifdef NOT_USED
77 void
78 ResetTupleCount(void)
79 {
80         NTupleProcessed = 0;
81         NTupleRetrieved = 0;
82         NTupleAppended = 0;
83         NTupleDeleted = 0;
84         NTupleReplaced = 0;
85         NIndexTupleProcessed = 0;
86 }
87 #endif
88
89 /* ----------------------------------------------------------------
90  *              PrintTupleCount
91  * ----------------------------------------------------------------
92  */
93 #ifdef NOT_USED
94 void
95 DisplayTupleCount(FILE *statfp)
96 {
97         if (NTupleProcessed > 0)
98                 fprintf(statfp, "!\t%d tuple%s processed, ", NTupleProcessed,
99                                 (NTupleProcessed == 1) ? "" : "s");
100         else
101         {
102                 fprintf(statfp, "!\tno tuples processed.\n");
103                 return;
104         }
105         if (NIndexTupleProcessed > 0)
106                 fprintf(statfp, "%d indextuple%s processed, ", NIndexTupleProcessed,
107                                 (NIndexTupleProcessed == 1) ? "" : "s");
108         if (NIndexTupleInserted > 0)
109                 fprintf(statfp, "%d indextuple%s inserted, ", NIndexTupleInserted,
110                                 (NIndexTupleInserted == 1) ? "" : "s");
111         if (NTupleRetrieved > 0)
112                 fprintf(statfp, "%d tuple%s retrieved. ", NTupleRetrieved,
113                                 (NTupleRetrieved == 1) ? "" : "s");
114         if (NTupleAppended > 0)
115                 fprintf(statfp, "%d tuple%s appended. ", NTupleAppended,
116                                 (NTupleAppended == 1) ? "" : "s");
117         if (NTupleDeleted > 0)
118                 fprintf(statfp, "%d tuple%s deleted. ", NTupleDeleted,
119                                 (NTupleDeleted == 1) ? "" : "s");
120         if (NTupleReplaced > 0)
121                 fprintf(statfp, "%d tuple%s replaced. ", NTupleReplaced,
122                                 (NTupleReplaced == 1) ? "" : "s");
123         fprintf(statfp, "\n");
124 }
125 #endif
126
127 /* ----------------------------------------------------------------
128  *                               miscellaneous node-init support functions
129  * ----------------------------------------------------------------
130  */
131
132 /* ----------------
133  *              ExecAssignExprContext
134  *
135  *              This initializes the ExprContext field.  It is only necessary
136  *              to do this for nodes which use ExecQual or ExecProject
137  *              because those routines depend on econtext.      Other nodes that
138  *              don't have to evaluate expressions don't need to do this.
139  *
140  * Note: we assume CurrentMemoryContext is the correct per-query context.
141  * This should be true during plan node initialization.
142  * ----------------
143  */
144 void
145 ExecAssignExprContext(EState *estate, PlanState *planstate)
146 {
147         ExprContext *econtext = makeNode(ExprContext);
148
149         econtext->ecxt_scantuple = NULL;
150         econtext->ecxt_innertuple = NULL;
151         econtext->ecxt_outertuple = NULL;
152         econtext->ecxt_per_query_memory = CurrentMemoryContext;
153
154         /*
155          * Create working memory for expression evaluation in this context.
156          */
157         econtext->ecxt_per_tuple_memory =
158                 AllocSetContextCreate(CurrentMemoryContext,
159                                                           "PlanExprContext",
160                                                           ALLOCSET_DEFAULT_MINSIZE,
161                                                           ALLOCSET_DEFAULT_INITSIZE,
162                                                           ALLOCSET_DEFAULT_MAXSIZE);
163         econtext->ecxt_param_exec_vals = estate->es_param_exec_vals;
164         econtext->ecxt_param_list_info = estate->es_param_list_info;
165         econtext->ecxt_aggvalues = NULL;
166         econtext->ecxt_aggnulls = NULL;
167         econtext->ecxt_callbacks = NULL;
168
169         planstate->ps_ExprContext = econtext;
170 }
171
172 /* ----------------
173  *              MakeExprContext
174  *
175  *              Build an expression context for use outside normal plan-node cases.
176  *              A fake scan-tuple slot can be supplied (pass NULL if not needed).
177  *              A memory context sufficiently long-lived to use as fcache context
178  *              must be supplied as well.
179  * ----------------
180  */
181 ExprContext *
182 MakeExprContext(TupleTableSlot *slot,
183                                 MemoryContext queryContext)
184 {
185         ExprContext *econtext = makeNode(ExprContext);
186
187         econtext->ecxt_scantuple = slot;
188         econtext->ecxt_innertuple = NULL;
189         econtext->ecxt_outertuple = NULL;
190         econtext->ecxt_per_query_memory = queryContext;
191
192         /*
193          * We make the temporary context a child of current working context,
194          * not of the specified queryContext.  This seems reasonable but I'm
195          * not totally sure about it...
196          *
197          * Expression contexts made via this routine typically don't live long
198          * enough to get reset, so specify a minsize of 0.      That avoids
199          * alloc'ing any memory in the common case where expr eval doesn't use
200          * any.
201          */
202         econtext->ecxt_per_tuple_memory =
203                 AllocSetContextCreate(CurrentMemoryContext,
204                                                           "TempExprContext",
205                                                           0,
206                                                           ALLOCSET_DEFAULT_INITSIZE,
207                                                           ALLOCSET_DEFAULT_MAXSIZE);
208         econtext->ecxt_param_exec_vals = NULL;
209         econtext->ecxt_param_list_info = NULL;
210         econtext->ecxt_aggvalues = NULL;
211         econtext->ecxt_aggnulls = NULL;
212         econtext->ecxt_callbacks = NULL;
213
214         return econtext;
215 }
216
217 /*
218  * Free an ExprContext made by MakeExprContext, including the temporary
219  * context used for expression evaluation.      Note this will cause any
220  * pass-by-reference expression result to go away!
221  */
222 void
223 FreeExprContext(ExprContext *econtext)
224 {
225         /* Call any registered callbacks */
226         ShutdownExprContext(econtext);
227         /* And clean up the memory used */
228         MemoryContextDelete(econtext->ecxt_per_tuple_memory);
229         pfree(econtext);
230 }
231
232 /*
233  * Build a per-output-tuple ExprContext for an EState.
234  *
235  * This is normally invoked via GetPerTupleExprContext() macro.
236  */
237 ExprContext *
238 MakePerTupleExprContext(EState *estate)
239 {
240         if (estate->es_per_tuple_exprcontext == NULL)
241         {
242                 MemoryContext oldContext;
243
244                 oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
245                 estate->es_per_tuple_exprcontext =
246                         MakeExprContext(NULL, estate->es_query_cxt);
247                 MemoryContextSwitchTo(oldContext);
248         }
249         return estate->es_per_tuple_exprcontext;
250 }
251
252 /* ----------------------------------------------------------------
253  *              Result slot tuple type and ProjectionInfo support
254  * ----------------------------------------------------------------
255  */
256
257 /* ----------------
258  *              ExecAssignResultType
259  * ----------------
260  */
261 void
262 ExecAssignResultType(PlanState *planstate,
263                                          TupleDesc tupDesc, bool shouldFree)
264 {
265         TupleTableSlot *slot = planstate->ps_ResultTupleSlot;
266
267         ExecSetSlotDescriptor(slot, tupDesc, shouldFree);
268 }
269
270 /* ----------------
271  *              ExecAssignResultTypeFromOuterPlan
272  * ----------------
273  */
274 void
275 ExecAssignResultTypeFromOuterPlan(PlanState *planstate)
276 {
277         PlanState  *outerPlan;
278         TupleDesc       tupDesc;
279
280         outerPlan = outerPlanState(planstate);
281         tupDesc = ExecGetTupType(outerPlan);
282
283         ExecAssignResultType(planstate, tupDesc, false);
284 }
285
286 /* ----------------
287  *              ExecAssignResultTypeFromTL
288  * ----------------
289  */
290 void
291 ExecAssignResultTypeFromTL(PlanState *planstate)
292 {
293         ResultRelInfo *ri;
294         bool            hasoid = false;
295         TupleDesc       tupDesc;
296
297         /*
298          * This is pretty grotty: we need to ensure that result tuples have
299          * space for an OID iff they are going to be stored into a relation
300          * that has OIDs.  We assume that estate->es_result_relation_info is
301          * already set up to describe the target relation.      One reason this is
302          * ugly is that all plan nodes in the plan tree will emit tuples with
303          * space for an OID, though we really only need the topmost plan to do
304          * so.
305          *
306          * It would be better to have InitPlan adjust the topmost plan node's
307          * output descriptor after plan tree initialization.  However, that
308          * doesn't quite work because in an UPDATE that spans an inheritance
309          * tree, some of the target relations may have OIDs and some not. We
310          * have to make the decision on a per-relation basis as we initialize
311          * each of the child plans of the topmost Append plan.  So, this is
312          * ugly but it works, for now ...
313          */
314         ri = planstate->state->es_result_relation_info;
315         if (ri != NULL)
316         {
317                 Relation        rel = ri->ri_RelationDesc;
318
319                 if (rel != NULL)
320                         hasoid = rel->rd_rel->relhasoids;
321         }
322
323         /*
324          * ExecTypeFromTL needs the parse-time representation of the tlist, not
325          * a list of ExprStates.  This is good because some plan nodes don't
326          * bother to set up planstate->targetlist ...
327          */
328         tupDesc = ExecTypeFromTL(planstate->plan->targetlist, hasoid);
329         ExecAssignResultType(planstate, tupDesc, true);
330 }
331
332 /* ----------------
333  *              ExecGetResultType
334  * ----------------
335  */
336 TupleDesc
337 ExecGetResultType(PlanState *planstate)
338 {
339         TupleTableSlot *slot = planstate->ps_ResultTupleSlot;
340
341         return slot->ttc_tupleDescriptor;
342 }
343
344 /* ----------------
345  *              ExecAssignProjectionInfo
346                   forms the projection information from the node's targetlist
347  * ----------------
348  */
349 void
350 ExecAssignProjectionInfo(PlanState *planstate)
351 {
352         ProjectionInfo *projInfo;
353         List       *targetList;
354         int                     len;
355
356         targetList = planstate->targetlist;
357         len = ExecTargetListLength(targetList);
358
359         projInfo = makeNode(ProjectionInfo);
360         projInfo->pi_targetlist = targetList;
361         projInfo->pi_len = len;
362         projInfo->pi_tupValue = (len <= 0) ? NULL : (Datum *) palloc(sizeof(Datum) * len);
363         projInfo->pi_exprContext = planstate->ps_ExprContext;
364         projInfo->pi_slot = planstate->ps_ResultTupleSlot;
365
366         planstate->ps_ProjInfo = projInfo;
367 }
368
369
370 /* ----------------
371  *              ExecFreeProjectionInfo
372  * ----------------
373  */
374 void
375 ExecFreeProjectionInfo(PlanState *planstate)
376 {
377         ProjectionInfo *projInfo;
378
379         /*
380          * get projection info.  if NULL then this node has none so we just
381          * return.
382          */
383         projInfo = planstate->ps_ProjInfo;
384         if (projInfo == NULL)
385                 return;
386
387         /*
388          * clean up memory used.
389          */
390         if (projInfo->pi_tupValue != NULL)
391                 pfree(projInfo->pi_tupValue);
392
393         pfree(projInfo);
394         planstate->ps_ProjInfo = NULL;
395 }
396
397 /* ----------------
398  *              ExecFreeExprContext
399  * ----------------
400  */
401 void
402 ExecFreeExprContext(PlanState *planstate)
403 {
404         ExprContext *econtext;
405
406         /*
407          * get expression context.      if NULL then this node has none so we just
408          * return.
409          */
410         econtext = planstate->ps_ExprContext;
411         if (econtext == NULL)
412                 return;
413
414         /*
415          * clean up any registered callbacks
416          */
417         ShutdownExprContext(econtext);
418
419         /*
420          * clean up memory used.
421          */
422         MemoryContextDelete(econtext->ecxt_per_tuple_memory);
423         pfree(econtext);
424         planstate->ps_ExprContext = NULL;
425 }
426
427 /* ----------------------------------------------------------------
428  *              the following scan type support functions are for
429  *              those nodes which are stubborn and return tuples in
430  *              their Scan tuple slot instead of their Result tuple
431  *              slot..  luck fur us, these nodes do not do projections
432  *              so we don't have to worry about getting the ProjectionInfo
433  *              right for them...  -cim 6/3/91
434  * ----------------------------------------------------------------
435  */
436
437 /* ----------------
438  *              ExecGetScanType
439  * ----------------
440  */
441 TupleDesc
442 ExecGetScanType(ScanState *scanstate)
443 {
444         TupleTableSlot *slot = scanstate->ss_ScanTupleSlot;
445
446         return slot->ttc_tupleDescriptor;
447 }
448
449 /* ----------------
450  *              ExecAssignScanType
451  * ----------------
452  */
453 void
454 ExecAssignScanType(ScanState *scanstate,
455                                    TupleDesc tupDesc, bool shouldFree)
456 {
457         TupleTableSlot *slot = scanstate->ss_ScanTupleSlot;
458
459         ExecSetSlotDescriptor(slot, tupDesc, shouldFree);
460 }
461
462 /* ----------------
463  *              ExecAssignScanTypeFromOuterPlan
464  * ----------------
465  */
466 void
467 ExecAssignScanTypeFromOuterPlan(ScanState *scanstate)
468 {
469         PlanState  *outerPlan;
470         TupleDesc       tupDesc;
471
472         outerPlan = outerPlanState(scanstate);
473         tupDesc = ExecGetTupType(outerPlan);
474
475         ExecAssignScanType(scanstate, tupDesc, false);
476 }
477
478
479 /* ----------------------------------------------------------------
480  *                                ExecInsertIndexTuples support
481  * ----------------------------------------------------------------
482  */
483
484 /* ----------------------------------------------------------------
485  *              ExecOpenIndices
486  *
487  *              Find the indices associated with a result relation, open them,
488  *              and save information about them in the result ResultRelInfo.
489  *
490  *              At entry, caller has already opened and locked
491  *              resultRelInfo->ri_RelationDesc.
492  *
493  *              This used to be horribly ugly code, and slow too because it
494  *              did a sequential scan of pg_index.      Now we rely on the relcache
495  *              to cache a list of the OIDs of the indices associated with any
496  *              specific relation, and we use the pg_index syscache to get the
497  *              entries we need from pg_index.
498  * ----------------------------------------------------------------
499  */
500 void
501 ExecOpenIndices(ResultRelInfo *resultRelInfo)
502 {
503         Relation        resultRelation = resultRelInfo->ri_RelationDesc;
504         List       *indexoidlist,
505                            *indexoidscan;
506         int                     len,
507                                 i;
508         RelationPtr relationDescs;
509         IndexInfo **indexInfoArray;
510
511         resultRelInfo->ri_NumIndices = 0;
512
513         /* checks for disabled indexes */
514         if (!RelationGetForm(resultRelation)->relhasindex)
515                 return;
516         if (IsIgnoringSystemIndexes() &&
517                 IsSystemRelation(resultRelation))
518                 return;
519
520         /*
521          * Get cached list of index OIDs
522          */
523         indexoidlist = RelationGetIndexList(resultRelation);
524         len = length(indexoidlist);
525         if (len == 0)
526                 return;
527
528         /*
529          * allocate space for result arrays
530          */
531         relationDescs = (RelationPtr) palloc(len * sizeof(Relation));
532         indexInfoArray = (IndexInfo **) palloc(len * sizeof(IndexInfo *));
533
534         resultRelInfo->ri_NumIndices = len;
535         resultRelInfo->ri_IndexRelationDescs = relationDescs;
536         resultRelInfo->ri_IndexRelationInfo = indexInfoArray;
537
538         /*
539          * For each index, open the index relation and save pg_index info.
540          */
541         i = 0;
542         foreach(indexoidscan, indexoidlist)
543         {
544                 Oid                     indexOid = lfirsti(indexoidscan);
545                 Relation        indexDesc;
546                 IndexInfo  *ii;
547
548                 /*
549                  * Open (and lock, if necessary) the index relation
550                  *
551                  * If the index AM is not safe for concurrent updates, obtain an
552                  * exclusive lock on the index to lock out other updaters as well
553                  * as readers (index_beginscan places AccessShareLock). We will
554                  * release this lock in ExecCloseIndices.
555                  *
556                  * If the index AM supports concurrent updates, we obtain no lock
557                  * here at all, which is a tad weird, but safe since any critical
558                  * operation on the index (like deleting it) will acquire
559                  * exclusive lock on the parent table.  Perhaps someday we should
560                  * acquire RowExclusiveLock on the index here?
561                  *
562                  * If there are multiple not-concurrent-safe indexes, all backends
563                  * must lock the indexes in the same order or we will get
564                  * deadlocks here during concurrent updates.  This is guaranteed
565                  * by RelationGetIndexList(), which promises to return the index
566                  * list in OID order.
567                  */
568                 indexDesc = index_open(indexOid);
569
570                 if (!indexDesc->rd_am->amconcurrent)
571                         LockRelation(indexDesc, AccessExclusiveLock);
572
573                 /*
574                  * extract index key information from the index's pg_index tuple
575                  */
576                 ii = BuildIndexInfo(indexDesc->rd_index);
577
578                 relationDescs[i] = indexDesc;
579                 indexInfoArray[i] = ii;
580                 i++;
581         }
582
583         freeList(indexoidlist);
584 }
585
586 /* ----------------------------------------------------------------
587  *              ExecCloseIndices
588  *
589  *              Close the index relations stored in resultRelInfo
590  * ----------------------------------------------------------------
591  */
592 void
593 ExecCloseIndices(ResultRelInfo *resultRelInfo)
594 {
595         int                     i;
596         int                     numIndices;
597         RelationPtr indexDescs;
598
599         numIndices = resultRelInfo->ri_NumIndices;
600         indexDescs = resultRelInfo->ri_IndexRelationDescs;
601
602         for (i = 0; i < numIndices; i++)
603         {
604                 if (indexDescs[i] == NULL)
605                         continue;
606
607                 /* Drop lock, if one was acquired by ExecOpenIndices */
608                 if (!indexDescs[i]->rd_am->amconcurrent)
609                         UnlockRelation(indexDescs[i], AccessExclusiveLock);
610
611                 index_close(indexDescs[i]);
612         }
613
614         /*
615          * XXX should free indexInfo array here too.
616          */
617 }
618
619 /* ----------------------------------------------------------------
620  *              ExecInsertIndexTuples
621  *
622  *              This routine takes care of inserting index tuples
623  *              into all the relations indexing the result relation
624  *              when a heap tuple is inserted into the result relation.
625  *              Much of this code should be moved into the genam
626  *              stuff as it only exists here because the genam stuff
627  *              doesn't provide the functionality needed by the
628  *              executor.. -cim 9/27/89
629  * ----------------------------------------------------------------
630  */
631 void
632 ExecInsertIndexTuples(TupleTableSlot *slot,
633                                           ItemPointer tupleid,
634                                           EState *estate,
635                                           bool is_vacuum)
636 {
637         HeapTuple       heapTuple;
638         ResultRelInfo *resultRelInfo;
639         int                     i;
640         int                     numIndices;
641         RelationPtr relationDescs;
642         Relation        heapRelation;
643         TupleDesc       heapDescriptor;
644         IndexInfo **indexInfoArray;
645         ExprContext *econtext;
646         Datum           datum[INDEX_MAX_KEYS];
647         char            nullv[INDEX_MAX_KEYS];
648
649         heapTuple = slot->val;
650
651         /*
652          * Get information from the result relation info structure.
653          */
654         resultRelInfo = estate->es_result_relation_info;
655         numIndices = resultRelInfo->ri_NumIndices;
656         relationDescs = resultRelInfo->ri_IndexRelationDescs;
657         indexInfoArray = resultRelInfo->ri_IndexRelationInfo;
658         heapRelation = resultRelInfo->ri_RelationDesc;
659         heapDescriptor = RelationGetDescr(heapRelation);
660
661         /*
662          * We will use the EState's per-tuple context for evaluating
663          * predicates and functional-index functions (creating it if it's not
664          * already there).
665          */
666         econtext = GetPerTupleExprContext(estate);
667
668         /* Arrange for econtext's scan tuple to be the tuple under test */
669         econtext->ecxt_scantuple = slot;
670
671         /*
672          * for each index, form and insert the index tuple
673          */
674         for (i = 0; i < numIndices; i++)
675         {
676                 IndexInfo  *indexInfo;
677                 List       *predicate;
678                 InsertIndexResult result;
679
680                 if (relationDescs[i] == NULL)
681                         continue;
682
683                 indexInfo = indexInfoArray[i];
684                 predicate = indexInfo->ii_PredicateState;
685                 if (predicate != NIL)
686                 {
687                         /* Skip this index-update if the predicate isn't satisfied */
688                         if (!ExecQual(predicate, econtext, false))
689                                 continue;
690                 }
691
692                 /*
693                  * FormIndexDatum fills in its datum and null parameters with
694                  * attribute information taken from the given heap tuple.
695                  */
696                 FormIndexDatum(indexInfo,
697                                            heapTuple,
698                                            heapDescriptor,
699                                            econtext->ecxt_per_tuple_memory,
700                                            datum,
701                                            nullv);
702
703                 /*
704                  * The index AM does the rest.  Note we suppress unique-index
705                  * checks if we are being called from VACUUM, since VACUUM may
706                  * need to move dead tuples that have the same keys as live ones.
707                  */
708                 result = index_insert(relationDescs[i], /* index relation */
709                                                           datum,        /* array of heaptuple Datums */
710                                                           nullv,        /* info on nulls */
711                                                           &(heapTuple->t_self),         /* tid of heap tuple */
712                                                           heapRelation,
713                                   relationDescs[i]->rd_index->indisunique && !is_vacuum);
714
715                 /*
716                  * keep track of index inserts for debugging
717                  */
718                 IncrIndexInserted();
719
720                 if (result)
721                         pfree(result);
722         }
723 }
724
725 void
726 SetChangedParamList(PlanState *node, List *newchg)
727 {
728         List       *nl;
729
730         foreach(nl, newchg)
731         {
732                 int                     paramId = lfirsti(nl);
733
734                 /* if this node doesn't depend on a param ... */
735                 if (!intMember(paramId, node->plan->extParam) &&
736                         !intMember(paramId, node->plan->locParam))
737                         continue;
738                 /* if this param is already in list of changed ones ... */
739                 if (intMember(paramId, node->chgParam))
740                         continue;
741                 /* else - add this param to the list */
742                 node->chgParam = lappendi(node->chgParam, paramId);
743         }
744 }
745
746 /*
747  * Register a shutdown callback in an ExprContext.
748  *
749  * Shutdown callbacks will be called (in reverse order of registration)
750  * when the ExprContext is deleted or rescanned.  This provides a hook
751  * for functions called in the context to do any cleanup needed --- it's
752  * particularly useful for functions returning sets.  Note that the
753  * callback will *not* be called in the event that execution is aborted
754  * by an error.
755  */
756 void
757 RegisterExprContextCallback(ExprContext *econtext,
758                                                         ExprContextCallbackFunction function,
759                                                         Datum arg)
760 {
761         ExprContext_CB *ecxt_callback;
762
763         /* Save the info in appropriate memory context */
764         ecxt_callback = (ExprContext_CB *)
765                 MemoryContextAlloc(econtext->ecxt_per_query_memory,
766                                                    sizeof(ExprContext_CB));
767
768         ecxt_callback->function = function;
769         ecxt_callback->arg = arg;
770
771         /* link to front of list for appropriate execution order */
772         ecxt_callback->next = econtext->ecxt_callbacks;
773         econtext->ecxt_callbacks = ecxt_callback;
774 }
775
776 /*
777  * Deregister a shutdown callback in an ExprContext.
778  *
779  * Any list entries matching the function and arg will be removed.
780  * This can be used if it's no longer necessary to call the callback.
781  */
782 void
783 UnregisterExprContextCallback(ExprContext *econtext,
784                                                           ExprContextCallbackFunction function,
785                                                           Datum arg)
786 {
787         ExprContext_CB **prev_callback;
788         ExprContext_CB *ecxt_callback;
789
790         prev_callback = &econtext->ecxt_callbacks;
791
792         while ((ecxt_callback = *prev_callback) != NULL)
793         {
794                 if (ecxt_callback->function == function && ecxt_callback->arg == arg)
795                 {
796                         *prev_callback = ecxt_callback->next;
797                         pfree(ecxt_callback);
798                 }
799                 else
800                         prev_callback = &ecxt_callback->next;
801         }
802 }
803
804 /*
805  * Call all the shutdown callbacks registered in an ExprContext.
806  *
807  * The callback list is emptied (important in case this is only a rescan
808  * reset, and not deletion of the ExprContext).
809  */
810 static void
811 ShutdownExprContext(ExprContext *econtext)
812 {
813         ExprContext_CB *ecxt_callback;
814
815         /*
816          * Call each callback function in reverse registration order.
817          */
818         while ((ecxt_callback = econtext->ecxt_callbacks) != NULL)
819         {
820                 econtext->ecxt_callbacks = ecxt_callback->next;
821                 (*ecxt_callback->function) (ecxt_callback->arg);
822                 pfree(ecxt_callback);
823         }
824 }