Skip to content

Commit 046a00d

Browse files
authored
Improve comments and build flags (#167)
1 parent de6ef4f commit 046a00d

File tree

8 files changed

+50
-36
lines changed

8 files changed

+50
-36
lines changed

.github/workflows/test.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -116,14 +116,14 @@ jobs:
116116
runs-on: ${{ matrix.os }}
117117
steps:
118118
- uses: actions/checkout@v4
119-
- name: Install wasm-pack
120-
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
119+
- uses: dtolnay/rust-toolchain@1.82.0
120+
with:
121+
targets: wasm32-unknown-unknown
122+
components: rust-src
121123
- name: Test MSRV
122124
run: |
123-
rustup toolchain install 1.82.0
124-
rustup default 1.82.0
125-
wasm-pack test --node
126-
wasm-pack test --node --features sqlite3mc
125+
cargo build --target wasm32-unknown-unknown
126+
cargo build --features sqlite3mc --target wasm32-unknown-unknown
127127
128128
test_nodejs:
129129
strategy:

build.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
const FULL_FEATURED: [&str; 24] = [
1+
// SQLite compile flags tuned for WASM: no threads/dlopen, keep common extensions.
2+
const FULL_FEATURED: [&str; 23] = [
23
"-DSQLITE_OS_OTHER",
34
"-DSQLITE_USE_URI",
45
// SQLite is configured for a single-threaded environment, as WebAssembly is single-threaded by default.
@@ -13,7 +14,6 @@ const FULL_FEATURED: [&str; 24] = [
1314
"-DSQLITE_OMIT_SHARED_CACHE",
1415
"-DSQLITE_ENABLE_UNLOCK_NOTIFY",
1516
"-DSQLITE_ENABLE_API_ARMOR",
16-
"-DSQLITE_ENABLE_MATH_FUNCTIONS",
1717
"-DSQLITE_ENABLE_BYTECODE_VTAB",
1818
"-DSQLITE_ENABLE_DBPAGE_VTAB",
1919
"-DSQLITE_ENABLE_DBSTAT_VTAB",
@@ -152,6 +152,7 @@ fn bindgen(output: &std::path::PathBuf) {
152152
// Block deprecated functions that are omitted from the build via the DSQLITE_OMIT_DEPRECATED flag.
153153
.blocklist_function("sqlite3_profile")
154154
.blocklist_function("sqlite3_trace")
155+
// Exclude UTF-16 entrypoints to keep the WASM surface minimal.
155156
.blocklist_function(".*16.*")
156157
.blocklist_function("sqlite3_close_v2")
157158
.blocklist_function("sqlite3_create_collation")

crates/rsqlite-vfs/src/lib.rs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -266,8 +266,7 @@ pub struct SQLiteVfsFile {
266266
pub vfs: *mut sqlite3_vfs,
267267
/// Flags used to open the database.
268268
pub flags: i32,
269-
/// The pointer to the file name.
270-
/// If it is a leaked static pointer, you need to drop it manually when xClose it.
269+
/// The pointer to the file name (owned by the VFS, freed in xClose).
271270
pub name_ptr: *const u8,
272271
/// Length of the file name, on wasm32 platform, usize is u32.
273272
pub name_length: usize,
@@ -287,7 +286,7 @@ impl SQLiteVfsFile {
287286
///
288287
/// # Safety
289288
///
290-
/// When xClose, you can free the memory by `drop(Box::from_raw(ptr));`.
289+
/// The name is created from a UTF-8 Rust `String` and leaked for SQLite.
291290
///
292291
/// Do not use again after free.
293292
pub unsafe fn name(&self) -> &'static mut str {
@@ -329,6 +328,7 @@ pub fn register_vfs<IO: SQLiteIoMethods, V: SQLiteVfs<IO>>(
329328
let name = CString::new(vfs_name).map_err(|_| RegisterVfsError::ToCStr)?;
330329
let name_ptr = name.into_raw();
331330

331+
// `name_ptr` and `app_data` are owned by SQLite until the VFS is unregistered.
332332
let app_data = VfsAppData::new(app_data).leak();
333333
let vfs = Box::leak(Box::new(V::vfs(name_ptr, app_data.cast())));
334334
let ret = unsafe { sqlite3_vfs_register(vfs, i32::from(default_vfs)) };
@@ -383,7 +383,7 @@ impl<T> VfsAppData<T> {
383383

384384
/// # Safety
385385
///
386-
/// You have to make sure the pointer is correct
386+
/// Takes ownership of a pointer returned by `leak`.
387387
pub unsafe fn from_raw(t: *mut Self) -> VfsAppData<T> {
388388
*Box::from_raw(t)
389389
}
@@ -836,6 +836,7 @@ pub trait SQLiteIoMethods {
836836
pFile: *mut sqlite3_file,
837837
eLock: ::core::ffi::c_int,
838838
) -> ::core::ffi::c_int {
839+
// No-op: in-memory/WASM VFS does not support file locking.
839840
unused!((pFile, eLock));
840841
SQLITE_OK
841842
}
@@ -844,6 +845,7 @@ pub trait SQLiteIoMethods {
844845
pFile: *mut sqlite3_file,
845846
eLock: ::core::ffi::c_int,
846847
) -> ::core::ffi::c_int {
848+
// No-op: in-memory/WASM VFS does not support file locking.
847849
unused!((pFile, eLock));
848850
SQLITE_OK
849851
}
@@ -888,19 +890,15 @@ pub enum ImportDbError {
888890
}
889891

890892
/// Simple verification when importing db, and return page size;
893+
/// This only checks size/header; validate page size via `check_db_and_page_size`.
891894
pub fn check_import_db(bytes: &[u8]) -> Result<usize, ImportDbError> {
892895
let length = bytes.len();
893896

894897
if length < 512 || length % 512 != 0 {
895898
return Err(ImportDbError::InvalidDbSize);
896899
}
897900

898-
if SQLITE3_HEADER
899-
.as_bytes()
900-
.iter()
901-
.zip(bytes)
902-
.any(|(x, y)| x != y)
903-
{
901+
if !bytes.starts_with(SQLITE3_HEADER.as_bytes()) {
904902
return Err(ImportDbError::InvalidHeader);
905903
}
906904

crates/rsqlite-vfs/src/memvfs.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ where
210210
{
211211
/// Get management tool
212212
pub fn new() -> Self {
213+
// Registers memvfs globally if not already present.
213214
MemVfsUtil(unsafe { install::<C>() }, PhantomData)
214215
}
215216
}
@@ -235,6 +236,7 @@ where
235236
let mut file = MemFile::Main(MemChunksFile::new(page_size));
236237
file.write(bytes, 0).unwrap();
237238
if clear_wal {
239+
// Force rollback journal mode by updating the header at offset 18.
238240
file.write(&[1, 1], 18).unwrap();
239241
}
240242
file

crates/sqlite-wasm-vfs/src/relaxed_idb.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -676,10 +676,10 @@ impl SQLiteIoMethods for RelaxedIdbIoMethods {
676676
bail!(name.is_null());
677677
bail!(value.is_null(), SQLITE_NOTFOUND);
678678

679-
let key = check_result!(CStr::from_ptr(name).to_str()).to_ascii_lowercase();
680-
let value = check_result!(CStr::from_ptr(value).to_str()).to_ascii_lowercase();
679+
let key = check_result!(CStr::from_ptr(name).to_str());
680+
let value = check_result!(CStr::from_ptr(value).to_str());
681681

682-
if key == "page_size" {
682+
if key.eq_ignore_ascii_case("page_size") {
683683
let page_size = check_result!(value.parse::<usize>());
684684
if page_size == file.block_size {
685685
return SQLITE_OK;
@@ -691,7 +691,9 @@ impl SQLiteIoMethods for RelaxedIdbIoMethods {
691691
"page_size cannot be changed".into(),
692692
));
693693
}
694-
} else if key == "synchronous" && value != "off" {
694+
} else if key.eq_ignore_ascii_case("synchronous")
695+
&& !value.eq_ignore_ascii_case("off")
696+
{
695697
return pool.store_err(VfsError::new(
696698
SQLITE_ERROR,
697699
"relaxed-idb vfs only supports synchronous=off".into(),

src/bindings/mod.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//! This module is codegen from build.rs
1+
//! This module is codegen from build.rs. Avoid manual edits.
22
33
#[cfg(all(not(feature = "bindgen"), feature = "sqlite3mc"))]
44
mod sqlite3mc_bindgen;
@@ -31,17 +31,22 @@ pub fn SQLITE_STATIC() -> sqlite3_destructor_type {
3131

3232
#[must_use]
3333
pub fn SQLITE_TRANSIENT() -> sqlite3_destructor_type {
34-
Some(unsafe { mem::transmute::<isize, unsafe extern "C" fn(*mut core::ffi::c_void)>(-1_isize) })
34+
// SQLite uses -1 as a sentinel for "make your own copy".
35+
Some(unsafe {
36+
mem::transmute::<isize, unsafe extern "C" fn(*mut core::ffi::c_void)>(-1_isize)
37+
})
3538
}
3639

3740
impl Default for sqlite3_vtab {
3841
fn default() -> Self {
42+
// C expects zero-initialized vtab structs.
3943
unsafe { mem::zeroed() }
4044
}
4145
}
4246

4347
impl Default for sqlite3_vtab_cursor {
4448
fn default() -> Self {
49+
// C expects zero-initialized vtab cursor structs.
4550
unsafe { mem::zeroed() }
4651
}
4752
}

src/shim.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ impl OsCallback for WasmOsCallback {
1919
while nanos > 0 {
2020
let amt = core::cmp::min(i64::MAX as u128, nanos);
2121
let mut x = 0;
22+
// memory_atomic_wait32 returns 2 on timeout; loop until elapsed.
2223
let val = unsafe { core::arch::wasm32::memory_atomic_wait32(&mut x, 0, amt as i64) };
2324
debug_assert_eq!(val, 2);
2425
nanos -= amt;
@@ -30,6 +31,7 @@ impl OsCallback for WasmOsCallback {
3031

3132
fn random(buf: &mut [u8]) {
3233
fn fallback(buf: &mut [u8]) {
34+
// Non-cryptographic fallback when crypto.getRandomValues is unavailable.
3335
for b in buf {
3436
*b = (Math::random() * 255000.0) as u32 as u8;
3537
}
@@ -92,6 +94,7 @@ fn yday_from_date(date: &Date) -> u32 {
9294
/// https://github.com/emscripten-core/emscripten/blob/df69e2ccc287beab6f580f33b33e6b5692f5d20b/system/lib/libc/emscripten_internal.h#L42
9395
///
9496
/// https://github.com/sqlite/sqlite-wasm/blob/7c1b309c3bd07d8e6d92f82344108cebbd14f161/sqlite-wasm/jswasm/sqlite3-bundler-friendly.mjs#L3404
97+
// Mirrors emscripten/sqlite-wasm localtime handling, including DST logic.
9598
unsafe fn localtime_js(t: c_time_t, tm: *mut tm) {
9699
let date = Date::new(&Number::from((t * 1000) as f64).into());
97100

@@ -105,15 +108,14 @@ unsafe fn localtime_js(t: c_time_t, tm: *mut tm) {
105108
(*tm).tm_yday = yday_from_date(&date) as _;
106109

107110
let start = Date::new_with_year_month_day(date.get_full_year(), 0, 1);
111+
let tz_offset = date.get_timezone_offset();
108112
let summer_offset =
109113
Date::new_with_year_month_day(date.get_full_year(), 6, 1).get_timezone_offset();
110114
let winter_offset = start.get_timezone_offset();
111-
(*tm).tm_isdst = i32::from(
112-
summer_offset != winter_offset
113-
&& date.get_timezone_offset() == winter_offset.min(summer_offset),
114-
);
115+
(*tm).tm_isdst =
116+
i32::from(summer_offset != winter_offset && tz_offset == winter_offset.min(summer_offset));
115117

116-
(*tm).tm_gmtoff = -(date.get_timezone_offset() * 60.0) as _;
118+
(*tm).tm_gmtoff = -(tz_offset * 60.0) as _;
117119
}
118120

119121
/// https://github.com/emscripten-core/emscripten/blob/df69e2ccc287beab6f580f33b33e6b5692f5d20b/system/lib/libc/musl/include/time.h#L40
@@ -179,6 +181,7 @@ pub unsafe extern "C" fn rust_sqlite_wasm_abort() {
179181
/// See <https://github.com/emscripten-core/emscripten/blob/089590d17eeb705424bf32f8a1afe34a034b4682/system/lib/libc/mktime.c#L28>.
180182
#[no_mangle]
181183
pub unsafe extern "C" fn rust_sqlite_wasm_localtime(t: *const c_time_t) -> *mut tm {
184+
// Single shared buffer, matches libc behavior; assumes no concurrent callers.
182185
static mut TM: tm = tm {
183186
tm_sec: 0,
184187
tm_min: 0,
@@ -207,13 +210,15 @@ pub unsafe extern "C" fn rust_sqlite_wasm_malloc(size: c_size_t) -> *mut c_void
207210
if ptr.is_null() {
208211
return ptr::null_mut();
209212
}
213+
// Store size for free/realloc; pointer returned is offset by ALIGN.
210214
*ptr.cast::<usize>() = size;
211215

212216
ptr.add(ALIGN).cast()
213217
}
214218

215219
#[no_mangle]
216220
pub unsafe extern "C" fn rust_sqlite_wasm_free(ptr: *mut c_void) {
221+
// Only accepts pointers allocated by rust_sqlite_wasm_malloc/realloc.
217222
let ptr: *mut u8 = ptr.sub(ALIGN).cast();
218223
let size = *(ptr.cast::<usize>());
219224

@@ -226,6 +231,7 @@ pub unsafe extern "C" fn rust_sqlite_wasm_realloc(
226231
ptr: *mut c_void,
227232
new_size: c_size_t,
228233
) -> *mut c_void {
234+
// Only accepts pointers allocated by rust_sqlite_wasm_malloc/realloc.
229235
let ptr: *mut u8 = ptr.sub(ALIGN).cast();
230236
let size = *(ptr.cast::<usize>());
231237

tests/tests/full/sqlite3mc.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::full::{check_result, prepare_simple_db};
77

88
unsafe fn set_cipher(cipher: &str, db: *mut sqlite3) {
99
let set_cipher = format!("PRAGMA cipher = {cipher};");
10-
let c_name = CString::new(set_cipher.clone()).unwrap();
10+
let c_name = CString::new(set_cipher).unwrap();
1111
let ret = sqlite3_exec(
1212
db,
1313
c_name.as_ptr().cast(),
@@ -32,7 +32,7 @@ unsafe fn test_memvfs_cipher(cipher: &str) {
3232
let mut db = std::ptr::null_mut();
3333
let db_name = format!("test_memvfs_vfs_{cipher}.db");
3434

35-
let c_name = CString::new(db_name.clone()).unwrap();
35+
let c_name = CString::new(db_name.as_str()).unwrap();
3636
let ret = sqlite3_open_v2(
3737
c_name.as_ptr().cast(),
3838
&mut db as *mut _,
@@ -55,7 +55,7 @@ unsafe fn test_memvfs_cipher(cipher: &str) {
5555
let db2 = util.export_db(&new_db_name).unwrap();
5656
assert_eq!(db1, db2);
5757

58-
let c_name = CString::new(db_name.clone()).unwrap();
58+
let c_name = CString::new(db_name.as_str()).unwrap();
5959
let ret = sqlite3_open_v2(
6060
c_name.as_ptr().cast(),
6161
&mut db as *mut _,
@@ -85,7 +85,7 @@ async unsafe fn test_relaxed_idb_vfs_cipher(cipher: &str) {
8585
let mut db = std::ptr::null_mut();
8686
let db_name = format!("test_relaxed_db_vfs_{cipher}.db");
8787

88-
let c_name = CString::new(db_name.clone()).unwrap();
88+
let c_name = CString::new(db_name.as_str()).unwrap();
8989
let ret = sqlite3_open_v2(
9090
c_name.as_ptr().cast(),
9191
&mut db as *mut _,
@@ -110,7 +110,7 @@ async unsafe fn test_relaxed_idb_vfs_cipher(cipher: &str) {
110110
assert_eq!(db1, db2);
111111

112112
let mut db = std::ptr::null_mut();
113-
let c_name = CString::new(new_db_name).unwrap();
113+
let c_name = CString::new(new_db_name.as_str()).unwrap();
114114
let ret = sqlite3_open_v2(
115115
c_name.as_ptr().cast(),
116116
&mut db as *mut _,
@@ -141,7 +141,7 @@ async unsafe fn test_opfs_sah_vfs_cipher(cipher: &str) {
141141
let mut db = std::ptr::null_mut();
142142
let db_name = format!("test_opfs_sah_vfs_{cipher}.db");
143143

144-
let c_name = CString::new(db_name.clone()).unwrap();
144+
let c_name = CString::new(db_name.as_str()).unwrap();
145145
let ret = sqlite3_open_v2(
146146
c_name.as_ptr().cast(),
147147
&mut db as *mut _,
@@ -163,7 +163,7 @@ async unsafe fn test_opfs_sah_vfs_cipher(cipher: &str) {
163163
assert_eq!(db1, db2);
164164

165165
let mut db = std::ptr::null_mut();
166-
let c_name = CString::new(new_db_name).unwrap();
166+
let c_name = CString::new(new_db_name.as_str()).unwrap();
167167
let ret = sqlite3_open_v2(
168168
c_name.as_ptr().cast(),
169169
&mut db as *mut _,

0 commit comments

Comments
 (0)