Update execUtils.cpp

This commit is contained in:
LYLlyl 2023-08-20 18:10:07 +08:00
parent 279749ec0a
commit 58d7fc03e6
1 changed files with 208 additions and 277 deletions

View File

@ -1,44 +1,44 @@
/* -------------------------------------------------------------------------
*
* execUtils.cpp
* miscellaneous executor utility routines
*
*
* Portions Copyright (c) 2020 Huawei Technologies Co.,Ltd.
* Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
* Portions Copyright (c) 2021, openGauss Contributors
* (c) 2020
* (c) 1996-2012PostgreSQL全球开发团队
* (c) 1994
* (c) 2021openGauss
*
*
* IDENTIFICATION
*
* src/gausskernel/runtime/executor/execUtils.cpp
*
* -------------------------------------------------------------------------
* INTERFACE ROUTINES
* CreateExecutorState Create/delete executor working state
*
* CreateExecutorState /
* FreeExecutorState
* CreateExprContext
* CreateStandaloneExprContext
* FreeExprContext
* ReScanExprContext
*
* ExecAssignExprContext Common code for plan node init routines.
* ExecAssignExprContext
* ExecAssignResultType
* etc
*
*
* ExecOpenScanRelation Common code for scan node init routines.
* ExecOpenScanRelation
* ExecCloseScanRelation
*
* ExecOpenIndices \
* ExecCloseIndices | referenced by InitPlan, EndPlan,
* ExecInsertIndexTuples / ExecInsert, ExecUpdate
* ExecCloseIndices | InitPlanEndPlanExecInsertExecUpdate
* ExecInsertIndexTuples /
*
* RegisterExprContextCallback Register function shutdown callback
* UnregisterExprContextCallback Deregister function shutdown callback
* RegisterExprContextCallback
* UnregisterExprContextCallback
*
* 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 "knl/knl_variable.h"
@ -74,30 +74,31 @@ static bool check_violation(Relation heap, Relation index, IndexInfo *indexInfo,
Oid *conflictPartOid = NULL, int2 *conflictBucketid = NULL);
/* ----------------------------------------------------------------
* 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.
* EState
*
* 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.
*
* CurrentMemoryContext
* ----------------
*/
EState* CreateExecutorState(MemoryContext saveCxt)
{
EState* estate = NULL;
MemoryContext qcontext;
MemoryContext oldcontext;
/*
* Create the per-query context for this Executor run.
/*
* Executor
*/
if (saveCxt != NULL) {
qcontext = saveCxt;
} else {
@ -108,16 +109,16 @@ EState* CreateExecutorState(MemoryContext saveCxt)
ALLOCSET_DEFAULT_MAXSIZE);
}
/*
* Make the EState node within the per-query context. This way, we don't
* need a separate pfree_ext() operation for it at shutdown.
/*
* EState pfree_ext()
*/
oldcontext = MemoryContextSwitchTo(qcontext);
estate = makeNode(EState);
/*
* Initialize all fields of the Executor State structure
/*
* Executor
*/
estate->es_direction = ForwardScanDirection;
estate->es_snapshot = SnapshotNow;
@ -146,7 +147,8 @@ EState* CreateExecutorState(MemoryContext saveCxt)
estate->es_param_exec_vals = NULL;
estate->es_query_cxt = qcontext;
estate->es_const_query_cxt = qcontext; /* context query context, it will not be changed */
estate->es_const_query_cxt = qcontext;/* 查询上下文的上下文,它不会被更改 */
estate->es_tupleTable = NIL;
estate->es_epqTupleSlot = NULL;
@ -184,86 +186,77 @@ EState* CreateExecutorState(MemoryContext saveCxt)
estate->pruningResult = NULL;
/*
* Return the executor state structure
*/
/*
*
*/
MemoryContextSwitchTo(oldcontext);
return estate;
}
/* ----------------
* FreeExecutorState
/*
* EState及其所有剩余的工作存储空间
*
* Release an EState along with all remaining working storage.
* EState中的任何仍处于活动状态的ExprContext
*
*
* 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.
* ----------------
* ...
*/
void FreeExecutorState(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).
*/
/*
* ExprContexts
*/
while (estate->es_exprcontexts) {
/*
* XXX: seems there ought to be a faster way to implement this than
* repeated list_delete(), no?
*/
/*
* XXX使list_delete()
*/
FreeExprContext((ExprContext*)linitial(estate->es_exprcontexts), true);
/* FreeExprContext removed the list link for us */
/* FreeExprContext 为我们移除了链表的链接 */
}
/*
* Free the per-query memory context, thereby releasing all working
* memory, including the EState node itself.
*/
/*
* per-query EState
*/
MemoryContextDelete(estate->es_query_cxt);
}
/* ----------------
* CreateExprContext
/*
* EState
*
* Create a context for expression evaluation within an EState.
* ExprContexts
* ExprContext "每个元组"
*
* 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 = NULL;
MemoryContext oldcontext;
/* Create the ExprContext node within the per-query memory context */
/* 在每个查询的内存上下文中创建 ExprContext 节点 */
oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
econtext = makeNode(ExprContext);
/* Initialize fields of ExprContext */
/* 初始化 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,
@ -287,11 +280,7 @@ ExprContext* CreateExprContext(EState* estate)
econtext->ecxt_callbacks = NULL;
econtext->plpgsql_estate = 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.
*/
/* 将ExprContext链接到EState以确保在释放EState时关闭它。由于我们使用lcons(),关闭将按照创建的相反顺序发生,这可能不是必需的,但不会有害。 */
estate->es_exprcontexts = lcons(econtext, estate->es_exprcontexts);
MemoryContextSwitchTo(oldcontext);
@ -302,38 +291,31 @@ ExprContext* CreateExprContext(EState* estate)
/* ----------------
* CreateStandaloneExprContext
*
* Create a context for standalone expression evaluation.
*
*
* An ExprContext made this way can be used for evaluation of expressions
* that contain no Params, subplans, or Var references (it might work to
* put tuple references into the scantuple field, but it seems unwise).
* ExprContext可用于评估不包含ParamsVar引用的表达式scantuple字段是可行的
*
* The ExprContext struct is allocated in the caller's current memory
* context, which also becomes its "per query" context.
* ExprContext结构在调用者的当前内存上下文中分配
*
* It is caller's responsibility to free the ExprContext when done,
* or at least ensure that any shutdown callbacks have been called
* (ReScanExprContext() is suitable). Otherwise, non-memory resources
* might be leaked.
* ExprContextReScanExprContext()
* ----------------
*/
ExprContext* CreateStandaloneExprContext(void)
{
ExprContext* econtext = NULL;
/* Create the ExprContext node within the caller's memory context */
/* 在调用者的内存上下文中创建ExprContext节点 */
econtext = makeNode(ExprContext);
/* Initialize fields of ExprContext */
/* 初始化ExprContext的字段 */
econtext->ecxt_scantuple = NULL;
econtext->ecxt_innertuple = NULL;
econtext->ecxt_outertuple = NULL;
econtext->ecxt_per_query_memory = CurrentMemoryContext;
/*
* Create working memory for expression evaluation in this context.
*/
/* 在这个上下文中为表达式评估创建工作内存 */
econtext->ecxt_per_tuple_memory = AllocSetContextCreate(CurrentMemoryContext,
"ExprContext",
ALLOCSET_DEFAULT_MINSIZE,
@ -359,62 +341,55 @@ ExprContext* CreateStandaloneExprContext(void)
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!
*
* If isCommit is false, we are being called in error cleanup, and should
* not call callbacks but only release memory. (It might be better to call
* the callbacks and pass the isCommit flag to them, but that would require
* more invasive code changes than currently seems justified.)
*
* Note we make no assumption about the caller's memory context.
* ----------------
*/
/* 释放表达式上下文,包括调用任何剩余的关闭回调函数。
isCommit false
isCommit
*/
void FreeExprContext(ExprContext* econtext, bool isCommit)
{
EState* estate = NULL;
/* Call any registered callbacks */
/* 调用所有已注册的回调函数 */
ShutdownExprContext(econtext, isCommit);
/* And clean up the memory used */
/* 然后清理使用的内存 */
MemoryContextDelete(econtext->ecxt_per_tuple_memory);
/* Unlink self from owning EState, if any */
/* 如果有的话,从拥有它的 EState 中解除链接 */
estate = econtext->ecxt_estate;
if (estate != NULL)
estate->es_exprcontexts = list_delete_ptr(estate->es_exprcontexts, econtext);
/* And delete the ExprContext node */
/* 然后删除 ExprContext 节点 */
pfree_ext(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.
*
*/
void ReScanExprContext(ExprContext* econtext)
{
/* Call any registered callbacks */
/* 调用任何已注册的回调函数 */
ShutdownExprContext(econtext, true);
/* And clean up the memory used */
/* 清理使用的内存 */
MemoryContextReset(econtext->ecxt_per_tuple_memory);
}
/*
* Build a per-output-tuple ExprContext for an EState.
* EState ExprContext
*
* This is normally invoked via GetPerTupleExprContext() macro,
* not directly.
* GetPerTupleExprContext()
*/
ExprContext* MakePerTupleExprContext(EState* estate)
{
if (estate->es_per_tuple_exprcontext == NULL)
@ -423,22 +398,19 @@ ExprContext* MakePerTupleExprContext(EState* 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
/*
* 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.
* ----------------
* ps_ExprContext 使 ExecQual ExecProject
* econtext
*/
void ExecAssignExprContext(EState* estate, PlanState* planstate)
{
planstate->ps_ExprContext = CreateExprContext(estate);
@ -465,17 +437,15 @@ void ExecAssignResultTypeFromTL(PlanState* planstate, TableAmType tam)
TupleDesc tupDesc;
if (ExecContextForcesOids(planstate, &hasoid)) {
/* context forces OID choice; hasoid is now set correctly */
/* context 强制 OID 选择;现在 hasoid 被正确设置 */
} else {
/* given free choice, don't leave space for OIDs in result tuples */
/* 在给定自由选择的情况下,不要在结果元组中留出 OID 的空间 */
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 ...
*/
/* ExecTypeFromTL 需要 tlist 的解析时表示,而不是 ExprStates 的列表。
* planstate->targetlist ...
*/
tupDesc = ExecTypeFromTL(planstate->plan->targetlist, hasoid, false, tam);
ExecAssignResultType(planstate, tupDesc);
}
@ -487,7 +457,7 @@ void ExecAssignResultTypeFromTL(PlanState* planstate, TableAmType tam)
TupleDesc ExecGetResultType(PlanState* planstate)
{
TupleTableSlot* slot = NULL;
/* if the child node is PartIteratorState, overhead to it's child node */
/* 如果子节点是 PartIteratorState则将开销传递给其子节点 */
if (IsA(planstate, PartIteratorState) || IsA(planstate, VecPartIteratorState)) {
planstate = outerPlanState(planstate);
}
@ -516,8 +486,9 @@ void ExecAssignVectorForExprEval(ExprContext* econtext)
econtext->caseValue_vector->init(CurrentMemoryContext, unknownDesc);
}
/* Support info for column store.*/
/* targetList is given from ExprState tree, qual is given from Expr node tree.*/
/* 用于列存储的支持信息。 */
/* targetList 是从 ExprState 树中获取的qual 是从 Expr 节点树中获取的。 */
static void GetAccessedVarNumbers(ProjectionInfo* projInfo, List* targetList, List* qual)
{
List* vars = NIL;
@ -534,7 +505,7 @@ static void GetAccessedVarNumbers(ProjectionInfo* projInfo, List* targetList, Li
GenericExprState* gstate = (GenericExprState*)lfirst(l);
TargetEntry* tle = (TargetEntry*)gstate->xprstate.expr;
/* Pull vars from the targetlist .*/
/* 从目标列表中提取变量。 */
vars = pull_var_clause((Node*)tle, PVC_RECURSE_AGGREGATES, PVC_RECURSE_PLACEHOLDERS);
foreach (vl, vars) {
@ -550,12 +521,12 @@ static void GetAccessedVarNumbers(ProjectionInfo* projInfo, List* targetList, Li
}
}
/*
* Used for PackT optimization: PackTCopyVarsList records those columns what we need to move.
*/
/*
* PackT PackTCopyVarsList
*/
List* PackTCopyVarsList = list_copy(varattno_list);
/* Now consider the quals */
/* 现在考虑条件表达式quals */
vars = pull_var_clause((Node*)qual, PVC_RECURSE_AGGREGATES, PVC_RECURSE_PLACEHOLDERS);
foreach (l, vars) {
Var* var = (Var*)lfirst(l);
@ -573,10 +544,9 @@ static void GetAccessedVarNumbers(ProjectionInfo* projInfo, List* targetList, Li
isConst = true;
}
// Now we need get which var can be late accessed.
// In other words, these columns can be load after filter
// We can read these columns as late as possible
//
// 现在我们需要确定哪些变量可以被延迟访问。
// 换句话说,这些列可以在过滤后加载。
// 我们可以尽可能晚地读取这些列。
if (qualVarNoList != NIL) {
lateAccessVarNoList = list_difference_int(varattno_list, qualVarNoList);
list_free_ext(qualVarNoList);
@ -586,8 +556,8 @@ static void GetAccessedVarNumbers(ProjectionInfo* projInfo, List* targetList, Li
PackLateAccessList = list_difference_int(PackTCopyVarsList, lateAccessVarNoList);
}
/*
* Here projInfo->pi_PackTCopyVars records the specific column data what we want.
/*
* projInfo->pi_PackTCopyVars
*/
projInfo->pi_PackTCopyVars = PackTCopyVarsList;
projInfo->pi_acessedVarNumbers = varattno_list;
@ -601,7 +571,7 @@ List* GetAccessedVarnoList(List* targetList, List* qual)
{
ProjectionInfo tmp_pi;
/* get accessed attno of this query statement */
/* 获取此查询语句的已访问的属性号(列号) */
GetAccessedVarNumbers(&tmp_pi, targetList, qual);
if (tmp_pi.pi_PackTCopyVars) {
list_free_ext(tmp_pi.pi_PackTCopyVars);
@ -623,14 +593,14 @@ ProjectionInfo* ExecBuildVecProjectionInfo(
bool directMap = false;
ListCell* tl = NULL;
// Guard for zero length projection
// 保护零长度投影
//
if (len == 0)
return NULL;
projInfo->pi_exprContext = econtext;
projInfo->pi_slot = slot;
/* since these are all int arrays, we need do just one palloc */
// 由于这些都是整数数组,我们只需要执行一次 palloc 操作
workspace = (int*)palloc(len * 3 * sizeof(int));
projInfo->pi_varSlotOffsets = varSlotOffsets = workspace;
projInfo->pi_varNumbers = varNumbers = workspace + len;
@ -638,20 +608,18 @@ ProjectionInfo* ExecBuildVecProjectionInfo(
projInfo->pi_lastInnerVar = 0;
projInfo->pi_lastOuterVar = 0;
projInfo->pi_lastScanVar = 0;
/* Support info for column store.*/
/* 列存储的支持信息 */
GetAccessedVarNumbers(projInfo, targetList, nt_qual);
// Allocate batch for current project.
// 为当前的投影操作分配批处理内存。
//
projInfo->pi_batch = New(CurrentMemoryContext) VectorBatch(CurrentMemoryContext, slot->tts_tupleDescriptor);
/*
* We separate the target list elements into simple Var references and
* expressions which require the full ExecTargetList machinery. To be a
* simple Var, a Var has to be a user attribute and not mismatch the
* inputDesc. (Note: if there is a type mismatch then ExecEvalVar will
* probably throw an error at runtime, but we leave that to it.)
*/
/*
* Var ExecTargetList
* VarVar
* ExecEvalVar
*/
exprlist = NIL;
numSimpleVars = 0;
directMap = true;
@ -662,7 +630,7 @@ ProjectionInfo* ExecBuildVecProjectionInfo(
if (variable != NULL && IsA(variable, Var) && variable->varattno > 0) {
if (!inputDesc)
isSimpleVar = true; /* can't check type, assume OK */
isSimpleVar = true; /* 无法检查类型,假设是没问题的 */
else if (variable->varattno <= inputDesc->natts) {
Form_pg_attribute attr;
@ -702,9 +670,9 @@ ProjectionInfo* ExecBuildVecProjectionInfo(
}
numSimpleVars++;
} else {
/* Not a simple variable, add it to generic targetlist */
/* 不是一个简单的变量,将其添加到通用目标列表中 */
exprlist = lappend(exprlist, gstate);
/* Examine expr to include contained Vars in lastXXXVar counts */
/* 检查表达式以包括在 lastXXXVar 计数中包含的变量 */
get_last_attnums((Node*)variable, projInfo);
}
}
@ -735,20 +703,12 @@ ProjectionInfo* ExecBuildVecProjectionInfo(
return projInfo;
}
/* ----------------
* 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.
*
* inputDesc can be NULL, but if it is not, we check to see whether simple
* Vars in the tlist match the descriptor. It is important to provide
* inputDesc for relation-scan plan nodes, as a cross check that the relation
* hasn't been changed since the plan was made. At higher levels of a plan,
* there is no need to recheck.
* ----------------
/* 构建 ProjectionInfo 结构,用于在给定的 econtext 中计算给定的 tlist并将结果存储到元组槽中。
* tlist tlist ExprState Expr
* inputDesc NULL NULL tlist
* inputDesc
*
*/
ProjectionInfo* ExecBuildProjectionInfo(
List* targetList, ExprContext* econtext, TupleTableSlot* slot, TupleDesc inputDesc)
@ -766,7 +726,7 @@ ProjectionInfo* ExecBuildProjectionInfo(
projInfo->pi_exprContext = econtext;
projInfo->pi_slot = slot;
/* since these are all int arrays, we need do just one palloc */
/* 由于这些都是 int 数组我们只需要进行一次内存分配palloc */
workspace = (int*)palloc(len * 3 * sizeof(int));
projInfo->pi_varSlotOffsets = varSlotOffsets = workspace;
projInfo->pi_varNumbers = varNumbers = workspace + len;
@ -775,13 +735,11 @@ ProjectionInfo* ExecBuildProjectionInfo(
projInfo->pi_lastOuterVar = 0;
projInfo->pi_lastScanVar = 0;
/*
* We separate the target list elements into simple Var references and
* expressions which require the full ExecTargetList machinery. To be a
* simple Var, a Var has to be a user attribute and not mismatch the
* inputDesc. (Note: if there is a type mismatch then ExecEvalScalarVar
* will probably throw an error at runtime, but we leave that to it.)
*/
/*
* Var ExecTargetList
* VarVar inputDesc
* ExecEvalScalarVar
*/
exprlist = NIL;
numSimpleVars = 0;
directMap = true;
@ -835,7 +793,7 @@ ProjectionInfo* ExecBuildProjectionInfo(
} else {
/* Not a simple variable, add it to generic targetlist */
exprlist = lappend(exprlist, gstate);
/* Examine expr to include contained Vars in lastXXXVar counts */
/* 检查表达式以包含在 lastXXXVar 计数中包含的变量 */
get_last_attnums((Node*)variable, projInfo);
}
}
@ -852,10 +810,9 @@ ProjectionInfo* ExecBuildProjectionInfo(
}
/*
* get_last_attnums: expression walker for ExecBuildProjectionInfo
* get_last_attnums: ExecBuildProjectionInfo
*
* Update the lastXXXVar counts to be at least as large as the largest
* attribute numbers found in the expression
* lastXXXVar 使
*/
static bool get_last_attnums(Node* node, ProjectionInfo* projInfo)
{
@ -885,12 +842,10 @@ static bool get_last_attnums(Node* node, ProjectionInfo* projInfo)
return false;
}
/*
* Don't examine the arguments of Aggrefs or WindowFuncs, because those do
* not represent expressions to be evaluated within the overall
* overall targetlist's econtext. GroupingFunc arguments are never
* evaluated at all.
*/
/*
* Aggrefs WindowFuncs econtext
* GroupingFunc
*/
if (IsA(node, Aggref) || IsA(node, GroupingFunc))
return false;
if (IsA(node, WindowFunc))
@ -898,55 +853,37 @@ static bool get_last_attnums(Node* node, ProjectionInfo* projInfo)
return expression_tree_walker(node, (bool (*)())get_last_attnums, (void*)projInfo);
}
/* ----------------
* ExecAssignProjectionInfo
/*
*
*
* forms the projection information from the node's targetlist
*
* Notes for inputDesc are same as for ExecBuildProjectionInfo: supply it
* for a relation-scan node, can pass NULL for upper-level nodes
* ----------------
* inputDesc ExecBuildProjectionInfo NULL
*/
void ExecAssignProjectionInfo(PlanState* planstate, TupleDesc inputDesc)
{
planstate->ps_ProjInfo = ExecBuildProjectionInfo(
planstate->targetlist, planstate->ps_ExprContext, planstate->ps_ResultTupleSlot, inputDesc);
}
/* ----------------
* ExecFreeExprContext
/*
* ExprContext
*
* 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.
* ----------------
* ... ExecEndNode FreeExecutorState EState ExprContext FreeExecutorState ExprContexts FreeExprContext O(N^2)
*/
void ExecFreeExprContext(PlanState* planstate)
{
/*
* Per above discussion, don't actually delete the ExprContext. We do
* unlink it from the plan node, though.
*/
/*
* ExprContext
*/
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
* ----------------------------------------------------------------
/*
*
* ProjectionInfo -cim 6/3/91
*/
/* ----------------
* ExecGetScanType
* ----------------
@ -991,8 +928,7 @@ void ExecAssignScanTypeFromOuterPlan(ScanState* scanstate)
/* ----------------------------------------------------------------
* ExecRelationIsTargetRelation
*
* Detect whether a relation (identified by rangetable index)
* is one of the target relations of the query.
*
* ----------------------------------------------------------------
*/
bool ExecRelationIsTargetRelation(EState* estate, Index scanrelid)
@ -1008,16 +944,11 @@ bool ExecRelationIsTargetRelation(EState* estate, Index scanrelid)
return false;
}
/* ----------------------------------------------------------------
* ExecOpenScanRelation
/* ExecOpenScanRelation
* ExecInit例程中调用此函数
*
* Open the heap relation to be scanned by a base-level scan plan node.
* This should be called during the node's ExecInit routine.
*
* By default, this acquires AccessShareLock on the relation. However,
* if the relation was already locked by InitPlan, we don't need to acquire
* any additional lock. This saves trips to the shared lock manager.
* ----------------------------------------------------------------
* AccessShareLockInitPlan锁定访
*/
Relation ExecOpenScanRelation(EState* estate, Index scanrelid)
{
@ -1025,11 +956,11 @@ Relation ExecOpenScanRelation(EState* estate, Index scanrelid)
LOCKMODE lockmode;
Relation rel;
/*
* Determine the lock type we need. First, scan to see if target relation
* is a result relation. If not, check if it's a FOR UPDATE/FOR SHARE
* relation. In either of those cases, we got the lock already.
*/
/*
*
* FOR UPDATE/FOR SHARE关系
*
*/
lockmode = AccessShareLock;
if (ExecRelationIsTargetRelation(estate, scanrelid))
lockmode = NoLock;
@ -1039,7 +970,7 @@ Relation ExecOpenScanRelation(EState* estate, Index scanrelid)
foreach (l, estate->es_rowMarks) {
ExecRowMark* erm = (ExecRowMark*)lfirst(l);
/* Keep this check in sync with InitPlan! */
/* 保持这个检查与InitPlan同步 */
if (erm->rti == scanrelid && erm->relation != NULL) {
lockmode = NoLock;
break;
@ -1047,12 +978,12 @@ Relation ExecOpenScanRelation(EState* estate, Index scanrelid)
}
}
/* Open the relation and acquire lock as needed */
/* 打开关系并根据需要获取锁定 */
reloid = getrelid(scanrelid, estate->es_range_table);
rel = heap_open(reloid, lockmode);
if (STMT_RETRY_ENABLED) {
// do noting for now, if query retry is on, just to skip validateTempRelation here
// 目前什么都不做,如果查询重试已启用,则跳过在这里进行 validateTempRelation 操作
} else
validateTempRelation(rel);
@ -1062,17 +993,17 @@ Relation ExecOpenScanRelation(EState* estate, Index scanrelid)
/* ----------------------------------------------------------------
* ExecCloseScanRelation
*
* Close the heap relation scanned by a base-level scan plan node.
* This should be called during the node's ExecEnd routine.
*
* ExecEnd
*
* Currently, we do not release the lock acquired by ExecOpenScanRelation.
* This lock should be held till end of transaction. (There is a faction
* that considers this too much locking, however.)
* ExecOpenScanRelation
* ()
*
* If we did want to release the lock, we'd have to repeat the logic in
* ExecOpenScanRelation in order to figure out what to release.
* ExecOpenScanRelation
* 便
* ----------------------------------------------------------------
*/
void ExecCloseScanRelation(Relation scanrel)
{
heap_close(scanrel, NoLock);
@ -1080,14 +1011,14 @@ void ExecCloseScanRelation(Relation scanrel)
/*
* @@GaussDB@@
* Target : data partition
* Brief : Open the heap partition to be scanned by a base-level scan plan
* : node. This should be called during the node's ExecInit routine.
* Description :
* Notes : By default, this acquires AccessShareLock on the partitioned relation.
* : However, if the relation was already locked by InitPlan, we don't need
* : to acquire any additional lock. This saves trips to the shared lock manager.
*
* ExecInit
*
* AccessShareLock
* InitPlan
* 访
*/
Partition ExecOpenScanParitition(EState* estate, Relation parent, PartitionIdentifier* partID, LOCKMODE lockmode)
{
Oid partoid = InvalidOid;
@ -1096,7 +1027,7 @@ Partition ExecOpenScanParitition(EState* estate, Relation parent, PartitionIdent
Assert(PointerIsValid(parent));
Assert(PointerIsValid(partID));
/* OK, open the relation and acquire lock as needed */
/* 打开关系并根据需要获取锁 */
partoid = partIDGetPartOid(parent, partID);
return partitionOpen(parent, partoid, lockmode);