“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.db1 | t1 | 0 | 10 |
test.db2 | t2 | 11 | 20 |
test.db3 | t1 | 21 | 30 |
test.db4 | t1 | 31 | 40 |
并且用户查询 swarmvtab 表以获取行 ID 值为 25 的行。swarmvtab 表将打开数据库文件“test.db3”并从表“t1”中读取数据以返回(因为 25 位于分配给“test.db3”中表“t1”的行 ID 范围内)。
Swarmvtab 有效地处理了对行 ID(或其他 INTEGER PRIMARY KEY)字段的范围和相等性约束。如果查询不包含此类约束,则 swarmvtab 通过依次打开每个数据库并线性扫描组件表来查找结果。这将生成正确的结果,但通常速度很慢。
SQL 语句返回的行中不能有重叠的行 ID 范围。如果有,则为错误。
swarmvtab 实现可以在任何时候打开或关闭数据库。默认情况下,它尝试将同时打开的数据库文件数量限制为九个。这不是硬性限制 - 可以构建会导致 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 捆绑在一起。
大多数 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 );
以下各节描述了支持的参数。指定无法识别的参数名称将导致错误。
如果参数名称以“:”开头,则假定它是要在执行之前绑定到 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 参数。
默认情况下,swarmvtab 尝试将同时打开的数据库数量限制为九个。此参数允许更改该限制。例如,要创建一个 swarmvtab 表,该表可以同时容纳多达 30 个打开的数据库
CREATE VIRTUAL TABLE temp.x1 USING swarmvtab ( "SELECT ...", maxopen=30 );
在某些情况下,增加打开的数据库数量可能会提高性能。
“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”调用返回的错误始终被忽略。
“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!
如果作为 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