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

返回:SQLite—系列文章目录   

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

下一篇:SQLite—系列文章目录   

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进行编译,以省略扩展加载代码 从构建。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

TBWeb开发版V3.2.6免授权无后门Chatgpt系统源码下载及详细安装教程

TBWeb系统是基于 NineAI 二开的可商业化 TB Web 应用&#xff08;免授权&#xff0c;无后门&#xff0c;非盗版&#xff0c;已整合前后端&#xff0c;支持快速部署&#xff09;。相比稳定版&#xff0c;开发版进度更快一些。前端改进&#xff1a;对话页UI重构&#xff0c;参考C…

Go源码--Strings库

1. 简介 strings库 存储了 一些针对 字符串的具体操作 其 代码短小精悍 可以学习到很多编程的思路 尤其是 涉及到字符串使用性能的方面&#xff0c;其源码库有好多的优秀案例可以学习。向强者对齐不一定成为强者&#xff0c;但向弱者对齐一定变为弱者。 介绍思路是先介绍 stri…

9.列表渲染

列表渲染 我们可以使用 v-for 指令基于一个数组来渲染一个列表。v-for 指令的值需要使用 item in items 形式的特殊语法&#xff0c;其中 items 是源数据的数组&#xff0c;而 item 是迭代项的别名 <template><div><p v-for"item in names">{{ it…

基于 RT-Thread 的 PPP Device 软件包的详细使用以及AT通用配网过程

一、AT通用上网过程 网络初始化流程 一般情况如下 1、先上电复位模块&#xff1b; 2、间隔一直发送 AT\r 等待模组响应,表示模组启动&#xff0c;并且调试好了波特率&#xff1b; 3、发送ATCPIN?\r 测试卡是否插好&#xff1b; 4、发送 ATCSQ\r 查询信号质量&#xff0c;只有…

【QT进阶】Qt http编程之后端API测试工具postman使用介绍

往期回顾 【QT进阶】Qt Web混合编程之使用ECharts显示各类折线图等-CSDN博客 【QT进阶】Qt Web混合编程之实现ECharts数据交互动态修改-CSDN博客 【QT进阶】Qt http编程之http与https简单介绍-CSDN博客 【QT进阶】Qt http编程之后端API测试工具postman使用介绍 其实这个工具的…

【简单介绍下Faiss原理和使用】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

Docker - 入门基础

原文地址&#xff0c;使用效果更佳&#xff01; Docker - 入门基础 | CoderMast编程桅杆https://www.codermast.com/dev-tools/docker/docker-basic.html Docker架构 Docker 使用的是客户端-服务端&#xff08;C/S&#xff09;架构模式&#xff0c;使用远程 API 来管理和创建…

【Leetcode每日一题】 穷举vs暴搜vs深搜vs回溯vs剪枝_全排列 - 全排列(难度⭐⭐)(62)

1. 题目解析 题目链接&#xff1a;46. 全排列 这个问题的理解其实相当简单&#xff0c;只需看一下示例&#xff0c;基本就能明白其含义了。 2.算法原理 回溯算法是一种通过探索所有可能的候选解来找出所有解的算法。当候选解被确认不是一个解&#xff08;或者至少不是最后一…

MyBatis 框架学习(II)

MyBatis 框架学习(II) 文章目录 MyBatis 框架学习(II)1. 介绍2. 准备&测试2.1 配置数据库连接字符串和MyBatis2.2 编写持久层代码 3. MyBatis XML基础操作3.1 Insert 操作3.2 Delete 操作3.3 Update 操作3.4 Select 操作 4. #{} 与 ${}的使用5. 动态SQL操作5.1 < if >…

4.2冰达机器人:视觉实例-机器人视觉循线、视觉实例-调整循线颜色

4.2.10a视觉实例-机器人视觉循线 本节内容演示一个机器人视觉的视觉循线实例 准备工作&#xff1a;布置一块区域作为循线场所&#xff0c;如下图所示。用蓝色胶带在地面贴一条路线&#xff08;机器人极限转弯半径0.5m&#xff0c;不要贴得过于曲折&#xff09;&#xff0c;将…

leetcode:438. 找到字符串中所有字母异位词

给定两个字符串 s 和 p&#xff0c;找到 s 中所有 p 的 异位词 的子串&#xff0c;返回这些子串的起始索引。不考虑答案输出的顺序。 异位词 指由相同字母重排列形成的字符串&#xff08;包括相同的字符串&#xff09;。 示例 1: 输入: s "cbaebabacd", p "…

形态学初步

其实在考虑集合的位移z的时候我发现了个问题&#xff0c;以书上的图9.4为例子。现实中&#xff0c;位移z不需要坐标系&#xff0c;但是实际上&#xff0c;不给出坐标系描述位移量是不方便的。其次&#xff0c;位移的前提是需要一个起始位置&#xff0c;但是起始位置如何建立呢&…

Docker - HelloWorld

原文地址&#xff0c;使用效果更佳&#xff01; Docker - HelloWorld | CoderMast编程桅杆https://www.codermast.com/dev-tools/docker/docker-helloworld.html 开始之前 在学习本小节之前&#xff0c;你必须确保你正确安装了 Docker&#xff0c;正确安装 Docker 是后续学习的…

.net8系列-02图文并茂手把手教你编写增删改查接口

前情提要 接上篇文章&#xff0c;我们的应用已经创建完毕了&#xff0c;接下来我们编写几个自己的接口 快速开始 新增Controller 复制一份WeatherForecastController.cs,改名为CommonInfoController 设置Class名 将CommonInfoController中的复制过来的class名改成新名 …

.NET .exe .dll 反编译 程序反编译 程序逆向

反编译是对程序进行逆向分析、研究&#xff0c;以推导出软件产品所使用的思路、原理、结构、算法、处理过程、运行方法等设计要素。 反编译.NET程序需要使用专门的反编译工具 &#x1f9ff;使用dotPeek进行反编译 1.下载dotPeek dotPeek&#xff1a;JetBrains 出品的免费 .N…

[阅读笔记25][WebArena]A Realistic Web Environment for Building Autonomous Agents

这篇论文提出了WebArena这个环境与测试基准&#xff0c;在24年1月发表。 之前的agent都是在一些简化过的合成环境中测试的&#xff0c;这会导致与现实场景脱节。这篇论文构建了一个高度逼真、可复现的环境。该环境涉及四个领域&#xff1a;电子商务、论坛讨论、软件开发和内容管…

【linux运维】系统常见管理命令

系列综述&#xff1a; &#x1f49e;目的&#xff1a;本系列是个人整理为了学习基本的shell编程和linux命令&#xff0c;整理期间苛求每个知识点&#xff0c;平衡理解简易度与深入程度。 &#x1f970;来源&#xff1a;材料主要源于b站大学——linux运维课程进行的&#xff0c;…

数据结构 -- 二叉树二叉搜索树

二叉树 二叉树是这么一种树状结构&#xff1a;每个节点最多有两个孩子&#xff0c;左孩子和右孩子 重要的二叉树结构 完全二叉树&#xff08;complete binary tree&#xff09;是一种二叉树结构&#xff0c;除最后一层以外&#xff0c;每一层都必须填满&#xff0c;填充时要遵…

自然语言处理基础面试

文章目录 TF-IDFbag-of-wordsBert 讲道理肯定还得有Transformer&#xff0c;我这边先放着&#xff0c;以后再加吧。 TF-IDF TF&#xff08;全称TermFrequency&#xff09;&#xff0c;中文含义词频&#xff0c;简单理解就是关键词出现在网页当中的频次。 IDF&#xff08;全称…

【C++初识继承】

博主首页&#xff1a; 有趣的中国人 专栏首页&#xff1a; C进阶 本篇文章主要讲解 继承 的相关内容 目录 1. 继承的概念和定义 1.1 继承的概念 1.2 继承的定义 1.2.1 继承定义格式 1.2.2 继承方式与访问修饰限定符 2. 基类和派生类对象赋值转换 3. 继承中的作用域 …