Postgresql源码(138)alter table增加列的执行流程分析
alter table 逻辑比较繁琐,但并不复杂,这里以增加列为例简单梳理流程。
测试用例
drop table t_echo;
create table t_echo(a int,b int);
insert into t_echo select t.i, t.i*10 from generate_series(1,10) t(i);
alter table t_echo add c varchar(32) default pg_backend_pid();
postgres=# select * from t_echo;
a | b | c
----+-----+-------
1 | 10 | 13425
2 | 20 | 13425
3 | 30 | 13425
4 | 40 | 13425
5 | 50 | 13425
6 | 60 | 13425
7 | 70 | 13425
8 | 80 | 13425
9 | 90 | 13425
10 | 100 | 13425
(10 rows)
alter table流程分析
alter table t_echo add c varchar(32) default pg_backend_pid();
1 analyze_and_rewrite阶段
parse_analyze_fixedparams
transform阶段对语句没有太多处理。使用Parse树直接返回。
在transformStmt中,使用switch (nodeTag(parseTree))来决定对一些需要处理的parseTree进行语义分析:
switch (nodeTag(parseTree))
case T_InsertStmt:
result = transformInsertStmt(pstate, (InsertStmt *) parseTree);
break;
case T_DeleteStmt:
result = transformDeleteStmt(pstate, (DeleteStmt *) parseTree);
break;
...
...
这里比较好扩展,如果想自己对alter语句进行处理:在switch中截获需要的类型,写个类似上面的函数进行处理即可。
alter table t_echo add c varchar(32) default pg_backend_pid();
输出Query树:
pg_rewrite_query
rewrite阶段对ddl也没有什么特殊处理:
2 plan阶段
优化器对DDL也不做特殊处理。
3 执行阶段
3.1 DDL走哪个分支处理?
ProcessUtilitySlow
Node *parsetree = pstmt->utilityStmt;
switch (nodeTag(parsetree))
case T_AlterTableStmt:
...
AlterTable
...
3.2 处理流程
#0 pg_backend_pid (fcinfo=0x3249ea0) at pgstatfuncs.c:663
#1 0x0000000000748fea in ExecInterpExpr (state=0x3249ce0, econtext=0x324a460, isnull=0x7ffffe4d9f07) at execExprInterp.c:746
#2 0x000000000074b332 in ExecInterpExprStillValid (state=0x3249ce0, econtext=0x324a460, isNull=0x7ffffe4d9f07) at execExprInterp.c:2033
#3 0x00000000005e6ab7 in ExecEvalExpr (state=0x3249ce0, econtext=0x324a460, isNull=0x7ffffe4d9f07) at ../../../src/include/executor/executor.h:348
#4 0x00000000005e6e3a in StoreAttrDefault (rel=0x7fc0d9c1e6a8, attnum=3, expr=0x325b718, is_internal=false, add_column_mode=true) at pg_attrdef.c:131
#5 0x00000000005c5270 in AddRelationNewConstraints (rel=0x7fc0d9c1e6a8, newColDefaults=0x325b208, newConstraints=0x0, allow_merge=false, is_local=true, is_internal=false, queryString=0x0) at heap.c:2337
#6 0x00000000006f4e32 in ATExecAddColumn (wqueue=0x7ffffe4da448, tab=0x3237e80, rel=0x7fc0d9c1e6a8, cmd=0x7ffffe4da328, recurse=true, recursing=false, lockmode=8, cur_pass=AT_PASS_ADD_COL, context=0x7ffffe4da5e0) at tablecmds.c:7174
#7 0x00000000006f09bc in ATExecCmd (wqueue=0x7ffffe4da448, tab=0x3237e80, cmd=0x32468b8, lockmode=8, cur_pass=AT_PASS_ADD_COL, context=0x7ffffe4da5e0) at tablecmds.c:5182
#8 0x00000000006f075a in ATRewriteCatalogs (wqueue=0x7ffffe4da448, lockmode=8, context=0x7ffffe4da5e0) at tablecmds.c:5129
#9 0x00000000006efafe in ATController (parsetree=0x313d2d8, rel=0x7fc0d9c1e6a8, cmds=0x313d288, recurse=true, lockmode=8, context=0x7ffffe4da5e0) at tablecmds.c:4722
#10 0x00000000006ef752 in AlterTable (stmt=0x313d2d8, lockmode=8, context=0x7ffffe4da5e0) at tablecmds.c:4368
#11 0x00000000009f7816 in ProcessUtilitySlow (pstate=0x3237d70, pstmt=0x313d388, queryString=0x313c360 "alter table t_echo add c varchar(32) default pg_backend_pid();", context=PROCESS_UTILITY_TOPLEVEL, params=0x0, queryEnv=0x0, dest=0x313d748, qc=0x7ffffe4dac10) at utility.c:1318
#12 0x00000000009f71ed in standard_ProcessUtility (pstmt=0x313d388, queryString=0x313c360 "alter table t_echo add c varchar(32) default pg_backend_pid();", readOnlyTree=false, context=PROCESS_UTILITY_TOPLEVEL, params=0x0, queryEnv=0x0, dest=0x313d748, qc=0x7ffffe4dac10) at utility.c:1067
#13 0x00000000009f6389 in ProcessUtility (pstmt=0x313d388, queryString=0x313c360 "alter table t_echo add c varchar(32) default pg_backend_pid();", readOnlyTree=false, context=PROCESS_UTILITY_TOPLEVEL, params=0x0, queryEnv=0x0, dest=0x313d748, qc=0x7ffffe4dac10) at utility.c:523
#14 0x00000000009f4fab in PortalRunUtility (portal=0x31e4ca0, pstmt=0x313d388, isTopLevel=true, setHoldSnapshot=false, dest=0x313d748, qc=0x7ffffe4dac10) at pquery.c:1158
#15 0x00000000009f5200 in PortalRunMulti (portal=0x31e4ca0, isTopLevel=true, setHoldSnapshot=false, dest=0x313d748, altdest=0x313d748, qc=0x7ffffe4dac10) at pquery.c:1316
#16 0x00000000009f4731 in PortalRun (portal=0x31e4ca0, count=9223372036854775807, isTopLevel=true, run_once=true, dest=0x313d748, altdest=0x313d748, qc=0x7ffffe4dac10) at pquery.c:791
#17 0x00000000009edfba in exec_simple_query (query_string=0x313c360 "alter table t_echo add c varchar(32) default pg_backend_pid();") at postgres.c:1284
#18 0x00000000009f288e in PostgresMain (dbname=0x3174b70 "postgres", username=0x3174b58 "mingjie") at postgres.c:4766
#19 0x00000000009ea38d in BackendMain (startup_data=0x7ffffe4daf10 "", startup_data_len=4) at backend_startup.c:107
#20 0x000000000091675c in postmaster_child_launch (child_type=B_BACKEND, startup_data=0x7ffffe4daf10 "", startup_data_len=4, client_sock=0x7ffffe4daf40) at launch_backend.c:274
#21 0x000000000091bca8 in BackendStartup (client_sock=0x7ffffe4daf40) at postmaster.c:3414
#22 0x0000000000919607 in ServerLoop () at postmaster.c:1648
#23 0x0000000000918fd5 in PostmasterMain (argc=1, argv=0x3136e70) at postmaster.c:1346
#24 0x00000000007d9efd in main (argc=1, argv=0x3136e70) at main.c:197
AlterTable执行:
AlterTable
ATController
/* Phase 1: preliminary examination of commands, create work queue */
foreach
ATPrepCmd
/* Phase 2: update system catalogs */
ATRewriteCatalogs
/* Phase 3: scan/rewrite tables as needed, and run afterStmts */
ATRewriteTables
处理分为三个阶段:
- 预检查:主要是权限检查,会递归到每一层函数。
- 改表结构:ATExecCmd函数中的大switch控制具体执行的指令,例如add column、column default等等。
- 例如本文开头提供的用例:
alter table t_echo add c varchar(32) default pg_backend_pid();
- ATExecCmd
- ATExecAddColumn:增加列
- AddRelationNewConstraints
- StoreAttrDefault:设置列默认值
- ExecEvalExpr:计算列默认值表达式
- …
- ExecInterpExpr
- pg_backend_pid
- ExecInterpExpr
- …
- ExecEvalExpr:计算列默认值表达式
- StoreAttrDefault:设置列默认值
- AddRelationNewConstraints
- ATExecAddColumn:增加列
- 例如本文开头提供的用例:
- 收尾工作:比如修改某些数据类型了要检查依赖、修改约束了要检查约束等等。