SQLite3源程序分析

上传人:我*** 文档编号:135813732 上传时间:2020-06-19 格式:DOC 页数:52 大小:418KB
返回 下载 相关 举报
SQLite3源程序分析_第1页
第1页 / 共52页
SQLite3源程序分析_第2页
第2页 / 共52页
SQLite3源程序分析_第3页
第3页 / 共52页
SQLite3源程序分析_第4页
第4页 / 共52页
SQLite3源程序分析_第5页
第5页 / 共52页
点击查看更多>>
资源描述

《SQLite3源程序分析》由会员分享,可在线阅读,更多相关《SQLite3源程序分析(52页珍藏版)》请在金锄头文库上搜索。

1、SQLite3源程序分析作者:空转本文分析的SQLite版本为3.6.18。现在已经变成3.6.20了,但本文中所涉及的内容变化不大。读者最好能下载一个源程序,然后将本文与源程序对照阅读。这样也有利于发现本文的错误,说实话吧,我写的时候是连分析带猜的,错误肯定很多。参考文献:1-The Definitive Guide to SQLite . Michael Owens:比较经典的SQLite著作。我边看边翻译了其中的部分内容,但翻得不好,大家还是看原文吧。2-SQLite文件格式分析_v102 . 空转:我写的,写得特好。现在是v102版,跟前面的版本相比增加了不少背景知识,对文件格式的介绍

2、算是很全面了。看本文之前,应该先浏览一下此参考文献。1. SQLite3程序分析1.1. 主程序流程所谓“主程序”是指SQLite所提供的命令行处理程序(CLP)。通过对它的分析可以对SQLite源程序建立整体概念,比一上来就直接分析单独API的处理过程要容易。CLP的主要程序都在shell.c中。CLP的执行流程很简单:循环接受用户输入的SQL命令,处理SQL命令。命令的执行都是调用sqlite3_exec()函数完成,也就是采用的是“执行封装的Query”的形式1。程序定义了一个功能比较强大的回叫函数来处理SQL命令执行的返回结果:static int callback(void *pAr

3、g, int nArg, char *azArg, char *azCol);程序定义了9种回显的形式,通过一个callback_data结构来对回显参数进行配置。1.1.1. 程序主函数程序的main()函数在shell.c的尾部,简化后的main()函数的执行过程主要分为5步:1. 设置回显参数2. 取数据库文件名3. 打开数据库4. 循环处理SQL命令5. 关闭数据库如下:int main(int argc, char *argv)struct callback_data data;/回显参数int rc = 0;Argv0 = argv0;main_init(&data);/设置默认的

4、回显形式/取数据库文件名,如没有,默认为内存数据库data.zDbFilename = argv1;data.out = stdout;/* 如果数据库文件存在,则打开它。* 如果不存在,先不打开(现在什么都不做),* 可以防止用户因错误的输入而创建空文件。*/if( access(data.zDbFilename, 0)=0 ) open_db(&data);printf(SQLite version %snEnter .help for instructionsnEnter SQL statements terminated with a ;n,sqlite3_libversion();r

5、c = process_input(&data, 0);if( db )/关闭数据库if( sqlite3_close(db)!=SQLITE_OK )fprintf(stderr,error closing database: %sn, sqlite3_errmsg(db);return rc;说明:上述函数与源程序相比做了很大的简化,去掉的部分不是不重要的,而是“可以不解释”的。实用程序的流程一般都是复杂的,SQLite也不例外。本文按照自己的主线进行介绍,只求能说明问题(自圆其说),主线之外的东西,不管重不重要,都尽量忽略。后面的函数也存在这样情况,就不再说明了。回显参数的设置就不再介绍

6、了,参考源程序的callback()函数和callback_data结构,有关回叫函数的使用见参考文献一。下面介绍数据库的打开过程。1.1.2. 打开数据库数据库文件的打开过程在SQLite的权威文档中有介绍,过程如下图:图1-1 数据库文件的打开过程在CLP中打开数据库,比上图又多了两层,其调用层次如下:1-main():位于shell.c。从命令行参数中得到数据库名,如果数据库文件存在,则打开它。2-open_db():位于shell.c。功能:确认数据库是否已经打开。如果已打开,则什么都不做。如果没有,则打开它。如果打开失败,输出一个错误信息。3-sqlite3_open():位于mai

7、n.c。功能:打开一个数据库。该函数中只包含对opendatabase()的调用,但调用的参数与sqlite3_open_v2()所使用的参数不同。4-opendatabase():位于main.c。功能:这个函数为sqlite3_open()和sqlite3_open16()工作,打开一个数据库。数据库文件名zFilename采用UTF-8编码。先生成各类标志什么的,然后生成默认的排序法。当需要生成数据库后台驱动时,调用sqlite3BtreeFactory()。在此函数中真正分配sqlite结构的空间:db = sqlite3MallocZero( sizeof(sqlite3) )。在调

8、用sqlite3BtreeFactory()之前,需要对db的一些域进行设置。5-sqlite3BtreeFactory()位于main.c。功能:本函数创建到数据库BTree驱动的连接。如果zFilename是文件名,则打开并使用它。如果zFilename是:memory:,则使用内存数据库(在连接断开时释放)。如果zFilename为空且数据库是虚拟(virtual)的,则只是暂时使用,在连接断开时被删除。虚拟数据库可以是磁盘文件或就在内存中,由sqlite3TempInMemory()函数来决定是哪一种情况。6-sqlite3BtreeOpen():位于btree.c。功能:打开一个数据

9、库文件。由于在sqlite3BtreeFactory()中已经调用过sqlite3TempInMemory()函数,所以此处逻辑稍简单了一些。zFilename是数据库文件名。如果zFilename为空,创建一个具有随机文件名的数据库,这个数据库会在调用sqlite3BtreeClose()时被删除。如果zFilename是:memory:,创建内存数据库,并在关闭时被释放。如果此Btree是共享缓冲区的候选者,则尝试寻找一个已存在的BtShared来共享。(参本文后面关于内存数据结构的介绍)如果不是共享缓冲区的候选者或未找到已存在的BtShared,则调用sqlite3PagerOpen()

10、函数打开文件。文件打开之后,调用sqlite3PagerReadFileheader()来读文件头中的配置信息。7-sqlite3PagerOpen():位于pager.c。功能:分配并初始化一个新Pager对象,将其指针放到*ppPager。该pager会在调用sqlite3PagerClose()时被释放。zFilename参数是要打开的数据库文件的路径。如果zFilename为空,创建随机文件名的文件。如果zFilename为:memory:,所有信息都放到缓冲区中,不会被写入磁盘。这用来实现内存数据库。如果pager对象已分配且指定文件打开成功,返回SQLITE_OK并将*ppPage

11、r指向新pager对象。如果有错误发生,*ppPager置空并返回错误代码。执行过程是:先申请空间,再调用sqlite3OsOpen()打开文件(如果需要),再根据打开的文件设置内存。8-sqlite3OsOpen():位于os.c。功能:打开一个文件,与具体的操作系统无关。是一种VFS封装。VFS的意思是virtual file system,虚拟文件系统。本函数只有几条语句,只有一条关键语句:rc = pVfs-xOpen(pVfs, zPath, pFile, flags & 0x7f1f, pFlagsOut);对于Win32操作系统,该语句实际调用的是winOpen()函数。9-wi

12、nOpen():位于os_win.c。功能:打开一个Windows操作系统文件。先将文件名转换为操作系统所使用的编码。再设置一系列参数。最终调用操作系统函数CreateFileA()打开文件。10-CreateFileA():位于WINBASE.H。功能:打开文件名所指定的文件。如果文件不存在,则创建。1.1.3. 循环处理SQL命令SQL命令的处理是由process_input()函数完成的。该函数还完成”.”命令的处理,这我们就不管了。简化后的process_input()函数如下:static int process_input(struct callback_data *p, FILE

13、 *in)while( 1 )zLine = one_input_line(zSql, in);if( zLine & zLine0=. & nSql=0 )rc = do_meta_command(zLine, p);continue;rc = sqlite3_exec(p-db, zSql, callback, p, &zErrMsg);if( rc | zErrMsg )处理出错信息;return errCnt;这么简化应该就不用解释了。1.2. SQL命令编译与执行的过程1.2.1. sqlite3_exec()函数函数sqlite3_exec()位于文件legacy.c的尾部,其函数

14、头为:int sqlite3_exec( sqlite3 *db, /* 一个打开的数据库连接 */ const char *zSql, /* 要执行的SQL语句 */ sqlite3_callback xCallback, /* 回叫函数 */ void *pArg, /* 传递给xCallback()的第一个参数 */ char *pzErrMsg /* 将错误信息写到*pzErrMsg中 */)sqlite3_exec()函数一次可以执行多条SQL命令。执行完成后返回一个SQLITE_ success/failure代码,还会将错误信息写到*pzErrMsg中。如果SQL是查询,查询结果中的每一行都会调用xCallback()函数。pArg为传递给xCallback()的第一个参数。如果xCallback=NULL,即使对查询命令也没有回叫调用。sqlite3_exec()函数的实现体现了一个典型的、实用的SQL语句处理过程,我认为对应用程序的开发很有借鉴意义,所以就不过多简化了,去掉一些测试代码,增加一些注释,源程序基本如下:int sqlite3_exec( sqlite3 *db, /* 一个打开的数据库连接 */ const char *zSql,

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 办公文档 > 事务文书

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号