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;

}

Sqlite源码解读(十二)相关推荐

  1. 价值4500的国际版多语言点赞抖音分享点赞任务平台源码(十二种语言)

    介绍: 平台会员分享给我的,他自己搭建成功了,测试可用!我就不测试了,需要的拿! 九种语言 :西班牙语,泰语.日语,印度尼西亚语言.越南语言.英文.繁体中文,简体中文,印度语 前台支持更换5种颜色风格 ...

  2. 【vue-router源码】十二、useRoute、useRouter、useLink源码分析

    [vue-rouer源码]系列文章 [vue-router源码]一.router.install解析 [vue-router源码]二.createWebHistory.createWebHashHis ...

  3. print python 带回车_python标准库threading源码解读【二】

    紧接着上一篇文章继续解析源码 甘蔗:python标准库threading源码解读[一]​zhuanlan.zhihu.com 目录 Event的介绍和用法 Event源码解析 以后的内容尽量少一点并且 ...

  4. x264源码解读(二)- VCL和NAL那些事

    目录 ANNEXB vs. AVCC VCL vs. NAL signal函数响应键盘事件 收尾清理工作 x264的编码 ANNEXB vs. AVCC 今天我们继续来说一下x264结构中非常重要的属 ...

  5. JAVA ssm b2b2c多用户商城系统源码 (十二)springboot集成apidoc

    首先声明下,apidoc是基于注释来生成文档的,它不基于任何框架,而且支持大多数编程语言,为了springboot系列的完整性,所以标了个题. 一.apidoc简介 apidoc通过在你代码的注释来生 ...

  6. ReactiveCocoa源码解读(二)

    上一篇解读了ReactiveCocoa的三个重要的类的底层实现,本篇继续. 一.RACMulticastConnection 1.应用 RACMulticastConnection: 用于当一个信号被 ...

  7. Spring源码系列(十二)Spring创建Bean的过程(二)

    1.写在前面 上篇博客主要Spring在创建Bean的时候,第一次调用的Bean的后置处理器的过程,同时笔者也打算将整个Spring创建的Bean的过程,通过这个系列,将Bean的创建过程给讲清楚,废 ...

  8. jpcsp源码解读之二:main函数与jpcsp的初始化流程

    虽然这个软件是用java语言编写,面向对象,可是总要有个开始的入口,这里关心的就是,main函数在哪里. 似乎java中也可以没有main函数,也可能是我的错误认识.暂且不管,jpcsp中是有main ...

  9. 【转】ABP源码分析十二:本地化

    本文逐个分析ABP中涉及到localization的接口和类,以及他们之间的关系.本地化主要涉及两个方面:一个是语言(Language)的管理,这部分相对简单.另一个是语言对应得本地化资源(Local ...

  10. PhotoSwipe源码解读系列(二)

    作者: 铁锚 日期: 2013年12月19日 说明: 本系列文章为草稿,等待后期完善.源码是jQuery版本的,code.photoswipe-3.0.5.js 1. 代码开头,就是一些版权申明,没什 ...

最新文章

  1. 研究生应当具备的三种基本技能
  2. BASIC-3 字母图形
  3. 基于单样本单统计推断-假设检验
  4. 两次被简书签约作者拉黑的经历
  5. 在matlab中实现PCA算法
  6. Flutter RotatedBox旋转容器
  7. DSP28335的RS232串口通讯试验
  8. 【头像变更】自己瞎做一个头像,放真实头像做头像虽然真诚,但是心里实在不想!
  9. 聚合直播,直播接口的使用
  10. 中控,中控系统,中控会议室
  11. 戒指你戴对了吗?Meet Surprise教你正确的戴法
  12. Shader学习7——法线贴图
  13. 怎么设置计算机网络打印机共享,打印机共享设置,告诉你打印机共享怎么设置...
  14. [ML-03] Matplotlib-3
  15. bind9 dlz mysql_源码安装Bind 9.10 正式版 开启DLZ数据库支持 和 数据库view查询
  16. 可以DIY装修的商城系统,你也能拥有
  17. php点击同一个按钮实现正序倒叙,php foreach正序倒序输出
  18. day2-----k8s集群管理常用知识点(1)
  19. 使用Pandas读取CSV文件:sep操作
  20. github Action使用

热门文章

  1. java程序毕设javaweb程序分享
  2. k8s --> 19 k8s集群down机
  3. 计算机设置位蓝牙播放xp,winxp系统电脑连接蓝牙耳机听音乐的方法
  4. 2016服务器文件夹权限设置,Server 2016特定用户权限划分,只显示有权限的文件夹,无法权限文件夹无法看到...
  5. k8s问题及解决方法
  6. python回溯算法_回溯算法经典问题及python代码实现
  7. ZOJ The Sum of Unitary Totient
  8. python爬取饿了么订单_python爬虫:爬取某图外卖数据有这篇文章就够了
  9. 2022-2028年全球与中国智能停车系统行业竞争格局与投资战略研究
  10. matlab绘制曲线相交的交点