不可优化语句包括DDL、DCL等。与DML语句不同,它们的处理方式是为每一个类型的语句提供相应的处理函数。
PostgreSQL在SQL语法解析时,对于所有的SQL语句都会生成相应的Statement数据结构。例如,SELECT语句有对应的SelectStmt数据结构,CREATE TABLE语句有对应的CreateStmt语句。解析的结果就是一个ParseTree的链表,链上的每一个节点都是一个Statement的数据结构。
在语义分析阶段,会对Statement进行分析转换。具体的转换过程在函数transformStmt
中,这里不展开叙述。分析的结果是将ParseTree转换成便于优化器工作的QueryTree。而对于不可优化语句,在分析阶段只是简单的创建一个Query对象,并将具体的Statement挂载到Query::utilityStmt
字段上,并将Query::commandType
字段设置为CMD_UTILITY
。
在查询重写阶段,不可优化语句被直接跳过,不需要重写。
在查询优化阶段,不可优化语句不需要规划路径,被直接挂载到生成的PlannedStmt
上。
因此,对于不可优化语句,执行器得到的计划树中只有SQL语法解析后的Statement数据结构。该计划树在函数PortalDefineQuery
中被设置到Portal上。
在PortalStart
中选择执行策略时,对于不可优化语句,只有返回元组时(参见函数UtilityReturnsTuples
)才会选择PORTAL_UTIL_SELECT
,否则选择PORTAL_MULTI_QUERY
。
在PortalRun
阶段,执行流程最终会进入到函数ProcessUtility
中,对不同的Statement执行特定的处理逻辑。
针对各种不同的査询树,査询编译器在执行处理前会做一些额外的处理对査询树进行分析、处理与转换。例如,创建表的语句会用函数transformCreateStmt
进行査询树的处理。这些处理过程可能会在当前操作之前和之后增加一些新的操作(例如在创建表的操作之前增加创建serial序列表操作、之后增加创建触发器用于外键约束操作等),也可能会执行对数据结构的处理操作(例如将CreateStmt
节点tableElts字段中CONST_CHECK类型的Constraint
节点转存到CreateStmt
的ccmstraints链表中等)。由于这些处理过程会产生一些新的操作,因此最终会生成一个由多个操作构成的链表。因此,执行过程需要依次扫描该链表,为每一个原子操作调用相应的处理函数。
下面是创建表进入到执行阶段时的函数栈调用:
transformCreateStmt parse_utilcmd.c:171
ProcessUtilitySlow utility.c:996
standard_ProcessUtility utility.c:923
ProcessUtility utility.c:360
PortalRunUtility pquery.c:1178
PortalRunMulti pquery.c:1324
PortalRun pquery.c:799
exec_simple_query postgres.c:1145
PostgresMain postgres.c:4182
BackendRun postmaster.c:4358
BackendStartup postmaster.c:4030
ServerLoop postmaster.c:1707
PostmasterMain postmaster.c:1380
main main.c:228
start 0x00007fff709083d5
从实现上看,ProcessUtility
只作为入口选择函数,它会根据输人的节点类型调用相应的处理过程。
网友评论