Sqlite源码解读(十二)

2021SC@SDUSC

第八篇到第十一篇讲解了所有sqlite3_file方法的实现。

接下来是Sqlite的OS Interface部分收尾阶段。

首先是定义了win32一些vfs方法的两个向量。

/*该向量定义了对Win 32的sqlite 3_file进行操作的所有方法。*/

static const sqlite3_io_methods winIoMethod = {

  3,                              /* 版本号 */

  winClose,                    

  winRead,                   

  winWrite,                    

  winTruncate,                

  winSync,                   

  winFileSize,                  

  winLock,                    

  winUnlock,                 

  winCheckReservedLock,      

  winFileControl,               

  winSectorSize,              

  winDeviceCharacteristics,      

  winShmMap,               

  winShmLock,               

  winShmBarrier,              

  winShmUnmap,            

  winFetch,                 

  winUnfetch               

};

/*该向量定义了所有可以对Win 32的sqlite 3_file进行操作而不执行任何锁定的方法。*/

static const sqlite3_io_methods winIoNolockMethod = {

  3,                          /* 版本号 */

  winClose,                   

  winRead,                   

  winWrite,                   

  winTruncate,                

  winSync,                    

  winFileSize,                 

  winNolockLock,               

  winNolockUnlock,            

  winNolockCheckReservedLock, 

  winFileControl,               

  winSectorSize,               

  winDeviceCharacteristics,      

  winShmMap,                 

  winShmLock,                 

  winShmBarrier,                

  winShmUnmap,              

  winFetch,                    

  winUnfetch                  

};

static winVfsAppData winAppData = {

  &winIoMethod,       /* pMethod */

  0,                  /* pAppData */

  0                   /* bNoLock */

};

static winVfsAppData winNolockAppData = {

  &winIoNolockMethod, /* pMethod */

  0,                  /* pAppData */

  1                   /* bNoLock */

};


/*此分区包含sqlite3_VFS对象上方法的实现*/

#if defined(__CYGWIN__)

/* 将文件名从任何底层操作系统支持的文件名转换为UTF-8。保存结果的空间是从malloc获得的,必须由调用函数释放*/

static char *winConvertToUtf8Filename(const void *zFilename){

  char *zConverted = 0;

  if( osIsNT() ){

    zConverted = winUnicodeToUtf8(zFilename);

  }

#ifdef SQLITE_WIN32_HAS_ANSI

  else{

    zConverted = winMbcsToUtf8(zFilename, osAreFileApisANSI());

  }

#endif

  /* 调用者将处理内存不足 */

  return zConverted;

}

#endif

/*是上面的逆操作。将UTF-8文件名转换为底层操作系统想要的任何形式的文件名。保存结果的空间同样是从malloc获得的,必须通过调用函数来释放。*/

static void *winConvertFromUtf8Filename(const char *zFilename){

  void *zConverted = 0;

  if( osIsNT() ){

    zConverted = winUtf8ToUnicode(zFilename);

  }

#ifdef SQLITE_WIN32_HAS_ANSI

  else{

    zConverted = winUtf8ToMbcs(zFilename, osAreFileApisANSI());

  }

#endif

    /* 调用者将处理内存不足 */

  return zConverted;

}

如果指定的UTF-8字符串缓冲区以目录分隔符结束,或者成功地将一个字符添加到其中,则此函数返回非零。

static int winMakeEndInDirSep(int nBuf, char *zBuf){

  if( zBuf ){

    int nLen = sqlite3Strlen30(zBuf);

    if( nLen>0 ){

      if( winIsDirSep(zBuf[nLen-1]) ){

        return 1;

      }else if( nLen+1<nBuf ){

        zBuf[nLen] = winGetDirSep();

        zBuf[nLen+1] = '\0';

        return 1;

      }

    }

  }

  return 0;

}

创建一个临时文件名,并将结果指针存储到pzBuf中。必须通过sqlite 3_free()释放pzBuf中返回的指针。

static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){

  static char zChars[] =

    "abcdefghijklmnopqrstuvwxyz"

    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

    "0123456789";

  size_t i, j;

  int nPre = sqlite3Strlen30(SQLITE_TEMP_FILE_PREFIX);

  int nMax, nBuf, nDir, nLen;

  char *zBuf;

/*计算出有效的临时目录。首先,检查应用程序是否显式设置了一个;否则,使用操作系统配置的一个*/

nDir = nMax - (nPre + 15);

  assert( nDir>0 );

  if( sqlite3_temp_directory ){

    int nDirLen = sqlite3Strlen30(sqlite3_temp_directory);

    if( nDirLen>0 ){

      if( !winIsDirSep(sqlite3_temp_directory[nDirLen-1]) ){

        nDirLen++;

      }

      if( nDirLen>nDir ){

        sqlite3_free(zBuf);

        OSTRACE(("TEMP-FILENAME rc=SQLITE_ERROR\n"));

        return winLogError(SQLITE_ERROR, 0, "winGetTempname1", 0);

      }

      sqlite3_snprintf(nMax, zBuf, "%s", sqlite3_temp_directory);

    }

  }

如果指定的文件实际上是目录,则返回true。如果它不是目录,或者是任何类型的内存分配失败,则返回False。

static int winIsDir(const void *zConverted){

  DWORD attr;

  int rc = 0;

  DWORD lastErrno;

  if( osIsNT() ){

    int cnt = 0;

    WIN32_FILE_ATTRIBUTE_DATA sAttrData;

    memset(&sAttrData, 0, sizeof(sAttrData));

    while( !(rc = osGetFileAttributesExW((LPCWSTR)zConverted,

                             GetFileExInfoStandard,

                             &sAttrData)) && winRetryIoerr(&cnt, &lastErrno) ){}

    if( !rc ){

      return 0;  /* 无效名? */

    }

    attr = sAttrData.dwFileAttributes;

#if SQLITE_OS_WINCE==0

  }else{

    attr = osGetFileAttributesA((char*)zConverted);

#endif

  }

  return (attr!=INVALID_FILE_ATTRIBUTES) && (attr&FILE_ATTRIBUTE_DIRECTORY);

}

/*前瞻性参考*/

static int winAccess(

  sqlite3_vfs *pVfs,          /* 未用于win32 */

  const char *zFilename,     /* 要检查的文件名*/

  int flags,                 /* 要对此文件进行测试的类型 */

  int *pResOut              /*退出:结果 */

);

/* 打开一个文件*/

static int winOpen(

  sqlite3_vfs *pVfs,          /* 用来获取最大路径长度和AppData */

  const char *zName,        /* 文件名 (UTF-8) */

  sqlite3_file *id,           /* 在这里写入SQLite 文件句柄 */

  int flags,                /* 打开模式标志 */

  int *pOutFlags            /* 状态返回标志 */

){

  HANDLE h;

  DWORD lastErrno = 0;

  DWORD dwDesiredAccess;

  DWORD dwShareMode;

  DWORD dwCreationDisposition;

  DWORD dwFlagsAndAttributes = 0;

#if SQLITE_OS_WINCE

  int isTemp = 0;

#endif

  winVfsAppData *pAppData;

  winFile *pFile = (winFile*)id;

  void *zConverted;                 /* OS编码中的文件名*/

  const char *zUtf8Name = zName;    /* UTF-8编码中的文件名 */

  int cnt = 0;

 /* 如果参数zPath是空指针, 则需要这个函数打开一个临时文件。用这个缓冲区来存储文件名 */

  char *zTmpname = 0;    /*用于临时文件名,如果需要的话 */

  int rc = SQLITE_OK;            /* 函数返回代码 */

#if !defined(NDEBUG) || SQLITE_OS_WINCE

  int eType = flags&0xFFFFFF00;  /* 要打开的文件类型 */

#endif

  int isExclusive  = (flags & SQLITE_OPEN_EXCLUSIVE);

  int isDelete     = (flags & SQLITE_OPEN_DELETEONCLOSE);

  int isCreate     = (flags & SQLITE_OPEN_CREATE);

  int isReadonly   = (flags & SQLITE_OPEN_READONLY);

  int isReadWrite  = (flags & SQLITE_OPEN_READWRITE);

#ifndef NDEBUG

  int isOpenJournal = (isCreate && (

        eType==SQLITE_OPEN_SUPER_JOURNAL

     || eType==SQLITE_OPEN_MAIN_JOURNAL

     || eType==SQLITE_OPEN_WAL

  ));

#endif

  OSTRACE(("OPEN name=%s, pFile=%p, flags=%x, pOutFlags=%p\n",

           zUtf8Name, id, flags, pOutFlags));

检查以下语句为true

/*必须设置READWRITE 或READONLY标志之一*/

/*如果CREATE被设置,则READWRITE也必须被设置*/

/*如果EXCLUSIVE被设置,则CREATE也必须被设置*/

/*如果DELETEONCLOSE被设置,则CREATE也必须被设置*/

assert((isReadonly==0 || isReadWrite==0) && (isReadWrite || isReadonly));

assert(isCreate==0 || isReadWrite);

assert(isExclusive==0 || isCreate);

assert(isDelete==0 || isCreate);

主数据库、主日志、WAL文件和超级日志永远不会被自动删除,它们也不是临时文件

assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB );

  assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL );

  assert( (!isDelete && zName) || eType!=SQLITE_OPEN_SUPER_JOURNAL );

  assert( (!isDelete && zName) || eType!=SQLITE_OPEN_WAL );

断言上层设置了“文件类型”标志之一

  assert( eType==SQLITE_OPEN_MAIN_DB      || eType==SQLITE_OPEN_TEMP_DB

       || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL

       || eType==SQLITE_OPEN_SUBJOURNAL   || eType==SQLITE_OPEN_SUPER_JOURNAL

       || eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL

  );

如果这个函数的第二个参数为空,则生成一个临时文件名使用

if( !zUtf8Name ){

    assert( isDelete && !isOpenJournal );

    rc = winGetTempname(pVfs, &zTmpname);

    if( rc!=SQLITE_OK ){

      OSTRACE(("OPEN name=%s, rc=%s", zUtf8Name, sqlite3ErrName(rc)));

      return rc;

    }

    zUtf8Name = zTmpname;

  }

如果数据库文件名不是带参数的URI,则为双零终止。因此,它们总是可以传递给sqlite3_uri_parameter()。

  assert( (eType!=SQLITE_OPEN_MAIN_DB) || (flags & SQLITE_OPEN_URI) ||

       zUtf8Name[sqlite3Strlen30(zUtf8Name)+1]==0 );

把文件名转化为系统编码

  zConverted = winConvertFromUtf8Filename(zUtf8Name);

  if( zConverted==0 ){

    sqlite3_free(zTmpname);

    OSTRACE(("OPEN name=%s, rc=SQLITE_IOERR_NOMEM", zUtf8Name));

    return SQLITE_IOERR_NOMEM_BKPT;

  }

  if( winIsDir(zConverted) ){

    sqlite3_free(zConverted);

    sqlite3_free(zTmpname);

    OSTRACE(("OPEN name=%s, rc=SQLITE_CANTOPEN_ISDIR", zUtf8Name));

    return SQLITE_CANTOPEN_ISDIR;

  }

  if( isReadWrite ){

    dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;

  }else{

    dwDesiredAccess = GENERIC_READ;

  }

猜你喜欢

转载自blog.csdn.net/qq_53825872/article/details/121529532
今日推荐