📄 executils.c
字号:
/*------------------------------------------------------------------------- * * execUtils.c * miscellaneous executor utility routines * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.126.2.3 2005/11/23 20:28:04 tgl Exp $ * *------------------------------------------------------------------------- *//* * INTERFACE ROUTINES * CreateExecutorState Create/delete executor working state * FreeExecutorState * CreateExprContext * FreeExprContext * ReScanExprContext * * ExecAssignExprContext Common code for plan node init routines. * ExecAssignResultType * etc * * ExecOpenIndices \ * ExecCloseIndices | referenced by InitPlan, EndPlan, * ExecInsertIndexTuples / ExecInsert, ExecUpdate * * RegisterExprContextCallback Register function shutdown callback * UnregisterExprContextCallback Deregister function shutdown callback * * NOTES * This file has traditionally been the place to stick misc. * executor support stuff that doesn't really go anyplace else. */#include "postgres.h"#include "access/genam.h"#include "access/heapam.h"#include "catalog/index.h"#include "catalog/catalog.h"#include "catalog/pg_index.h"#include "executor/execdebug.h"#include "miscadmin.h"#include "utils/builtins.h"#include "utils/fmgroids.h"#include "utils/memutils.h"#include "utils/relcache.h"#include "utils/syscache.h"/* ---------------------------------------------------------------- * global counters for number of tuples processed, retrieved, * appended, replaced, deleted. * ---------------------------------------------------------------- */int NTupleProcessed;int NTupleRetrieved;int NTupleReplaced;int NTupleAppended;int NTupleDeleted;int NIndexTupleInserted;extern int NIndexTupleProcessed; /* have to be defined in the access * method level so that the * cinterface.a will link ok. */static void ShutdownExprContext(ExprContext *econtext);/* ---------------------------------------------------------------- * statistic functions * ---------------------------------------------------------------- *//* ---------------------------------------------------------------- * ResetTupleCount * ---------------------------------------------------------------- */#ifdef NOT_USEDvoidResetTupleCount(void){ NTupleProcessed = 0; NTupleRetrieved = 0; NTupleAppended = 0; NTupleDeleted = 0; NTupleReplaced = 0; NIndexTupleProcessed = 0;}#endif/* ---------------------------------------------------------------- * PrintTupleCount * ---------------------------------------------------------------- */#ifdef NOT_USEDvoidDisplayTupleCount(FILE *statfp){ if (NTupleProcessed > 0) fprintf(statfp, "!\t%d tuple%s processed, ", NTupleProcessed, (NTupleProcessed == 1) ? "" : "s"); else { fprintf(statfp, "!\tno tuples processed.\n"); return; } if (NIndexTupleProcessed > 0) fprintf(statfp, "%d indextuple%s processed, ", NIndexTupleProcessed, (NIndexTupleProcessed == 1) ? "" : "s"); if (NIndexTupleInserted > 0) fprintf(statfp, "%d indextuple%s inserted, ", NIndexTupleInserted, (NIndexTupleInserted == 1) ? "" : "s"); if (NTupleRetrieved > 0) fprintf(statfp, "%d tuple%s retrieved. ", NTupleRetrieved, (NTupleRetrieved == 1) ? "" : "s"); if (NTupleAppended > 0) fprintf(statfp, "%d tuple%s appended. ", NTupleAppended, (NTupleAppended == 1) ? "" : "s"); if (NTupleDeleted > 0) fprintf(statfp, "%d tuple%s deleted. ", NTupleDeleted, (NTupleDeleted == 1) ? "" : "s"); if (NTupleReplaced > 0) fprintf(statfp, "%d tuple%s replaced. ", NTupleReplaced, (NTupleReplaced == 1) ? "" : "s"); fprintf(statfp, "\n");}#endif/* ---------------------------------------------------------------- * Executor state and memory management functions * ---------------------------------------------------------------- *//* ---------------- * CreateExecutorState * * Create and initialize an EState node, which is the root of * working storage for an entire Executor invocation. * * Principally, this creates the per-query memory context that will be * used to hold all working data that lives till the end of the query. * Note that the per-query context will become a child of the caller's * CurrentMemoryContext. * ---------------- */EState *CreateExecutorState(void){ EState *estate; MemoryContext qcontext; MemoryContext oldcontext; /* * Create the per-query context for this Executor run. */ qcontext = AllocSetContextCreate(CurrentMemoryContext, "ExecutorState", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); /* * Make the EState node within the per-query context. This way, we don't * need a separate pfree() operation for it at shutdown. */ oldcontext = MemoryContextSwitchTo(qcontext); estate = makeNode(EState); /* * Initialize all fields of the Executor State structure */ estate->es_direction = ForwardScanDirection; estate->es_snapshot = SnapshotNow; estate->es_crosscheck_snapshot = InvalidSnapshot; /* no crosscheck */ estate->es_range_table = NIL; estate->es_result_relations = NULL; estate->es_num_result_relations = 0; estate->es_result_relation_info = NULL; estate->es_junkFilter = NULL; estate->es_trig_tuple_slot = NULL; estate->es_into_relation_descriptor = NULL; estate->es_into_relation_use_wal = false; estate->es_param_list_info = NULL; estate->es_param_exec_vals = NULL; estate->es_query_cxt = qcontext; estate->es_tupleTable = NULL; estate->es_processed = 0; estate->es_lastoid = InvalidOid; estate->es_rowMarks = NIL; estate->es_forUpdate = false; estate->es_rowNoWait = false; estate->es_instrument = false; estate->es_select_into = false; estate->es_into_oids = false; estate->es_exprcontexts = NIL; estate->es_per_tuple_exprcontext = NULL; estate->es_topPlan = NULL; estate->es_evalPlanQual = NULL; estate->es_evTupleNull = NULL; estate->es_evTuple = NULL; estate->es_useEvalPlan = false; /* * Return the executor state structure */ MemoryContextSwitchTo(oldcontext); return estate;}/* ---------------- * FreeExecutorState * * Release an EState along with all remaining working storage. * * Note: this is not responsible for releasing non-memory resources, * such as open relations or buffer pins. But it will shut down any * still-active ExprContexts within the EState. That is sufficient * cleanup for situations where the EState has only been used for expression * evaluation, and not to run a complete Plan. * * This can be called in any memory context ... so long as it's not one * of the ones to be freed. * ---------------- */voidFreeExecutorState(EState *estate){ /* * Shut down and free any remaining ExprContexts. We do this explicitly * to ensure that any remaining shutdown callbacks get called (since they * might need to release resources that aren't simply memory within the * per-query memory context). */ while (estate->es_exprcontexts) { /* * XXX: seems there ought to be a faster way to implement this than * repeated list_delete(), no? */ FreeExprContext((ExprContext *) linitial(estate->es_exprcontexts)); /* FreeExprContext removed the list link for us */ } /* * Free the per-query memory context, thereby releasing all working * memory, including the EState node itself. */ MemoryContextDelete(estate->es_query_cxt);}/* ---------------- * CreateExprContext * * Create a context for expression evaluation within an EState. * * An executor run may require multiple ExprContexts (we usually make one * for each Plan node, and a separate one for per-output-tuple processing * such as constraint checking). Each ExprContext has its own "per-tuple" * memory context. * * Note we make no assumption about the caller's memory context. * ---------------- */ExprContext *CreateExprContext(EState *estate){ ExprContext *econtext; MemoryContext oldcontext; /* Create the ExprContext node within the per-query memory context */ oldcontext = MemoryContextSwitchTo(estate->es_query_cxt); econtext = makeNode(ExprContext); /* Initialize fields of ExprContext */ econtext->ecxt_scantuple = NULL; econtext->ecxt_innertuple = NULL; econtext->ecxt_outertuple = NULL; econtext->ecxt_per_query_memory = estate->es_query_cxt; /* * Create working memory for expression evaluation in this context. */ econtext->ecxt_per_tuple_memory = AllocSetContextCreate(estate->es_query_cxt, "ExprContext", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); econtext->ecxt_param_exec_vals = estate->es_param_exec_vals; econtext->ecxt_param_list_info = estate->es_param_list_info; econtext->ecxt_aggvalues = NULL; econtext->ecxt_aggnulls = NULL; econtext->caseValue_datum = (Datum) 0; econtext->caseValue_isNull = true; econtext->domainValue_datum = (Datum) 0; econtext->domainValue_isNull = true; econtext->ecxt_estate = estate; econtext->ecxt_callbacks = NULL; /* * Link the ExprContext into the EState to ensure it is shut down when the * EState is freed. Because we use lcons(), shutdowns will occur in * reverse order of creation, which may not be essential but can't hurt. */ estate->es_exprcontexts = lcons(econtext, estate->es_exprcontexts); MemoryContextSwitchTo(oldcontext); return econtext;}/* ---------------- * FreeExprContext * * Free an expression context, including calling any remaining * shutdown callbacks. * * Since we free the temporary context used for expression evaluation, * any previously computed pass-by-reference expression result will go away! * * Note we make no assumption about the caller's memory context. * ---------------- */voidFreeExprContext(ExprContext *econtext){ EState *estate; /* Call any registered callbacks */ ShutdownExprContext(econtext); /* And clean up the memory used */ MemoryContextDelete(econtext->ecxt_per_tuple_memory); /* Unlink self from owning EState */ estate = econtext->ecxt_estate; estate->es_exprcontexts = list_delete_ptr(estate->es_exprcontexts, econtext); /* And delete the ExprContext node */ pfree(econtext);}/* * ReScanExprContext * * Reset an expression context in preparation for a rescan of its * plan node. This requires calling any registered shutdown callbacks, * since any partially complete set-returning-functions must be canceled. * * Note we make no assumption about the caller's memory context. */voidReScanExprContext(ExprContext *econtext){ /* Call any registered callbacks */ ShutdownExprContext(econtext); /* And clean up the memory used */ MemoryContextReset(econtext->ecxt_per_tuple_memory);}/* * Build a per-output-tuple ExprContext for an EState. * * This is normally invoked via GetPerTupleExprContext() macro, * not directly. */ExprContext *MakePerTupleExprContext(EState *estate){ if (estate->es_per_tuple_exprcontext == NULL) estate->es_per_tuple_exprcontext = CreateExprContext(estate); return estate->es_per_tuple_exprcontext;}/* ---------------------------------------------------------------- * miscellaneous node-init support functions * * Note: all of these are expected to be called with CurrentMemoryContext * equal to the per-query memory context. * ---------------------------------------------------------------- *//* ---------------- * ExecAssignExprContext * * This initializes the ps_ExprContext field. It is only necessary * to do this for nodes which use ExecQual or ExecProject * because those routines require an econtext. Other nodes that * don't have to evaluate expressions don't need to do this. * ---------------- */voidExecAssignExprContext(EState *estate, PlanState *planstate){ planstate->ps_ExprContext = CreateExprContext(estate);}/* ---------------- * ExecAssignResultType * ---------------- */voidExecAssignResultType(PlanState *planstate, TupleDesc tupDesc, bool shouldFree){ TupleTableSlot *slot = planstate->ps_ResultTupleSlot; ExecSetSlotDescriptor(slot, tupDesc, shouldFree);}/* ---------------- * ExecAssignResultTypeFromTL * ---------------- */voidExecAssignResultTypeFromTL(PlanState *planstate){ bool hasoid; TupleDesc tupDesc; if (ExecContextForcesOids(planstate, &hasoid)) { /* context forces OID choice; hasoid is now set correctly */ } else { /* given free choice, don't leave space for OIDs in result tuples */ hasoid = false; } /* * ExecTypeFromTL needs the parse-time representation of the tlist, not a * list of ExprStates. This is good because some plan nodes don't bother * to set up planstate->targetlist ... */ tupDesc = ExecTypeFromTL(planstate->plan->targetlist, hasoid); ExecAssignResultType(planstate, tupDesc, true);}/* ---------------- * ExecGetResultType * ---------------- */TupleDescExecGetResultType(PlanState *planstate){ TupleTableSlot *slot = planstate->ps_ResultTupleSlot; return slot->tts_tupleDescriptor;}/* ---------------- * ExecBuildProjectionInfo * * Build a ProjectionInfo node for evaluating the given tlist in the given * econtext, and storing the result into the tuple slot. (Caller must have * ensured that tuple slot has a descriptor matching the tlist!) Note that * the given tlist should be a list of ExprState nodes, not Expr nodes. * ---------------- */ProjectionInfo *ExecBuildProjectionInfo(List *targetList, ExprContext *econtext, TupleTableSlot *slot){ ProjectionInfo *projInfo = makeNode(ProjectionInfo); int len; bool isVarList; ListCell *tl; len = ExecTargetListLength(targetList); projInfo->pi_targetlist = targetList; projInfo->pi_exprContext = econtext; projInfo->pi_slot = slot; /* * Determine whether the target list consists entirely of simple Var * references (ie, references to non-system attributes). If so, we can * use the simpler ExecVariableList instead of ExecTargetList. */ isVarList = true; foreach(tl, targetList) { GenericExprState *gstate = (GenericExprState *) lfirst(tl); Var *variable = (Var *) gstate->arg->expr; if (variable == NULL || !IsA(variable, Var) || variable->varattno <= 0) { isVarList = false; break; } } projInfo->pi_isVarList = isVarList; if (isVarList) { int *varSlotOffsets;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -