【PostgreSQL内核学习(二十八) —— 执行器 (表达式计算) 】

表达式计算

声明 :本文的部分内容参考了他人的文章。在编写过程中,我们尊重他人的知识产权和学术成果,力求遵循合理使用原则,并在适用的情况下注明引用来源。

本文主要参考了 postgresql-10.1 的开源代码和《OpenGauss数据库源码解析》和《PostgresSQL数据库内核分析》一书。

概述

PostgreSQL 系统的执行器模块中,"表达式计算 " 是一个核心功能 ,它负责处理和评估 SQL 查询中的各种表达式 ,包括算术运算逻辑判断函数调用等。这一过程涉及解析查询中的表达式树 ,然后按照操作符和函数的定义,逐节点计算表达式的值。执行器会利用类型系统来处理不同数据类型之间的操作,并可能涉及类型转换以确保操作的正确性。此外,表达式计算还可能包括对表达式中涉及的列数据进行访问和检索,以及应用优化策略如索引查找或缓存结果以提高计算效率。通过这一系列复杂的计算过程,PostgreSQL 能够准确执行 SQL 查询,返回用户所需的数据结果。

处理 SQL 语句中的函数调用计算式条件表达式 时需要用到表达式计算PostgreSQL 系统中实现了表达式计算子系统,用于表示和执行 SQL 语句中的各种表达式。

如下图所示,在 PosgreSQL 系统中,表达式的表示方式与查询计划树的计划节点类似 ,用各种表达式计划节点(下称表达式节点)来完成相应的操作。表达式继承层次中的公共根类为 ExpI 节点,其他表达式节点都继承 Expr 节点。表达式状态的公共根类为 ExprState ,定义了类型type )辅助表达式节点指针expr )以及用于实现该节点操作的函数指针evalfunc)。

表达式节点计划节点 的不同在于,并不是所有的表达式节点都需要定义特定的状态类型PostgreSQL 定义了一个 GenericExprState 基本的状态节点 ,没有特殊需要的表达式节点都用它来记录执行中的状态。GenericExprState 只在 ExprState 节点上扩展定义了子节点链表 args ,这也是该操作的参数来源。ExprContext (表达式上下文)则充当了 Estate 的角色,表达式计算过程的参数以及表达式所使用的内存上下文等会存放在此结构中。每个计划节点都会有表达式计算,因此在 PlanState 中定义了 ps_ExprContext 用于存储该计划节点的表达式上下文。

Expr 结构体

Expr 结构体作为可执行表达式节点的通用超类(或基类)。在 PostgreSQL 的查询执行框架中,所有用于可执行表达式树的节点类型都应该从 Expr 派生,即它们的第一个字段应该是 Expr 类型。这里的 Expr 结构体只包含一个名为 typeNodeTag 字段,用于标识具体的节点类型。

cpp 复制代码
/*
 * Expr - 可执行表达式节点的通用超类
 *
 * 所有在可执行表达式树中使用的节点类型都应该派生自Expr(即,将Expr作为它们的第一个字段)。
 * 由于Expr仅包含NodeTag,这更像是一种形式上的规定,但这也是一种简单的文档化形式。
 * 另见execnodes.h中的ExprState节点类型。
 */
typedef struct Expr
{
	NodeTag		type; /* 节点类型标识符,用于区分不同类型的表达式节点 */
} Expr;

其中,NodeTag 字段是一个枚举类型,它包含了 PostgreSQL所有节点类型的标识 ,通过这个字段,执行引擎可以确定每个节点的具体类型,从而执行相应的操作。NodeTag 具体如下所示:

c 复制代码
/*
 * The first field of every node is NodeTag. Each node created (with makeNode)
 * will have one of the following tags as the value of its first field.
 *
 * Note that inserting or deleting node types changes the numbers of other
 * node types later in the list.  This is no problem during development, since
 * the node numbers are never stored on disk.  But don't do it in a released
 * branch, because that would represent an ABI break for extensions.
 */
typedef enum NodeTag
{
	T_Invalid = 0,

	/*
	 * TAGS FOR EXECUTOR NODES (execnodes.h)
	 */
	T_IndexInfo,
	T_ExprContext,
	T_ProjectionInfo,
	T_JunkFilter,
	T_ResultRelInfo,
	T_EState,
	T_TupleTableSlot,

	/*
	 * TAGS FOR PLAN NODES (plannodes.h)
	 */
	T_Plan,
	T_Result,
	T_ProjectSet,
	T_ModifyTable,
	T_Append,
	T_MergeAppend,
	T_RecursiveUnion,
	T_BitmapAnd,
	T_BitmapOr,
	T_Scan,
	T_SeqScan,
	T_SampleScan,
	T_IndexScan,
	T_IndexOnlyScan,
	T_BitmapIndexScan,
	T_BitmapHeapScan,
	T_TidScan,
	T_SubqueryScan,
	T_FunctionScan,
	T_ValuesScan,
	T_TableFuncScan,
	T_CteScan,
	T_NamedTuplestoreScan,
	T_WorkTableScan,
	T_ForeignScan,
	T_CustomScan,
	T_Join,
	T_NestLoop,
	T_MergeJoin,
	T_HashJoin,
	T_Material,
	T_Sort,
	T_Group,
	T_Agg,
	T_WindowAgg,
	T_Unique,
	T_Gather,
	T_GatherMerge,
	T_Hash,
	T_SetOp,
	T_LockRows,
	T_Limit,
	/* these aren't subclasses of Plan: */
	T_NestLoopParam,
	T_PlanRowMark,
	T_PlanInvalItem,

	/*
	 * TAGS FOR PLAN STATE NODES (execnodes.h)
	 *
	 * These should correspond one-to-one with Plan node types.
	 */
	T_PlanState,
	T_ResultState,
	T_ProjectSetState,
	T_ModifyTableState,
	T_AppendState,
	T_MergeAppendState,
	T_RecursiveUnionState,
	T_BitmapAndState,
	T_BitmapOrState,
	T_ScanState,
	T_SeqScanState,
	T_SampleScanState,
	T_IndexScanState,
	T_IndexOnlyScanState,
	T_BitmapIndexScanState,
	T_BitmapHeapScanState,
	T_TidScanState,
	T_SubqueryScanState,
	T_FunctionScanState,
	T_TableFuncScanState,
	T_ValuesScanState,
	T_CteScanState,
	T_NamedTuplestoreScanState,
	T_WorkTableScanState,
	T_ForeignScanState,
	T_CustomScanState,
	T_JoinState,
	T_NestLoopState,
	T_MergeJoinState,
	T_HashJoinState,
	T_MaterialState,
	T_SortState,
	T_GroupState,
	T_AggState,
	T_WindowAggState,
	T_UniqueState,
	T_GatherState,
	T_GatherMergeState,
	T_HashState,
	T_SetOpState,
	T_LockRowsState,
	T_LimitState,

	/*
	 * TAGS FOR PRIMITIVE NODES (primnodes.h)
	 */
	T_Alias,
	T_RangeVar,
	T_TableFunc,
	T_Expr,
	T_Var,
	T_Const,
	T_Param,
	T_Aggref,
	T_GroupingFunc,
	T_WindowFunc,
	T_ArrayRef,
	T_FuncExpr,
	T_NamedArgExpr,
	T_OpExpr,
	T_DistinctExpr,
	T_NullIfExpr,
	T_ScalarArrayOpExpr,
	T_BoolExpr,
	T_SubLink,
	T_SubPlan,
	T_AlternativeSubPlan,
	T_FieldSelect,
	T_FieldStore,
	T_RelabelType,
	T_CoerceViaIO,
	T_ArrayCoerceExpr,
	T_ConvertRowtypeExpr,
	T_CollateExpr,
	T_CaseExpr,
	T_CaseWhen,
	T_CaseTestExpr,
	T_ArrayExpr,
	T_RowExpr,
	T_RowCompareExpr,
	T_CoalesceExpr,
	T_MinMaxExpr,
	T_SQLValueFunction,
	T_XmlExpr,
	T_NullTest,
	T_BooleanTest,
	T_CoerceToDomain,
	T_CoerceToDomainValue,
	T_SetToDefault,
	T_CurrentOfExpr,
	T_NextValueExpr,
	T_InferenceElem,
	T_TargetEntry,
	T_RangeTblRef,
	T_JoinExpr,
	T_FromExpr,
	T_OnConflictExpr,
	T_IntoClause,

	/*
	 * TAGS FOR EXPRESSION STATE NODES (execnodes.h)
	 *
	 * ExprState represents the evaluation state for a whole expression tree.
	 * Most Expr-based plan nodes do not have a corresponding expression state
	 * node, they're fully handled within execExpr* - but sometimes the state
	 * needs to be shared with other parts of the executor, as for example
	 * with AggrefExprState, which nodeAgg.c has to modify.
	 */
	T_ExprState,
	T_AggrefExprState,
	T_WindowFuncExprState,
	T_SetExprState,
	T_SubPlanState,
	T_AlternativeSubPlanState,
	T_DomainConstraintState,

	/*
	 * TAGS FOR PLANNER NODES (relation.h)
	 */
	T_PlannerInfo,
	T_PlannerGlobal,
	T_RelOptInfo,
	T_IndexOptInfo,
	T_ForeignKeyOptInfo,
	T_ParamPathInfo,
	T_Path,
	T_IndexPath,
	T_BitmapHeapPath,
	T_BitmapAndPath,
	T_BitmapOrPath,
	T_TidPath,
	T_SubqueryScanPath,
	T_ForeignPath,
	T_CustomPath,
	T_NestPath,
	T_MergePath,
	T_HashPath,
	T_AppendPath,
	T_MergeAppendPath,
	T_ResultPath,
	T_MaterialPath,
	T_UniquePath,
	T_GatherPath,
	T_GatherMergePath,
	T_ProjectionPath,
	T_ProjectSetPath,
	T_SortPath,
	T_GroupPath,
	T_UpperUniquePath,
	T_AggPath,
	T_GroupingSetsPath,
	T_MinMaxAggPath,
	T_WindowAggPath,
	T_SetOpPath,
	T_RecursiveUnionPath,
	T_LockRowsPath,
	T_ModifyTablePath,
	T_LimitPath,
	/* these aren't subclasses of Path: */
	T_EquivalenceClass,
	T_EquivalenceMember,
	T_PathKey,
	T_PathTarget,
	T_RestrictInfo,
	T_PlaceHolderVar,
	T_SpecialJoinInfo,
	T_AppendRelInfo,
	T_PartitionedChildRelInfo,
	T_PlaceHolderInfo,
	T_MinMaxAggInfo,
	T_PlannerParamItem,
	T_RollupData,
	T_GroupingSetData,
	T_StatisticExtInfo,

	/*
	 * TAGS FOR MEMORY NODES (memnodes.h)
	 */
	T_MemoryContext,
	T_AllocSetContext,
	T_SlabContext,

	/*
	 * TAGS FOR VALUE NODES (value.h)
	 */
	T_Value,
	T_Integer,
	T_Float,
	T_String,
	T_BitString,
	T_Null,

	/*
	 * TAGS FOR LIST NODES (pg_list.h)
	 */
	T_List,
	T_IntList,
	T_OidList,

	/*
	 * TAGS FOR EXTENSIBLE NODES (extensible.h)
	 */
	T_ExtensibleNode,

	/*
	 * TAGS FOR STATEMENT NODES (mostly in parsenodes.h)
	 */
	T_RawStmt,
	T_Query,
	T_PlannedStmt,
	T_InsertStmt,
	T_DeleteStmt,
	T_UpdateStmt,
	T_SelectStmt,
	T_AlterTableStmt,
	T_AlterTableCmd,
	T_AlterDomainStmt,
	T_SetOperationStmt,
	T_GrantStmt,
	T_GrantRoleStmt,
	T_AlterDefaultPrivilegesStmt,
	T_ClosePortalStmt,
	T_ClusterStmt,
	T_CopyStmt,
	T_CreateStmt,
	T_DefineStmt,
	T_DropStmt,
	T_TruncateStmt,
	T_CommentStmt,
	T_FetchStmt,
	T_IndexStmt,
	T_CreateFunctionStmt,
	T_AlterFunctionStmt,
	T_DoStmt,
	T_RenameStmt,
	T_RuleStmt,
	T_NotifyStmt,
	T_ListenStmt,
	T_UnlistenStmt,
	T_TransactionStmt,
	T_ViewStmt,
	T_LoadStmt,
	T_CreateDomainStmt,
	T_CreatedbStmt,
	T_DropdbStmt,
	T_VacuumStmt,
	T_ExplainStmt,
	T_CreateTableAsStmt,
	T_CreateSeqStmt,
	T_AlterSeqStmt,
	T_VariableSetStmt,
	T_VariableShowStmt,
	T_DiscardStmt,
	T_CreateTrigStmt,
	T_CreatePLangStmt,
	T_CreateRoleStmt,
	T_AlterRoleStmt,
	T_DropRoleStmt,
	T_LockStmt,
	T_ConstraintsSetStmt,
	T_ReindexStmt,
	T_CheckPointStmt,
	T_CreateSchemaStmt,
	T_AlterDatabaseStmt,
	T_AlterDatabaseSetStmt,
	T_AlterRoleSetStmt,
	T_CreateConversionStmt,
	T_CreateCastStmt,
	T_CreateOpClassStmt,
	T_CreateOpFamilyStmt,
	T_AlterOpFamilyStmt,
	T_PrepareStmt,
	T_ExecuteStmt,
	T_DeallocateStmt,
	T_DeclareCursorStmt,
	T_CreateTableSpaceStmt,
	T_DropTableSpaceStmt,
	T_AlterObjectDependsStmt,
	T_AlterObjectSchemaStmt,
	T_AlterOwnerStmt,
	T_AlterOperatorStmt,
	T_DropOwnedStmt,
	T_ReassignOwnedStmt,
	T_CompositeTypeStmt,
	T_CreateEnumStmt,
	T_CreateRangeStmt,
	T_AlterEnumStmt,
	T_AlterTSDictionaryStmt,
	T_AlterTSConfigurationStmt,
	T_CreateFdwStmt,
	T_AlterFdwStmt,
	T_CreateForeignServerStmt,
	T_AlterForeignServerStmt,
	T_CreateUserMappingStmt,
	T_AlterUserMappingStmt,
	T_DropUserMappingStmt,
	T_AlterTableSpaceOptionsStmt,
	T_AlterTableMoveAllStmt,
	T_SecLabelStmt,
	T_CreateForeignTableStmt,
	T_ImportForeignSchemaStmt,
	T_CreateExtensionStmt,
	T_AlterExtensionStmt,
	T_AlterExtensionContentsStmt,
	T_CreateEventTrigStmt,
	T_AlterEventTrigStmt,
	T_RefreshMatViewStmt,
	T_ReplicaIdentityStmt,
	T_AlterSystemStmt,
	T_CreatePolicyStmt,
	T_AlterPolicyStmt,
	T_CreateTransformStmt,
	T_CreateAmStmt,
	T_CreatePublicationStmt,
	T_AlterPublicationStmt,
	T_CreateSubscriptionStmt,
	T_AlterSubscriptionStmt,
	T_DropSubscriptionStmt,
	T_CreateStatsStmt,
	T_AlterCollationStmt,

	/*
	 * TAGS FOR PARSE TREE NODES (parsenodes.h)
	 */
	T_A_Expr,
	T_ColumnRef,
	T_ParamRef,
	T_A_Const,
	T_FuncCall,
	T_A_Star,
	T_A_Indices,
	T_A_Indirection,
	T_A_ArrayExpr,
	T_ResTarget,
	T_MultiAssignRef,
	T_TypeCast,
	T_CollateClause,
	T_SortBy,
	T_WindowDef,
	T_RangeSubselect,
	T_RangeFunction,
	T_RangeTableSample,
	T_RangeTableFunc,
	T_RangeTableFuncCol,
	T_TypeName,
	T_ColumnDef,
	T_IndexElem,
	T_Constraint,
	T_DefElem,
	T_RangeTblEntry,
	T_RangeTblFunction,
	T_TableSampleClause,
	T_WithCheckOption,
	T_SortGroupClause,
	T_GroupingSet,
	T_WindowClause,
	T_ObjectWithArgs,
	T_AccessPriv,
	T_CreateOpClassItem,
	T_TableLikeClause,
	T_FunctionParameter,
	T_LockingClause,
	T_RowMarkClause,
	T_XmlSerialize,
	T_WithClause,
	T_InferClause,
	T_OnConflictClause,
	T_CommonTableExpr,
	T_RoleSpec,
	T_TriggerTransition,
	T_PartitionElem,
	T_PartitionSpec,
	T_PartitionBoundSpec,
	T_PartitionRangeDatum,
	T_PartitionCmd,

	/*
	 * TAGS FOR REPLICATION GRAMMAR PARSE NODES (replnodes.h)
	 */
	T_IdentifySystemCmd,
	T_BaseBackupCmd,
	T_CreateReplicationSlotCmd,
	T_DropReplicationSlotCmd,
	T_StartReplicationCmd,
	T_TimeLineHistoryCmd,
	T_SQLCmd,

	/*
	 * TAGS FOR RANDOM OTHER STUFF
	 *
	 * These are objects that aren't part of parse/plan/execute node tree
	 * structures, but we give them NodeTags anyway for identification
	 * purposes (usually because they are involved in APIs where we want to
	 * pass multiple object types through the same pointer).
	 */
	T_TriggerData,				/* in commands/trigger.h */
	T_EventTriggerData,			/* in commands/event_trigger.h */
	T_ReturnSetInfo,			/* in nodes/execnodes.h */
	T_WindowObjectData,			/* private in nodeWindowAgg.c */
	T_TIDBitmap,				/* in nodes/tidbitmap.h */
	T_InlineCodeBlock,			/* in nodes/parsenodes.h */
	T_FdwRoutine,				/* in foreign/fdwapi.h */
	T_IndexAmRoutine,			/* in access/amapi.h */
	T_TsmRoutine,				/* in access/tsmapi.h */
	T_ForeignKeyCacheInfo		/* in utils/rel.h */
} NodeTag;

GenericExprState 结构体

GenericExprState 结构体主要用于 PostgreSQL 的查询执行树中,特别是那些不需要额外本地运行时状态信息,但具有单个子表达式节点的表达式类型。在执行查询时,每个表达式节点都需要一个与之对应的状态结构体来保存执行过程中的相关信息。GenericExprState 结构体中,xprstate 成员用于存储表达式执行过程中的通用状态信息 ,如执行上下文 等,而 arg 成员则指向这个表达式唯一的子节点的状态 ,这样就构成了一个可以递归处理表达式树 的结构。通过这种方式,PostgreSQL 能够有效地管理和执行查询中的表达式计算,确保查询执行的正确性和效率。

GenericExprState 定义如下:

c 复制代码
/* ----------------
 *      GenericExprState 结构体
 *
 * 这个结构体用于那些不需要本地运行时状态的Expr节点类型,
 * 但是有一个子Expr节点。
 * ----------------
 */
typedef struct GenericExprState {
    ExprState xprstate; 	/* 表达式状态,包含执行表达式所需的公共状态信息 */
    ExprState* arg; 		/* 子节点的状态,指向该节点唯一的子表达式状态 */
} GenericExprState;

表达式初始化

表达式的计算过程也分为三个部分:初始化、执行和清理。初始化过程使用统一接口 ExecInitExpr ,根据表达式节点类型进行相应的处理。执行过程 使用统一接口宏 ExecEvalExpr ,执行过程类似于计划节点的递归方式。清理工作会通过释放内存上下文来实现,因此本文不对清理操作进行展开。

ExecInitExpr 函数作用是为给定的表达式节点创建并初始化一个执行状态结构(ExprState),这包括将表达式本身与执行状态关联、初始化所需的槽位、编译表达式到一系列可执行的步骤,以及最终添加一个表示表达式执行完成的步骤。这个过程为表达式的运行时执行做好准备,确保表达式可以在查询执行期间被有效地评估。通过这种方式,PostgreSQL 执行器能够处理各种复杂的查询表达式,从而执行 SQL 语句中定义的操作。ExecInitExpr 函数源码如下所示:(src\backend\executor\execExpr.c

c 复制代码
xprState *ExecInitExpr(Expr *node, PlanState *parent)
{
	ExprState  *state; // 定义一个指向ExprState的指针,用于存储表达式的执行状态
	ExprEvalStep scratch; // 定义一个临时的ExprEvalStep结构,用于构建执行步骤

	/* 特殊情况:NULL表达式生成一个NULL的ExprState指针 */
	if (node == NULL)
		return NULL;

	/* 用空的步骤列表初始化ExprState */
	state = makeNode(ExprState); // 创建一个ExprState节点
	state->expr = node; // 将传入的表达式节点赋值给ExprState的expr成员

	/* 根据需要插入EEOP_*_FETCHSOME步骤 */
	ExecInitExprSlots(state, (Node *) node); // 初始化表达式中的槽位

	/* 编译表达式本身 */
	ExecInitExprRec(node, parent, state, &state->resvalue, &state->resnull); // 递归初始化表达式及其子表达式

	/* 最后,添加一个完成步骤 */
	scratch.opcode = EEOP_DONE; // 设置操作码为完成标志
	ExprEvalPushStep(state, &scratch); // 将完成步骤推入执行步骤列表

	ExecReadyExpr(state); // 准备表达式的执行,可能涉及一些最终的设置或优化

	return state; // 返回初始化好的ExprState
}

ExecInitExpr 函数在 PostgreSQL 的查询执行过程中扮演着核心角色,它是表达式执行框架的入口点 ,用于初始化和准备表达式的执行环境。当 PostgreSQL 的查询优化器生成了一个查询执行计划 后,这个计划会包含多个计划节点Plan Nodes ),每个节点代表了执行计划中的一个操作(例如,扫描表连接操作聚合 等),每个计划节点可能会包含一个或多个表达式(例如,过滤条件、投影列的计算表达式等)。这些表达式需要在查询执行时被评估。

其次,在执行阶段的开始,每个计划节点会通过 ExecInitNode 函数或类似的初始化函数被初始化。ExecInitExpr 负责为每个表达式生成一个 ExprState 结构,这个结构包含了执行该表达式所需的所有运行时信息,包括编译后的执行步骤列表和结果槽位。

最后,ExecInitExpr 还负责确保表达式执行时所需的资源被正确初始化和管理,包括内存分配和槽位管理。在查询执行结束后,相关资源和结构会被清理,以避免内存泄漏。

ExprState 结构体

上面提到,在执行阶段的开始,ExecInitExpr 负责为每个表达式生成一个 ExprState 结构。其中,ExprState 结构包含了执行表达式所需的各种信息 ,包括标记节点标志位掩码结果值的存储结果槽计算表达式返回值的指令实际评估表达式的函数指针 等等。这个结构体用于在 PostgreSQL 数据库系统中处理表达式的计算和执行过程,并提供了一些用于调试和优化的额外信息。结构体源码如下所示:(路径:src\include\nodes\execnodes.h

cpp 复制代码
/*
 * 表达式状态结构体,用于表示执行表达式的状态。
 * 该结构体包含了执行表达式所需的各种信息。
 */
typedef struct ExprState
{
	Node		tag;						/* 标记节点 */

	uint8		flags;						/* 标志位掩码,指示各种标志,见上方定义 */

	/*
	 * 用于存储标量表达式的结果值,或者由ExecBuildProjectionInfo()构建的表达式中的各个列结果。
	 */
	bool		resnull;					/* 结果是否为NULL */
	Datum		resvalue;					/* 结果值 */

	/*
	 * 如果投影一个元组结果,则此槽保存结果;否则为NULL。
	 */
	TupleTableSlot *resultslot;				/* 结果槽指针 */

	/*
	 * 计算表达式返回值的指令。
	 */
	struct ExprEvalStep *steps;				/* 计算表达式返回值的步骤 */

	/*
	 * 实际评估表达式的函数。根据表达式的复杂性可以设置为不同的值。
	 */
	ExprStateEvalFunc evalfunc;			/* 表达式评估函数指针 */

	/* 仅用于调试目的的原始表达式树 */
	Expr	   *expr;						/* 原始表达式树 */

	/*
	 * XXX: 以下内容仅在"编译"期间需要,可以丢弃。
	 */

	int			steps_len;					/* 当前步骤数量 */
	int			steps_alloc;				/* 步骤数组分配的长度 */

	Datum	   *innermost_caseval;			/* 最内层CASE表达式的值 */
	bool	   *innermost_casenull;		/* 最内层CASE表达式的NULL标志 */

	Datum	   *innermost_domainval;		/* 最内层域表达式的值 */
	bool	   *innermost_domainnull;		/* 最内层域表达式的NULL标志 */
} ExprState;

执行表达式

在数据库执行器中,ExecEvalExpr 函数用于实际执行查询计划中的表达式,通过 ExprState 中的 evalfunc 指针,它可以调用不同类型表达式的执行函数,以实现对各种类型表达式的支持。该函数接收一个 ExprState 结构体指针 state ,一个 ExprContext 结构体指针 econtext ,还有一个指向布尔值的指针 isNull 。函数内部通过调用 state 结构体中的 evalfunc 指针所指向的函数来执行表达式,并返回结果。结构体源码如下所示:(路径:src\include\executor\executor.h

c 复制代码
#ifndef FRONTEND
// 如果未定义 FRONTEND 宏,则进入条件编译,表示当前环境不是前端环境

// 定义了一个静态内联函数 ExecEvalExpr,该函数用于执行表达式
static inline Datum
ExecEvalExpr(ExprState *state,
			 ExprContext *econtext,
			 bool *isNull)
{
	// 通过表达式状态结构体中的 evalfunc 指针来调用相应的表达式执行函数
	return (*state->evalfunc) (state, econtext, isNull);
}
#endif

ExecEvalExpr 函数在执行器中通常作为一个通用的表达式执行函数 存在,被调用的位置取决于数据库管理系统的架构和实现。一般来说,它会在执行查询计划的过程中被调用,用于执行各种类型的表达式,包括但不限于选择条件投影列表聚合函数等。

在执行器的调用关系中,ExecEvalExpr 函数可能会被以下几个部分调用:

  • 查询计划的执行过程中,当需要计算表达式的值时,例如在过滤条件中对记录进行筛选、在投影列表中对结果进行处理等。
  • 聚合函数的计算过程中,当需要计算聚合函数的参数时,例如对分组进行聚合操作时,需要计算每个分组的聚合结果。
  • 索引扫描过程中,当需要计算索引条件的值时,用于判断索引是否符合查询条件。

ExecScan 函数为例,简述一下 ExecEvalExpr 函数的调用过程:

  • 使用 ExecScan 函数进行表格扫描,并且在扫描的过程中会调用 ExecQual 函数来执行过滤条件。ExecQual 函数用于评估查询的 WHERE 子句或者 JOIN 条件等过滤条件是否成立。
  • ExecQual 函数内部会对每一条记录进行条件判断,如果符合条件,则返回 true ,否则返回 false 。在条件判断的过程中,可能会涉及到各种类型的表达式,例如比较操作逻辑操作函数调用等。
  • 在执行这些表达式的过程中,ExecQual 函数会调用 ExecEvalExpr 函数来执行具体的表达式,并获取表达式的结果值。因此,ExecQual 函数和 ExecEvalExpr 函数之间存在着联系,ExecQual 函数负责调用 ExecEvalExpr 函数来执行过滤条件中的各种表达式,从而完成条件判断的过程。

总结

我们在本文中已经初步学习了表达式计算的基本流程,但还没有对具体的表达式进行深入的学习和分析。我们计划在未来的学习中,有机会的话再给予更多时间和精力来探索各种表达式的计算方法,以便更加全面地掌握这一领域的知识。

相关推荐
vvvae12342 小时前
分布式数据库
数据库
雪域迷影2 小时前
PostgreSQL Docker Error – 5432: 地址已被占用
数据库·docker·postgresql
bug菌¹3 小时前
滚雪球学Oracle[4.2讲]:PL/SQL基础语法
数据库·oracle
逸巽散人3 小时前
SQL基础教程
数据库·sql·oracle
月空MoonSky3 小时前
Oracle中TRUNC()函数详解
数据库·sql·oracle
momo小菜pa3 小时前
【MySQL 06】表的增删查改
数据库·mysql
向上的车轮4 小时前
Django学习笔记二:数据库操作详解
数据库·django
编程老船长4 小时前
第26章 Java操作Mongodb实现数据持久化
数据库·后端·mongodb
全栈师5 小时前
SQL Server中关于个性化需求批量删除表的做法
数据库·oracle
Data 3175 小时前
Hive数仓操作(十七)
大数据·数据库·数据仓库·hive·hadoop