sqlite 源码学习
记录一下学习过程吧
sqlite数据库,没用过,但相对其它数据库来说,比较简单,容易了解sql原理
sqlite 使用流程
1. 打开数据库
sqlite3_open
2. 执行sql语句
sqlite3_exec
3. 关闭数据库
sqlite3_close
大致流程就是如此,先按流程来分析源码吧
sqlite编译的时候,默认要添加下面2个预定义,这2个我们也默认认为定义了
SQLITE_ENABLE_COLUMN_METADATA
SQLITE_ENABLE_RTREE
看看整合代码里面的sqlite.c,10多万行,可以想象的到,不会容易了
1. 打开数据库
打开数据库有几个函数可以用,sqlite3_open_v2,sqlite3_open,sqlite3_open16
其中sqlite3_open16用的utf16格式,其他2个都是utf8格式
sqlite3_open_v2函数较新,官方建议使用这个
看下2个utf8的函数:
SQLITE_API int sqlite3_open(
const char *zFilename,
sqlite3 **ppDb
)
{
return openDatabase(zFilename, ppDb,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0);
}
SQLITE_API int sqlite3_open_v2(
const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb, /* OUT: SQLite db handle */
int flags, /* Flags */
const char *zVfs /* Name of VFS module to use */
)
{
return openDatabase(filename, ppDb, (unsigned int)flags, zVfs);
}
可以看出,sqlite3_open和sqlite3_open_v2本质是一样的,都是掉用openDatabase打开数据库
不同的是sqlite3_open默认打开标识为SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE
,vfs 默认为空而sqlite3_open16,看下面的代码
SQLITE_API int sqlite3_open16(
const void *zFilename,
sqlite3 **ppDb
)
{
char const *zFilename8; /* zFilename encoded in UTF-8 instead of UTF-16 */
sqlite3_value *pVal;
int rc;
#ifdef SQLITE_ENABLE_API_ARMOR
if( ppDb==0 ) return SQLITE_MISUSE_BKPT;
#endif
*ppDb = 0;
#ifndef SQLITE_OMIT_AUTOINIT
rc = sqlite3_initialize();
if( rc ) return rc;
#endif
if( zFilename==0 ) zFilename = "\000\000";
pVal = sqlite3ValueNew(0);
sqlite3ValueSetStr(pVal, -1, zFilename, SQLITE_UTF16NATIVE, SQLITE_STATIC);
zFilename8 = sqlite3ValueText(pVal, SQLITE_UTF8);
if( zFilename8 ){
rc = openDatabase(zFilename8, ppDb,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0);
assert( *ppDb || rc==SQLITE_NOMEM );
if( rc==SQLITE_OK && !DbHasProperty(*ppDb, 0, DB_SchemaLoaded) ){
SCHEMA_ENC(*ppDb) = ENC(*ppDb) = SQLITE_UTF16NATIVE;
}
}else{
rc = SQLITE_NOMEM_BKPT;
}
sqlite3ValueFree(pVal);
return rc & 0xff;
}
开始的时候,先将utf16编码转为utf8,再使用转换后的变量去调用openDatabase
有几个宏定义,
SQLITE_OPEN_CREATE,表示如果数据库不存在,就创建
SQLITE_OPEN_READWRITE,表示以读写方式打开,如果写被操作系统保护就以只读方式打开
SQLITE_ENABLE_API_ARMOR,检测API是否被误用,比如传空指针作为请求参数或使用已经销毁的objects
SQLITE_OMIT_AUTOINIT, 禁止自动初始化,如果定义了,程序在使用库之前,必须先调用sqlite3_initialize()
sqlite3_initialize这个函数也是一个大函数,比较重要,在openDatabase中,会在较前的位置调用,所以这里先看下:
int sqlite3_initialize(void){
//#define MUTEX_LOGIC(X) X
MUTEX_LOGIC( sqlite3_mutex *pMaster; ) /* The main static mutex */
int rc; /* Result code */
#ifdef SQLITE_EXTRA_INIT
int bRunExtraInit = 0; /* Extra initialization needed */
#endif
//又一个宏,SQLITE_OMIT_WSD,这个宏表示不含有不支持全局变量或静态变量可写
//关于这个,还专门去搜了下,真发现有平台不支持全局变量和静态变量可写,比如塞班 s60系统:
//The Symbian operating system does not support the use of writable static data in DLL's.
//This can be a major problem if your application uses global variables.
#ifdef SQLITE_OMIT_WSD
rc = sqlite3_wsd_init(4096, 24);
if( rc!=SQLITE_OK ){
return rc;
}
#endif
/* If the following assert() fails on some obscure processor/compiler
** combination, the work-around is to set the correct pointer
** size at compile-time using -DSQLITE_PTRSIZE=n compile-time option */
//判断是32位系统还是64位系统,确定指针所占空间的大小
//确保编译器指针大小为4
assert( SQLITE_PTRSIZE==sizeof(char*) );
/* If SQLite is already completely initialized, then this call
** to sqlite3_initialize() should be a no-op. But the initialization
** must be complete. So isInit must not be set until the very end
** of this routine.
*/
//判断是否初始化完成,如果完成,返回,不执行后面的操作
if( sqlite3GlobalConfig.isInit ) return SQLITE_OK;
/* Make sure the mutex subsystem is initialized. If unable to
** initialize the mutex subsystem, return early with the error.
** If the system is so sick that we are unable to allocate a mutex,
** there is not much SQLite is going to be able to do.
**
** The mutex subsystem must take care of serializing its own
** initialization.
*/
//初始化mutex子系统
rc = sqlite3MutexInit();
if( rc ) return rc;
/* Initialize the malloc() system and the recursive pInitMutex mutex.
** This operation is protected by the STATIC_MASTER mutex. Note that
** MutexAlloc() is called for a static mutex prior to initializing the
** malloc subsystem - this implies that the allocation of a static
** mutex must not require support from the malloc subsystem.
*/
//初始化malloc子系统
MUTEX_LOGIC( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
sqlite3_mutex_enter(pMaster);
//设置isMutexInit,表示mutex初始化完成
sqlite3GlobalConfig.isMutexInit = 1;
//判断malloc是否初始化,如果没有,则进行初始化
if( !sqlite3GlobalConfig.isMallocInit ){
rc = sqlite3MallocInit();
}
if( rc==SQLITE_OK ){
//初始化 pInitMutex
sqlite3GlobalConfig.isMallocInit = 1;
if( !sqlite3GlobalConfig.pInitMutex ){
sqlite3GlobalConfig.pInitMutex =
sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE);
if( sqlite3GlobalConfig.bCoreMutex && !sqlite3GlobalConfig.pInitMutex ){
//返回失败,SQLITE_NOMEM_BKPT表示malloc失败
rc = SQLITE_NOMEM_BKPT;
}
}
}
if( rc==SQLITE_OK ){
//pInitMutex引用计数加1
sqlite3GlobalConfig.nRefInitMutex++;
}
sqlite3_mutex_leave(pMaster);
/* If rc is not SQLITE_OK at this point, then either the malloc
** subsystem could not be initialized or the system failed to allocate
** the pInitMutex mutex. Return an error in either case. */
//如果malloc子系统初始化失败, 或pInitMutex生成失败,返回
if( rc!=SQLITE_OK ){
return rc;
}
/* Do the rest of the initialization under the recursive mutex so
** that we will be able to handle recursive calls into
** sqlite3_initialize(). The recursive calls normally come through
** sqlite3_os_init() when it invokes sqlite3_vfs_register(), but other
** recursive calls might also be possible.
**
** IMPLEMENTATION-OF: R-00140-37445 SQLite automatically serializes calls
** to the xInit method, so the xInit method need not be threadsafe.
**
** The following mutex is what serializes access to the appdef pcache xInit
** methods. The sqlite3_pcache_methods.xInit() all is embedded in the
** call to sqlite3PcacheInitialize().
*/
sqlite3_mutex_enter(sqlite3GlobalConfig.pInitMutex);
//如果初始化没有完成,并且,没有正在进行初始化
if( sqlite3GlobalConfig.isInit==0 && sqlite3GlobalConfig.inProgress==0 ){
/设置正在进行初始化标识位
sqlite3GlobalConfig.inProgress = 1;
//sqlite 日志选项,test_sqllog.c是一个日志的例子
//如果需要自定义日志,可以重新test_sqllog.c
//使用-DSQLITE_ENABLE_SQLLOG选项来编译日志
#ifdef SQLITE_ENABLE_SQLLOG
{
extern void sqlite3_init_sqllog(void);
sqlite3_init_sqllog();
}
#endif
//重置sqlite3BuiltinFunctions,sqlite3BuiltinFunctions是一个 struct FuncDefHash
//简略的说就是一个存放内建方法的数组
memset(&sqlite3BuiltinFunctions, 0, sizeof(sqlite3BuiltinFunctions));
//注册方法,包括内建方法,也包括其他一些方法,也是个大函数
sqlite3RegisterBuiltinFunctions();
if( sqlite3GlobalConfig.isPCacheInit==0 ){
rc = sqlite3PcacheInitialize();
}
if( rc==SQLITE_OK ){
sqlite3GlobalConfig.isPCacheInit = 1;
rc = sqlite3OsInit();
}
//SQLITE_ENABLE_DESERIALIZE,是否支持序列化,反序列化接口,定义了为支持
#ifdef SQLITE_ENABLE_DESERIALIZE
if( rc==SQLITE_OK ){
rc = sqlite3MemdbInit();
}
#endif
if( rc==SQLITE_OK ){
//设置page-cache
//pPage,内存中的page页面
//szPage,页面大小
//nPage,页面数量
sqlite3PCacheBufferSetup( sqlite3GlobalConfig.pPage,
sqlite3GlobalConfig.szPage, sqlite3GlobalConfig.nPage);
sqlite3GlobalConfig.isInit = 1;
#ifdef SQLITE_EXTRA_INIT
bRunExtraInit = 1;
#endif
}
//重置inprogress
sqlite3GlobalConfig.inProgress = 0;
}
sqlite3_mutex_leave(sqlite3GlobalConfig.pInitMutex);
/* Go back under the static mutex and clean up the recursive
** mutex to prevent a resource leak.
*/
sqlite3_mutex_enter(pMaster);
sqlite3GlobalConfig.nRefInitMutex--;
//如果引用计数器为0,释放pInitMutex
if( sqlite3GlobalConfig.nRefInitMutex<=0 ){
assert( sqlite3GlobalConfig.nRefInitMutex==0 );
sqlite3_mutex_free(sqlite3GlobalConfig.pInitMutex);
sqlite3GlobalConfig.pInitMutex = 0;
}
sqlite3_mutex_leave(pMaster);
/* The following is just a sanity check to make sure SQLite has
** been compiled correctly. It is important to run this code, but
** we don't want to run it too often and soak up CPU cycles for no
** reason. So we run it once during initialization.
*/
//检查sqlite是否正确编译。为了防止浪费cpu时间片,只在初始化时运行一次
#ifndef NDEBUG
//允许浮点数
#ifndef SQLITE_OMIT_FLOATING_POINT
/* This section of code's only "output" is via assert() statements. */
if( rc==SQLITE_OK ){
u64 x = (((u64)1)<<63)-1;
double y;
assert(sizeof(x)==8);
assert(sizeof(x)==sizeof(y));
memcpy(&y, &x, 8);
assert( sqlite3IsNaN(y) );
}
#endif
#endif
/* Do extra initialization steps requested by the SQLITE_EXTRA_INIT
** compile-time option.
*/
#ifdef SQLITE_EXTRA_INIT
if( bRunExtraInit ){
int SQLITE_EXTRA_INIT(const char*);
rc = SQLITE_EXTRA_INIT(0);
}
#endif
return rc;
}
对于函数中的SQLITE_MUTEX_OMIT,在代码里面找到这样一段话
** SQLITE_MUTEX_OMIT No mutex logic. Not even stubs. The
** mutexes implementation cannot be overridden
** at start-time.
默认是没有定义SQLITE_MUTEX_OMIT,那么
#define MUTEX_LOGIC(X) X
所以MUTEX_LOGIC( sqlite3_mutex *pMaster; ) 即为 sqlite3_mutex *pMaster;
其中
struct sqlite3_mutex {
pthread_mutex_t mutex; /* Mutex controlling the lock */
#if SQLITE_MUTEX_NREF || defined(SQLITE_ENABLE_API_ARMOR)
int id; /* Mutex type */
#endif
#if SQLITE_MUTEX_NREF
volatile int nRef; /* Number of entrances */
volatile pthread_t owner; /* Thread that is within this mutex */
int trace; /* True to trace changes */
#endif
};
可以看出,sqlite3_mutex就是互斥锁,关于其他的变量,比如id,nRef,owner,trace
代码中有下面的注释:
/*
** The sqlite3_mutex.id, sqlite3_mutex.nRef, and sqlite3_mutex.owner fields
** are necessary under two condidtions: (1) Debug builds and (2) using
** home-grown mutexes. Encapsulate these conditions into a single #define.
*/
#if defined(SQLITE_DEBUG) || defined(SQLITE_HOMEGROWN_RECURSIVE_MUTEX)
# define SQLITE_MUTEX_NREF 1
#else
# define SQLITE_MUTEX_NREF 0
#endif
只有debug或使用home-grown mutexes的时候,才会有sqlite3_mutex中除mutex外其他的变量
但 SQLITE_HOMEGROWN_RECURSIVE_MUTEX 设为1,所以其他变量是有的
继续,看看openDatabase,里面包含的东西相当的多,先大致走一下流程,一些重要的函数后面再看:
static int openDatabase(
const char *zFilename, /* Database filename UTF-8 encoded */
sqlite3 **ppDb, /* OUT: Returned database handle */
unsigned int flags, /* Operational flags */
const char *zVfs /* Name of the VFS to use */
){
sqlite3 *db; /* Store allocated handle here */
int rc; /* Return code */
int isThreadsafe; /* True for threadsafe connections */
char *zOpen = 0; /* Filename argument to pass to BtreeOpen() */
char *zErrMsg = 0; /* Error message from sqlite3ParseUri() */
#ifdef SQLITE_ENABLE_API_ARMOR
if( ppDb==0 ) return SQLITE_MISUSE_BKPT;
#endif
*ppDb = 0;
//SQLITE_OMIT_AUTOINIT,自动初始化,如果没有设置,需要手动调用初始化函数
#ifndef SQLITE_OMIT_AUTOINIT
rc = sqlite3_initialize();
if( rc ) return rc;
#endif
//设置是否线程安全
//SQLITE_OPEN_NOMUTEX,只要单线程模式没有设置,打开数据库连接就使用多线程模式
//SQLITE_OPEN_FULLMUTEX,如果单线程模式没有设置,使用串行线程模式打开数据库连接
if( sqlite3GlobalConfig.bCoreMutex==0 ){
isThreadsafe = 0;
}else if( flags & SQLITE_OPEN_NOMUTEX ){
isThreadsafe = 0;
}else if( flags & SQLITE_OPEN_FULLMUTEX ){
isThreadsafe = 1;
}else{
isThreadsafe = sqlite3GlobalConfig.bFullMutex;
}
//设置打开标识
//SQLITE_OPEN_PRIVATECACHE,禁止共享cache模式,即使设置了共享模式也不行
//SQLITE_OPEN_SHAREDCACHE,共享cacche模式,无论sqlite3_enable_shared_cache()如何设置
if( flags & SQLITE_OPEN_PRIVATECACHE ){
flags &= ~SQLITE_OPEN_SHAREDCACHE;
}else if( sqlite3GlobalConfig.sharedCacheEnabled ){
flags |= SQLITE_OPEN_SHAREDCACHE;
}
/* Remove harmful bits from the flags parameter
**
** The SQLITE_OPEN_NOMUTEX and SQLITE_OPEN_FULLMUTEX flags were
** dealt with in the previous code block. Besides these, the only
** valid input flags for sqlite3_open_v2() are SQLITE_OPEN_READONLY,
** SQLITE_OPEN_READWRITE, SQLITE_OPEN_CREATE, SQLITE_OPEN_SHAREDCACHE,
** SQLITE_OPEN_PRIVATECACHE, and some reserved bits. Silently mask
** off all other flags.
*/
//禁止除SQLITE_OPEN_READONLY, SQLITE_OPEN_READWRITE,
//SQLITE_OPEN_CREATE, SQLITE_OPEN_SHAREDCACHE,
// SQLITE_OPEN_PRIVATECACHE, 和一些保留位之外的其它标志位
//SQLITE_OPEN_DELETEONCLOSE,关闭数据库时删除文件,主要用于临时数据库
//SQLITE_OPEN_EXCLUSIVE,一般和SQLITE_OPEN_CREATE成对使用,表示如果文件不存在,就创建,
//如果存在,就返回错误,此标识不表示获得独占权限
flags &= ~( SQLITE_OPEN_DELETEONCLOSE |
SQLITE_OPEN_EXCLUSIVE |
SQLITE_OPEN_MAIN_DB |
SQLITE_OPEN_TEMP_DB |
SQLITE_OPEN_TRANSIENT_DB |
SQLITE_OPEN_MAIN_JOURNAL |
SQLITE_OPEN_TEMP_JOURNAL |
SQLITE_OPEN_SUBJOURNAL |
SQLITE_OPEN_MASTER_JOURNAL |
SQLITE_OPEN_NOMUTEX |
SQLITE_OPEN_FULLMUTEX |
SQLITE_OPEN_WAL
);
/* Allocate the sqlite data structure */
//生成db句柄
db = sqlite3MallocZero( sizeof(sqlite3) );
if( db==0 ) goto opendb_out;
if( isThreadsafe
#ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS
|| sqlite3GlobalConfig.bCoreMutex
#endif
){
db->mutex = sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE);
if( db->mutex==0 ){
sqlite3_free(db);
db = 0;
goto opendb_out;
}
if( isThreadsafe==0 ){
sqlite3MutexWarnOnContention(db->mutex);
}
}
sqlite3_mutex_enter(db->mutex);
//错误码掩码
db->errMask = 0xff;
//正在使用的schema数量
db->nDb = 2;
//数据库状态魔数,SQLITE_MAGIC_BUSY,数据库正在使用
db->magic = SQLITE_MAGIC_BUSY;
//所有的后台schema
db->aDb = db->aDbStatic;
//aHardLimit,一些限制值的上限
assert( sizeof(db->aLimit)==sizeof(aHardLimit) );
memcpy(db->aLimit, aHardLimit, sizeof(db->aLimit));
//设置工作线程数量限制,默认为0
db->aLimit[SQLITE_LIMIT_WORKER_THREADS] = SQLITE_DEFAULT_WORKER_THREADS;
//是否自动提交
db->autoCommit = 1;
db->nextAutovac = -1;
//默认mmap_size
db->szMmap = sqlite3GlobalConfig.szMmap;
//VACUUM之后的pagesize
//vacuum,sqlite自动整理储存文件,减少空间占用
//有以下几种情况会调用vacuum:
//1.大量的数据被删除了,这时,数据库实际占用的空间比需要的空间大
// 此时运行vacuum会减少空间占用,但是如果设置了auto_vacuum=FULL,那么就不会运行vacuum
//2.频繁的insert,update,delete导致数据库碎片化,主要是索引或者单个表中的数据在存储文件中比较零散
// 此时运行vacuum会使得索引或者表中数据连续存储,在某些情况下,也减少了分页,减小了存储空间
//3.一般来说,数据库创建的时候,pagesize和 auto_vacuum都已经配置了,但如果对存在的数据修改pagesize或者
// auto_vacuum属性,会导致运行vacuum,如果是 write-ahead log模式,如果支持auto_vacuum,当auto_vacuum被修改了
// 会运行vacuum
db->nextPagesize = 0;
//有序regions的最大值
db->nMaxSorterMmap = 0x7FFFFFFF;
//SQLITE_ShortColNames,显示短列名
//SQLITE_EnableTrigger,允许触发器
//SQLITE_CacheSpill, 允许pager缓存溢写,每一个数据库链接都有一个pager对象,对象管理了链接的缓存信息
//pager是sqlite中的一个重要的模块,实现了存储的持久化和事务的原子性
db->flags |= SQLITE_ShortColNames | SQLITE_EnableTrigger | SQLITE_CacheSpill
#if !defined(SQLITE_DEFAULT_AUTOMATIC_INDEX) || SQLITE_DEFAULT_AUTOMATIC_INDEX
| SQLITE_AutoIndex
#endif
#if SQLITE_DEFAULT_CKPTFULLFSYNC
| SQLITE_CkptFullFSync
#endif
#if SQLITE_DEFAULT_FILE_FORMAT<4
| SQLITE_LegacyFileFmt
#endif
#ifdef SQLITE_ENABLE_LOAD_EXTENSION
| SQLITE_LoadExtension
#endif
#if SQLITE_DEFAULT_RECURSIVE_TRIGGERS
| SQLITE_RecTriggers
#endif
#if defined(SQLITE_DEFAULT_FOREIGN_KEYS) && SQLITE_DEFAULT_FOREIGN_KEYS
| SQLITE_ForeignKeys
#endif
#if defined(SQLITE_REVERSE_UNORDERED_SELECTS)
| SQLITE_ReverseOrder
#endif
#if defined(SQLITE_ENABLE_OVERSIZE_CELL_CHECK)
| SQLITE_CellSizeCk
#endif
#if defined(SQLITE_ENABLE_FTS3_TOKENIZER)
| SQLITE_Fts3Tokenizer
#endif
#if defined(SQLITE_ENABLE_QPSG)
| SQLITE_EnableQPSG
#endif
;
//初始化hash表
sqlite3HashInit(&db->aCollSeq);
#ifndef SQLITE_OMIT_VIRTUALTABLE
sqlite3HashInit(&db->aModule);
#endif
/* Add the default collation sequence BINARY. BINARY works for both UTF-8
** and UTF-16, so add a version for each to avoid any unnecessary
** conversions. The only error that can occur here is a malloc() failure.
**
** EVIDENCE-OF: R-52786-44878 SQLite defines three built-in collating
** functions:
*/
//生成排序,utf8和utf16都适用
createCollation(db, sqlite3StrBINARY, SQLITE_UTF8, 0, binCollFunc, 0);
createCollation(db, sqlite3StrBINARY, SQLITE_UTF16BE, 0, binCollFunc, 0);
createCollation(db, sqlite3StrBINARY, SQLITE_UTF16LE, 0, binCollFunc, 0);
createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc, 0);
createCollation(db, "RTRIM", SQLITE_UTF8, (void*)1, binCollFunc, 0);
//处理malloc失败的情况,这是唯一可能产生的错误
if( db->mallocFailed ){
goto opendb_out;
}
/* EVIDENCE-OF: R-08308-17224 The default collating function for all
** strings is BINARY.
*/
db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, sqlite3StrBINARY, 0);
assert( db->pDfltColl!=0 );
/* Parse the filename/URI argument
**
** Only allow sensible combinations of bits in the flags argument.
** Throw an error if any non-sense combination is used. If we
** do not block illegal combinations here, it could trigger
** assert() statements in deeper layers. Sensible combinations
** are:
**
** 1: SQLITE_OPEN_READONLY
** 2: SQLITE_OPEN_READWRITE
** 6: SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE
*/
db->openFlags = flags;
assert( SQLITE_OPEN_READONLY == 0x01 );
assert( SQLITE_OPEN_READWRITE == 0x02 );
assert( SQLITE_OPEN_CREATE == 0x04 );
testcase( (1<<(flags&7))==0x02 ); /* READONLY */
testcase( (1<<(flags&7))==0x04 ); /* READWRITE */
testcase( (1<<(flags&7))==0x40 ); /* READWRITE | CREATE */
//打开标志异常
if( ((1<<(flags&7)) & 0x46)==0 ){
rc = SQLITE_MISUSE_BKPT; /* IMP: R-65497-44594 */
}else{
//解析文件名或者文件路径
rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg);
}
if( rc!=SQLITE_OK ){
//解析失败,记录错误信息
if( rc==SQLITE_NOMEM ) sqlite3OomFault(db);
sqlite3ErrorWithMsg(db, rc, zErrMsg ? "%s" : 0, zErrMsg);
sqlite3_free(zErrMsg);
goto opendb_out;
}
/* Open the backend database driver */
rc = sqlite3BtreeOpen(db->pVfs, zOpen, db, &db->aDb[0].pBt, 0,
flags | SQLITE_OPEN_MAIN_DB);
if( rc!=SQLITE_OK ){
if( rc==SQLITE_IOERR_NOMEM ){
rc = SQLITE_NOMEM_BKPT;
}
sqlite3Error(db, rc);
goto opendb_out;
}
sqlite3BtreeEnter(db->aDb[0].pBt);
db->aDb[0].pSchema = sqlite3SchemaGet(db, db->aDb[0].pBt);
if( !db->mallocFailed ) ENC(db) = SCHEMA_ENC(db);
sqlite3BtreeLeave(db->aDb[0].pBt);
db->aDb[1].pSchema = sqlite3SchemaGet(db, 0);
/* The default safety_level for the main database is FULL; for the temp
** database it is OFF. This matches the pager layer defaults.
*/
//设置默认打开的2个数据库,并设置同步级别
db->aDb[0].zDbSName = "main";
//safety_level,同步数据到磁盘的级别
//SQLITE_DEFAULT_SYNCHRONOUS,同步级别full
db->aDb[0].safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1;
db->aDb[1].zDbSName = "temp";
//PAGER_SYNCHRONOUS_OFF,关闭同步
db->aDb[1].safety_level = PAGER_SYNCHRONOUS_OFF;
//SQLITE_MAGIC_OPEN,数据库已经打开
db->magic = SQLITE_MAGIC_OPEN;
if( db->mallocFailed ){
goto opendb_out;
}
/* Register all built-in functions, but do not attempt to read the
** database schema yet. This is delayed until the first time the database
** is accessed.
*/
sqlite3Error(db, SQLITE_OK);
//注册内建方法,但不会读数据库schema。第一次数据库链接的时候才会去读
sqlite3RegisterPerConnectionBuiltinFunctions(db);
rc = sqlite3_errcode(db);
//SQLITE_ENABLE_FTS5, 使用第5版的全文搜索引擎,默认是禁止的
//FTS5,versions 5 of the full-text search engine
#ifdef SQLITE_ENABLE_FTS5
/* Register any built-in FTS5 module before loading the automatic
** extensions. This allows automatic extensions to register FTS5
** tokenizers and auxiliary functions. */
if( !db->mallocFailed && rc==SQLITE_OK ){
rc = sqlite3Fts5Init(db);
}
#endif
/* Load automatic extensions - extensions that have been registered
** using the sqlite3_automatic_extension() API.
*/
if( rc==SQLITE_OK ){
sqlite3AutoLoadExtensions(db);
rc = sqlite3_errcode(db);
if( rc!=SQLITE_OK ){
goto opendb_out;
}
}
//FTS1,第一版全文搜索引擎,依次类推
#ifdef SQLITE_ENABLE_FTS1
if( !db->mallocFailed ){
extern int sqlite3Fts1Init(sqlite3*);
rc = sqlite3Fts1Init(db);
}
#endif
#ifdef SQLITE_ENABLE_FTS2
if( !db->mallocFailed && rc==SQLITE_OK ){
extern int sqlite3Fts2Init(sqlite3*);
rc = sqlite3Fts2Init(db);
}
#endif
#ifdef SQLITE_ENABLE_FTS3 /* automatically defined by SQLITE_ENABLE_FTS4 */
if( !db->mallocFailed && rc==SQLITE_OK ){
rc = sqlite3Fts3Init(db);
}
#endif
//SQLITE_ENABLE_ICU,编译添加icu组件
//ICU, International Components for Unicode
#if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS)
if( !db->mallocFailed && rc==SQLITE_OK ){
rc = sqlite3IcuInit(db);
}
#endif
//SQLITE_ENABLE_RTREE, 支持r-tree
//R-Tree,是B-tree的另外一种新式,空间索引结构
#ifdef SQLITE_ENABLE_RTREE
if( !db->mallocFailed && rc==SQLITE_OK){
rc = sqlite3RtreeInit(db);
}
#endif
//SQLITE_ENABLE_DBPAGE_VTAB, 允许sqlite_dbpage使用虚表
//eponymous virtual table,与一般的虚表有一些区别
//一般的虚表是使用create进行创建的,但是eponymous virtual table,
//是在每个数据库连接的主schema中根据注册的模块自动创建的
//使用的时候使用模块名作为表名,其他按正常表使用就行
#ifdef SQLITE_ENABLE_DBPAGE_VTAB
if( !db->mallocFailed && rc==SQLITE_OK){
rc = sqlite3DbpageRegister(db);
}
#endif
//SQLITE_ENABLE_DBSTAT_VTAB,使能DBSTAT 虚表
//DBSTAT 虚表是只读的eponymous virtual table,
//内容是schema中表和索引使用的数据库文件的pages
#ifdef SQLITE_ENABLE_DBSTAT_VTAB
if( !db->mallocFailed && rc==SQLITE_OK){
rc = sqlite3DbstatRegister(db);
}
#endif
//SQLITE_ENABLE_JSON1,使能json扩展,管理数据库中json方式存储的数据
//共有17个方法
#ifdef SQLITE_ENABLE_JSON1
if( !db->mallocFailed && rc==SQLITE_OK){
rc = sqlite3Json1Init(db);
}
#endif
//SQLITE_ENABLE_STMTVTAB,使能SQLITE_STMT
//SQLITE_STMT,是一个保护所有数据库连接的状态信息的eponymous virtual table
#ifdef SQLITE_ENABLE_STMTVTAB
if( !db->mallocFailed && rc==SQLITE_OK){
rc = sqlite3StmtVtabInit(db);
}
#endif
/* -DSQLITE_DEFAULT_LOCKING_MODE=1 makes EXCLUSIVE the default locking
** mode. -DSQLITE_DEFAULT_LOCKING_MODE=0 make NORMAL the default locking
** mode. Doing nothing at all also makes NORMAL the default.
*/
//SQLITE_DEFAULT_LOCKING_MODE,锁模式设置,1为独占模式,0为正常模式
//正常模式是指在数据库读写操作期间,不会对数据库文件进行加锁
//独占模式,是指用户对数据库进行读写时,立即获得读写锁并持有,直到关闭链接才释放
//当然,如果修改了锁模式为正常模式,在下个连接到来时,也会释放锁
//独占模式下,读锁是共享锁,写锁是独占锁
#ifdef SQLITE_DEFAULT_LOCKING_MODE
db->dfltLockMode = SQLITE_DEFAULT_LOCKING_MODE;
sqlite3PagerLockingMode(sqlite3BtreePager(db->aDb[0].pBt),
SQLITE_DEFAULT_LOCKING_MODE);
#endif
if( rc ) sqlite3Error(db, rc);
/* Enable the lookaside-malloc subsystem */
//为每个连接设置lookaside缓冲区
setupLookaside(db, 0, sqlite3GlobalConfig.szLookaside,
sqlite3GlobalConfig.nLookaside);
sqlite3_wal_autocheckpoint(db, SQLITE_DEFAULT_WAL_AUTOCHECKPOINT);
opendb_out:
if( db ){
assert( db->mutex!=0 || isThreadsafe==0
|| sqlite3GlobalConfig.bFullMutex==0 );
sqlite3_mutex_leave(db->mutex);
}
rc = sqlite3_errcode(db);
assert( db!=0 || rc==SQLITE_NOMEM );
if( rc==SQLITE_NOMEM ){
sqlite3_close(db);
db = 0;
}else if( rc!=SQLITE_OK ){
//SQLITE_MAGIC_SICK 错误,等待关闭
db->magic = SQLITE_MAGIC_SICK;
}
*ppDb = db;
#ifdef SQLITE_ENABLE_SQLLOG
if( sqlite3GlobalConfig.xSqllog ){
/* Opening a db handle. Fourth parameter is passed 0. */
void *pArg = sqlite3GlobalConfig.pSqllogArg;
sqlite3GlobalConfig.xSqllog(pArg, db, zFilename, 0);
}
#endif
//SQLITE_HAS_CODEC,是否支持加密选项
#if defined(SQLITE_HAS_CODEC)
if( rc==SQLITE_OK ){
const char *zKey;
if( (zKey = sqlite3_uri_parameter(zOpen, "hexkey"))!=0 && zKey[0] ){
u8 iByte;
int i;
char zDecoded[40];
for(i=0, iByte=0; i