📄 executils.c
字号:
ExecBuildProjectionInfo(List *targetList, ExprContext *econtext, TupleTableSlot *slot){ ProjectionInfo *projInfo = makeNode(ProjectionInfo); int len; len = ExecTargetListLength(targetList); projInfo->pi_targetlist = targetList; projInfo->pi_exprContext = econtext; projInfo->pi_slot = slot; if (len > 0) { projInfo->pi_tupValues = (Datum *) palloc(len * sizeof(Datum)); projInfo->pi_tupNulls = (char *) palloc(len * sizeof(char)); projInfo->pi_itemIsDone = (ExprDoneCond *) palloc(len * sizeof(ExprDoneCond)); } return projInfo;}/* ---------------- * ExecAssignProjectionInfo * * forms the projection information from the node's targetlist * ---------------- */voidExecAssignProjectionInfo(PlanState *planstate){ planstate->ps_ProjInfo = ExecBuildProjectionInfo(planstate->targetlist, planstate->ps_ExprContext, planstate->ps_ResultTupleSlot);}/* ---------------- * ExecFreeExprContext * * A plan node's ExprContext should be freed explicitly during ExecEndNode * because there may be shutdown callbacks to call. (Other resources made * by the above routines, such as projection info, don't need to be freed * explicitly because they're just memory in the per-query memory context.) * ---------------- */voidExecFreeExprContext(PlanState *planstate){ ExprContext *econtext; /* * get expression context. if NULL then this node has none so we just * return. */ econtext = planstate->ps_ExprContext; if (econtext == NULL) return; FreeExprContext(econtext); planstate->ps_ExprContext = NULL;}/* ---------------------------------------------------------------- * the following scan type support functions are for * those nodes which are stubborn and return tuples in * their Scan tuple slot instead of their Result tuple * slot.. luck fur us, these nodes do not do projections * so we don't have to worry about getting the ProjectionInfo * right for them... -cim 6/3/91 * ---------------------------------------------------------------- *//* ---------------- * ExecGetScanType * ---------------- */TupleDescExecGetScanType(ScanState *scanstate){ TupleTableSlot *slot = scanstate->ss_ScanTupleSlot; return slot->ttc_tupleDescriptor;}/* ---------------- * ExecAssignScanType * ---------------- */voidExecAssignScanType(ScanState *scanstate, TupleDesc tupDesc, bool shouldFree){ TupleTableSlot *slot = scanstate->ss_ScanTupleSlot; ExecSetSlotDescriptor(slot, tupDesc, shouldFree);}/* ---------------- * ExecAssignScanTypeFromOuterPlan * ---------------- */voidExecAssignScanTypeFromOuterPlan(ScanState *scanstate){ PlanState *outerPlan; TupleDesc tupDesc; outerPlan = outerPlanState(scanstate); tupDesc = ExecGetResultType(outerPlan); ExecAssignScanType(scanstate, tupDesc, false);}/* ---------------------------------------------------------------- * ExecInsertIndexTuples support * ---------------------------------------------------------------- *//* ---------------------------------------------------------------- * ExecOpenIndices * * Find the indices associated with a result relation, open them, * and save information about them in the result ResultRelInfo. * * At entry, caller has already opened and locked * resultRelInfo->ri_RelationDesc. * * This used to be horribly ugly code, and slow too because it * did a sequential scan of pg_index. Now we rely on the relcache * to cache a list of the OIDs of the indices associated with any * specific relation, and we use the pg_index syscache to get the * entries we need from pg_index. * ---------------------------------------------------------------- */voidExecOpenIndices(ResultRelInfo *resultRelInfo){ Relation resultRelation = resultRelInfo->ri_RelationDesc; List *indexoidlist, *indexoidscan; int len, i; RelationPtr relationDescs; IndexInfo **indexInfoArray; resultRelInfo->ri_NumIndices = 0; /* fast path if no indexes */ if (!RelationGetForm(resultRelation)->relhasindex) return; /* * Get cached list of index OIDs */ indexoidlist = RelationGetIndexList(resultRelation); len = length(indexoidlist); if (len == 0) return; /* * allocate space for result arrays */ relationDescs = (RelationPtr) palloc(len * sizeof(Relation)); indexInfoArray = (IndexInfo **) palloc(len * sizeof(IndexInfo *)); resultRelInfo->ri_NumIndices = len; resultRelInfo->ri_IndexRelationDescs = relationDescs; resultRelInfo->ri_IndexRelationInfo = indexInfoArray; /* * For each index, open the index relation and save pg_index info. */ i = 0; foreach(indexoidscan, indexoidlist) { Oid indexOid = lfirsto(indexoidscan); Relation indexDesc; IndexInfo *ii; /* * Open (and lock, if necessary) the index relation * * If the index AM is not safe for concurrent updates, obtain an * exclusive lock on the index to lock out other updaters as well * as readers (index_beginscan places AccessShareLock). We will * release this lock in ExecCloseIndices. * * If the index AM supports concurrent updates, we obtain no lock * here at all, which is a tad weird, but safe since any critical * operation on the index (like deleting it) will acquire * exclusive lock on the parent table. Perhaps someday we should * acquire RowExclusiveLock on the index here? * * If there are multiple not-concurrent-safe indexes, all backends * must lock the indexes in the same order or we will get * deadlocks here during concurrent updates. This is guaranteed * by RelationGetIndexList(), which promises to return the index * list in OID order. */ indexDesc = index_open(indexOid); if (!indexDesc->rd_am->amconcurrent) LockRelation(indexDesc, AccessExclusiveLock); /* extract index key information from the index's pg_index info */ ii = BuildIndexInfo(indexDesc); relationDescs[i] = indexDesc; indexInfoArray[i] = ii; i++; } freeList(indexoidlist);}/* ---------------------------------------------------------------- * ExecCloseIndices * * Close the index relations stored in resultRelInfo * ---------------------------------------------------------------- */voidExecCloseIndices(ResultRelInfo *resultRelInfo){ int i; int numIndices; RelationPtr indexDescs; numIndices = resultRelInfo->ri_NumIndices; indexDescs = resultRelInfo->ri_IndexRelationDescs; for (i = 0; i < numIndices; i++) { if (indexDescs[i] == NULL) continue; /* Drop lock, if one was acquired by ExecOpenIndices */ if (!indexDescs[i]->rd_am->amconcurrent) UnlockRelation(indexDescs[i], AccessExclusiveLock); index_close(indexDescs[i]); } /* * XXX should free indexInfo array here too? Currently we assume that * such stuff will be cleaned up automatically in FreeExecutorState. */}/* ---------------------------------------------------------------- * ExecInsertIndexTuples * * This routine takes care of inserting index tuples * into all the relations indexing the result relation * when a heap tuple is inserted into the result relation. * Much of this code should be moved into the genam * stuff as it only exists here because the genam stuff * doesn't provide the functionality needed by the * executor.. -cim 9/27/89 * ---------------------------------------------------------------- */voidExecInsertIndexTuples(TupleTableSlot *slot, ItemPointer tupleid, EState *estate, bool is_vacuum){ HeapTuple heapTuple; ResultRelInfo *resultRelInfo; int i; int numIndices; RelationPtr relationDescs; Relation heapRelation; TupleDesc heapDescriptor; IndexInfo **indexInfoArray; ExprContext *econtext; Datum datum[INDEX_MAX_KEYS]; char nullv[INDEX_MAX_KEYS]; heapTuple = slot->val; /* * Get information from the result relation info structure. */ resultRelInfo = estate->es_result_relation_info; numIndices = resultRelInfo->ri_NumIndices; relationDescs = resultRelInfo->ri_IndexRelationDescs; indexInfoArray = resultRelInfo->ri_IndexRelationInfo; heapRelation = resultRelInfo->ri_RelationDesc; heapDescriptor = RelationGetDescr(heapRelation); /* * We will use the EState's per-tuple context for evaluating * predicates and index expressions (creating it if it's not already * there). */ econtext = GetPerTupleExprContext(estate); /* Arrange for econtext's scan tuple to be the tuple under test */ econtext->ecxt_scantuple = slot; /* * for each index, form and insert the index tuple */ for (i = 0; i < numIndices; i++) { IndexInfo *indexInfo; InsertIndexResult result; if (relationDescs[i] == NULL) continue; indexInfo = indexInfoArray[i]; /* Check for partial index */ if (indexInfo->ii_Predicate != NIL) { List *predicate; /* * If predicate state not set up yet, create it (in the * estate's per-query context) */ predicate = indexInfo->ii_PredicateState; if (predicate == NIL) { predicate = (List *) ExecPrepareExpr((Expr *) indexInfo->ii_Predicate, estate); indexInfo->ii_PredicateState = predicate; } /* Skip this index-update if the predicate isn't satisfied */ if (!ExecQual(predicate, econtext, false)) continue; } /* * FormIndexDatum fills in its datum and null parameters with * attribute information taken from the given heap tuple. It also * computes any expressions needed. */ FormIndexDatum(indexInfo, heapTuple, heapDescriptor, estate, datum, nullv); /* * The index AM does the rest. Note we suppress unique-index * checks if we are being called from VACUUM, since VACUUM may * need to move dead tuples that have the same keys as live ones. */ result = index_insert(relationDescs[i], /* index relation */ datum, /* array of heaptuple Datums */ nullv, /* info on nulls */ &(heapTuple->t_self), /* tid of heap tuple */ heapRelation, relationDescs[i]->rd_index->indisunique && !is_vacuum); /* * keep track of index inserts for debugging */ IncrIndexInserted(); if (result) pfree(result); }}/* * UpdateChangedParamSet * Add changed parameters to a plan node's chgParam set */voidUpdateChangedParamSet(PlanState *node, Bitmapset *newchg){ Bitmapset *parmset; /* * The plan node only depends on params listed in its allParam set. * Don't include anything else into its chgParam set. */ parmset = bms_intersect(node->plan->allParam, newchg); /* * Keep node->chgParam == NULL if there's not actually any members; * this allows the simplest possible tests in executor node files. */ if (!bms_is_empty(parmset)) node->chgParam = bms_join(node->chgParam, parmset); else bms_free(parmset);}/* * Register a shutdown callback in an ExprContext. * * Shutdown callbacks will be called (in reverse order of registration) * when the ExprContext is deleted or rescanned. This provides a hook * for functions called in the context to do any cleanup needed --- it's * particularly useful for functions returning sets. Note that the * callback will *not* be called in the event that execution is aborted * by an error. */voidRegisterExprContextCallback(ExprContext *econtext, ExprContextCallbackFunction function, Datum arg){ ExprContext_CB *ecxt_callback; /* Save the info in appropriate memory context */ ecxt_callback = (ExprContext_CB *) MemoryContextAlloc(econtext->ecxt_per_query_memory, sizeof(ExprContext_CB)); ecxt_callback->function = function; ecxt_callback->arg = arg; /* link to front of list for appropriate execution order */ ecxt_callback->next = econtext->ecxt_callbacks; econtext->ecxt_callbacks = ecxt_callback;}/* * Deregister a shutdown callback in an ExprContext. * * Any list entries matching the function and arg will be removed. * This can be used if it's no longer necessary to call the callback. */voidUnregisterExprContextCallback(ExprContext *econtext, ExprContextCallbackFunction function, Datum arg){ ExprContext_CB **prev_callback; ExprContext_CB *ecxt_callback; prev_callback = &econtext->ecxt_callbacks; while ((ecxt_callback = *prev_callback) != NULL) { if (ecxt_callback->function == function && ecxt_callback->arg == arg) { *prev_callback = ecxt_callback->next; pfree(ecxt_callback); } else prev_callback = &ecxt_callback->next; }}/* * Call all the shutdown callbacks registered in an ExprContext. * * The callback list is emptied (important in case this is only a rescan * reset, and not deletion of the ExprContext). */static voidShutdownExprContext(ExprContext *econtext){ ExprContext_CB *ecxt_callback; MemoryContext oldcontext; /* Fast path in normal case where there's nothing to do. */ if (econtext->ecxt_callbacks == NULL) return; /* * Call the callbacks in econtext's per-tuple context. This ensures * that any memory they might leak will get cleaned up. */ oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory); /* * Call each callback function in reverse registration order. */ while ((ecxt_callback = econtext->ecxt_callbacks) != NULL) { econtext->ecxt_callbacks = ecxt_callback->next; (*ecxt_callback->function) (ecxt_callback->arg); pfree(ecxt_callback); } MemoryContextSwitchTo(oldcontext);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -