文章正文
SQLITE虚表
SQLite的虚表的机制
虚表是一种自定义的扩展,允许用户通过代码定制表的数据结构和数据内容;对于数据库引擎,它和普通表一样,允许进行大多数的sql操作。虚表和普通表的主要不同在于以下几点:
1. 其表中的数据的来源不同;对于普通表,来源于数据库的行列值;而对于虚表,来源于用户自定义的函数,可以使数据库中的数据,也可以使其他的外部数据,如:磁盘文件(csv, excel)等;
2. 虚表是sqlite的一种高级特性,它的实现基于sqlite module;
3. 虚表被用于连接数据库引擎和可变的数据源,分为两种:internals and externals;
4. internal modules的数据来自于数据库文件本身,它的主要目的并不是做普通表不能做的,而是作为智能视图,更具扩展性的、更方便的、更快速的处理一些特定格式的数据;sqlite本身带有两个modules:FTS3和R*Tree,用于全文检索;由于虚表属于扩展所以对应的源码存放在ext目录下。
5. external modules的数据来自于数据库文件外部,如cvs、excel文件等;这样,在不导入外部数据到数据库的情况下,用户能够以sql的方式访问和处理外部数据源 (对于10万条记录,速度可以是秒级的);
Module APIs(这些API在下面的文档中会详细说明):
1. int sqlite3_create_module(sqlite3 *db, const char *name, const sqlite3_module *module, void*udp)
2. CREATE VIRTUAL TABLE table_name USING module_name(arg)
表操作:
1. xCreate, xConnect, xDisConnect, xDestroy
2. xBestIndex, xFindFunction, xUpdate, xRename
表扫描:
1. xOpen, xClose, xFilter, xNext, xEof
2. xRowid, xColumn
事务处理:
1. xBegin, xSync, xCommit, xRollback
l R*Tree
代码目录:ext/rtree
R树是一种特殊的索引,用于做范围查询。树是最常用的地理信息系统,每个条目是一个最小和最大的X和Y坐标的矩形。给定一个查询矩形,R-树是能够迅速找到所有条目都包含查询矩形内或重叠的矩形的查询。这个想法很容易扩展到三个维度中,用于现在使用的计算机辅助设计系统(CAD)。树也发现使用在时域范围内查找。例如,假设一个数据库记录了大量的事件的开始和结束时间。R树是能够迅速找到所有的事件,是活跃在任何时间在一个给定的时间间隔,或所有的事件开始,在一个特定的时间间隔,或是开始和结束的一个给定的时间间隔内的所有事件。等等。
l 全文检索
代码目录:ext/fts3(3.8.10.2版本)
全文检索是internals module的一种应用,使用了fts3或fts4 module。
1. 该模块优化了对全文索引的插入和查询,减少了用户的工作量;
2. 该虚表对应了3~6个影子表,其存储实际的数据;当向虚表中插入文本内容时,相应的数据和索引会被插入到各影子表中
3. 对应若干种关键字查询方式;
4. 涉及多种toknizer,用户也可以定制词法分析器;
5. 索引表采取B-tree的存储方式,每插入一行,都会生成一个新的索引表,这可以降低索引表更新的效率,但是占用了大量的存储空间,因此,需要定期的merge索引表。
可以到sqlite官方网站上查询对虚表的解释(http://www.sqlite.org/vtab.html),而对与全文索引,sqlite源码中有相应的单元测试用例,可以通过这些用例查看全文索引的使用方法。
翻译官网http://www.sqlite.org/vtab.html:参考:http://www.helplib.net/s/sqlite/
1 简介
虚拟表格是一个对象, 其在数据库链接打开的时候被注册。 从执行计划的角度讲,该虚表对象看上去像其它的表或视图。但在幕后, 查询或更新虚表是通过调用回调方法操作虚表对象,而不是读取和写入的数据库文件
使用虚表的机制允许应用程序公开一些让执行引擎可访问的接口,使得就像它们是普通表一样。SQL语句对于虚表,一般操作上与真实表没有区别, 但下列情况除外:
· 在虚表上,无法创建触发器。
· 不能在虚拟创建额外的索引的表(虚表可以有索引, 但必须构建到虚拟表的实现,不能使用CREATE INDEX 语句添加单独的索引)
· 针对虚拟表,无法运行ALTER TABLE ...ADD COLUMN 等命令.
虚表的实现可能添加额外的限制,例如, 有些虚表的实现可能会提供的只读操作,或有些虚拟表的实现可能允许INSERT 或DELETE 但不能UPDATE ,在或着某些虚拟表的实现可能会限制部分的UPDATE 命令。
虚拟表可能表示一个内存中的数据结构,它也可能是一个磁盘上数据的视图,而这些数据不以SQLite 格式存储,从而根据需要,应用程序可能会计算虚表的内容。
下面是一些假定的虚表使用的规则:
· 一个全文搜索接口
· 使用R-Trees的特殊的索引
· 读取和写入CSV文件的内容
· 访问主机的文件系统
· 启用像R之类的SQL统计软件包,实现SQL个性化
2 用法
创建一个虚拟表,使用CREATE VIRTUAL TABLE 语句,此语句创建一个具有特殊名称的表,并有module 与该表关联
CREATE VIRTUAL TABLE tablename USING modulename ;
也可以像下例一样,提供逗号分隔的参数在模块的名称中:
CREATE VIRTUAL TABLE tablename USING modulename(arg1 , arg2 , ...) ;
指定的参数到模块非常一般,每个参数可以包含关键字、字符串的详细信息, 标识符、数字和标点符号。当虚拟表被创建时,传递的所有参数都是作为写入文件(文本),传入到虚表实现的构造函数中,构造函数负责解析并解释参数。如果需要, 它的参数都解释为列定义,就像在一个普通的CREATE TABLE 语句实现一样。当然可能在参数实现其他的操作。
一旦创建了虚拟表, 它能像其他任何表操作,除外上面提供的以外。使用普通DROP TABLE 语法,实现一个虚表的销毁。
3 实现
3.1 数据结构
对于虚表的实现,使用了几个新的C层级的对象:
typedef struct sqlite3_vtab sqlite3_vtab ;
typedef struct sqlite3_index_info sqlite3_index_info ;
typedef struct sqlite3_vtab_cursor sqlite3_vtab_cursor ;
typedef struct sqlite3_module sqlite3_module ;
sqlite3_module 结构定义一个模块对象,用于实现虚表。可以想到,module可以构造具有相似属性的多个虚表。例如, 可能会有一个模块, 提供CSV文件的只读访问权,或一个模块可以创建几个虚拟表, 其中每个虚拟表引用一个不同的CSV 文件。
模块结构包含有由SQLite调用的方法以执行对于虚表的各种操作,如创建一个新实例的虚表或销毁旧的虚表,读取和写入数据,查找和删除、更新或插入行。
下面还会详细介绍的模块结构。
每个虚表实例, 由一个虚拟表sqlite3_vtab结构表示,sqlite3_vtab结构如下所示:
struct sqlite3_vtab {
const sqlite3_module *pmodule ;
int nref ;
char *zErrMsg;
};
字段nref字段为SQLite核心所用,不能在虚表的实现中使用。虚表将错误消息通过zErrMsg变量传递给SQL核心。 消息字符串必须是从一个SQLite 内存分配函数分配的空间, 如sqlite3_mprintf( )或sqlite3_malloc( )。虚表的实现必须释放所有原有的内容通过使用sqlite3_free( )。如果不这样做, 将会导致内存泄漏。SQLite核心会在提供零错误消息文本到客户端或者销毁此虚表是,将zErrMsg释放,所以虚表的实现只需要关心释放zErrMsg,只有当新的不同的错误消息内容覆盖旧的时.
sqlite3_vtab_cursor 结构表示指向某个特定的虚拟表的行。
sqlite3_vtab_cursor 类似如下的内容:
struct sqlite3_vtab_cursor {
sqlite3_vtab *pvtab ;
};
再一次说明, 对于特殊的实现,可以添加其他专用字段。
sqlite3_index_info 结构用于传递信息使用,这个传递由虚表实现xBestIndex的方法来实现.
在一个CREATE VIRTUAL TABLE 语句运行前,相应的模块必须指定到数据的链接中,注册可以使用sqlite3_create_module( )或sqlite3_create_module_v2( )接口实现:
int sqlite3_create_module(
sqlite3 *db , /* SQLite 与注册模块带*/
const char *zname , /* 的模块的名称输入*/
const sqlite3_module *模块, /* 方法的*/
void * /* 客户数据的xCreate/xConnect */
);
int sqlite3_create_module_v2(
sqlite3 *db , /* SQLite 与注册模块带*/
const char *zname , /* 的模块的名称输入*/
const sqlite3_module *模块, /* 方法的*/
void *, /* 客户数据的xCreate/xConnect */
void(*xdestroy)(void* )/*客户数据析构函数函数*/
);
sqlite3_create_module( )和sqlite3_create_module_v2( )函数将会关联一个模块的名称与sqlite3_module 结构和分离的客户数据。两个创建模块的方法的区别在于, _v2 方法包括一个额外的参数, 用于指定一个客户数据指针的析构函数。模块结构体定义了一个虚表的行为。模块结构体如下:
struct sqlite3_module {
int iversion ;
int (*xcreate)(sqlite3* , *paux void ,
int argc , 字符**argv ,
sqlite3_vtab **ppVTab,
char **pzerr) ;
int (*xconnect)(sqlite3* , *paux void ,
int argc , 字符**argv ,
sqlite3_vtab **ppVTab,
char **pzerr) ;
int (*xBestIndex)(sqlite3_vtab *pVTab, sqlite3_index_info*) ;
int (*xdisconnect)(sqlite3_vtab *pVTab);
int (*xdestroy)(sqlite3_vtab *pVTab);
int (*xopen)(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppcursor) ;
int (*xclose)(sqlite3_vtab_cursor*) ;
int (*xfilter)(sqlite3_vtab_cursor* , int idxnum 、const char *idxstr ,
int argc 、sqlite3_value **argv) ;
int (*xnext)(sqlite3_vtab_cursor*) ;
int (*xeof)(sqlite3_vtab_cursor*) ;
int (*xcolumn)(sqlite3_vtab_cursor* 、sqlite3_context* int) ;
int (*xrowid)(sqlite3_vtab_cursor* , sqlite_int64 *prowid) ;
int (*xupdate)(sqlite3_vtab *、int 、sqlite3_value ** , sqlite_int64 *) ;
int (*xbegin)(sqlite3_vtab *pVTab);
int (*xsync)(sqlite3_vtab *pVTab);
int (*xcommit)(sqlite3_vtab *pVTab);
int (*xrollback)(sqlite3_vtab *pVTab);
int (*xFindFunction)(sqlite3_vtab *pvtab 、int narg 、const char *zname ,
void (**pxfunc)(sqlite3_context*, int, sqlite3_value**) ,
void **pparg) ;
int (*rename)(sqlite3_vtab *pvtab , const char *znew) ;
/* 方法上面的都是在版本1中的sqlite_module 对象这些
** 下面属于版本2及更高版本*/
int (*xsavepoint)(sqlite3_vtab *pVTab, int) ;
int (*xrelease)(sqlite3_vtab *pVTab, int) ;
int (*xRollbackTo)(sqlite3_vtab *pVTab, int) ;
};
模块结构定义每虚表对象的所有方法。模块结构还包含了iversion 字段, 它定义了这个特定的版本,模块结构当前版本总为1,但在以后的版本中, SQLite 的模块结构定义可能已被扩展的.在这种情况下, iversion 的值将增加
模块结构的其余部分包含用于实现虚拟表的各种功能。后面详细说明每个方法。
1.3 虚拟表和共享缓存
SQLite 版本3.6.17之前,虚拟表机制假定每个数据库连接保留自己的复制该数据库的schema.因此, 在开启共享高速缓存模式的时候,虚表的机制不能用. 如果启用共享高速缓存模式,数据库调用sqlite3_create_module( )接口时会产生错误。这个限制在SQLite 版本3617之后解除.
3.2 创建新虚拟表的过程
按照以下的步骤来创建您自己的虚拟表格:
1. 写入所有必要的方法
2. 创建一个实例sqlite3_module 结构, 其中包含所有方法的指针。
3. 注册您的sqlite3_module 使用sqlite3_create_module( )或sqlite3_create_module_v2( )接口.
4. 运行一个CREATE VIRTUAL TABLE 命令,在USING 子句中指定新模块的名称.
唯一比较难的步骤在步骤1。SQL源码中实现了用于测试的的一些虚表,可能对其进行修改以满足开发的需求。
您可能还想要实现您的新虚表作为可载入族扩展.
3.3 虚表实现的方法
3.3.1 xcreate 方法
int (*xcreate)(sqlite3 *db , *paux void ,
int argc , 字符**argv ,
sqlite3_vtab **ppVTab,
char **pzerr) ;
调用此方法来创建新实例的虚表,响应CREATE VIRTUAL TABLE 语句,db参数是指向执行的CREATE VIRTUAL TABLE 语句的数据库连接.paux参数是在复制的数据指针第四个参数到sqlite3_create_module( )或sqlite3_create_module_v2( )注册的虚拟表的模块。argv 参数数组是argc 个指针,以null 结尾的字符串。第一个字符串, argv[0] , 是被调用的模块的名称。提供的模块的名称是sqlite3_create_module( )的第二个参数,第二字符串, argv[1] , 是数据库的名称,如果正在创建新虚表所在的数据库, 但"main "主或”temp” 为TEMP 数据. 或ATTACH附加的数据库名称。数组的第三个元素, argv[2] , 新虚表的名称, 如在CREATE VIRTUAL TABLE 语句中存在的TABLE type 关键字, 第四条和后续的字符串所有参数表示模块执行CREATE VIRTUAL TABLE 语句时的参数.
此方法的任务就是要构造新的虚表对象(一个sqlite3_vtab 对象),并通过*ppVTab返回一个它的指针.
在创建sqlite3_vtab结构时, 方法必须调用sqlite3_declare_vtab( ),去在SQLite 核心申明关于该虚拟表的列和数据类型。sqlite3_declare_vtab( )API 有以下原型:
int sqlite3_declare_vtab(sqlite3 *db , const char *zCreateTable)
sqlite3_declare_vtab( )第一个参数必须相同数据库连接指针作为第一个参数传递到此方法,第二个参数必须以0结尾的UTF-8 字符串, 它包含一个形式完好的CREATE TABLE 语句包含的列和它们的数据类型,在此语句中表的名称将被忽略,。CREATE TABLE 语句字符串不需要永久在内存中,sqlite3_declare_vtab( )函数返回后,该字符串可以重用。.
xcreate 方法不需要初始化sqlite3_vtab 对象的pmodule , nref , zErrMsg 字段,在SQLite 核心并不关心这些东西。
如果创建成功新的虚表,xcreate 必须返回SQLITE_OK , 如果不成功返回SQLITE_ERROR。如果不成功sqlite3_vtab 结构不能分配。*pzerr中可能(可选)返回一个错误。
在每个虚拟表的实现中,xcreate 方法是必需的,如果不用初始化后备存储,在sqlite3_module结构中xCreate 和 xConnect 可能指向相同的函数。
表中的列
如果一个列的数据类型包含为特殊关键字"HIDDEN "(在任意组合的大写和小写字符), 则该列数据类型的名称将被忽略,同时被标记为隐藏的列。隐藏的列与普通的列有三点不同:
· 隐藏的列不会使用PRAGMA table_info 返回。
· 隐藏的列不会在SELECT*表达式的结果集中
· 隐藏的列不会INSERT 语句中。
例如, 如果下面的SQL语句输入到sqlite3_declare_vtab( )函数:
CREATE TABLE x(a HIDDEN VARCHAR(12), bINTEGER, cINTEGER hidden) ;
然后虚表将会创建两个隐藏的列.并带有"VARCHAR(12) "和"INTEGER "数据类型.
使用隐藏的列的一个例子在FTS3虚表中实现, 其中每个FTS 虚表都包含一个FTS 隐藏的列用于从虚表中传递信息到FTS 辅助函数以及FTS MATCH 运算符.
3.3.2 xconnect 方法
int (*xconnect)(sqlite3* , *paux void ,
int argc , 字符**argv ,
sqlite3_vtab **ppVTab,
char **pzerr) ;
xconnect方法与xcreate非常相似,它具有相同的参数构造一个新的sqlite3_vtab 结构就像xcreate一样, 并且还必须调用sqlite3_declare_vtab( ).
两个函数的区别是xconnect 来建立一个新连接到现有的虚拟表,而调用xcreate 来从头开始设计查询创建新虚表.
xcreate 和xconnect 方法, 可以用不同的当表某种后备存储, 必须先初始化首次在创建虚拟表xcreate方法创建并初始化后备存储,xconnect方法连接到一个现有的后备存储
例如, 考虑一个虚拟表的实现, 如果提供只读访问现有的comma-separated-value (CSV) 文件,没有后备存储需要创建或初始化虚表(文件已经存在), xcreate 和xconnect 方法将指向相同的函数
另一个示例是一个实现全文索引虚表,xcreate参数可以是创建和初始化数据结构以保持为该索引字典和投递列表,另一方面, xconnect方法只有来查找和使用现有的字典和投递列表这些东西在xcreate生成。
如果成功创建虚表,xconnect 方法返回SQLITE_OK , 如果不成功返回SQLITE_ERROR,sqlite3_vtab 结构不能分配,*pzerr中可能(可选)返回一个错误。
xconnect 方法在虚表的实现中必须有, 但可能与xcreate指向同一个函数。
3.3.3 xBestIndex 方法
SQLite 使用虚表模块中的xBestIndex 方法,来确定访问虚拟表的最佳方式。xBestIndex方法的一个原型, 如下所示:
int (*xBestIndex)(sqlite3_vtab *pVTab, sqlite3_index_info*) ;
SQLite 核心与xBestIndex 方法通信,通过填写sqlite3_index_info 结构的特定的字段将其作为xBestIndex 的第二个参数。xBestIndex方法会填充其他的字段,用于回复。sqlite3_index_info 结构是这个样子:
struct sqlite3_index_info {
/* 输入*/
const int nconstraint ;/* 在aconstraint */
const struct sqlite3_index_constraint {
int icolumn ;/* 列在图表上并且磁盘未满*/
unsigned char op ;/* 约束运算符*/
unsigned char 可用的;/* 如果此值为true .则此约束是*/
int iTermOffset; /* 内部使用-xBestIndex 应忽略*/
}*const aconstraint ;/* 表WHERE 子句约束*/
const int nOrderBy; 中/* 数目的字词ORDER BY 子句*/
const struct sqlite3_index_orderby {
int icolumn ;/* 列数*/
DESC unsigned char desc ;/* true .为ASC false*/
}*const aOrderBy; /* 的ORDER BY 子句*/
/* 输出*/
struct sqlite3_index_constraint_usage {
int argvindex ;/* 如果> 0, 约束是argv 的一部分要xfilter */
unsigned char 省略;/* 不为此约束中编写一个测试*/
}*const aConstraintUsage;
int idxnum ;/* 用于识别*/ 的索引
char *idxstr ;/* 字符串, 可能是从sqlite3_malloc 获取*/
int needToFreeIdxStr; /* 使用idxstr sqlite3_free( )如果为true */
int orderByConsumed; /* 如果此值为true .则输出已经有序*/
double estimatedCost; /* 使用此索引预计成本*/
/* Fields below are only available in SQLite 3.8.2 and later */
sqlite3_int64 estimatedRows; /* Estimated number of rows returned */
};
estimatedRows字段从版本3.8.2开始引入,所以需要时,先使用sqlite3_version()获取版本号。此外,还有一些定义的常量:
#define SQLITE_INDEX_CONSTRAINT_EQ 2
#define SQLITE_INDEX_CONSTRAINT_GT 4
#define SQLITE_INDEX_CONSTRAINT_LE 8
#define SQLITE_INDEX_CONSTRAINT_LT 16
#define SQLITE_INDEX_CONSTRAINT_GE 32
#define SQLITE_INDEX_CONSTRAINT_MATCH 64
SQLite 核心在编译一个涉及虚表的查询时调用xBestIndex 方法。换句话说, SQLite调用此方法,在它的prepare阶段。通过调用此方法,SQLite核心需要访问某些的虚拟行的结果时,执行xBestIndex方法获取最有效搜索虚拟表的方法。
编译单个SQL 查询时, SQLite 核心可能多次以不同的sqlite3_index_info设置调用xBestIndex用于寻找最佳性能。传入信息被标记为"Inputs",输出段初始化为0.
调用此方法前, SQLite 核心会初始化一个实例sqlite3_index_info结构,这个结构中包含着WHERE子句和ORDER BY 或GROUP BY 子句以及ON 或USING的信息。将SQLite 核心信息提供给xBestIndex 方法的一部分的结构标记为"inputs ","outputs "部分被初始化为零
信息sqlite3_index_info是临时的,可能会被覆盖,所以xBestIndex 方法需要复制sqlite3_index_info结构,保存一份。
注意: xBestIndex 将会一直在xfilter调用之前调用, 因此xBestIndex 的输出idxnum 和idxstr都需要输入到xfilter函数,但是,没有保证xfilter 一定会调用。
xBestIndex 方法对于每个虚拟表的实现是必需的
3.3.3.1 输入
SQLite 核心与虚表通信的主要的事情是约束,这些约束会限制搜索的行数.aconstraint[] 数组包含每个约束。在数组中总共有nconstraint条目。
每个限制对应于一个术语在WHERE 子句中.或在USING 或ON 子句中,格式如下:
column OP EXPR
其中"column "是在虚表中的列, OP 是一个运算符例如:"= "或"< ", 和EXPR 是任意表达式。例如, 例如在WHERE 子句包含一个字词, 如下所示:
a=5
约束不需要必须是一个常量,查询优化可能会改变where子句抽取成更多的约束。例如, 如果WHERE 子句像这样:
X BETWEEN 10 AND 100 AND 999 > y
查询优化器可能翻为三个独立的约束:
x> =10
x< =100
y< 999
对于每个约束, aConstraint[].iColumn 字段表明约束左边的列。虚表中第一列为列0,rowid列的标为-1. aconstraint[] op为使用哪个运算符。SQLITE_INDEX_CONSTRAINT_*映射为整数常量。列下标的顺序由调用sqlite3_declare_vtab( )在"xcreate 或xconnect 方法定义,隐藏的列也是需要计算的。
aconstraint[] 数组某些约束可能无法使用, 因为表可能是一个连接,aConstraint[].usable会表明这个约束虚表是否可用。
除了WHERE 子句约束, SQLite 核心也将告诉xBestIndex 方法有关ORDER BY、GROUP BY 子句。例如:orderBy[] 数组将标识在order by 子句中的每个约束等。
3.3.3.2 输出
根据以上给出的信息,xBestIndex函数的作用就是得出搜索虚表的最佳方式。
xBestIndex方法使用idxnum 和idxstr 字段与xfilter 方法通信,这些信息会指导xfilter如何索引。对于SQLITE核心,idxnum和idxstr 信息是任意的. SQLite核心只是简单的传输相应的信息到xfilter方法。idxnum 和idxstr可以表示任何的意义,只有xBestIndex 和xfilter都知道其中的含义即可。
如果虚表需要以特定的按照ORDER BY 子句的顺序输出行时, 则orderByConsumed 标志可能设置为true,如果没有以正确的顺序输出,那么orderByConsumed 必须在其默认值为false。 设置这将指示SQLite core是否需要单独将这些数据排序。
estimatedCost的字段应该被设为估计执行此查询所需的访问磁盘操作的数目。SQLite核心通常调用xBestIndex 多次实现指定的不同约束, 获得多个成本估计, 然后选择最优的方式。
aConstraintUsage[] 数组对于每一个输入结构体的nconstraint 的约束包含一个元素, aConstraintUsage[] 用于表明如何使用这些约束
xBestIndex 方法可能设置aConstraintUsage[].argvIndex 条目的值大于0, xBestIndex 方法需要多少就会设置为多少, 相应的约束EXPR将被作为argv[]参数传递到xfilter函数。
例如, 如果aConstraint[3].argvIndex 设置为1, 然后调用xfilter 时, 将调用argv[0]就会存在aconstraint[3]约束。
默认情况下, SQLite核心会重复检查所有约束。如果一个检查是多余的, xBestFilter 方法可以设置aConstraintUsage[].omit用于防止重复检查。
3.3.4 xdisconnect 方法
int (*xdisconnect)(sqlite3_vtab *pVTab);
此方法用于释放虚表的连接。sqlite3_vtab对象被销毁。虚表不会被销毁和任何与虚表相关的都会持久化.
此方法是虚表链接的析构函数。相比xdestroy函数,xdestroy会析构整个虚表
在xdisconnect方法是每个虚表必须实现的, 但是在一些场景下可以和xdestroy 方法指向相同的方法。
3.3.5 xdestroy 方法
int (*xdestroy)(sqlite3_vtab *pVTab);
与xdisconnect 方法相同,这个方法用于释放一个链接。
xdisconnect 方法会在数据库关闭的时候都会调用,xdestroy 方法只有在调用DROP TABLE时候调用。
在xdestroy方法是每个虚表必须实现的, 但是在一些场景下可以和xdisconnect方法指向相同的方法。
3.3.6 xopen 方法
int (*xopen)(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppcursor) ;
使用xopen 方法创建一个新的游标用于访问读取或写入的虚表。成功调用该方法返回SQLITE_OK,并将分配一个sqlite3_vtab_cursor (或一个子类) , 初始化新对象, 并使*ppcursor 指向新的对象。
对于每成功调用该方法, SQLite 核心将调用xclose 销毁该方法分配的游标.
xopen 方法不需要初始化sqlite3_vtab_cursor 结构中的pvtab 字段。SQLite核心会自动处理。
虚表的实现必须能够支持同时打开任意数目的游标.
初次打开时, 光标位于一个未定义的状态,SQLite核心将在读写这个cursor的之前调用xfilter。
xopen 方法对于每个虚拟表的实现是必需的
3.3.7 xclose 方法
int (*xclose)(sqlite3_vtab_cursor*) ;
xclose 关闭先前使用xopen打开的游标。SQLite 核心对于每次调用xopen,都会对应调用一次xclose.
此方法必须释放所有在xopen调用中分配的资源。在调用这个方法后,SQLite核心将不会使用sqlite3_vtab_cursor。
xclose 方法对于每个虚拟表的实现是必需的
3.3.8 xeof 方法
int (*xeof)(sqlite3_vtab_cursor*) ;
如果游标指向一个有效的行的数据这个xeof 方法必须返回false (零)。SQL引擎在调用xfilter 和xnext后会立即调用此方法。
xeof 方法对于每个虚拟表的实现是必需的
3.3.9 xfilter 方法
int (*xfilter)(sqlite3_vtab_cursor* , int idxnum 、const char *idxstr ,
int argc 、sqlite3_value **argv) ;
此方法开始一个特定的虚表的搜索。第一个参数为xopen打开的游标。在接下来的两个参数用于定义由xBestIndex返回的特定搜索方式。idxnum 和idxstr 的含义由xfilter 和xBestIndex 两个函数约定
以下xBestIndex 函数使用的sqlite3_index_info结构会通过使用argc 和argv 参数传递给xfilter
如果虚表包含一个或多个行与搜索标准匹配, cursor必须在第一行。在调用xeof后必须返回false (zero)。如果没有匹配的行, 调用xeof返回true (non-zero)。SQLite 引擎的使用xcolumn 和xrowid 方法访问所对应的行内容。xnext方法被用来移动cursor到下一行
如果成功,此方法必须返回SQLITE_OK ,如果出错,返回一个错误代码。
xfilter 方法对于每个虚拟表的实现是必需的
3.3.10 xnext 方法
int (*xnext)(sqlite3_vtab_cursor*) ;
使用xnext 方法将一个虚表的光标移动到下一行结果集。
xnext 方法对于每个虚拟表的实现是必需的
3.3.11 xcolumn 方法
int (*xcolumn)(sqlite3_vtab_cursor* , sqlite3_context* , int n) ;
SQLite 核心调用此方法用以查找当前行第n列的值。n第一个列为0,xcolumn 方法可能返回其结果通过使用以下接口:
· sqlite3_result_blob( )
· sqlite3_result_double( )
· sqlite3_result_int( )
· sqlite3_result_int64( )
· sqlite3_result_null( )
· sqlite3_result_text( )
· sqlite3_result_text16( )
· sqlite3_result_text16le( )
· sqlite3_result_text16be( )
· sqlite3_result_zeroblob( )
如果xcolumn 的函数没有实现上述的任何一种方法,则默认的值为SQL NULL.
xcolumn 会产生错误, 该方法会使用result_text( )方法来设置错误消息文本,并返回特定的错误代码.
xcolumn 方法对于每个虚拟表的实现是必需的
3.3.12 xrowid 方法
int (*xrowid)(sqlite3_vtab_cursor *pcur , sqlite_int64 *prowid) ;
调用该方法会通过*prowid获得虚表的光标目前所在行的rowid。
xrowid 方法对于每个虚拟表的实现是必需的
3.3.13 xupdate 方法
int (*xupdate)(
sqlite3_vtab *pVTab,
int argc ,
sqlite3_value **argv ,
sqlite_int64 *prowid
);
虚表使用xupdate 方法可用于插入、删除或更新数据。
argc 参数表示argv 数组条目的数目。如果是删除操作argc的值是1。对于insert 或替换或删除操作值n+2, 其中n为在表中的列数,包括所有隐藏的列
每个argv 项都不是一个NULL值但是可以是一个SQL意义上的NULL。在换句话说,对于表达式argv[i]!=0它始终为true,在i介于0和argc-1 但是, 它可能会sqlite3_value_type(argv[i])==SQLITE_NULL .
如果是删除,argv[0]表示要删除的rowid的值,如果不是为SQLITE_NULL
argv[1] 参数的值是被插入的新行的rowid.后续argv[]是输入值,这些值的顺序以该列的申明顺序。
如果一个插入中没有使用rowid(argc > 1, argv[1] 是一个SQL NULL), *prowid 必须为新插入的行的id ;这个值也可以通过sqlite3_last_insert_rowid( )函数获得。设置此值,在其他情况下是一个无害的操作; 如果argc==1 或argv[1] 不是一个SQL NULL,SQLite 引擎忽略该*prowid
总结来说
argc =1
argv[0]对于的id将会被删除。
argc > 1
argv[0] =NULL
插入argv[1]所对应的rowid,其中列argv[2]与后面的参数表示列的值。如果argv[1] 是一个SQL NULL, 系统自动将生成一个新的唯一的id
argc > 1
argv[0] ≠NULL
argv[0] =argv[1]
更新argv[0]对于的rowid的行。
argc > 1
argv[0] ≠NULL
argv[0] ≠argv[1]
设置argv[0] 行使用argv[1]行和新argv[2] 中的值,这种情况也是可能的,如下面的语句:
UPDATE 表SET rowid=rowid+1 WHERE ...;
如果执行成功这个函数会返回SQLITE_OK。
如果xupdate 方法违反了一些虚表的约束(包括但不限于, 正在试图存储的错误数据类型的值, 试图存储一个值, 该值太大或太小, 或尝试更改一个只读值), 就会返回相应的错误代码.
可能有一个或更多sqlite3_vtab_cursor 对象在虚拟表的打开,如果要修改的rowid在其他的表中,对于这样的情况,xupdate 方法必须返回一个错误代码.
xupdate 方法是可选的,如果sqlite3_module的xupdate 指针为空, 则表示对于的虚表是只读的。
3.3.14 xFindFunction 方法
int (*xFindFunction)(
sqlite3_vtab *pvtab ,
int narg ,
const char *zname ,
void (**pxfunc)(sqlite3_context*, int, sqlite3_value**) ,
void **pparg
);
此方法在sqlite3_prepare( )中调用,这个函数使虚表实现一个重载的机会,在没有发生重载的情况下,函数此方法可能设置为NULL ,
当一个函数使用虚表的一列作为函数的第一个参数,则调用该方法, 以查看该虚表是否想重载函数的功能。这个函数有三个参数,第一个输入表示虚拟.第二个表示函数参数的个数以及函数的名称。如果没有所需的重载,则此方法将返回0。如果重载的函数,该方法将使*pxfunc指向新的函数实现并将数据写入到*pparg,并返回1。
此函数返回有效的函数指针必须在sqlite3_vtab有效的时候也是有效的.
3.3.15 xbegin 方法
int (*xbegin)(sqlite3_vtab *pVTab);
此方法开始一个虚表上的事务,这是方法是可选的,sqlite3_module的xbegin指针可能NULL.
此方法后总会跟一个xcommit 或xrollback调用。由于虚表的事务不能嵌入, 所以不能连续调用两次.
3.3.16 xsync 方法
int (*xsync)(sqlite3_vtab *pVTab);
此方法用于启动两阶段提交。这是方法是可选的,sqlite3_module的xsync指针可能NULL.
此方法调用在调用xbegin 方法之后和在xcommit 或xrollback调用之前。为了实现两阶段提交, 保证xsync成功,如果调用方法失败,将回滚整个事务
3.3.17 xcommit 方法
int (*xcommit)(sqlite3_vtab *pVTab);
此方法实现虚表事务的提交,这是方法是可选的,sqlite3_module中xcommit指针可能NULL.
调用此方法始终在调用xbegin 和xsync之后.
3.3.18 xrollback 方法
int (*xrollback)(sqlite3_vtab *pVTab);
此方法使虚表做事务回滚。这是方法是可选的,所以sqlite3_module的变量xrollback指针可能NULL.
调用此方法始终在调用xbegin之后.
3.3.19 xrename 方法
int (*xrename)(sqlite3_vtab *pvtab , const char *znew) ;
此方法提供的通知虚表实现表的重命名, 如果成功返回SQLITE_OK如果失败返回一个错误代码.
xrename 方法对于虚表必须实现
3.3.20 xsavepoint , xrelease 和xRollbackTo 方法
int (*xsavepoint)(sqlite3_vtab *pvtab , int) ;
int (*xrelease)(sqlite3_vtab *pvtab , int) ;
int (*xRollbackTo)(sqlite3_vtab *pvtab , int) ;
这些方法提供虚拟表的实现,用于支持嵌套的事务。这个在SQLite 始终是可选的, 只会在版本377 和更高版本支持。
当调用xSavepoint(X, N) 时, 这是一个信号给虚表,表明应该保存自己的状态在第N个保存点。
xRollbackTo(X, R) 意味着虚表的需要回滚到状态R。xsavepoint() , xrelease() 、xRollbackTo() 方法只会在调用xbegin( )、xcommit( )、xrollback() 时调用。
Oct. 21, 2015, 11:12 p.m. 作者:zachary 分类:数据库 阅读(3332) 评论(0)