1 /*-------------------------------------------------------------------------
4 * miscellaneous executor utility routines
6 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.92 2002/12/13 19:45:52 tgl Exp $
13 *-------------------------------------------------------------------------
17 * ExecAssignExprContext Common code for plan node init routines.
20 * ExecCloseIndices | referenced by InitPlan, EndPlan,
21 * ExecInsertIndexTuples / ExecInsert, ExecUpdate
23 * RegisterExprContextCallback Register function shutdown callback
24 * UnregisterExprContextCallback Deregister function shutdown callback
27 * This file has traditionally been the place to stick misc.
28 * executor support stuff that doesn't really go anyplace else.
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"
49 /* ----------------------------------------------------------------
50 * global counters for number of tuples processed, retrieved,
51 * appended, replaced, deleted.
52 * ----------------------------------------------------------------
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. */
65 static void ShutdownExprContext(ExprContext *econtext);
67 /* ----------------------------------------------------------------
69 * ----------------------------------------------------------------
72 /* ----------------------------------------------------------------
74 * ----------------------------------------------------------------
85 NIndexTupleProcessed = 0;
89 /* ----------------------------------------------------------------
91 * ----------------------------------------------------------------
95 DisplayTupleCount(FILE *statfp)
97 if (NTupleProcessed > 0)
98 fprintf(statfp, "!\t%d tuple%s processed, ", NTupleProcessed,
99 (NTupleProcessed == 1) ? "" : "s");
102 fprintf(statfp, "!\tno tuples processed.\n");
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");
127 /* ----------------------------------------------------------------
128 * miscellaneous node-init support functions
129 * ----------------------------------------------------------------
133 * ExecAssignExprContext
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.
140 * Note: we assume CurrentMemoryContext is the correct per-query context.
141 * This should be true during plan node initialization.
145 ExecAssignExprContext(EState *estate, PlanState *planstate)
147 ExprContext *econtext = makeNode(ExprContext);
149 econtext->ecxt_scantuple = NULL;
150 econtext->ecxt_innertuple = NULL;
151 econtext->ecxt_outertuple = NULL;
152 econtext->ecxt_per_query_memory = CurrentMemoryContext;
155 * Create working memory for expression evaluation in this context.
157 econtext->ecxt_per_tuple_memory =
158 AllocSetContextCreate(CurrentMemoryContext,
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;
169 planstate->ps_ExprContext = econtext;
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.
182 MakeExprContext(TupleTableSlot *slot,
183 MemoryContext queryContext)
185 ExprContext *econtext = makeNode(ExprContext);
187 econtext->ecxt_scantuple = slot;
188 econtext->ecxt_innertuple = NULL;
189 econtext->ecxt_outertuple = NULL;
190 econtext->ecxt_per_query_memory = queryContext;
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...
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
202 econtext->ecxt_per_tuple_memory =
203 AllocSetContextCreate(CurrentMemoryContext,
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;
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!
223 FreeExprContext(ExprContext *econtext)
225 /* Call any registered callbacks */
226 ShutdownExprContext(econtext);
227 /* And clean up the memory used */
228 MemoryContextDelete(econtext->ecxt_per_tuple_memory);
233 * Build a per-output-tuple ExprContext for an EState.
235 * This is normally invoked via GetPerTupleExprContext() macro.
238 MakePerTupleExprContext(EState *estate)
240 if (estate->es_per_tuple_exprcontext == NULL)
242 MemoryContext oldContext;
244 oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
245 estate->es_per_tuple_exprcontext =
246 MakeExprContext(NULL, estate->es_query_cxt);
247 MemoryContextSwitchTo(oldContext);
249 return estate->es_per_tuple_exprcontext;
252 /* ----------------------------------------------------------------
253 * Result slot tuple type and ProjectionInfo support
254 * ----------------------------------------------------------------
258 * ExecAssignResultType
262 ExecAssignResultType(PlanState *planstate,
263 TupleDesc tupDesc, bool shouldFree)
265 TupleTableSlot *slot = planstate->ps_ResultTupleSlot;
267 ExecSetSlotDescriptor(slot, tupDesc, shouldFree);
271 * ExecAssignResultTypeFromOuterPlan
275 ExecAssignResultTypeFromOuterPlan(PlanState *planstate)
277 PlanState *outerPlan;
280 outerPlan = outerPlanState(planstate);
281 tupDesc = ExecGetTupType(outerPlan);
283 ExecAssignResultType(planstate, tupDesc, false);
287 * ExecAssignResultTypeFromTL
291 ExecAssignResultTypeFromTL(PlanState *planstate)
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
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 ...
314 ri = planstate->state->es_result_relation_info;
317 Relation rel = ri->ri_RelationDesc;
320 hasoid = rel->rd_rel->relhasoids;
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 ...
328 tupDesc = ExecTypeFromTL(planstate->plan->targetlist, hasoid);
329 ExecAssignResultType(planstate, tupDesc, true);
337 ExecGetResultType(PlanState *planstate)
339 TupleTableSlot *slot = planstate->ps_ResultTupleSlot;
341 return slot->ttc_tupleDescriptor;
345 * ExecAssignProjectionInfo
346 forms the projection information from the node's targetlist
350 ExecAssignProjectionInfo(PlanState *planstate)
352 ProjectionInfo *projInfo;
356 targetList = planstate->targetlist;
357 len = ExecTargetListLength(targetList);
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;
366 planstate->ps_ProjInfo = projInfo;
371 * ExecFreeProjectionInfo
375 ExecFreeProjectionInfo(PlanState *planstate)
377 ProjectionInfo *projInfo;
380 * get projection info. if NULL then this node has none so we just
383 projInfo = planstate->ps_ProjInfo;
384 if (projInfo == NULL)
388 * clean up memory used.
390 if (projInfo->pi_tupValue != NULL)
391 pfree(projInfo->pi_tupValue);
394 planstate->ps_ProjInfo = NULL;
398 * ExecFreeExprContext
402 ExecFreeExprContext(PlanState *planstate)
404 ExprContext *econtext;
407 * get expression context. if NULL then this node has none so we just
410 econtext = planstate->ps_ExprContext;
411 if (econtext == NULL)
415 * clean up any registered callbacks
417 ShutdownExprContext(econtext);
420 * clean up memory used.
422 MemoryContextDelete(econtext->ecxt_per_tuple_memory);
424 planstate->ps_ExprContext = NULL;
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 * ----------------------------------------------------------------
442 ExecGetScanType(ScanState *scanstate)
444 TupleTableSlot *slot = scanstate->ss_ScanTupleSlot;
446 return slot->ttc_tupleDescriptor;
454 ExecAssignScanType(ScanState *scanstate,
455 TupleDesc tupDesc, bool shouldFree)
457 TupleTableSlot *slot = scanstate->ss_ScanTupleSlot;
459 ExecSetSlotDescriptor(slot, tupDesc, shouldFree);
463 * ExecAssignScanTypeFromOuterPlan
467 ExecAssignScanTypeFromOuterPlan(ScanState *scanstate)
469 PlanState *outerPlan;
472 outerPlan = outerPlanState(scanstate);
473 tupDesc = ExecGetTupType(outerPlan);
475 ExecAssignScanType(scanstate, tupDesc, false);
479 /* ----------------------------------------------------------------
480 * ExecInsertIndexTuples support
481 * ----------------------------------------------------------------
484 /* ----------------------------------------------------------------
487 * Find the indices associated with a result relation, open them,
488 * and save information about them in the result ResultRelInfo.
490 * At entry, caller has already opened and locked
491 * resultRelInfo->ri_RelationDesc.
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 * ----------------------------------------------------------------
501 ExecOpenIndices(ResultRelInfo *resultRelInfo)
503 Relation resultRelation = resultRelInfo->ri_RelationDesc;
508 RelationPtr relationDescs;
509 IndexInfo **indexInfoArray;
511 resultRelInfo->ri_NumIndices = 0;
513 /* checks for disabled indexes */
514 if (!RelationGetForm(resultRelation)->relhasindex)
516 if (IsIgnoringSystemIndexes() &&
517 IsSystemRelation(resultRelation))
521 * Get cached list of index OIDs
523 indexoidlist = RelationGetIndexList(resultRelation);
524 len = length(indexoidlist);
529 * allocate space for result arrays
531 relationDescs = (RelationPtr) palloc(len * sizeof(Relation));
532 indexInfoArray = (IndexInfo **) palloc(len * sizeof(IndexInfo *));
534 resultRelInfo->ri_NumIndices = len;
535 resultRelInfo->ri_IndexRelationDescs = relationDescs;
536 resultRelInfo->ri_IndexRelationInfo = indexInfoArray;
539 * For each index, open the index relation and save pg_index info.
542 foreach(indexoidscan, indexoidlist)
544 Oid indexOid = lfirsti(indexoidscan);
549 * Open (and lock, if necessary) the index relation
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.
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?
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
568 indexDesc = index_open(indexOid);
570 if (!indexDesc->rd_am->amconcurrent)
571 LockRelation(indexDesc, AccessExclusiveLock);
574 * extract index key information from the index's pg_index tuple
576 ii = BuildIndexInfo(indexDesc->rd_index);
578 relationDescs[i] = indexDesc;
579 indexInfoArray[i] = ii;
583 freeList(indexoidlist);
586 /* ----------------------------------------------------------------
589 * Close the index relations stored in resultRelInfo
590 * ----------------------------------------------------------------
593 ExecCloseIndices(ResultRelInfo *resultRelInfo)
597 RelationPtr indexDescs;
599 numIndices = resultRelInfo->ri_NumIndices;
600 indexDescs = resultRelInfo->ri_IndexRelationDescs;
602 for (i = 0; i < numIndices; i++)
604 if (indexDescs[i] == NULL)
607 /* Drop lock, if one was acquired by ExecOpenIndices */
608 if (!indexDescs[i]->rd_am->amconcurrent)
609 UnlockRelation(indexDescs[i], AccessExclusiveLock);
611 index_close(indexDescs[i]);
615 * XXX should free indexInfo array here too.
619 /* ----------------------------------------------------------------
620 * ExecInsertIndexTuples
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 * ----------------------------------------------------------------
632 ExecInsertIndexTuples(TupleTableSlot *slot,
638 ResultRelInfo *resultRelInfo;
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];
649 heapTuple = slot->val;
652 * Get information from the result relation info structure.
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);
662 * We will use the EState's per-tuple context for evaluating
663 * predicates and functional-index functions (creating it if it's not
666 econtext = GetPerTupleExprContext(estate);
668 /* Arrange for econtext's scan tuple to be the tuple under test */
669 econtext->ecxt_scantuple = slot;
672 * for each index, form and insert the index tuple
674 for (i = 0; i < numIndices; i++)
676 IndexInfo *indexInfo;
678 InsertIndexResult result;
680 if (relationDescs[i] == NULL)
683 indexInfo = indexInfoArray[i];
684 predicate = indexInfo->ii_PredicateState;
685 if (predicate != NIL)
687 /* Skip this index-update if the predicate isn't satisfied */
688 if (!ExecQual(predicate, econtext, false))
693 * FormIndexDatum fills in its datum and null parameters with
694 * attribute information taken from the given heap tuple.
696 FormIndexDatum(indexInfo,
699 econtext->ecxt_per_tuple_memory,
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.
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 */
713 relationDescs[i]->rd_index->indisunique && !is_vacuum);
716 * keep track of index inserts for debugging
726 SetChangedParamList(PlanState *node, List *newchg)
732 int paramId = lfirsti(nl);
734 /* if this node doesn't depend on a param ... */
735 if (!intMember(paramId, node->plan->extParam) &&
736 !intMember(paramId, node->plan->locParam))
738 /* if this param is already in list of changed ones ... */
739 if (intMember(paramId, node->chgParam))
741 /* else - add this param to the list */
742 node->chgParam = lappendi(node->chgParam, paramId);
747 * Register a shutdown callback in an ExprContext.
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
757 RegisterExprContextCallback(ExprContext *econtext,
758 ExprContextCallbackFunction function,
761 ExprContext_CB *ecxt_callback;
763 /* Save the info in appropriate memory context */
764 ecxt_callback = (ExprContext_CB *)
765 MemoryContextAlloc(econtext->ecxt_per_query_memory,
766 sizeof(ExprContext_CB));
768 ecxt_callback->function = function;
769 ecxt_callback->arg = arg;
771 /* link to front of list for appropriate execution order */
772 ecxt_callback->next = econtext->ecxt_callbacks;
773 econtext->ecxt_callbacks = ecxt_callback;
777 * Deregister a shutdown callback in an ExprContext.
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.
783 UnregisterExprContextCallback(ExprContext *econtext,
784 ExprContextCallbackFunction function,
787 ExprContext_CB **prev_callback;
788 ExprContext_CB *ecxt_callback;
790 prev_callback = &econtext->ecxt_callbacks;
792 while ((ecxt_callback = *prev_callback) != NULL)
794 if (ecxt_callback->function == function && ecxt_callback->arg == arg)
796 *prev_callback = ecxt_callback->next;
797 pfree(ecxt_callback);
800 prev_callback = &ecxt_callback->next;
805 * Call all the shutdown callbacks registered in an ExprContext.
807 * The callback list is emptied (important in case this is only a rescan
808 * reset, and not deletion of the ExprContext).
811 ShutdownExprContext(ExprContext *econtext)
813 ExprContext_CB *ecxt_callback;
816 * Call each callback function in reverse registration order.
818 while ((ecxt_callback = econtext->ecxt_callbacks) != NULL)
820 econtext->ecxt_callbacks = ecxt_callback->next;
821 (*ecxt_callback->function) (ecxt_callback->arg);
822 pfree(ecxt_callback);