create table d (
id integer primary key, name text, loca text );
向表中插入4条记录:
insert into d (name,loca) values ('accounting','Beijing'); insert into d (name,loca) values ('research','Nanjing'); insert into d (name,loca) values ('marketing','Xining'); insert into d (name,loca) values ('operation','Baoding'); 执行下列命令: .m col .h on
.w 4 15 3 3 3 20 3
explain select * from d; 返回结果如下:
addr opcode p1 p2 p3 p4 p5 comment ---- --------------- --- --- --- -------------------- --- ------- 0 Trace 0 0 0 00 1 Goto 0 11 0 00 2 OpenRead 0 2 0 3 00 3 Rewind 0 9 0 00 4 Rowid 0 1 0 00 5 Column 0 1 2 00 6 Column 0 2 3 00 7 ResultRow 1 3 0 00 8 Next 0 4 0 01 9 Close 0 0 0 00 10 Halt 0 0 0 00 11 Transaction 0 0 0 00 12 VerifyCookie 0 2 0 00 13 TableLock 0 2 0 d 00 14 Goto 0 2 0 00
上面显示了一条select语句经编译后所生成的VDBE程序。有关VDBE程序的介绍请参考《SQLite权威指南》[1]。其中相关介绍好像有些过时,主要是由于这部分程序变化比较快,但还是很有参考价值的,反正我看了那部分内容之后,上面的程序就能看懂个大概意思了。
下面,我们就在此数据库基础上跟踪查询语句select * from d的处理过程。主要是罗列在处理过程所执行过的函数。每次调用的相关说明并不多,有的只说明关键变量的值,有的简单说明执行过程。主要是调用的太多了,实在没法对每次调用都详细说明。读者最好按上面的方法创建示例数据库,然后边看边跟踪执行。
注意:函数前面的数字表示调用的层次,而不是序号。
1-sqlite3_exec:
zSql=\
2-sqlite3Prepare:
zSql=\调用sqlite3RunParser。
3-sqlite3RunParser:
每处理一个单词,调用一次sqlite3Parser。
当语句处理完毕,语句串变为\,最后一次调用sqlite3Parser。
在sqlite3Parser中,后部有一个do while循环。循环了好多遍,下面一句也执行了好多遍: yy_reduce(yypParser,yyact-YYNSTATE);
yy_reduce中有一个大的switch语句,每次调用执行的分支不同。终于有一遍中调用了sqlite3Select。
sqlite3Select是select语句的处理主程序,在其中又经过如下调用层次(太多,这些层次就没编号了):
sqlite3Select(在select.c中) ↓
sqlite3SelectPrep(在select.c中) ↓
sqlite3SelectExpand(在select.c中) ↓
sqlite3WalkSelect(在walker.c中) ↓
selectExpander(在select.c中) ↓
sqlite3LocateTable(在build.c中) ↓
sqlite3ReadSchema(在prepare.c中) ↓
sqlite3Init(在prepare.c中)。
4-sqlite3Init: 功能:
初始化所有数据库文件——主数据库、临时数据库和所有附加的数据库。返回成功码。如果有错误发生,将错误信息写入*pzErrMsg。 执行:
进入第一个循环语句。在循环语句中调用sqlite3InitOne。 需要注意的是程序中有一小句很重要: db->init.busy = 1;
当db->init.busy被设为1时,就不会再有VDBE代码生成或执行。后面就可以在回叫函数中通过执行系统表中的create语句的方式为对象创建内部数据结构而又不会实际地执行这些创建语句。
5-sqlite3InitOne: (在prepare.c中)
功能:
读入一个单独数据库文件的schema,并初始化内部的数据结构。 执行:
调用回叫函数sqlite3InitCallback,执行系统表的创建语句,为系统表创建内部数据结构。
6-sqlite3InitCallback: (在prepare.c中) 功能:
本函数是初始化数据库时的回叫程序。 执行:
调用sqlite3_exec。
7-sqlite3_exec:
zSql=CREATE TABLE sqlite_master( type text, name text, tbl_name text, rootpage integer, sql text )
8-sqlite3Prepare:
zSql=CREATE TABLE sqlite_master( type text, name text, tbl_name text, rootpage integer, sql text )
7-sqlite3_exec:
从sqlite3Prepare返回后,执行到sqlite3_step一句。
8-sqlite3_step:
sqlite3_step是顶层函数,它调用sqlite3Step完成主要工作。
9-sqlite3Step:
此函数中调用了sqlite3VdbeExec。
10-sqlite3VdbeExec: p->zSql=\p->nOp=2 p->aOp:
0 21 OP_Trace
1 40 OP_Halt
可见,不执行实际的创建功能,直接返回。
9-sqlite3Step:
回到sqlite3Step后,发现sqlite3VdbeExec调用的返回结果为101。 rc又与另一个数“与”操作后,值为21,返回。
8-sqlite3_step:
rc值在其后的运算中变为101,返回。
7-sqlite3_exec:
rc!=SQLITE_ROW,不回显,退出循环。返回。
6-sqlite3InitCallback: 返回。
5-sqlite3InitOne:
继续执行,很多语句之后,遇到调用sqlite3_exec,查询系统表的内容。
6-sqlite3_exec:
zSql=SELECT name, rootpage, sql FROM 'main'.sqlite_master
7-sqlite3Prepare:
zSql=SELECT name, rootpage, sql FROM 'main'.sqlite_master 正常返回。
6-sqlite3_exec:
从sqlite3Prepare返回后,在sqlite3_step中经过几层(略)调用到sqlite3VdbeExec。
7-sqlite3VdbeExec: p->zSql=\p->nOp=14
p->aOp[]的内容为: 0 21 OP_Trace 1 96 OP_Goto 2 13 OP_OpenRead 3 120 OP_Rewind 4 3 OP_Column 5 3 OP_Column 6 3 OP_Column 7 90 OP_ResultRow 8 104 OP_Next 9 34 OP_Close 10 40 OP_Halt
11 101 OP_Transaction 12 97 OP_TableLock 13 96 OP_Goto
可见,这次要真正地执行查询功能。
6-sqlite3_exec:
注:仍然在SELECT name, rootpage, sql FROM 'main'.sqlite_master的STEP循环中。 从sqlite3_step返回后,rc==SQLITE_ROW,继续处理返回的记录。
在“if( xCallback(pArg, nCol, azVals, azCols) ){”一句中调用sqlite3InitCallback,然后,又调用sqlite3_exec。
这里调用sqlite3_exec是要执行系统表中每个对象的创建语句,目的是为这些对象创建内存数据结构。
7-sqlite3_exec: zSql=
create table d (
id integer primary key, name text, loca text )
8-sqlite3Prepare: zSql=
create table d (
id integer primary key, name text, loca text )
7-sqlite3_exec:
从sqlite3Prepare返回后,在sqlite3_step中经过几层(略)调用sqlite3VdbeExec。
8-sqlite3VdbeExec: p->zSql=\p->nOp=2
7-sqlite3_exec:
rc!=SQLITE_ROW,不回显,退出循环。返回。
6-sqlite3_exec:
注:仍然在SELECT name, rootpage, sql FROM 'main'.sqlite_master的STEP循环中。 循环处理下一条记录。
从sqlite3Prepare返回后,在sqlite3_step中经过几层(略)调用sqlite3VdbeExec。
7-sqlite3VdbeExec: p->zSql=\
百度搜索“70edu”或“70教育网”即可找到本站免费阅读全部范文。收藏本站方便下次阅读,70教育网,提供经典综合文库SQLite3源程序分析 - v100(3)在线全文阅读。
相关推荐: