#sqlite #brotli #sqlite-extension #gzip #bsdiff

sqlite-compressions

SQLite的压缩、解压缩、测试、差异比较和打补丁函数:gzip、brotli、bsdiff

15个版本

0.2.14 2024年7月24日
0.2.13 2024年7月23日
0.2.12 2024年6月19日
0.2.10 2024年4月11日
0.1.2 2023年12月17日

#226数据库接口

Download history 8/week @ 2024-05-26 188/week @ 2024-06-02 21/week @ 2024-06-09 177/week @ 2024-06-16 142/week @ 2024-06-23 95/week @ 2024-06-30 153/week @ 2024-07-07 107/week @ 2024-07-14 439/week @ 2024-07-21 219/week @ 2024-07-28 110/week @ 2024-08-04 139/week @ 2024-08-11

910 每月下载量
2 个Crates中使用 (通过 mbtiles)

MIT/Apache

39KB
520

sqlite-compressions

GitHub crates.io version docs.rs docs crates.io version CI build

实现了对Brotli、bzip2和gzip编码的SQLite压缩、解压缩和测试函数,以及bsdiff4raw bsdiff的二进制差异比较和打补丁支持。这些函数可以作为可加载的扩展或Rust库提供。

另请参阅SQLite-hashes扩展,其中包含MD5, SHA1, SHA224, SHA256, SHA384, SHA512, FNV1a, xxHash哈希函数。

用法

SQLite扩展添加了brotli、bzip2和gzip压缩函数,如gzip(data, [quality])、解码gzip_decode(data)和测试gzip_test(data)函数。编码和解码函数返回二进制数据,测试函数返回true/false。编码函数可以编码文本和二进制数据,但会在整数和浮点数等类型上引发错误。如果输入数据是NULL,所有函数将返回NULL

bsdiff4(, 目标) 将返回两个块之间的二进制差异,而 bspatch4(, 差异) 将将差异应用于源块以生成目标块。如果输入数据不是块或差异无效,diff 和 patch 函数将引发错误。如果任一输入为 NULL,diff 和 patch 函数将返回 NULL

类似地,还有用于原始 bsdiff 格式的 bsdiffraw(, 目标)bspatchraw(, 差异) 函数。原始格式未压缩且没有任何魔术数字前缀。如果由 bsdiff crate 提供的内部格式更改,我们将为它添加一个单独的函数。

扩展

要将它用作扩展,请将共享库 libsqlite_compressions.so 加载到 SQLite

$ sqlite3
sqlite> .load ./libsqlite_compressions
sqlite> SELECT hex(brotli('Hello world!'));
8B058048656C6C6F20776F726C642103
sqlite> SELECT brotli_decode(x'8B058048656C6C6F20776F726C642103');
Hello world!
sqlite> SELECT brotli_test(x'8B058048656C6C6F20776F726C642103');
1

Rust 库

要将它用作 Rust 库,请将 sqlite-compressions 添加到您的 Cargo.toml 依赖项中。然后,使用 register_compression_functions(&db) 注册所需的函数。这将注册所有可用的函数,或者您可以使用 register_gzip_functions(&db)register_brotli_functions(&db)register_bzip2_functions(&db) 仅注册所需的函数(您还可以禁用默认功能以减少编译时间和二进制文件大小)。

use sqlite_compressions::{register_compression_functions, rusqlite::Connection};

// Connect to SQLite DB and register needed functions
let db = Connection::open_in_memory().unwrap();
// can also use encoding-specific ones like register_gzip_functions(&db)  
register_compression_functions( & db).unwrap();

// Encode 'password' using GZIP, and dump resulting BLOB as a HEX string
let sql = "SELECT hex(gzip('password'));";
let res: String = db.query_row_and_then( & sql, [], | r| r.get(0)).unwrap();
assert_eq!(res, "1F8B08000000000000FF2B482C2E2ECF2F4A0100D546C23508000000");

// Encode 'password' using Brotli, decode it, and convert the blob to text
let sql = "SELECT CAST(brotli_decode(brotli('password')) AS TEXT);";
let res: String = db.query_row_and_then( & sql, [], | r| r.get(0)).unwrap();
assert_eq!(res, "password");

// Test that Brotli-encoded value is correct.
let sql = "SELECT brotli_test(brotli('password'));";
let res: bool = db.query_row_and_then( & sql, [], | r| r.get(0)).unwrap();
assert!(res);

// Test that diffing source and target blobs can be applied to source to get target.
let sql = "SELECT bspatch4('source', bsdiff4('source', 'target'));";
let res: Vec<u8> = db.query_row_and_then( & sql, [], | r| r.get(0)).unwrap();
assert_eq!(res, b"target");

// Test that diffing source and target blobs can be applied
// to source to get target when using raw bsdiff format.
let sql = "SELECT bspatchraw('source', bsdiffraw('source', 'target'));";
let res: Vec<u8> = db.query_row_and_then( & sql, [], | r| r.get(0)).unwrap();
assert_eq!(res, b"target");

SQLx 一起使用

要使用 SQLx,您需要从 SqliteConnection 获取原始句柄并将其传递给注册函数。

use rusqlite::Connection;
use sqlite_compressions::register_compression_functions;
use sqlx::sqlite::SqliteConnection;

async fn register_functions(sqlx_conn: &mut SqliteConnection) {
    // SAFETY: No query must be performed on `sqlx_conn` until `handle_lock` is dropped.
    let mut handle_lock = sqlx_conn.lock_handle().await.unwrap();
    let handle = handle_lock.as_raw_handle().as_ptr();

    // SAFETY: this is safe as long as handle_lock is valid.
    let rusqlite_conn = unsafe { Connection::from_handle(handle) }.unwrap();

    // Registration is attached to the connection, not to rusqlite_conn,
    // so it will be available for the entire lifetime of the `sqlx_conn`.
    // Registration will be automatically dropped when SqliteConnection is dropped.
    register_compression_functions(&rusqlite_conn).unwrap();
}

包功能

默认情况下,此包将使用所有功能编译。您可以选择仅启用您需要的功能以减少编译时间和二进制文件大小。

[dependencies]
sqlite-compressions = { version = "0.2", default-features = false, features = ["brotli"] }
  • trace - 启用跟踪支持,记录所有函数调用及其参数
  • brotli - 启用 Brotli 压缩支持
  • bzip2 - 启用 bzip2 压缩支持
  • gzip - 启用 GZIP 压缩支持
  • bsdiff4 - 启用 bsdiff4 二进制差异和修补支持
  • bsdiffraw - 启用使用原始格式进行 bsdiff 二进制差异和修补支持

loadable_extension 功能仅在构建可以直接加载到 sqlite3 可执行文件的 .so / .dylib / .dll 扩展文件时使用。

开发

  • 此项目使用 just(make 的现代替代品)更容易进行开发。使用 cargo install just 安装它。
  • 要获取可用的命令列表,请运行 just
  • 要运行测试,请使用 just test
  • git push 操作中,它将执行一些验证,包括 cargo fmtcargo clippy,以及 cargo test。使用 git push --no-verify 来跳过这些检查。

许可证

根据以下任一许可证授权

贡献

除非您明确表示,否则根据 Apache-2.0 许可证定义的,您有意提交并包含在作品中的任何贡献,将按上述方式双授权,不附加任何额外条款或条件。

依赖项

~30MB
~703K SLoC