postgresql version :9.4.4
源码路径:src/backend/parser
@H_301_5@
所谓查询分析就是把SQL查询语句生成查询树。查询分析是查询编译的第一个模块。主要包括:词法分析,语法分析和语义分析这三个部分。
@H_301_5@
现在看的源码是9.4.4版本,在9.0词法分析借用了lex,语法分析是yacc。现在是升级的flex跟bison。在postgresql中,对应的是src/backend/parser/gram.y&scan.l,这2个文件在编译的时候会生成gram.c/h,scan.c
关键字是在src/include/parser/kwlist.h,如果我们想添加一个关键字,可以在这个头文件添加。(注意添加顺序哦)
@H_301_5@
查询分析的基本流程:
@H_301_5@
@H_301_5@
@H_301_5@
我们现在来看看源码:
首先我们创建一张测试表,插入一条数据.
create table sangli(x text,y text,z bigint); insert into sangli(x,y,z) values('x','y',99);
@H_301_5@
再gdb到这个进程: @H_301_5@@H_301_5@
(gdb) b exec_simple_query
Breakpoint 1 at 0x7d35c0: file postgres.c,line 883.
(gdb) c
Continuing.
在exec_simple_query 打个断点。
@H_301_5@
我们进入了这个函数,可以进行调试跟踪了。
首先,sql命令为:query_string=select * from sangli;
(gdb) p query_string
$1 = 0x1a22e58 "select * from sangli;"
next......
@H_301_5@
我们主要是看方法pg_parse_query(const char *query_string)这个就是parse sql语句函数。这个函数返回个List,这个List是个parsetree.
这个List的返回值类型为:SelectStmt@H_301_5@
@H_301_5@
我们进来函数,raw_parser(query_string),这个函数就是词法的语法分析的入口函数,这个会生成一个未分析的语法解析树。返回值是个yyextra.parsetree;
/* 29│ * raw_parser 30│ * Given a query in string form,do lexical and grammatical analysis. 31│ * 32│ * Returns a list of raw (un-analyzed) parse trees. 33│ */ 34│ List * 35│ raw_parser(const char *str)
@H_301_5@
@H_301_5@
我们看看头文件:/* * The YY_EXTRA data that a flex scanner allows us to pass around. Private * state needed for raw parsing/lexing goes here. */ typedef struct base_yy_extra_type { /* * Fields used by the core scanner. */ core_yy_extra_type core_yy_extra; /* * State variables for base_yylex(). */ bool have_lookahead; /* is lookahead info valid? */ int lookahead_token; /* one-token lookahead */ core_YYSTYPE lookahead_yylval; /* yylval for lookahead token */ YYLTYPE lookahead_yylloc; /* yylloc for lookahead token */ /* * State variables that belong to the grammar. */ List *parsetree; /* final parse result is delivered here */ } base_yy_extra_type;@H_301_5@ 上面的yyextra就是base_yy_extra_type。
@H_301_5@
targetList&fromClause我们来看看是什么东西。
@H_301_5@
targetList:
@H_301_5@
上面的gdb内容是:
p *(A_Star*)(*(ColumnRef*)(*(ResTarget*)(*(SelectStmt*)yyextra.parsetree->head->data->ptr_value)->targetList->head->data->ptr_value)->val)->fields->head->data->ptr_value什么是A_Star?
我们查询语句select * from sangli;
这个*就是A_Star类型。这个应该很直观就能知道的。这样我们就知道什么是targetList.
@H_301_5@
fromClause:
@H_301_5@
很清楚,relname="sangli" 这个就是表的名称。别的参数可能在后面会重写的时候会赋值,可能没有.
@H_301_5@
这样pg_parse_query执行完毕,返回raw_parsetree_list.
其实这里还没有到返回Query,这个具体是在pg_analyze_and_rewrite里面返回的。
而这部分最主要的就是解析sql文本。后面的analyze&rewrite 都是通过这里返回的parsetree进行操作的。
大概流程就是这样,这个里面最主要的是flex&bison没讲,我下一篇打算讲讲他是如何工作的。