sqlite 源码学习

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<sizeof(zDecoded)*2 && sqlite3Isxdigit(zKey[i]); i++){
        iByte = (iByte<<4) + sqlite3HexToInt(zKey[i]);
        if( (i&1)!=0 ) zDecoded[i/2] = iByte;
      }
      sqlite3_key_v2(db, 0, zDecoded, i/2);
    }else if( (zKey = sqlite3_uri_parameter(zOpen, "key"))!=0 ){
      sqlite3_key_v2(db, 0, zKey, sqlite3Strlen30(zKey));
    }
  }
#endif
  sqlite3_free(zOpen);
  return rc & 0xff;
}

猜你喜欢

转载自blog.csdn.net/ybn187/article/details/82019826