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 在 数据库接口
1,145 每月下载量
用于 6 个 Crates (3 个直接使用)
44KB
507 行
sqlite-hashes
实现支持聚合的 SQLite 哈希函数,包括 MD5、SHA1、SHA224、SHA256、SHA384、SHA512、FNV-1a、xxHash。函数可作为可加载扩展或 Rust 库使用。
另见 SQLite-compressions 扩展对 gzip、brotli 和 bsdiff 的支持。
用途
此 SQLite
扩展增加了哈希函数,如 sha256
、sha256_hex
、sha256_concat
和 sha256_concat_hex
,用于多种哈希算法。函数可以返回二进制值或十六进制字符串。
函数支持任何数量的参数,例如 sha256("hello", "world")
。所有 NULL
值都将被忽略。当调用内建的 SQLite
函数时,结果为空字符串,因此 sha256_hex(NULL)
将返回空字符串。
*_concat
函数支持聚合计算一组值(如表中的列)的哈希值,例如 sha256_concat
和 sha256_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");
聚合和窗口函数
当启用 aggregate
或 window
功能(默认)时,有函数可以计算一组值(如表中的列)的哈希值,例如 sha256_concat
和 sha256_concat_hex
。与标量函数一样,也支持多个参数,因此可以计算一组列的哈希值,例如 sha256_concat(col1, col2, col3)
。请注意,在可加载扩展中不支持窗口功能。
重要提示:排序
SQLite
不保证在执行聚合函数时行的顺序。查询 SELECT sha256_concat(v) FROM tbl ORDER BY v;
将不会按排序顺序连接值,而是使用某种内部存储顺序。
SQLite
在 v3.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
功能。
开发
- 该项目使用 just(
make
的现代替代品)更容易开发。使用cargo install just
安装它。 - 要获取可用命令列表,请运行
just
。 - 要运行测试,请使用
just test
。 - 在
git push
时,它将运行一些验证,包括cargo fmt
,cargo clippy
和cargo test
。使用git push --no-verify
来跳过这些检查。
许可证
许可协议为以下之一
- Apache License, Version 2.0 (LICENSE-APACHE 或 http://www.apache.org/licenses/LICENSE-2.0)
- MIT 许可协议 (LICENSE-MIT 或 http://opensource.org/licenses/MIT),您可选择其中之一。
贡献
除非您明确声明,否则根据 Apache-2.0 许可证定义的,您有意提交以包含在作品中的任何贡献,均将根据上述协议双重许可,不附加任何额外条款或条件。
依赖项
~22MB
~430K SLoC