SQLite运行时可加载扩展(三十五)

返回:SQLite—系列文章目录   

上一篇:SQLite轻量级会话扩展(三十四)

下一篇:SQLite的DBSTAT 虚拟表(三十六)

1. 概述

SQLite 能够在运行时加载扩展(包括新的应用程序定义的 SQL 函数、整理序列、虚拟表和 VFS)。 此功能允许开发扩展代码和 与应用程序分开测试,然后加载 根据需要。

扩展也可以与应用程序静态链接。 下面显示的代码模板将像静态一样工作 链接扩展,因为它作为运行时可加载扩展,除了 您应该提供入口点函数 (“sqlite3_extension_init”) 如果应用程序包含以下内容,则使用其他名称以避免名称冲突 两个或多个扩展。

2. 加载扩展

SQLite 扩展是共享库或 DLL。要加载它,您需要 需要向 SQLite 提供包含 共享库或 DLL 以及用于初始化扩展的入口点。 在 C 代码中,此信息是使用 sqlite3_load_extension() API 提供的。请参阅有关此内容的文档 例程以获取更多信息。

请注意,不同的操作系统使用不同的文件名 其共享库的后缀。Windows 使用“.dll”,Mac 使用 “.dylib”,除 Mac 外的大多数 Unix 都使用“.so”。如果你想 使你的代码可移植,你可以从共享中省略后缀 将自动添加库文件名和相应的后缀 通过 sqlite3_load_extension() 接口。

还有一个可用于加载扩展的 SQL 函数:load_extension(X,Y)。它的工作方式与 sqlite3_load_extension() C 接口类似。

加载扩展的两种方法都允许您指定 扩展的入口点的名称。 您可以将此参数留空 - 传入 sqlite3_load_extension() C 语言接口的 NULL 指针 或省略 load_extension() SQL 接口的第二个参数 - 扩展加载器逻辑将尝试找出入口点 靠它自己。它将首先尝试通用扩展名 “sqlite3_extension_init”。如果这不起作用,它会构造一个 使用模板“sqlite3_X_init”的入口点,其中 X 被替换 与文件名中每个 ASCII 字符的小写等效值 在最后一个“/”之后和第一个“.”之前省略 前三个字符(如果它们恰好是“lib”)。因此,例如, 如果文件名为“/usr/lib/libmathfunc-4.8.so”,则为入口点名称 将是“sqlite3_mathfunc_init”。或者,如果文件名是 “./SpellFixExt.dll”,则将调用入口点 “sqlite3_spellfixext_init”。

出于安全原因,扩展加载默认处于关闭状态。 为了使用 C 语言或 SQL 扩展加载函数, 必须首先使用

​ sqlite3_db_config(db,SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION,1,NULL)

启用扩展加载 应用程序中的 C 语言 API。

在命令行 shell 中,可以使用 “.load” 点命令。例如:

.load ./YourCode

请注意,命令行 shell 程序已启用 扩展加载(通过调用 sqlite3_enable_load_extension() 接口作为其设置的一部分),因此上面的命令无需 任何特殊开关、设置或其他复杂情况。

带有一个参数的“.load”命令调用 sqlite3_load_extension() 将 zProc 参数设置为 NULL,导致 SQLite 首先查找 名为“sqlite3_extension_init”,然后名为“sqlite3_X_init”的入口点 其中“X”派生自文件名。如果扩展有条目 点与不同的名称,只需提供该名称作为第二个 论点。例如:

.load ./YourCode nonstandard_entry_point

3. 编译可加载扩展

可加载的扩展是 C 代码。要编译它们,请执行以下操作 最像 UNIX 的操作 系统,通常的命令是这样的:

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

Mac 是类似 unix 的,但它们不遵循通常的共享库 约定。要在 Mac 上编译共享库,请使用类似 这:

gcc -g -fPIC -dynamiclib YourCode.c -o YourCode.dylib

如果在尝试加载库时收到错误消息 这说“Mach-O,但架构错误”,那么您可能需要添加 命令行选项“-arch i386”或“arch x86_64”到 gcc,具体取决于 关于如何构建应用程序。

若要使用 MSVC 在 Windows 上编译,请使用类似于以下内容的命令 通常可以:

cl YourCode.c -link -dll -out:YourCode.dll

要使用 MinGW 为 Windows 编译,命令行就像它一样 适用于 UNIX,但输出文件后缀更改为“.dll”,并且 省略了 -fPIC 参数:

gcc -g -shared YourCode.c -o YourCode.dll

4. 对可加载扩展进行编程

模板可加载扩展包含以下三个元素:

  1. 使用源顶部的“#include < sqlite3ext.h>” 代码文件,而不是“#include < sqlite3.h>”。

  2. 将宏“SQLITE_EXTENSION_INIT1”单独放在一行上 紧接在“#include < sqlite3ext.h>”行之后。

  3. 添加一个扩展加载入口点例程,如下所示 内容如下:

    #ifdef _WIN32
    __declspec(dllexport)
    #endif
    int sqlite3_extension_init( /* <== Change this name, maybe */sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi
    ){int rc = SQLITE_OK;SQLITE_EXTENSION_INIT2(pApi);/* insert code to initialize your extension here */return rc;
    }

    您可以很好地将入口点的名称自定义为 对应于您将要生成的共享库的名称, 而不是使用通用的“sqlite3_extension_init”名称。给 您的扩展自定义入口点名称将使您能够静态地 在没有链接器的情况下将两个或多个扩展链接到同一程序中 冲突(如果您以后决定使用静态链接而不是运行时) 连接。 如果您的共享库最终被命名为“YourCode.so”或 编译器示例中显示的“YourCode.dll”或“YourCode.dylib” ,那么正确的入口点名称将是 “sqlite3_yourcode_init”。

这是一个完整的模板扩展,您可以复制/粘贴 要开始使用,请执行以下操作:

/* Add your header comment here */
#include <sqlite3ext.h> /* Do not use <sqlite3.h>! */
SQLITE_EXTENSION_INIT1/* Insert your extension code here */#ifdef _WIN32
__declspec(dllexport)
#endif
/* TODO: Change the entry point name so that "extension" is replaced by
** text derived from the shared library filename as follows:  Copy every
** ASCII alphabetic character from the filename after the last "/" through
** the next following ".", converting each character to lowercase, and
** discarding the first three characters if they are "lib".
*/
int sqlite3_extension_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi
){int rc = SQLITE_OK;SQLITE_EXTENSION_INIT2(pApi);/* Insert here calls to**     sqlite3_create_function_v2(),**     sqlite3_create_collation_v2(),**     sqlite3_create_module_v2(), and/or**     sqlite3_vfs_register()** to register the new features that your extension adds.*/return rc;
}

4.1. 示例扩展

完整且可加载扩展的许多示例可以是 在 ext/misc 子目录的 SQLite 源代码树中看到。 该目录中的每个文件都是一个单独的扩展名。文档 由文件上的标题注释提供。 以下是对 ext/misc 子目录:

  • 卡雷.c — carray 表值函数的实现。

  • 压缩.c — 实现应用程序定义的 SQL 函数 compress()和 uncompress()对文本或 blob 内容进行 zLib 压缩。

  • json1.c — JSON SQL 函数和表值函数的实现。 这是一个更大、更复杂的扩展。

  • memvfs.c — 实现将所有内容存储在内存中的新 VFS。

  • rot13.c — rot13() SQL 函数的实现。这是一个非常简单的扩展函数示例 并可用作创建新扩展的模板。

  • 系列.c — 实现generate_series虚拟表和表值函数。这是一个相对简单的示例 虚拟表实现,可以作为编写模板 新的虚拟表。

其他更复杂的扩展可以在子文件夹中找到 在 ext/ 下,除 ext/misc/ 外。

5. 持久可加载扩展

可加载扩展的默认行为是卸载它 当最初调用 sqlite3_load_extension() 的数据库连接关闭时,从进程内存中。(换言之,xDlClose 方法 的 sqlite3_vfs 对象在数据库时为所有扩展调用 连接关闭。但是,如果初始化过程返回 SQLITE_OK_LOAD_PERMANENTLY 而不是 SQLITE_OK,则扩展将 未卸载(不会调用 xDlClose),并且扩展将保留 无限期地在进程内存中。SQLITE_OK_LOAD_PERMANENTLY回归 value 对于想要注册新 VFS 的扩展非常有用。

澄清一下:初始化函数返回的扩展 SQLITE_OK_LOAD_PERMANENTLY在数据库之后继续存在于内存中 连接关闭。但是,扩展不会自动进行 注册到后续数据库连接。这使它成为可能 加载实现新 VFS 的扩展。 持久加载和注册实现新 SQL 的扩展 函数、整理序列和/或虚拟表,使得那些 添加的功能可用于所有后续数据库连接, 然后,初始化例程还应该在将注册这些服务的子函数上调用 sqlite3_auto_extension()。

vfsstat.c 扩展 显示一个可加载扩展的示例,该扩展永久注册两者 新的 VFS 和新的虚拟表。该扩展中的 sqlite3_vfsstat_init() 初始化例程仅调用一次,当 首先加载扩展。它注册了新的“vfslog”VFS 一次,它返回SQLITE_OK_LOAD_PERMANENTLY,以便使用的代码 要实现“vfslog”,VFS 将保留在内存中。初始化例程 还在指向“vstatRegister()”的指针上调用 sqlite3_auto_extension(函数,以便所有后续数据库连接都将调用 “vstatRegister()”函数,因此注册 “vfsstat”虚拟表。

6. 静态链接运行时可加载扩展

完全相同的源代码可用于运行时可加载 共享库或 DLL,并作为与 应用。这提供了灵活性,并允许你重复使用相同的内容 以不同的方式编写代码。

要静态链接扩展,只需添加 -DSQLITE_CORE 编译时选项。SQLITE_CORE宏会导致SQLITE_EXTENSION_INIT1 并将宏SQLITE_EXTENSION_INIT2为无操作。然后修改你的 应用程序直接调用入口点,传入 NULL 指针 作为第三个“pApi”参数。

使用入口点名称尤为重要 基于扩展名文件名,而不是通用 “sqlite3_extension_init”入口点名称,如果将静态 链接两个或多个扩展。如果使用通用名称,则有 将是同一符号的多个定义,并且链接将失败。

如果要在应用程序中打开多个数据库连接, 而不是调用每个数据库的扩展入口点 连接 另外,您可能需要考虑使用 sqlite3_auto_extension() 接口来注册您的扩展和 使它们在每个数据库连接时自动启动 已打开。您只需注册每个扩展一次,就可以 在 main() 例程的开头附近执行此操作。使用 sqlite3_auto_extension() 接口注册扩展使 您的扩展就像它们内置在核心 SQLite 中一样 - 它们 每当打开新的数据库连接时,自动存在 无需初始化。只要确保完成任何 您需要先使用 sqlite3_config() 完成的配置 注册扩展,因为 sqlite3_auto_extension() 接口隐式调用 sqlite3_initialize()。

7. 实施细节

SQLite 使用 sqlite3_vfs 对象的 xDlOpen()、xDlError()、xDlSym()和 xDlClose()方法。这些方法是使用 unix 上的 dlopen()库(这解释了为什么 SQLite 通常 需要链接到 Unix 系统上的“-ldl”库) 并在 Windows 上使用 LoadLibrary()API。在自定义 VFS 中 不寻常的系统,这些方法都可以省略,在这种情况下 运行时扩展加载机制将不起作用(尽管 您仍然可以静态链接扩展代码,假设 入口指针是唯一命名的)。 SQLite可以用SQLITE_OMIT_LOAD_EXTENSION进行编译,以省略扩展加载代码 从构建。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/652655.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vue项目中引入高德地图步骤详解,附示例代码

vue中如何使用高德地图&#xff0c;下面为您详解。 步骤一&#xff1a;安装高德地图的JavaScript API 在Vue项目的根目录下打开终端&#xff0c;执行以下命令安装高德地图的JavaScript API&#xff1a; npm install amap/amap-jsapi-loader --save 步骤二&#xff1a;创建地…

安居水站:自来水:日常中的安全与奥秘

在我们的日常生活中&#xff0c;自来水如同空气一样&#xff0c;是生活中不可或缺的一部分。每当我们拧开水龙头&#xff0c;清澈的水流便汩汩而出&#xff0c;滋养着我们的生活和健康。然而&#xff0c;这看似普通的自来水背后&#xff0c;却隐藏着许多我们可能并不了解的知识…

PCIe协议Ack/NAK详解

✨前言&#xff1a; 在PCIe通信协议中&#xff0c;ACK&#xff08;Acknowledgement&#xff09;和NAK&#xff08;Negative Acknowledgement&#xff09;是两种重要的信号&#xff0c;它们用于控制和确保数据传输的可靠性。 ACK&#xff08;Acknowledgement&#xff09; ACK信…

mac资源库的东西可以删除吗?提升Mac运行速度秘籍 Mac实用软件

很多小伙伴在使用mac电脑处理工作的时候&#xff0c;就会很疑惑&#xff0c;电脑的运行速度怎么越来越慢&#xff0c;就想着通过删除mac资源库的东西&#xff0c;那么mac资源库的东西可以删除吗&#xff1f;删除了会不会造成电脑故障呢&#xff1f; 首先&#xff0c;mac资源库…

快速排序详解及优化方式

目录 1.快速排序的核心思想 2.快速排序的两个重要方法 Hoare法 quickHoare函数&#xff08;想办法把基准放到数组正确排序好的位置&#xff09; 代码&#xff1a; 挖坑法 逻辑&#xff1a; 翻译成代码&#xff1a; 3.快速排序的时间/空间复杂度分析 最好情况 最坏情…

江湖工具箱一款功能强大的短视频提取与数据分析多功能百宝箱(PC免安装)

江湖工具箱 今天要给大家推荐一款Windows平台超级实用的短视频提取、数据分析工具&#xff0c;让你在短视频江湖畅通无阻——江湖工具箱&#xff01; 江湖工具箱是一款免费的短视频多多多功能百宝箱&#xff0c;支持市面上绝大多数短视频平台(D音、K手、X瓜、T条&#xff0c;T…

CentOS yum make cache/clean all 提示yum lock

错误信息 Another app is currently holding the yum lock; waiting for it to exit 问题描述&#xff1a; 已加载插件&#xff1a;fastestmirror Repository base is listed more than once in the configuration Repository updates is listed more than once in the config…

Centos8操作系统安装mysql5.7版本以及报错解决

目录 一、卸载MySql 1.首先查看已安装的mysql 2.逐个或者执行一下命令统一卸载掉 注意&#xff1a; 3. 卸载其他相关文件 二、安装MySql 1.安装mysql的rpm源 2.安装MySql 如果遇到以下错误&#xff1a; 问题一: 解决方法&#xff1a; 问题二、 解决方法&#xff1…

机器学习 | 准确率、召回率、精准率、特异度傻傻分不清?ROC曲线怎么看?一篇文章帮你搞定

一、真正类、假负类、假正类与真负类 二、准确率、召回率、精准率、特异度与假正率 1. 准确率 (Accuracy) 准确率表明成功预测&#xff08;预测为负或为正&#xff09;的结果占总样本的百分比。 准确率 &#xff0c; 2. 召回率/查全率/灵敏度/真正率&#xff08;Recall&a…

DML触发器的创建

目录 触发器的创建 DML触发器的创建 语句级 DML 触发器的创建 创建触发器&#xff0c;当对emp数据表进行添加记录、更新记录和删除记录的时候&#xff0c;判断是否是工作时间段&#xff0c;如果不是工作时间段&#xff0c;不允许执行 在数据表 dept 上创建触发器&#xff…

Packet Tracer - 交换机安全配置解析

第一步先连线SW1连到SW2接口连接G0/2到G0/2 指令配置 SW-1 SW-1>enable SW-1#conf t Enter configuration commands, one per line. End with CNTL/Z. SW-1(config)#interface range G0/1-2 SW-1(config-if-range)#switchport mode SW-1(config-if-range)#switchport no…

tcp服务器端与多个客户端连接

如果希望Tcp服务器端可以与多个客户端连接&#xff0c;可以这样写&#xff1a; tcpServernew QTcpServer(this);connect(tcpServer,SIGNAL(newConnection()),this,SLOT(onNewConnection())); void MainWindow::onNewConnection() {QTcpSocket *tcpSocket;//TCP通讯的Sockettcp…