虚拟表和表值函数

另请参阅:JS中的C结构体

虚拟表 是sqlite最强大的功能之一,它为客户端提供了一种通过SQL访问几乎任意数据的方式。但是,强大的功能也伴随着非凡的复杂性

虚拟表(又名vtab)API是库的一个高级特性,关于它有大量的文档,并且有示例程序演示它这些文档没有尝试教用户如何编写自己的虚拟表,而是仅关注JS中这样做的特定组件。

JS虚拟表API与C API几乎是一一对应的,唯一的区别是增加了一些辅助例程来访问和操作API使用的C端状态。此处描述的API对于在JS中定义虚拟表不是必需的,但仅是为了简化流程而提供。如果客户端愿意,可以使用仅C风格的API来实现虚拟表。

管理指向结构体的指针的生命周期

sqlite3_module接口对sqlite3_vtabsqlite3_vtab_cursor对象有明确的生命周期规则,其工作方式如下

JS代码无法对原始指针做太多操作,需要包装对象才能访问和操作它们,如C结构体文档中所述。类似地,JS端实例不能像C代码那样“扩展”这些类型,但它们可以将任何实现特定的状态附加到JS实例(因此,实际上,比它们的C对应物更容易自定义其状态)。

sqlite3.vtab对象提供API来简化JS中这些对象的生命周期管理和指针映射。这些API对sqlite3_vtabsqlite3_vtab_cursor的工作方式相同,但在sqlite3_module接口的不同位置使用。

API对象分别命名为vtab.xVtabvtab.xCursor,用于sqlite3_vtabsqlite3_vtab_cursor类型,它们的方法将在下面描述。

主要的sqlite3 JS单元测试有一些示例虚拟表,演示了这些API的使用。

create()

传递来自适当sqlite3_module方法(见下文)的输出指针参数,这将创建一个新的结构体实例,将它的pointer值写入给定的输出指针,并返回该对象。如果结构体实例的分配失败,则会抛出异常。

用法

get()

传递来自适当sqlite3_module方法(见下文)的结构体指针,这将返回为该指针创建并由create()返回的相同结构体实例包装器。

用法

要记住的规则:永远不要对该函数返回的实例调用dispose()。延迟到调用...之前。

unget()dispose()

unget()get()相同,但它还会断开给定指针与返回的结构体对象之间的映射,以便将来使用相同指针调用此函数或get()将返回undefined值。调用者有责任在封闭函数返回之前对返回的对象调用theStruct.dispose()

dispose()的工作方式与unget()类似,但它会调用theStruct.dispose()而不是返回对象。调用unget()会强制调用者在完成对返回的对象的操作后调用dispose()

用法

sqlite3_module方法

sqlite3_module类继承自核心C结构体类型并扩展了层次结构...

setupModule()

sqlite3_module setupModule(options)

设置此模块对象。

一个帮助程序,用于初始化和设置sqlite3_module()对象,以便稍后使用sqlite3_create_module()安装到各个数据库中。需要一个具有以下属性的对象

某些方法可能引用相同的实现。为了简化此类方法的定义

这是为了便于在传递的对象中内联创建这些方法,而无需客户端显式获取其中一个的引用以将其分配给另一个。

已安装的catchExceptions处理程序将考虑对上述函数的相同引用,并为两者安装相同的包装器函数,以便底层库看到这两个函数的相同指针值。

期望给定的方法返回整数类型,如C API所期望的那样。如果catchExceptions为真,则包装函数的返回值将按原样使用,如果函数返回假值(例如,如果没有显式返回),则将其转换为0。如果catchExceptions激活,则方法实现必须显式返回整数类型。否则会导致失败,特别是在错误情况下,因为这些错误将不会被报告。

在发生错误时抛出异常。成功时,返回一个sqlite3_module对象:thisopt.struct或一个新的sqlite3_module实例,具体取决于它的调用方式。

sqlite3_index_info

sqlite3_index_info对象用于在sqlite3_module::xBestIndex()实现和sqlite3引擎之间传递信息。JS代码不管理这些对象的生命周期,并且不得将指针保留在这些对象上,时间长于接收指针作为参数的函数调用。JS代码需要使用capi.sqlite3_index_info包装器对象来与C级结构体状态进行交互。

示例

const xBestIndex = function(pVtab, pIdxInfo){
  const vtab = sqlite3.vtab.xVtab.get(pVtab); // documented above
  const sii = new sqlite3.capi.sqlite3_index_info(pIdxInfo);
  ...
  sii.dispose(); // see notes below
  return 0;
};

C结构体包装器使用指针参数构造时,如上所示,它们不会分配新的实例,而是提供对现有实例的访问。在这种情况下,调用它们的dispose()方法并非严格必要,但通常养成一个好习惯,以避免在确实需要的情况下出现内存泄漏。

除了所有JS绑定C结构体都可以使用的与结构体相关的API之外,sqlite3_index_info还在其原型中安装了以下辅助方法,所有实例都可以使用这些方法

这些都已在主要的单元测试脚本中进行了演示。