#sqlite #ffi

rusqlite-ic

SQLite 的舒适包装

1 个不稳定版本

0.28.1 2023 年 1 月 17 日
0.28.0 2023 年 1 月 17 日

#203#sqlite

Download history 18/week @ 2024-04-02

56 每月下载
ic-sqlite 中使用

MIT 许可证

625KB
13K SLoC

Rusqlite

Latest Version Documentation Build Status (GitHub) Build Status (AppVeyor) Code Coverage Dependency Status Discord Chat

Rusqlite 是从 Rust 使用 SQLite 的舒适包装。

历史上,API 是基于 rust-postgres 的。然而,这两个项目在很多方面都发生了分歧,并且不打算在它们之间提供兼容性。

用法

在您的 Cargo.toml 中

[dependencies]
# `bundled` causes us to automatically compile and link in an up to date
# version of SQLite for you. This avoids many common build issues, and
# avoids depending on the version of SQLite on the users system (or your
# system), which may be old or missing. It's the right choice for most
# programs that control their own SQLite databases.
#
# That said, it's not ideal for all scenarios and in particular, generic
# libraries built around `rusqlite` should probably not enable it, which
# is why it is not a default feature -- it could become hard to disable.
rusqlite = { version = "0.28.0", features = ["bundled"] }

简单示例用法

use rusqlite::{Connection, Result};

#[derive(Debug)]
struct Person {
    id: i32,
    name: String,
    data: Option<Vec<u8>>,
}

fn main() -> Result<()> {
    let conn = Connection::open_in_memory()?;

    conn.execute(
        "CREATE TABLE person (
            id    INTEGER PRIMARY KEY,
            name  TEXT NOT NULL,
            data  BLOB
        )",
        (), // empty list of parameters.
    )?;
    let me = Person {
        id: 0,
        name: "Steven".to_string(),
        data: None,
    };
    conn.execute(
        "INSERT INTO person (name, data) VALUES (?1, ?2)",
        (&me.name, &me.data),
    )?;

    let mut stmt = conn.prepare("SELECT id, name, data FROM person")?;
    let person_iter = stmt.query_map([], |row| {
        Ok(Person {
            id: row.get(0)?,
            name: row.get(1)?,
            data: row.get(2)?,
        })
    })?;

    for person in person_iter {
        println!("Found person {:?}", person.unwrap());
    }
    Ok(())
}

支持的 SQLite 版本

基础 rusqlite 包支持 SQLite 版本 3.6.8 或更高版本。如果您需要支持旧版本,请提交一个问题。某些 cargo 功能需要更高版本的 SQLite;请参见下文详情。

可选功能

Rusqlite 提供了几个在 Cargo 功能 之后的特性。它们是:

  • load_extension 允许加载基于动态库的 SQLite 扩展。
  • backup 允许使用 SQLite 的在线备份 API。注意:此功能需要 SQLite 3.6.11 或更高版本。
  • functions 允许您将 Rust 闭包加载到 SQLite 连接中用于查询。注意:此功能需要 SQLite 3.7.3 或更高版本。
  • window 用于 窗口函数 支持 (fun(...) OVER ...)。 (隐含 functions)
  • trace 允许钩子操作 SQLite 的跟踪和性能分析 API。注意:此功能需要 SQLite 3.6.23 或更高版本。
  • blob 提供了对 SQL BLOB 的 std::io::{Read, Write, Seek} 访问。注意:此功能需要 SQLite 3.7.4 或更高版本。
  • limits 允许您设置和检索 SQLite 的每连接限制。
  • chrono 实现了 FromSqlToSql 接口,用于 chrono 中的多种类型。
  • serde_json 实现了 FromSqlToSql 接口,用于 serde_json 中的 Value 类型。
  • time 实现了 FromSqlToSql 接口,用于 time 中的 time::OffsetDateTime 类型。
  • url 实现了 FromSqlToSql 接口,用于 url 中的 Url 类型。
  • bundled 使用了捆绑版的 SQLite。在连接 SQLite 复杂的情况下,如 Windows,这是一个不错的选择。
  • sqlcipher 寻找 SQLCipher 库进行链接,而不是 SQLite。此功能覆盖了 bundled
  • bundled-sqlcipher 使用了捆绑版的 SQLCipher。它搜索并链接到一个系统安装的加密库,以提供加密实现。
  • bundled-sqlcipher-vendored-openssl 允许使用捆绑的 SQLCipher 和由 OpenSSL(通过 openssl-sys 库)提供的版本作为加密提供者。
    • 正如其名所示,这依赖于 bundled-sqlcipher 功能,并且会自动开启它。
    • 如果开启,这将使用 openssl-sys 库,并启用 vendored 功能以构建和捆绑 OpenSSL 加密库。
  • hooks 用于 提交、回滚数据更改 通知回调。
  • unlock_notify 用于 解锁 通知。
  • vtab 用于 虚拟表 支持(允许你在 Rust 中编写虚拟表实现)。目前仅支持只读虚拟表。
  • series 提供了 generate_series() 表值函数。(隐含 vtab。)
  • csvtab,用 Rust 编写的 CSV 虚拟表。(隐含 vtab。)
  • arrayrarray() 表值函数。(隐含 vtab。)
  • i128_blob 允许在 SQLite 数据库中存储类型为 i128 的值。内部,数据以 16 字节的大端 blob 存储并翻转最高位,这使得不同 blob 存储的 i128 值的排序和比较能够按预期工作。
  • uuid 允许使用 blob 存储和检索 Uuid 值,该功能通过 uuid 包实现。
  • session,Session 模块扩展。需要 buildtime_bindgen 功能。(隐含 hooks。)
  • extra_check 当执行查询时,如果查询是只读的或者列数大于 0,则会失败。
  • column_decltype 为语句和行提供 columns() 方法;如果链接到使用 -DSQLITE_OMIT_DECLTYPE 编译的 SQLite/SQLCipher 版本,则省略。
  • collation 提供了 sqlite3_create_collation_v2
  • winsqlite3 允许链接到 Windows 新版本中现有的 SQLite。

关于构建 rusqlite 和 libsqlite3-sys 的注意事项

libsqlite3-sys 是一个与 rusqlite 分离的 crate,它提供了 SQLite C API 的 Rust 声明。默认情况下,libsqlite3-sys 尝试使用 pkg-config 在您的系统上查找已存在的 SQLite 库,或者对于 MSVC ABI 构建使用 Vcpkg 安装。

您可以通过多种方式调整此行为

  • 如果您使用 bundledbundled-sqlcipherbundled-sqlcipher-vendored-openssl 功能,libsqlite3-sys 将使用 cc crate 从源代码编译 SQLite 或 SQLCipher 并将其链接。此源代码嵌入在 libsqlite3-sys crate 中,目前是 SQLite 3.39.0(截至 rusqlite 0.28.0 / libsqlite3-sys 0.25.0)。这可能是解决任何构建问题的最简单方法。您可以在 Cargo.toml 文件中添加以下内容来启用此功能

    [dependencies.rusqlite]
    version = "0.28.0"
    features = ["bundled"]
    
  • 使用任何 bundled 功能时,构建脚本将遵守 SQLITE_MAX_VARIABLE_NUMBERSQLITE_MAX_EXPR_DEPTH 变量。它还将遵守一个 LIBSQLITE3_FLAGS 变量,其格式类似于 "-USQLITE_ALPHA -DSQLITE_BETA SQLITE_GAMMA ..."。这将禁用 SQLITE_ALPHA 标志,并设置 SQLITE_BETASQLITE_GAMMA 标志。(最后的 -D 可以省略。)

  • 当使用 bundled-sqlcipher(且不使用 bundled-sqlcipher-vendored-openssl)时,libsqlite3-sys 需要链接到系统上的加密库。如果构建脚本可以找到 OpenSSL 或 LibreSSL 的 libcrypto(它将咨询 OPENSSL_LIB_DIR/OPENSSL_INCLUDE_DIROPENSSL_DIR 环境变量),则使用该库。如果在 Mac 上构建并运行,并且没有设置这些变量,则将使用系统的 SecurityFramework。

  • 当链接系统上已存在的SQLite(或SQLCipher)库(因此使用任何捆绑功能)时,您可以设置SQLITE3_LIB_DIR(或SQLCIPHER_LIB_DIR)环境变量,指向包含库的目录。您还可以设置SQLITE3_INCLUDE_DIR(或SQLCIPHER_INCLUDE_DIR)变量,指向包含sqlite3.h的目录。

  • 安装sqlite3开发包通常就足够了,但pkg-configvcpkg的构建辅助工具有一些额外的配置选项。使用vcpkg的默认情况是动态链接,必须在构建前设置VCPKGRS_DYNAMIC=1环境变量。vcpkg install sqlite3:x64-windows将安装所需的库。

  • 当链接系统上已存在的SQLite(或SQLCipher)库时,您可以设置SQLITE3_STATIC(或SQLCIPHER_STATIC)环境变量为1,以请求库以静态方式而不是动态方式链接。

绑定生成

我们使用bindgen从SQLite的C头文件生成Rust声明。bindgen 建议将其作为使用此库的库的构建过程的一部分运行。我们尝试了这种方法(rusqlite 0.10.0,具体来说),但它有一些麻烦

  • libsqlite3-sys(因此rusqlite)的构建时间显著增加。
  • 运行bindgen需要相对较新的Clang版本,而许多系统默认没有安装。
  • 运行bindgen还要求SQLite头文件存在。

截至rusqlite 0.10.1,我们通过提供几个版本的SQLite的预生成绑定来避免在构建时运行bindgen。当编译rusqlite时,我们使用您选择的Cargo功能来选择支持您选择的特性的最低SQLite版本的绑定。如果您直接使用libsqlite3-sys,您可以使用相同的功能来选择预生成的绑定

  • min_sqlite_version_3_6_8 - SQLite 3.6.8绑定(这是默认值)
  • min_sqlite_version_3_6_23 - SQLite 3.6.23绑定
  • min_sqlite_version_3_7_7 - SQLite 3.7.7绑定

如果您使用任何捆绑功能,您将获得捆绑版SQLite/SQLCipher的预生成绑定。如果您需要其他特定版本的预生成绑定,请提交问题。如果您想在构建时运行bindgen以生成自己的绑定,请使用buildtime_bindgen Cargo功能。

如果您启用modern_sqlite功能,我们将使用与捆绑构建一起包含的绑定。通常,如果您启用此功能,您应该启用buildtime_bindgen,否则您需要将链接的SQLite版本与rusqlite捆绑的版本保持同步(通常是SQLite的最新版本)。未能这样做将导致运行时错误。

贡献

Rusqlite有许多功能,其中许多功能以不兼容的方式影响构建配置。这是不幸的,使得测试更改变得困难。

为了帮助这里:您通常应该确保您为--features bundled--features "bundled-full session buildtime_bindgen"运行测试/lint。

如果您运行bindgen存在问题,可以使用--features bundled-full启用捆绑和所有不需要绑定生成的功能,从而替代。

清单

  • 运行cargo fmt以确保您的Rust代码格式正确。
  • 确保cargo clippy --workspace --features bundled无警告通过。
  • 确保cargo clippy --workspace --features "bundled-full session buildtime_bindgen"无警告通过。
  • 确保cargo test --workspace --features bundled无失败报告。
  • 确保cargo test --workspace --features "bundled-full session buildtime_bindgen"无失败报告。

作者

Rusqlite是许多人共同努力的成果。名单在此:[链接](https://github.com/rusqlite/rusqlite/graphs/contributors)

社区

欢迎加入Rusqlite Discord服务器[链接](https://discord.gg/nFYfGPB8g4)讨论或寻求rusqlitelibsqlite3-sys的帮助。

许可证

Rusqlite和libsqlite3-sys在MIT许可证下可用。更多信息请参阅LICENSE文件。

捆绑软件的许可证

根据启用的cargo features集合,rusqlite和libsqlite3-sys还将捆绑其他库,它们有自己的许可条款。

  • 如果启用了--features=bundled-sqlcipher,将编译并静态链接SQLcipher的源代码。SQLcipher在BSD风格许可证下分发,如[此处](https://github.com/froghub-io/rusqlite/blob/8ee227ca4ac2ea9709d8c5a41f8aca216f15d84a/libsqlite3-sys/sqlcipher/LICENSE)所述。

  • 如果启用了--features=bundled,将编译并链接SQLite的源代码。SQLite属于公共领域,如[此处](https://www.sqlite.org/copyright.html)所述。

这两个都是相当自由的,不影响rusqlitelibsqlite3-sys本身的许可证,如果您不使用相关功能,可以完全忽略。

依赖项

~24–35MB
~550K SLoC