我是一名想学数据库内核的小白,欢迎大佬的建议和批评指正!
Pg源码分析第一阶段(select 1+1)
Parse
语法分析阶段,输入是原sql语句,输出是rawstsmt组合成的list。
然后对一些具体全局变量和条件进行判断后,最终处理在base_yyparse函数中,实际将sql转化为list的过程也是在这个过程中发生,具体转化过程中,:自动生成base_yyparse函数,其中rawstmt的装入通过lapend函数将makerawstmt函数返回的rawstmt装入list中,经过parse处理后,会生成若干个语句对应的rawstmt,他们在后续阶段都会被单独处理,互相独立。
Analyze
语义分析阶段,输入rawstmt,输出query组成的list
语义分析的核心目标:让底层能真正读懂sql语句,语义分析阶段会根据rawstmt的具体情况进行拆分,
1.先判读stmt的类型,不同的stmt会有对应的不同处理策略
2..对stmt的不同部分进行分别处理,分别对应原sql语句的,where,from,实际参数等等内容
3.处理过程涉及一个核心数据结构:TargetEntry,这个结构相比于parse阶段的restarget
多了三个核心结构:expr,resno,rejunk,分别代表数据表达式,列编号,和垃圾列。Analyze阶段主要核心目标就是expr,在select 1+1案例中,A_expr to Op_expr的转换是核心目标。Resno和resjunk会对后续plan与execut阶段读取数据提供依据。回到具体执行,targetentry的值也是通过lappend函数装载到query中的。
- transformExprRecurse会根据expr的nodetag(来源于restaget)来决定如何处理,在select 1+1;处理运算符的时候会递归调用处理参数,处理参数的过程直接停止即可无需递归,处理“+”的时候,会向系统表中查“+“对应的oid,放入opfuncid中,同样的consttype和opno也会存储参数类型和+对应函数的oid。
Rewrite
主要针对RIR规则(视图展开规则)和non-select规则
进行重写,select 1+1;并没有表和视图需要展开,rewrite阶段什么也不做
Optimzer
计划阶段,输入query组成的list,输出planstmt组成的list
计划的核心目标:将query变成执行计划,指导execute阶段的执行。
两个核心数据结构,
Plansnedtmt:记录了一些基础信息,例如表,子计划,当前是否为临时计划等等。
Plan:内含于plannedstmt,记录了开销代价等等。
在select 1+1中因为ratble=NIL,节点类型为result
Executor
执行阶段,输入plannedstmt组成的list,输出tupletableslot
这里三个核心结构,
Querydesc是个总闸,内含estate和planstate,
Estate内含状态信息,每个querydec只有一个,
Planstate则是根据算子类型(result,agg。。。)处理自带的指针,使用统一接口execprocnode处理不同类型算子,
在select 1+1过程中,在初始化阶段,通过fmgr_info(opfuncid, flinfo)根据opfuncid从系统表查找对应函数,将int4pl的地址存入fn_addr,执行时直接调用fn_addr完成计算。指针对应函数是execresult,经过filter之后,主要处理在projecttion中,经过两次函数调用后,retDatum = state->evalfunc(state, econtext, isNull);这一行同样通过指针统一接口调用最后在ExecInterpExpr里面完成计算1+1;返回的datum值直接赋值给tupletableslot中的tts_values[0]。
以后我会每周在这里分享自己的学习进度。