#sqlite #sha-256 #md5 #hash #rusqlite #sqlite-extension

sqlite-hashes

支持聚合的 SQLite 哈希函数:MD5、SHA1、SHA256、SHA512、FNV-1a、xxHash

19 个版本

0.7.5 2024 年 7 月 24 日
0.7.3 2024 年 6 月 19 日
0.7.1 2024 年 3 月 21 日
0.6.0 2023 年 12 月 21 日
0.1.1 2023 年 7 月 27 日

#109数据库接口

Download history 164/week @ 2024-05-04 200/week @ 2024-05-11 230/week @ 2024-05-18 236/week @ 2024-05-25 453/week @ 2024-06-01 218/week @ 2024-06-08 509/week @ 2024-06-15 219/week @ 2024-06-22 232/week @ 2024-06-29 252/week @ 2024-07-06 152/week @ 2024-07-13 708/week @ 2024-07-20 396/week @ 2024-07-27 230/week @ 2024-08-03 235/week @ 2024-08-10 230/week @ 2024-08-17

1,145 每月下载量
用于 6 个 Crates (3 个直接使用)

MIT/Apache

44KB
507

sqlite-hashes

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

实现支持聚合的 SQLite 哈希函数,包括 MD5、SHA1、SHA224、SHA256、SHA384、SHA512、FNV-1a、xxHash。函数可作为可加载扩展或 Rust 库使用。

另见 SQLite-compressions 扩展对 gzip、brotli 和 bsdiff 的支持。

用途

SQLite 扩展增加了哈希函数,如 sha256sha256_hexsha256_concatsha256_concat_hex,用于多种哈希算法。函数可以返回二进制值或十六进制字符串。

函数支持任何数量的参数,例如 sha256("hello", "world")。所有 NULL 值都将被忽略。当调用内建的 SQLite 函数时,结果为空字符串,因此 sha256_hex(NULL) 将返回空字符串。

*_concat 函数支持聚合计算一组值(如表中的列)的哈希值,例如 sha256_concatsha256_concat_hex。与标量函数一样,也支持多个参数,因此可以计算一组列的哈希值,例如 sha256_concat(col1, col2, col3)

注意:在可加载扩展中不支持窗口功能,仅在作为 Rust crate 使用时才支持。欢迎提交 PR。

扩展

要将此作为扩展使用,请将共享库 libsqlite_hashes.so 加载到 SQLite

$ sqlite3
sqlite> .load ./libsqlite_hashes
sqlite> SELECT md5_hex('Hello world!');
86FB269D190D2C85F6E0468CECA42A20

Rust 库

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

use sqlite_hashes::{register_hash_functions, rusqlite::Connection};

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

// Hash 'password' using SHA-256, and dump resulting BLOB as a HEX string
let sql = "SELECT hex(sha256('password'));";
let hash: String = db.query_row_and_then( & sql, [], | r| r.get(0)).unwrap();
assert_eq!(hash, "5E884898DA28047151D0E56F8DC6292773603D0D6AABBDD62A11EF721D1542D8");

// Same as above, but use sha256_hex() function to dump the result as a HEX string directly
let sql = "SELECT sha256_hex('password');";
let hash: String = db.query_row_and_then( & sql, [], | r| r.get(0)).unwrap();
assert_eq!(hash, "5E884898DA28047151D0E56F8DC6292773603D0D6AABBDD62A11EF721D1542D8");

// Hash 'pass' (as text) and 'word' (as blob) using SHA-256, and dump it as a HEX string
// The result is the same as the above 'password' example.
let sql = "SELECT sha256_hex(cast('pass' as text), cast('word' as blob));";
let hash: String = db.query_row_and_then( & sql, [], | r| r.get(0)).unwrap();
assert_eq!(hash, "5E884898DA28047151D0E56F8DC6292773603D0D6AABBDD62A11EF721D1542D8");

聚合和窗口函数

当启用 aggregatewindow 功能(默认)时,有函数可以计算一组值(如表中的列)的哈希值,例如 sha256_concatsha256_concat_hex。与标量函数一样,也支持多个参数,因此可以计算一组列的哈希值,例如 sha256_concat(col1, col2, col3)。请注意,在可加载扩展中不支持窗口功能。

重要提示:排序

SQLite 不保证在执行聚合函数时行的顺序。查询 SELECT sha256_concat(v) FROM tbl ORDER BY v; 将不会按排序顺序连接值,而是使用某种内部存储顺序。

SQLitev3.44.0(2023-11-01) 中添加了对聚合函数调用中 ORDER BY 子句的支持,例如 SELECT sha256_concat(v ORDER BY v) FROM tbl;。请确保使用它以确保结果的一致性。

对于较旧的 SQLite 版本,一种常见的解决方案是使用子查询,例如 SELECT group_concat(v) FROM (SELECT v FROM tbl ORDER BY v);。但这并不能保证在 SQLite 的未来版本中有效。有关更多详细信息,请参阅 讨论

对于较旧的 SQLite,另一种保证排序的方法是使用窗口函数。

SELECT sha256_concat_hex(v)
       OVER (ORDER BY v ROWS
           BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
FROM tbl
LIMIT 1;

只有在窗口的起始点不移动时(即 UNBOUNDED PRECEDING)散列窗口函数才会工作。要强制非空值,请使用 COALESCE。

SELECT coalesce(
               (SELECT sha256_concat_hex(v)
                       OVER (ORDER BY v ROWS
                           BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
                FROM tbl
                LIMIT 1),
               sha256_hex('')
       );

请注意,窗口函数仅在 SQLite 3.25 及以后版本中可用,因此至少目前必须使用捆绑的 SQLite 版本。

use sqlite_hashes::{register_hash_functions, rusqlite::Connection};

let db = Connection::open_in_memory().unwrap();
register_hash_functions( & db).unwrap();

// Pre-populate the DB with some data. Note that the b values are not alphabetical.
db.execute_batch("
    CREATE TABLE tbl(id INTEGER PRIMARY KEY, v TEXT);
    INSERT INTO tbl VALUES (1, 'bbb'), (2, 'ccc'), (3, 'aaa');
  ").unwrap();

let sql = "SELECT sha256_concat_hex(v) OVER (
    ORDER BY v ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
    FROM tbl LIMIT 1;";
let hash: String = db.query_row_and_then( & sql, [], | r| r.get(0)).unwrap();
assert_eq!(hash, "FB84A45F6DF7D1D17036F939F1CFEB87339FF5DBDF411222F3762DD76779A287");

// The above window aggregation example is equivalent to this scalar hash:
let sql = "SELECT sha256_hex('aaabbbccc');";
let hash: String = db.query_row_and_then( & sql, [], | r| r.get(0)).unwrap();
assert_eq!(hash, "FB84A45F6DF7D1D17036F939F1CFEB87339FF5DBDF411222F3762DD76779A287");

SQLx 一起使用

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

use rusqlite::Connection;
use sqlite_hashes::register_hash_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_hash_functions(&rusqlite_conn).unwrap();
}

包特性

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

[dependencies]
sqlite-hashes = { version = "0.7", default-features = false, features = ["hex", "window", "sha256"] }
  • trace - 启用跟踪支持,记录所有函数调用及其参数
  • hex - 启用十六进制字符串函数,如 *_hex()*_concat_hex()(如果启用 aggregate
  • aggregate - 启用聚合函数,如 *_concat()*_concat_hex()(如果启用 hex
  • window - 启用窗口函数支持(暗示 aggregate
  • md5 - 启用 MD5 哈希支持
  • sha1 - 启用 SHA1 哈希支持
  • sha224 - 启用 SHA224 哈希支持
  • sha256 - 启用 SHA256 哈希支持
  • sha384 - 启用 SHA384 哈希支持
  • sha512 - 启用 SHA512 哈希支持
  • fnv - 启用 FNV-1a 哈希支持
  • xxhash - 启用 xxh32, xxh64, xxh3_64, xxh3_128 哈希支持

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

开发

  • 该项目使用 justmake 的现代替代品)更容易开发。使用 cargo install just 安装它。
  • 要获取可用命令列表,请运行 just
  • 要运行测试,请使用 just test
  • git push 时,它将运行一些验证,包括 cargo fmtcargo clippycargo test。使用 git push --no-verify 来跳过这些检查。

许可证

许可协议为以下之一

贡献

除非您明确声明,否则根据 Apache-2.0 许可证定义的,您有意提交以包含在作品中的任何贡献,均将根据上述协议双重许可,不附加任何额外条款或条件。

依赖项

~22MB
~430K SLoC