前一篇(win10 源码编译安装postgresql数据库)介绍了windows下pg源码编译安装方法,那么装好之后从哪开始阅读学习pg源码?本文将介绍一种快速上手方法。
在进行源码编译时,务必编译成调式版(即执行perl build.pl DEBUG),便于调试学习。然后安装,运行,通过psql连接数据库,当然也可以通过pgAmin客户端连接,这里只介绍psql, 连接成功如下图:
对于一个有源码未知程序,如何快速掌握理解代码呢?当然是看运行堆栈,调试跟踪运行流程,掌握内部逻辑,理解各个函数功能。那么对于上百万行代码的pg源码,又从何处快速切入呢?请继续向下看。
在上面的psql连接窗口中执行 select pg_backend_pid(); 查询到当前服务pg后台进程,如我的是3956
通过vs2013打开pg代码工程:进入编译后的postgresql代码最上层目录,找到pgsql.sln 双击打开或先开vs2013在vs2013中,打开成功后会看到如下图:
依次点击最上面菜单栏中“调试”->“附加到进程”,在打开的窗口进找到上面查到的进程ID 3596 附加到当前工程(小技巧:按p可以快速定位到p开头的所有进程,找到ID为上面查到的那个)。附加成功后Visual Stdio 编译器左上角会显示“ pgsql(正在运行)”,如下图所示:
此时说明附加进程成功,那么一个可调试的pg环境就运行起来了,接下来就看怎么切入了。
可能大家会好奇,现在的pg是处于一种什么状态呢?结合前面的psql客户端来看,显然是正在等我们sql语句指令状态,在代码中又是怎么描述的呢?点击菜单栏中“调试”->“全部中断”(或者快捷键 Ctrl+Alt+Break),中断当前程序,如下图:
pg的代码风格很好,函数名差不多都能望文生义,一个个堆栈看下来基本能看出就是在等网络消息的状态,最终就停在WaitForMultipleObjects这个函数这了。当然如果在pg某个语句运行中也能通过“调试”->“全部中断”方式停下来,查看堆栈是否正常,如果语句运行太快了可以把数据量搞大点,这样就有时间做中断。
上面说的是运行中中断,实际使用中这样的操作场景可能比较少,更多的往往是出错情况下,想深究错误原因需要调试下。比方说执行某个语句,没有得出想要的结果,报错了,给出的错误信息不满意,或者说就是要看下执行流程,需要研究下代码,如何下手?下断点!当然,要在合适的地方下断点。pg内核报错接口已经封装好,只要在报错函数那下断点,所有错误都能断到,断到之后再看代码执行流程就很容易了,错误入口函数有这两个
errmsg(const char *fmt,...)
elog_finish(int elevel, const char *fmt,...)
找到这两个两个函数分别下断点,就能断到所有的内核报错信息,下面举个简单例子:
select *from txx; --txx表不存在,会报错,我们看堆栈
如图,在errmsg处被断到了,这里的堆栈我简单解释下,不做深入,以后再逐步展开,有兴趣者可以自己看代码,或找相关书籍深入研究。
main,相信每个写过代码的人都了解。
SubPostmasterMain,pg是一个多进程结构的数据库,这里会产生子进程。
BackendRun ,后台运行设置一些参数信息
PostgresMain,数据库主函数,从某种意义上说这是数据库的开始运行的地方
exec_simple_query ,执行一个Q报文协议语句
pg_analyze_and_rewrite,查询分析和重写
parse_analyze,语义分析
transformTopLevelStmt,解析树转查询树
transformStmt,同上,分类开始转
transformSelectStmt,转换一个select解析树(上一步已经分类到select类型语句)
transformFromClause,处理select中的from子句
transformFromClauseItem,处理from子句中每个项,from子句可以有多个项,如from t1,t2,t3多个表
transformTableEntry,转换具体表,如t1
addRangeTableEntry,同上
parserOpenTable,打开表,打开时发现表找不到,报错
errmsg,报错
这里是一个简单的报错用例,实际上还可能会有查询优化,查询执行等相关执行过程,暂不深入,本文只是告诉大家如何最简单快速的上手pg代码。
对于errmsg和elog_finish这两个报错接口的区别,大家可能有些疑问,我稍微介绍下。在代码中,errmsg被包成了ereport函数使用,elog_finish被包成了elog函数使用,对于ERROR级别的错误,ereport报的错是正常的错误,而elog报的错则是不正常的的错误。那么正常的错误,不正常的错误是什么意思?就拿上面的例子来说,我查一个表,这个表不存在,这就是正常的错误,但是如果一个值,按照设计只可能有三种值,比方说switch case1 case2 case3分别对应处理了,然后为了程序健壮性我们对其它所情况都报错,就应该用elog报,因为这是正常情况下不应该出现的错误,很可能是一个未初始化的值引发的。举个通俗点的例子,打篮球时别人进攻我防守不小心打手了,这犯规了,这种犯规就是正常的错误(用ereport),但是别人投球时我突然把篮筐扯掉不让人进,这肯定也犯规了,但这是非正常犯规,规则中没办法定义但的确又犯规(用elog)。
OK,本篇就这到,以后再出写一篇专门介绍postgresql在windows下调试的文章,希望能对大家有所帮助。