sqlite3源码分析(sqlite3 编译)
本文目录一览:
- 1、SQLite3懂的来,给最高分
- 2、Sqlite3 语句解析
- 3、sqlite数据库 在windows下的sqlite.lib的库文件
- 4、如何编译SQLite-How To Compile SQLite
- 5、MFC中,如何连接sqlite3的数据库,并对此数据库操作??
- 6、如何学习sqlite源码
SQLite3懂的来,给最高分
不可以修改从stmt中读取的值。
1、下面的语句可以从表test中读取记录:
pcSql = "SELECT number,name from test where number = '" + strNumber + "';";
sqlite3_prepare(pSqlite3,pcSql,(int)strlen(pcSql),pStmt,c_pcTail);
sqlite3_step(pStmt);
其中pStmt是指向数据集的指针。
从SQLite3的表中读取pStmt指向的数据集,只是内存中存在的数据结构,它与SQLite3的表再无关系。这就是轻量数据库的特点。它只做必须做的。
而不象sql server和oracal 那样,有后台进程管理与数据库双向连接的recordSet。
2、可以使用下列语句修改表test中的记录:
pcSql = "INSERT INTO test(number,name) VALUES("+ strNumber + "','"+ strName + "')";
sqlite3_exec(pSqlite3,pcSql,NULL,NULL,pcErrMsg);
Sqlite3 语句解析
自己看示例吧,解释的很清楚了。
void GetTable()
{
sqlite3 * db;
int result;
char * errmsg = NULL;
char **dbResult; //是 char ** 类型,两个*号
int nRow, nColumn;
int i , j;
int index;
result = sqlite3_open( “c:\\Dcg_database.db”, db );
if( result != SQLITE_OK )
{
//数据库打开失败
return -1;
}
//数据库操作代码
//假设前面已经创建了 MyTable_1 表
//开始查询,传入的 dbResult 已经是 char **,这里又加了一个 取地址符,传递进去的就成了 char ***
result = sqlite3_get_table( db, “select * from MyTable_1”, dbResult, nRow, nColumn, errmsg );
if( SQLITE_OK == result )
{
//查询成功
index = nColumn; //前面说过 dbResult 前面第一行数据是字段名称,从 nColumn 索引开始才是真正的数据
printf( “查到%d条记录\n”, nRow );
for( i = 0; i nRow ; i )
{
printf( “第 %d 条记录\n”, i 1 );
for( j = 0 ; j nColumn; j )
{
printf( “字段名:%s ? 字段值:%s\n”, dbResult[j], dbResult [index] );
index; // dbResult 的字段值是连续的,从第0索引到第 nColumn - 1索引都是字段名称,从第 nColumn 索引开始,后面都是字段值,它把一个二维的表(传统的行列表示法)用一个扁平的形式来表示
}
printf( “-------\n” );
}
}
//到这里,不论数据库查询是否成功,都释放 char** 查询结果,使用 sqlite 提供的功能来释放
sqlite3_free_table( dbResult );
//关闭数据库
sqlite3_close( db );
return 0;
}
}*/
sqlite数据库 在windows下的sqlite.lib的库文件
1). 打开VC新建一个“Win32 Dynamic-Link Library”工程,命名为:sqlite3
2). 在接下来的对话框中选择"An empty DLL project",点 FINISH-OK
3). 将源码中所有的 *.c *.h *.def 复制到工程文件夹下
4). 在工程的Source File中添加你下载到的SQLite源文件中所有*.c文件,
注意这里不要添加shell.c和tclsqlite.c这两个文件。
5). 将 SQLite 源文件中的 sqlite3.def 文件添加到在工程的Source File中
6). 在Header File中添加你下载到的SQLite源文件中所有*.h文件,
7). 开始编译,Build(F7)一下
也许到这里会遇到一个错误:
e:\zieckey\sqlite\sqlite3\sqlite3ext.h(22) : fatal error C1083: Cannot open include file: 'sqlite3.h': No such file or directory
经检查发现,源码中包含sqlite3.h都是以 #include sqlite3.h 方式包含的,
这就是说编译器在系统默认路径中搜索,这样当然搜索不到 sqlite3.h 这个头文件啦,
这时可以改为 #include "sqlite3.h" ,让编译器在工程路径中搜索,
但是如果还有其他地方也是以 #include sqlite3.h 方式包含的,那么改源码就显得有点麻烦,
好了,我们可以这样,在菜单栏依次选择:Tools-Options...-Directeries
在下面的Directeries选项中输入你的 sqlite3.h 的路径,这里也就是你的工程目录.
添加好后,我们在编译一下就好了,
最后我们在工程目录的 Debug 目录生成了下面两个重要文件:
动态链接库文件 sqlite3.dll 和引入库文件 sqlite3.lib
二. 使用动态链接库
下面我们来编写个程序来测试下我们的动态链接库.
在VC下新建一个空的"Win32 Console Application" Win32控制台程序,工程命名为:TestSqliteOnWindows
再新建一个 test.cpp 的C++语言源程序,源代码如下:
// name: test.cpp
// This prog is used to test C/C++ API for sqlite3 .It is very simple,ha !
// Author : zieckey
// data : 2006/11/28
#include stdio.h
#include stdlib.h
#include "sqlite3.h"
#define _DEBUG_
int main( void )
{
sqlite3 *db=NULL;
char *zErrMsg = 0;
int rc;
rc = sqlite3_open("zieckey.db", db); //打开指定的数据库文件,如果不存在将创建一个同名的数据库文件
if( rc )
{
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
sqlite3_close(db);
return (1);
}
else printf("You have opened a sqlite3 database named zieckey.db successfully!\nCongratulations! Have fun ! ^-^ \n");
如何编译SQLite-How To Compile SQLite
SQLite是ANSI-C的源代码。在使用之前必须要编译成机器码。这篇文章是用于各种编译SQLite方法的指南。
这篇文章不包含编译SQLite的每个步骤的反馈,那样可能会困难因为每种开发场景都不同。所以这篇文章描述和阐述了编译Sqlite的原则。典型的编译命令已经作为例子提供了,以期望应用开发者能够使用这些例子作为完成他们自己定制的编译过程的的一个指南。换句话说,这篇文章提供了想法和见解,而不是交钥匙的解决方法。
融合VS单独源文件
Sqlite是由超过一百个c源码文件以及众多的目录下的脚本构建的。Sqlite的实现是纯粹的ANSI-C,但是许多C语言源代码文件是由辅助的C程序生成或者转换来的,并且AWK,SED和TCL脚本会融合到完成的sqlite库中。对Sqlite构建需要的C程序和转换和创建C语言源码是一个复杂的过程。
为了简化这些,sqlite也通过一个预打包的合并后的源码文件:sqlite3.c。这个合并文件是一个ANSI-C源码实现整个SQLite库的唯一文件。合并后的文件更容易处理。所有的东西都包含在这一个文件里,所以很容易进入一个更大的C或者C++程序的源码树。所有的代码生成和转换步骤都已经实现了,因此没有辅助的C程序需要去配置和变异,也没有脚本需要去运行。并且,因此所有哭都包含在一个翻译单元,编译器可以做更多高级的优化从而提升5%到10%的性能。因为这些原因,融合后的源码文件sqlite3.c对所有程序来讲都是值得推荐的。
推荐所有的应用程序使用融合文件。
直接从单独的源码文件中构建sqlite当然可以,但是并不推荐。对一些特殊的应用程序,可能需要修改构建程序去处理使用那些从网站上下载的预构建的源码文件不能完成的情况。对于这些情况,推荐构建和使用一个定制过的合并文件。换句话说,即使一个工程需要以单独的源码文件构建sqlite,仍然推荐使用一个融合后的源码文件作为一个中间步骤。
编译命令行接口(CLI)
构建命令行接口需要三个源码文件:
sqlite3.c:Sqlite融合的源码文件
sqlite3.h:匹配sqlite3.c以及定义sqlite的c语言接口的头文件
shell.c:命令行接口程序本身。这个c源码文件包含一个main()的例程和每轮循环的用户输入的提示符并将输入传给sqlite数据库引擎用于处理。
所有的上述源码的三个文件都被包含在下载页面的amalgamation tarball中。
为了构建CLI,简单的将这三个文件放置在相同的目录下然后一起编译他们。用MSVC:
cl shell.c sqlite3.c -Fesqlite3.exe
在unix系统上(或者在windows上用cygwin或者mingw+msys)典型的命令会有些像这样:
gcc shell.c sqlite3.c -lpthread -ldl
为了SQLite线程安全,需要pthreads库。但是因为CLI是一个单线程的,我们可以指示SQLite构建一个非线程安全的库并因此护绿pthreads库:
gcc -DSQLITE_THREADSAFE=0 shell.c sqlite3.c -ldl
-ldl库是在支持动态装载时需要,例如sqlite3_load_extension() 接口和load_extension()
SQL function。如果这些特性都不要求,那么我们也可以使用SQLITE_OMIT_LOAD_EXTENSION编译时间选项忽略他们。
gcc -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION shell.c sqlite3.c
有人可能想要提供其他的编译时间选项(compile-time options),例如SQLITE_ENABLE_FTS3去全文本搜索或者SQLITE_ENABLE_RTREE用于R*树搜索引擎扩展。而有人将正常指定一些编译优化开关。(预编译的CLI可以从选择sqlite网站上使用“-Os”下载下来)有无数种可能的变数在这里。
关键点在这里:构建CLI需要编译一起两个C语言文件。shell.c文件包含入口的定义和用户输入的loop,而sqlite融合文件sqlite3.c包含完整的sqlite库的实现。
编译TCL接口
sqlite的tcl接口是一个小的模块被添加到一般的融合文件中。结果是一个新的融合后的源码文件,称之为“tclsqlite3.c”。这个源码文件是生成一个可以使用TCL
load命令去加载到一个标准的tclsh或者wish中,或者随着sqlite构建成功生成一个单独唯一的tclsh的共享库所需要的。一个tcl的融合的副本被包含在下载页的TEA
tarball中作为一个文件。
为了生成一个linux上的sqlite的TCL-loadable库,下面的命令需要满足:
gcc -o libtclsqlite3.so -shared tclsqlite3.c -lpthread -ldl -ltcl
不幸的是构建Mac OS X 和 Windows的共享库并不是如此简单。对于这些平台最好使用包含在TEA tarball中的configure脚本和makefile.
为了生成一个单独的tclsh,可以用于sqlite静态链接,使用如下的编译器调用:
gcc -DTCLSH=1 tclsqlite3.c -ltcl -lpthread -ldl -lz -lm
这里的技巧是-DTCLSH=1选项。sqlite的TCL接口模块包含一个main的过程,用于初始化一个TCL解释器并在以-DTCLSH=1编译后进入到一个命令行loop。上述命令可以工作在Linux和Mac
OS X,虽然有时可能需要依赖于平台调整库选项以及编译的TCL的哪一个版本。
构建融合文件
下载页提供的sqlite融合文件的版本对大多数用户来说是足够的。然而,一些工程可能想要或者需要构建他们自己的融合文件。一个常见的构建一个定制的融合文件的理由是为了使用特定的compile-time options来定制sqlite库。回想sqlite融合文件中包含了许多C代码由辅助程序和脚本生成。许多的编译时间选项影响这一成圣代码而且必须在融合文件组装前提供给代码生成器。这一系列必须传给代码生成器的编译时间相关的选项会使得sqlite的发布版本各不相同,但是在写这边文章的时候,代码生成器需要知道的这组选项包括:
SQLITE_ENABLE_UPDATE_DELETE_LIMIT
SQLITE_OMIT_ALTERTABLE
SQLITE_OMIT_ANALYZE
SQLITE_OMIT_ATTACH
SQLITE_OMIT_AUTOINCREMENT
SQLITE_OMIT_CAST
SQLITE_OMIT_COMPOUND_SELECT
SQLITE_OMIT_EXPLAIN
SQLITE_OMIT_FOREIGN_KEY
SQLITE_OMIT_PRAGMA
SQLITE_OMIT_REINDEX
SQLITE_OMIT_SUBQUERY
SQLITE_OMIT_TEMPDB
SQLITE_OMIT_TRIGGER
SQLITE_OMIT_VACUUM
SQLITE_OMIT_VIEW
SQLITE_OMIT_VIRTUALTABLE
为了构建一个定制的融合文件,先下载原始的独立源码文件到一个unix或者类unix开发平台。确定获取的原始源码文件不是“预编译过的源文件”。任何人都可以通过到下载页或者直接从configuration management system.获取完整的一套原始源码文件。
假设sqlite源码树被存在一个名为“sqlite”的目录下。计划构建一个平行目录下的名为“bld”的融合文件。首先通过运行sqlite源码树种的configure脚本运行或者通过制作一份源码树顶层的的makfile模板的一份,来构建一个合适的makefile.然后手动编辑这个Makfile去包含需要的编译时间相关的选项。最终运行:
make sqlite3.c
在windows上使用MSVC:
nmake /f Makefile.msc sqlite3.c
sqlite3.c的make
target会自动构造一般的“sqlite3.c”合并的源码文件,以及它的头文件“sqlite3.h”,和包含TCL接口的融合源码文件“tclsqlite3.c”。之后,需要的文件可以被拷贝到文件目录下然后根据上述勾勒的过程编译。
构建一个windows的动态链接库DLL
为了在windows构建一个sqlite的dll使用,首先获取对应的融合过的源码文件,sqlit3.c和sqlite.h。这些可以从SQLite website上下载或者和上述告知的一样去定制生成。
使用工作目录下的源码文件,一个dll可以在msvc中使用如下命令生成:
cl sqlite3.c -link -dll -out:sqlite3.dll
上述命令需要运行在msvc的MSVC Native Tools Command
Prompt.如何你已经在机器上安装了msvc,你可能有多个版本的这种命令提示符,针对于x86和x64的自带构建的,或者交叉编译到ARM的。依赖要求的DLL去使用对应合适的命令提示符工具。
如果使用MinGW编译器,命令是这样的:
gcc -shared sqlite3.c -o sqlite3.dll
注意MinGW只生成32位的dll。另有一个分开的MinGW64工程可以用来生成64位的dll。可以推断其命令行语法是类似的。需要注意的是最近的MSVC的版本生成的DLLs可能不能工作到WinXP或者更早版本的windows上。因此为了最大限度的兼容你的生成的dll,推荐MinGW。一个好的经验法则是使用MinGW去生成32位的dlls,使用msvc去生成64位的dlls。
MFC中,如何连接sqlite3的数据库,并对此数据库操作??
这个比较容易。按照网上提供的方法把sqlite编译成dll和lib
将dll和lib在项目的输入中添加好
在要操作的文件中#include “sqlite3.h”就可以了。我做过这方面的项目,虽然是嵌入式wince使用,但是基本和windows相同。
下面是详细的用法:
一. 编译动态链接库库文件
1). 打开VC新建一个“Win32 Dynamic-Link Library”工程,命名为:sqlite3(也可以是其他的,注意这个就是编译后的dll和lib的名字)
2). 在接下来的对话框中选择"An empty DLL project",点 FINISH-OK
3). 将源码中所有的 *.c *.h *.def 复制到工程文件夹下
4). 在工程的Source File中添加你下载到的SQLite源文件中所有*.c文件,
注意这里不要添加shell.c和tclsqlite.c这两个文件。*注意需要将tclsqlite.c和shell.c、icu.c去掉。其中tclsqlite.c用于生成基于tcl的api,如果要编译,这需要另外下载tcl.h;shell.c用于生成命令行模式的sqlite.exe,如果是静态库形式则可以选择; icu是internationalcomponents forunicode,如果需要则需另外下载相关头文件。
5). 将 SQLite 源文件中的 sqlite3.def 文件添加到在工程的Source File中
6). 在Header File中添加你下载到的SQLite源文件中所有*.h文件,
7). 开始编译,Build(F7)一下
也许到这里会遇到一个错误:
e:\zieckey\sqlite\sqlite3\sqlite3ext.h(22) : fatal error C1083: Cannot open include file: 'sqlite3.h': No such file or directory
经检查发现,源码中包含sqlite3.h都是以 #include sqlite3.h 方式包含的,
这就是说编译器在系统默认路径中搜索,这样当然搜索不到 sqlite3.h 这个头文件啦,
这时可以改为 #include "sqlite3.h" ,让编译器在工程路径中搜索,
但是如果还有其他地方也是以 #include sqlite3.h 方式包含的,那么改源码就显得有点麻烦,
好了,我们可以这样,在菜单栏依次选择:Tools-Options...-Directeries
在下面的Directeries选项中输入你的 sqlite3.h 的路径,这里也就是你的工程目录.
添加好后,我们在编译一下就好了,
最后我们在工程目录的 Debug 目录生成了下面两个重要文件:
动态链接库文件 sqlite3.dll 和引入库文件 sqlite3.lib
二. 使用动态链接库
下面我们来编写个程序来测试下我们的动态链接库.
在VC下新建一个空的"Win32 Console Application" Win32控制台程序,工程命名为:TestSqliteOnWindows
再新建一个 test.cpp 的C++语言源程序,源代码如下:
// name: test.cpp
// This prog is used to test C/C++ API for sqlite3 .It is very simple,ha !
// Author : zieckey
// data : 2006/11/28
#include stdio.h
#include stdlib.h
#include "sqlite3.h"
#define _DEBUG_
int main( void )
{
sqlite3 *db=NULL;
char *zErrMsg = 0;
int rc;
rc = sqlite3_open("zieckey.db", db); //打开指定的数据库文件,如果不存在将创建一个同名的数据库文件
if( rc )
{
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
sqlite3_close(db);
return (1);
}
else printf("You have opened a sqlite3 database named zieckey.db successfully!\nCongratulations! Have fun ! ^-^ \n");
//创建一个表,如果该表存在,则不创建,并给出提示信息,存储在 zErrMsg 中
char *sql = " CREATE TABLE SensorData(ID INTEGER PRIMARY KEY,SensorID INTEGER,SiteNum INTEGER,Time VARCHAR(12),SensorParameter REAL);" ;
sqlite3_exec( db , sql , 0 , 0 , zErrMsg );
#ifdef _DEBUG_
printf("zErrMsg = %s \n", zErrMsg);
#endif
//插入数据
sql = "INSERT INTO \"SensorData\" VALUES(NULL , 1 , 1 , '200605011206', 18.9 );" ;
sqlite3_exec( db , sql , 0 , 0 , zErrMsg );
sql = "INSERT INTO \"SensorData\" VALUES(NULL , 23 , 45 , '200605011306', 16.4 );" ;
sqlite3_exec( db , sql , 0 , 0 , zErrMsg );
sql = "INSERT INTO \"SensorData\" VALUES(NULL , 34 , 45 , '200605011306', 15.4 );" ;
sqlite3_exec( db , sql , 0 , 0 , zErrMsg );
int nrow = 0, ncolumn = 0;
char **azResult; //二维数组存放结果
//查询数据
sql = "SELECT * FROM SensorData ";
sqlite3_get_table( db , sql , azResult , nrow , ncolumn , zErrMsg );
int i = 0 ;
printf( "row:%d column=%d \n" , nrow , ncolumn );
printf( "\nThe result of querying is : \n" );
for( i=0 ; i( nrow + 1 ) * ncolumn ; i++ )
printf( "azResult[%d] = %s\n", i , azResult[i] );
//删除数据
sql = "DELETE FROM SensorData WHERE SensorID = 1 ;" ;
sqlite3_exec( db , sql , 0 , 0 , zErrMsg );
#ifdef _DEBUG_
printf("zErrMsg = %s \n", zErrMsg);
#endif
sql = "SELECT * FROM SensorData ";
sqlite3_get_table( db , sql , azResult , nrow , ncolumn , zErrMsg );
printf( "\n\n\n\nrow:%d column=%d " , nrow , ncolumn );
printf( "\nAfter deleting , the result of querying is : \n" );
for( i=0 ; i( nrow + 1 ) * ncolumn ; i++ )
printf( "azResult[%d] = %s\n", i , azResult[i] );
//释放掉 azResult 的内存空间
sqlite3_free_table( azResult );
#ifdef _DEBUG_
printf("zErrMsg = %s \n", zErrMsg);
#endif
sqlite3_close(db); //关闭数据库
return 0;
}
另外,将sqlite3.h sqlite3.lib sqlite3.dll文件复制到我们的工程目录.
最后 Project-Settings 在Link选项卡找到Object/library modules : 在最后填入sqlite3.lib 。
如果原来就有链接,请使用空格分隔。
现在可以编译了.
运行结果如下:
You have opened a sqlite3 database named zieckey.db successfully!
Congratulations! Have fun ! ^-^
zErrMsg = (null)
row:3 column=5
The result of querying is :
azResult[0] = ID
azResult[1] = SensorID
azResult[2] = SiteNum
azResult[3] = Time
azResult[4] = SensorParameter
azResult[5] = 1
azResult[6] = 1
azResult[7] = 1
azResult[8] = 200605011206
azResult[9] = 18.9
azResult[10] = 2
azResult[11] = 23
azResult[12] = 45
azResult[13] = 200605011306
azResult[14] = 16.4
azResult[15] = 3
azResult[16] = 34
azResult[17] = 45
azResult[18] = 200605011306
azResult[19] = 15.4
zErrMsg = (null)
row:2 column=5
After deleting , the result of querying is :
azResult[0] = ID
azResult[1] = SensorID
azResult[2] = SiteNum
azResult[3] = Time
azResult[4] = SensorParameter
azResult[5] = 2
azResult[6] = 23
azResult[7] = 45
azResult[8] = 200605011306
azResult[9] = 16.4
azResult[10] = 3
azResult[11] = 34
azResult[12] = 45
azResult[13] = 200605011306
azResult[14] = 15.4
zErrMsg = (null)
Press any key to continue
在上面的第五步
5). 将 SQLite 源文件中的 sqlite3.def 文件添加到在工程的Source File中
是必须的, sqlite3.def 这个文件的加入会生成 *.lib引入库文件,这个对于*.dll文件是很重要的.否则你光有*.dll文件在程序调用的时候就不是那么方便了,因为这样你只能通过动态加载dll的方式调用dll库中函数
这个程序,我们先创建一个数据库,然后新建一个表,然后插入一些数据,
再查询看看插入的数据是否正确,然后又删除一些数据,删除后我们再查询了一下,
发现我们的删除操作也是成功的.
这个程序简单的调用 sqlite 的函数接口来实现对数据库的管理,
包括创建数据库、创建表格、插入数据、查询数据、删除数据等。
如何学习sqlite源码
先来说说sqlite的资料.
首先sqlite的资料其实是不多不少的.
不少的原因是因为这些资料确实能够让你明白sqlite的设计原理.
说它不多的原因是也就让你明白其原理, 仅此而已.
sqlite的资料主要来自四个地方, 从简到深依次为:
1., 这是一本介绍sqlite"基本原理"的小书, 只有80页左右, 介绍了sqlite的"后端"原理. 这本书在百度有下载, 纯英文版的, 链接:inside sqlite_百度知道. 在上面的github上, 我们项目的同伴对这本书做了翻译, 不过还没完成, 建议直接扫原版.
2.官方文档, 连接:SQLite Documentation. 但是里面的文档对于学习者来说也有轻重之分, 建议主要阅读 "SQLite Technical/Design Documentation" 这一栏的技术文档.
3.SQLite Database System: Design and Implementation. 这也是一本说sqlite的小书, 不到200页. 这本书的内容其实和inside sqlite有重叠, 甚至不少地方的段落是直接复制过来的... 不过这本书比inside sqlite详细很多, 也建议扫描一遍. 这本书我目前在做翻译, 做了3,4,5,6四章的翻译了. 不过是很粗翻译, 不建议直接看...
4.源码注释. sqlite的源码注释非常详细, 详细到比上面两本书说的还多... sqlite的每份.c代码内的注释差不多快比代码还多了, 而且除了将基本架构外, 很多上述资料没有提到的细节, 也在源码注释中被提了出来.
================================================================
接下来说一下本人推荐的学习方法~~
================================================================
下面是认真学习的方法, 如果想快速暴力的学习, 直接看下一段.
想要认真点学习的话.
应该先去看"Architecture of SQLite"这篇文档, 该文档详细的介绍了sqlite的7层结构, 总体被分为了"前段", "中层VM", "后端".
看完arch.html那文过后, 你就知道"前端"主要做的是语法分析, "后端"主要实现了数据库性质(ACID, 增删查改).
个人建议从后端开始学习, 毕竟学习sqlite是学习怎么实现数据库.
后端的tree, pager, os三层, 其实都不难(起码理解起来不难),
我建议OS-PAGER-TREE这样边学习, 边写demo.
简要说一下我在学习这三层过程中遇到的一些点, 希望能帮到楼主.
OS:
os是很薄的一层, 主要是为了提高可移植性而被设计出来的.
学习这一层的方法很粗暴:看"The OS Backend (VFS) To SQLite", 然后去看源码中的"test_demovfs.c".
主要搞清下面三个结构体.
sqlite3_vfs
sqlite3_io_methods
sqlite3_file
在我github中的demo1.1中, 有一个更简单的demo, 可以参考看下里面的os.c, os.h, unix_os.c三份代码.
-------------------------------------------------
Pager:
Pager主要实现了三段功能: ACID, log, cache.
先说ACID:
ACID的这部分我只看了最最基本的方法, 然后选择跳过的, sqlite实现ACID的方法可以看"Atomic Commit In SQLite",
这里是我翻译的, 能看,
"how-to-implement-a-DB-like-sqlite/SQLite怎样实现原子性.md at master · qw4990/how-to-implement-a-DB-like-sqlite · GitHub".
除了这篇最基本的文档, 推荐看SQLite Database System: Design and Implementation的3章和4章, 看完能理解sqlite实现ACID的基本方法.
接着是cache, sqlite提供了插件式的cache结构, 所以你或许会惊讶为什么sqlite里面同时有pager.c, pcache.c, pcache1.c:
cache这个部分比较简单, inside sqlite第三章, SQLite Database System第五章都有详细的介绍, 主要讲解了pager实现cache的方法.
在我github中的demo1.1中, cache的功能也已经完成了, 1 可以参考看下里面的pager.h, pager.c, pcache.c, pcahce1这四份代码.
最后是log:
这部分我现在直接选择了忽视...
----------------------------------------------------
Tree层:
sqlite的tree层就是用B+/B-树维护数据, 以达到快速"增删查改"的目的.
这一层在官方文档里没多少资料.
先是算法本身, 也就是B+/B-/B树, 没什么好说的, 很多算法书都有.
接下来重点是sqlite怎么将B树应用到自身的数据库中的.
这一点可以看inside sqlite的第5章, SQLite Database System的第6章, 都有很详细的介绍.
SQLite Database System讲得更为仔细, 除了说原理外, 还说了sqlite里btree大致被分为了几个结构体在工作.
以上就是我学习后端遇到的一些点吧.
=============================================================
如果嫌弃上面的学习方法麻烦的话,
可以先扫一下"Architecture of SQLite",
接着再看一下"Atomic Commit In SQLite",
最后简单粗暴的把推荐的那两本书扫完,
也大致知道sqlite是怎么设计的了.
不过个人认为sqlite是一个"大师级的精致的工艺品", 光看完两本书就说自己学完了它, 未免有点"暴殄天物".
除了基本的数据库设计方法(也就是那两本书的内容), sqlite的源代码中所蕴含的编程技巧, 工程设计, 以及各种小考虑, 也是非常值得吸收学习的.
=============================================================
最后总结一下
如果想简单粗暴快捷的学习, 直接扫arch.html, atomiccommit.html和那两本书, 就能明白sqlite是怎样被设计的了.
如果想深入学习, 建议从7层开始向前学, 边翻文档边看源码边写demo.