Skip to content

Commit 5d557d8

Browse files
committed
zstd decompression POC.
1 parent b07e3e1 commit 5d557d8

4 files changed

Lines changed: 85 additions & 0 deletions

File tree

Cargo.lock

Lines changed: 36 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/core/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const_format = "0.2.34"
2323
futures-lite = { version = "2.6.0", default-features = false, features = ["alloc"] }
2424
rustc-hash = { version = "2.1", default-features = false }
2525
streaming-iterator = { version = "0.1.9", default-features = false, features = ["alloc"] }
26+
zstd-safe = { version = "7.2.4" }
2627

2728
[dependencies.uuid]
2829
version = "1.4.1"

crates/core/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ mod version;
3434
mod view_admin;
3535
mod views;
3636
mod vtab_util;
37+
mod zstd;
3738

3839
#[no_mangle]
3940
pub extern "C" fn sqlite3_powersync_init(
@@ -62,6 +63,7 @@ fn init_extension(db: *mut sqlite::sqlite3) -> Result<(), ResultCode> {
6263
crate::view_admin::register(db)?;
6364
crate::checkpoint::register(db)?;
6465
crate::kv::register(db)?;
66+
crate::zstd::register(db)?;
6567
sync::register(db)?;
6668

6769
crate::schema::register(db)?;

crates/core/src/zstd.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
extern crate alloc;
2+
3+
use alloc::string::String;
4+
use core::ffi::c_int;
5+
6+
use sqlite::ResultCode;
7+
use sqlite_nostd::{self as sqlite, Value};
8+
use sqlite_nostd::{Connection, Context};
9+
10+
use crate::create_sqlite_text_fn;
11+
use crate::error::SQLiteError;
12+
use zstd_safe::DCtx;
13+
14+
fn powersync_zstd_impl(
15+
_ctx: *mut sqlite::context,
16+
args: &[*mut sqlite::value],
17+
) -> Result<String, ResultCode> {
18+
let arg = args.get(0).ok_or(ResultCode::MISMATCH)?.blob();
19+
let dict = args.get(1).ok_or(ResultCode::MISMATCH)?.blob();
20+
// TODO: Use a form of streaming decompression to avoid pre-allocating a large buffer.
21+
let mut dest = alloc::vec![0u8; 1024 * 20];
22+
let mut ctx = DCtx::create();
23+
let size = ctx
24+
.decompress_using_dict(&mut dest[..], arg, dict)
25+
.map_err(|_| ResultCode::CORRUPT)?;
26+
dest.truncate(size);
27+
let text = String::from_utf8(dest).map_err(|_| ResultCode::MISUSE)?;
28+
Ok(text)
29+
}
30+
31+
create_sqlite_text_fn!(powersync_zstd, powersync_zstd_impl, "zstd_decompress_text");
32+
33+
pub fn register(db: *mut sqlite::sqlite3) -> Result<(), ResultCode> {
34+
db.create_function_v2(
35+
"zstd_decompress_text",
36+
2,
37+
sqlite::UTF8,
38+
None,
39+
Some(powersync_zstd),
40+
None,
41+
None,
42+
None,
43+
)?;
44+
45+
Ok(())
46+
}

0 commit comments

Comments
 (0)