📄 executils.c
字号:
int *varNumbers; AttrNumber lastInnerVar = 0; AttrNumber lastOuterVar = 0; AttrNumber lastScanVar = 0; projInfo->pi_itemIsDone = NULL; /* not needed */ projInfo->pi_varSlotOffsets = varSlotOffsets = (int *) palloc0(len * sizeof(int)); projInfo->pi_varNumbers = varNumbers = (int *) palloc0(len * sizeof(int)); /* * Set up the data needed by ExecVariableList. The slots in which the * variables can be found at runtime are denoted by the offsets of * their slot pointers within the econtext. This rather grotty * representation is needed because the caller may not have given us * the real econtext yet (see hacks in nodeSubplan.c). */ foreach(tl, targetList) { GenericExprState *gstate = (GenericExprState *) lfirst(tl); Var *variable = (Var *) gstate->arg->expr; AttrNumber attnum = variable->varattno; TargetEntry *tle = (TargetEntry *) gstate->xprstate.expr; AttrNumber resind = tle->resno - 1; Assert(resind >= 0 && resind < len); varNumbers[resind] = attnum; switch (variable->varno) { case INNER: varSlotOffsets[resind] = offsetof(ExprContext, ecxt_innertuple); lastInnerVar = Max(lastInnerVar, attnum); break; case OUTER: varSlotOffsets[resind] = offsetof(ExprContext, ecxt_outertuple); lastOuterVar = Max(lastOuterVar, attnum); break; default: varSlotOffsets[resind] = offsetof(ExprContext, ecxt_scantuple); lastScanVar = Max(lastScanVar, attnum); break; } } projInfo->pi_lastInnerVar = lastInnerVar; projInfo->pi_lastOuterVar = lastOuterVar; projInfo->pi_lastScanVar = lastScanVar; } else { projInfo->pi_itemIsDone = (ExprDoneCond *) palloc(len * sizeof(ExprDoneCond)); projInfo->pi_varSlotOffsets = NULL; projInfo->pi_varNumbers = NULL; } 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 executor * shutdown 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.) * * However ... there is no particular need to do it during ExecEndNode, * because FreeExecutorState will free any remaining ExprContexts within * the EState. Letting FreeExecutorState do it allows the ExprContexts to * be freed in reverse order of creation, rather than order of creation as * will happen if we delete them here, which saves O(N^2) work in the list * cleanup inside FreeExprContext. * ---------------- */voidExecFreeExprContext(PlanState *planstate){ /* * Per above discussion, don't actually delete the ExprContext. We do * unlink it from the plan node, though. */ 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->tts_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; ListCell *l; 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 = list_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(l, indexoidlist) { Oid indexOid = lfirst_oid(l); Relation indexDesc; IndexInfo *ii; /* * Open and lock the index relation * * If the index AM supports concurrent updates, obtain * RowExclusiveLock to signify that we are updating the index. This * locks out only operations that need exclusive access, such as * relocating the index to a new tablespace. * * 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). * * If there are multiple not-concurrent-safe indexes, all backends * must lock the indexes in the same order or we will get deadlocks * here. This is guaranteed by RelationGetIndexList(), which promises * to return the index list in OID order. * * The locks will be released in ExecCloseIndices. */ indexDesc = index_open(indexOid); if (indexDesc->rd_am->amconcurrent) LockRelation(indexDesc, RowExclusiveLock); else LockRelation(indexDesc, AccessExclusiveLock); /* extract index key information from the index's pg_index info */ ii = BuildIndexInfo(indexDesc); relationDescs[i] = indexDesc; indexInfoArray[i] = ii; i++; } list_free(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; /* shouldn't happen? */ /* Drop lock acquired by ExecOpenIndices */ if (indexDescs[i]->rd_am->amconcurrent) UnlockRelation(indexDescs[i], RowExclusiveLock); else 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){ ResultRelInfo *resultRelInfo; int i; int numIndices; RelationPtr relationDescs; Relation heapRelation; IndexInfo **indexInfoArray; ExprContext *econtext; Datum values[INDEX_MAX_KEYS]; bool isnull[INDEX_MAX_KEYS]; /* * 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; /* * 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; 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 values and isnull parameters with the * appropriate values for the column(s) of the index. */ FormIndexDatum(indexInfo, slot, estate, values, isnull); /* * 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. */ index_insert(relationDescs[i], /* index relation */ values, /* array of index Datums */ isnull, /* null flags */ tupleid, /* tid of heap tuple */ heapRelation, relationDescs[i]->rd_index->indisunique && !is_vacuum); /* * keep track of index inserts for debugging */ IncrIndexInserted(); }}/* * 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 + -