小巧、快速、可靠。
三者选其二。
Swarmvtab 虚拟表

1. 概述

“swarmvtab”虚拟表允许用户查询大量具有相似模式但行 ID 值范围不同的表(以下称为“组件”表),就好像它们是一个单个数据库表一样。这些表可以(通常是)位于不同的数据库中。Swarmvtab 表是只读的。

组件表不能声明为 WITHOUT ROWID,并且必须都具有相同的模式,但可以在其数据库中具有不同的名称。在此上下文中,“相同的模式”是指:

swarmvtab 表与每个组件表具有相同的模式。

swarmvtab 虚拟表如下创建:

CREATE VIRTUAL TABLE temp.<name> USING swarmvtab(<sql-statement>);

Swarmvtab 虚拟表必须在临时模式中创建。尝试在主数据库或附加数据库中创建 swarmvtab 将导致错误。

作为 CREATE VIRTUAL TABLE 语句参数提供的 SQL 语句将在表创建时执行。它必须返回四列或五列。返回的每一行都描述了一个组件表。前四列从第一列到最后一列的解释如下:

如果存在,最后一列的解释此处描述.

例如,假设 SQL 语句执行时返回以下数据:

数据库 URI表名最小行 ID最大行 ID
test.db1t10 10
test.db2t211 20
test.db3t121 30
test.db4t131 40

并且用户查询 swarmvtab 表以获取行 ID 值为 25 的行。swarmvtab 表将打开数据库文件“test.db3”并从表“t1”中读取数据以返回(因为 25 位于分配给“test.db3”中表“t1”的行 ID 范围内)。

Swarmvtab 有效地处理了对行 ID(或其他 INTEGER PRIMARY KEY)字段的范围和相等性约束。如果查询不包含此类约束,则 swarmvtab 通过依次打开每个数据库并线性扫描组件表来查找结果。这将生成正确的结果,但通常速度很慢。

SQL 语句返回的行中不能有重叠的行 ID 范围。如果有,则为错误。

swarmvtab 实现可以在任何时候打开或关闭数据库。默认情况下,它尝试将同时打开的数据库文件数量限制为九个。这不是硬性限制 - 可以构建会导致 swarmvtab 超出该限制的场景。

2. 编译和使用 Swarmvtab

swarmvtab 虚拟表的代码位于主 SQLite 源代码树的 ext/misc/unionvtab.c 文件中。可以使用类似以下命令将其编译到 SQLite 可加载扩展 中:

gcc -g -fPIC -shared unionvtab.c -o unionvtab.so

或者,可以将 unionvtab.c 文件编译到应用程序中。在这种情况下,应调用以下函数以将扩展注册到每个新的数据库连接中

int sqlite3_unionvtab_init(sqlite3 *db, void*, void*);

传递的第一个参数应该是要注册扩展的数据库句柄。第二个和第三个参数都应传递 0。

源文件和入口点被命名为“unionvtab”而不是“swarmvtab”。Unionvtab 是一个单独记录的虚拟表,与 swarmvtab 捆绑在一起。

3. 高级用法

大多数 swarmvtab 用户只会使用上面描述的功能。本节描述专为更深奥的用例而设计的功能。所有这些功能都涉及在 CREATE VIRTUAL TABLE 命令中作为 SQL 语句的一部分指定额外的可选参数。可选参数使用其名称、后跟“=”字符、后跟可选的引号值来指定。空格可以分隔名称、“=”字符和值。例如

CREATE VIRTUAL TABLE temp.sv USING swarmvtab (
  'SELECT ...',                -- the SELECT statement
  maxopen = 20,                -- An optional parameter
  missing='missing_udf'        -- Another optional parameter
);

以下各节描述了支持的参数。指定无法识别的参数名称将导致错误。

3.1. SQL 参数

如果参数名称以“:”开头,则假定它是要在执行之前绑定到 SQL 语句的值。该值始终绑定为文本。如果指定的 SQL 参数不存在,则为错误。例如

CREATE VIRTUAL TABLE temp.x1 USING swarmvtab (
  "SELECT :dir || local_filename, tbl, min, max FROM components",
  :dir = '/home/user/app/databases/'
);

当执行上述 CREATE VIRTUAL TABLE 语句时,swarmvtab 将文本值“/home/user/app/databases/”绑定到 SQL 语句的 :dir 参数,然后再执行它。

单个 CREATE VIRTUAL TABLE 语句可以包含任意数量的 SQL 参数。

3.2. “maxopen” 参数

默认情况下,swarmvtab 尝试将同时打开的数据库数量限制为九个。此参数允许更改该限制。例如,要创建一个 swarmvtab 表,该表可以同时容纳多达 30 个打开的数据库

CREATE VIRTUAL TABLE temp.x1 USING swarmvtab (
  "SELECT ...",
  maxopen=30
);

在某些情况下,增加打开的数据库数量可能会提高性能。

3.3. “openclose” 回调

“openclose” 参数允许用户指定应用程序定义的 SQL 函数的名称,该函数将在 swarmvtab 打开数据库之前调用,并在 swarmvtab 关闭数据库后调用。传递给 open close 函数的第一个参数是标识要打开或刚刚关闭的数据库的文件名或 URI(与 CREATE VIRTUAL TABLE 命令提供的 SQL 语句最左侧列中返回的值相同)。第二个参数是在打开数据库之前调用函数时为整数 0,在关闭数据库后调用函数时为 1。例如,如果

CREATE VIRTUAL TABLE temp.x1 USING swarmvtab (
  "SELECT ...",
  openclose = 'openclose_udf'
);

则在打开包含组件表的每个数据库之前,swarmvtab 实际上会执行

SELECT openclose_udf(<database-name>, 0);

数据库关闭后,swarmvtab 将运行等效于

SELECT openclose_udf(<database-name>, 1);

openclose 函数返回的任何值都将被忽略。如果在打开数据库之前进行的调用返回错误,则不会打开数据库文件,并且错误将返回给用户。这是 swarmvtab 在不最终发出相应的“close”调用的情况下发出“open”调用的唯一情况。如果仍然有数据库处于打开状态,则“close”调用可能会从应用程序数据库的最终 sqlite3_close() 调用中发出,该调用删除了包含 swarmvtab 表的临时模式。

“close”调用返回的错误始终被忽略。

3.4. “missing” 回调

“missing” 参数允许用户指定应用程序定义的 SQL 函数的名称,该函数将在 swarmvtab 打开数据库之前调用,如果它发现所需数据库文件不存在于磁盘上。这为应用程序提供了一个在 swarmvtab 尝试打开它之前从远程源检索所需数据库的机会。传递给“missing”函数的唯一参数是标识要打开的数据库的名称或 URI。假设

CREATE VIRTUAL TABLE temp.x1 USING swarmvtab (
  "SELECT ...",
  openclose = 'openclose_udf',
  missing='missing_udf'
);

则 missing 函数将如下调用

SELECT missing_udf(<database-name>);

如果 missing 函数返回错误,则不会打开数据库,并且错误将返回给用户。如果配置了 openclose 函数,则此时将发出“close”调用以匹配早期的“open”。以下伪代码说明了当打开组件数据库时,具有配置的 missing 和 openclose 函数的 swarmvtab 实例使用的过程。

SELECT openclose_udf(<database-name>, 0);
if( error ) return error;
if( db does not exist ){
  SELECT missing_udf(<database-name>);
  if( error ){
    SELECT openclose_udf(<database-name>, 1);
    return error;
  }
}
sqlite3_open_v2(<database-name>);
if( error ){
  SELECT openclose_udf(<database-name>, 1);
  return error;
}
// db successfully opened!

3.5. 组件表“context”值

如果作为 CREATE VIRTUAL TABLE 命令的一部分指定的 SELECT 语句返回五列,则最后一列仅用于应用程序上下文。Swarmvtab 根本不使用此值,除了在指定时将其传递给 openclose 和 missing 函数的 <database-name> 之后。换句话说,不是按照上述方式调用函数,如果存在“context”列,则 swarmvtab 相反会调用

SELECT missing_udf(<database-name>, <context>);
SELECT openclose_udf(<database-name>, <context>, 0);
SELECT openclose_udf(<database-name>, <context>, 1);

如需。

此页面最后修改于2022-01-08 05:02:57 UTC