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.rhkb.cn/news/314709.html

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

相关文章

【深度学习】烟雾和火焰数据集,野外数据集,超大量数据集,目标检测,YOLOv5

标注了2w张数据集&#xff0c;是目标检测yolo格式的&#xff0c;有火焰、烟雾两个目标&#xff0c;下图是训练时候的样子&#xff1a; 训练方法看这里&#xff1a; https://qq742971636.blog.csdn.net/article/details/138097481 数据集介绍 都是博主辛苦整理和标注的&…

C++必修:类与对象(一)

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;C学习 贝蒂的主页&#xff1a;Betty’s blog 1. 面向过程与面向对象 1.1. 面向过程 我们之前学习的C语言就是一种面向过程的语…

SVN小乌龟汉化问题

1.首先确认中文语言包和SVN版本需要一致&#xff08;点击右键 选择最后一个选项即可查看&#xff09; 官网链接 点击这个官网链接可以下载对应版本的中文包 2.下载好之后直接无脑下一步安装即可 3.如果还是没有中文&#xff0c;找到这个文件夹&#xff0c;把里面的内容全部删…

【css】select实现placeholder效果

场景&#xff1a;使用select下拉选择框的时候&#xff0c;需要像其他控件一样提示默认信息。 问题&#xff1a;表单控件select没有placeholder属性。 解决方案&#xff1a;通过css实现&#xff0c;不需要js <style>select > option[disabled]{ color:#999;cursor: n…

VUE3 ref,props,生命周期

1.--ref属性 1.1代码 1.1.1子表 <template><div class"person"><h1>中国</h1><h2 ref"title2">北京</h2><h3>尚硅谷</h3><button click"showLog">点我输出h2这个元素</button>&l…

【软测学习笔记】Day01

&#x1f31f;博主主页&#xff1a;我是一只海绵派大星 &#x1f4da;专栏分类&#xff1a;前端 &#x1f4da;参考教程&#xff1a;黑马教程❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 目录 一、测试介绍 1、什么是软件测试&#xff1f; 2、测试主流技能 二、测试常用分…

unity cinemachine相机 (案例 跟随角色移动)

安装相机包 打开包管理工具 在 unity registry 搜索cinemachine 会在maincamera中生成一个组件cinemachineBrain 只能通过虚拟相机操控 主相机 虚拟相机的参数 案例 1.固定相机效果 位置 在固定的地方 默认的模式 2.相机跟随人物效果 焦距设置 20 跟随设置 把playere…

Django框架之python后端框架介绍

一、网络框架及MVC、MTV模型 1、网络框架 网络框架&#xff08;Web framework&#xff09;是一种软件框架&#xff0c;用于帮助开发人员构建Web应用程序和Web服务。它提供了一系列预先编写好的代码和工具&#xff0c;以简化开发过程并提高开发效率。网络框架通常包括以下功能…

Web前端框架/库/工具

前言 俗话说&#xff1a;前端从步枪&#xff08;原生js&#xff09;到了半自动武器&#xff08;jQuery&#xff09;并进化为全自动武器&#xff08;三大框架&#xff08;angular&#xff0c;react&#xff0c;vue及其生态链&#xff09;&#xff09;。 常说工欲善其事必先利其…

python作业 切片逆转

题目&#xff1a; &#xff08;反转显示一个整数&#xff09;编写下面的函数&#xff0c;反向显示一个整数。 列如&#xff1a;reserse(3456)。编写一个测试程序&#xff0c;提示用户输入一个整数&#xff0c;然后显示它的反向数。 第一步定义一个函数&#xff1a; def rev…

AUTOSAR-SD篇

1 概述 服务发现模块的主要任务是管理在车内通信中被称为服务的功能实体的可用性&#xff0c;以及控制事件消息的发送行为。只允许向需要这些事件消息的接收器发送事件消息&#xff08;发布/订阅&#xff09;。 这里描述的解决方案也被称为SOME/IP-SD&#xff08;基于IP -服务发…

前端css中keyframes(关键帧)的简单使用

前端css中keyframes的使用 一、前言二、例子&#xff08;一&#xff09;、例子源码1&#xff08;二&#xff09;、源码1运行效果1.视频效果2.截图效果 三、结语四、定位日期 一、前言 关键帧keyframes是css动画的一种&#xff0c;主要用于定义动画过程中某一阶段的样式变化&am…

【STM32+HAL】读取电池电量

一、准备工作 有关CUBEMX的初始化配置&#xff0c;参见我的另一篇blog&#xff1a;【STM32HAL】CUBEMX初始化配置 有关定时器触发ADC模式配置&#xff0c;详见【STM32HAL】ADC采集波形实现 有关软件触发ADC模式配置&#xff0c;详见【STM32HAL】三轴按键PS2摇杆 二、所用工具…

Bytebase 2.16.0 - 支持 Oracle 和 SQL Server DML 变更的事前备份

&#x1f680; 新功能 支持 Oracle 和 SQL Server DML 变更的事前备份。 支持在 SQL 编辑器中显示存储过程和函数。 支持兼容 TDSQL 的 MySQL 和 PostgreSQL 版本。 支持把数据库密码存储在 AWS Secrets Manager 和 GCP Secret Manager。 支持通过 IAM 连接到 Google Clou…

VirtualBox7.0.16的蓝屏大坑与ssh登陆ubuntu虚拟机的办法

背景&#xff1a; 安装了最新版的VirtualBox&#xff0c;装了ubuntu系统&#xff0c;在win10下通过ssh死活无法与ubuntu进行正常登陆控制。 然后开始了踩坑。 问题1&#xff1a;ssh登陆失败&#xff0c;但是主机能ping通ubuntu&#xff0c;反过来也能ping通&#xff0c;网络…

线性代数基础1向量

1、向量是什么 1.1、向量的定义 在数学中&#xff0c;向量&#xff08;也称为欧几里得向量、几何向量、矢量&#xff09;&#xff0c;指具有大小和方向的量。它可以形象化地表示为带箭头的线段。箭头所指&#xff1a;代表向量的方向&#xff1b;线段长度&#xff1a;代表向量的…

增加PyQt5界面的交通流量预测(模型为CNN_GRU,CNN_BiGRU_ATTENTION,LSTM,Python代码)

1.效果视频&#xff1a;增加PyQt5界面的交通流量预测&#xff08;模型为CNN_GRU&#xff0c;CNN_BiGRU_ATTENTION&#xff0c;LSTM&#xff09;_哔哩哔哩_bilibili&#xff09; 2.三个模型和数据集的介绍 交通流量预测(python代码&#xff0c;压缩包中带有数据&#xff0c;CN…

NAT的知识点和实现

1.NAT的作用&#xff1a; &#xff08;1&#xff09;、把内网私网IP转换公网IP&#xff1b; &#xff08;2&#xff09;、隐藏内网&#xff0c;起到保护内网作用&#xff1b; &#xff08;3&#xff09;、适当的缓解的IPv4地址空间枯竭&#xff1b; &#xff08;4&#xff…

自己搭建的大疆无人机RTMP流媒体服务延迟太大

流程&#xff1a;无人机摄像头->图传->遥控器->流媒体服务器->取流播放&#xff0c;延迟有10秒来的&#xff0c;大家有没有什么好的方案。

【6】mysql查询性能优化-关联子查询

【README】 0. 先说结论&#xff1a;一般用inner join来改写in和exist&#xff0c;用left join来改写not in&#xff0c;not exist&#xff1b;&#xff08;本文会比较内连接&#xff0c;包含in子句的子查询&#xff0c;exist的性能 &#xff09; 1. 本文总结自高性能mysql 6…