Skip to content

Commit 081ca9a

Browse files
First draft of support for extensions and specifically uuid
1 parent a1fc2cb commit 081ca9a

10 files changed

Lines changed: 472 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
### Added
77

8+
* Added support for the SQLite `uuid` extension, enabled via the `uuid` feature flag.
9+
810
### Fixed
911

1012
### Changed

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ js-sys = { version = "0.3.81", default-features = false }
2323
# <https://github.com/utelle/SQLite3MultipleCiphers>
2424
# <https://utelle.github.io/SQLite3MultipleCiphers>
2525
sqlite3mc = []
26+
# Link the uuid extension to the library.
27+
uuid = []
2628

2729
[build-dependencies]
2830
cc = "1.2.27"

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,11 @@ The minimal officially supported rustc version is 1.82.0.
8282

8383
## Extensions
8484

85+
See [ADDING_EXTENSIONS.md](docs/ADDING_EXTENSIONS.md) for instructions on how to add new static extensions.
86+
8587
|Extension|About|
8688
|-|-|
89+
|`uuid`|RFC-4122 UUID generation (built-in)|
8790
|[sqlite-vec](./extensions/sqlite-vec)|A vector search SQLite extension that runs anywhere!|
8891

8992
Contributions are welcome!

build.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,5 +257,20 @@ fn compile() {
257257
#[cfg(feature = "sqlite3mc")]
258258
cc.flags(SQLITE3_MC_FEATURED);
259259

260+
// Extensions
261+
// Define a list of extensions with their feature flag and source file.
262+
// (feature_name, source_file)
263+
#[allow(unused_mut)]
264+
let mut extensions: Vec<(&str, &str)> = Vec::new();
265+
266+
#[cfg(feature = "uuid")]
267+
extensions.push(("uuid", "sqlite3/ext/uuid.c"));
268+
269+
for (_feature, source) in &extensions {
270+
cc.file(source);
271+
// Ensure extensions can find sqlite3ext.h
272+
cc.include("sqlite3");
273+
}
274+
260275
cc.compile("wsqlite3");
261276
}

docs/ADDING_EXTENSIONS.md

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
# Adding Static Extensions
2+
3+
This library supports statically linking SQLite extensions. This is necessary because WebAssembly environments typically do not support dynamic library loading (`dlopen`), so all extensions must be compiled and linked directly into the binary.
4+
5+
## Structure
6+
7+
We maintain a simple structure for single-file C extensions:
8+
9+
- `sqlite3/ext/`: Directory for C extension source files.
10+
11+
## Step-by-Step Guide
12+
13+
### 1. Add the Source File
14+
15+
Place your extension's C source code in `sqlite3/ext/`.
16+
17+
For example, for the `uuid` extension:
18+
19+
```bash
20+
cp path/to/uuid.c sqlite3/ext/uuid.c
21+
```
22+
23+
### 2. Define a Feature Flag
24+
25+
Add a new feature to `Cargo.toml` to allow users to opt-in to this extension.
26+
27+
```toml
28+
[features]
29+
# ...
30+
uuid = []
31+
```
32+
33+
### 3. Register in `build.rs`
34+
35+
Update `build.rs` to compile your extension when the feature is enabled. Looking for the `extensions` array in the `compile()` function:
36+
37+
```rust
38+
// Extensions
39+
// (feature_name, source_file)
40+
let extensions = [
41+
#[cfg(feature = "uuid")]
42+
("uuid", "sqlite3/ext/uuid.c"),
43+
// Add your new extension here:
44+
#[cfg(feature = "your_feature")]
45+
("your_feature", "sqlite3/ext/your_extension.c"),
46+
];
47+
```
48+
49+
The build script automatically handles:
50+
51+
- Compiling the C file.
52+
- Adding `sqlite3/` to the include path (so `#include "sqlite3ext.h"` works).
53+
- Linking it into the final `wsqlite3` library.
54+
55+
### 4. Expose Initialization in Rust
56+
57+
In `src/lib.rs`, allow users to register the extension.
58+
59+
First, declare the extension's initialization function. This name is defined in the C file (usually `sqlite3_EXTENSION_init`).
60+
61+
```rust
62+
#[cfg(feature = "your_feature")]
63+
extern "C" {
64+
pub fn sqlite3_your_extension_init(
65+
db: *mut sqlite3,
66+
pzErrMsg: *mut *mut core::ffi::c_char,
67+
pApi: *const sqlite3_api_routines,
68+
) -> core::ffi::c_int;
69+
}
70+
```
71+
72+
Then, provide a safe helper to register it using `sqlite3_auto_extension`:
73+
74+
```rust
75+
#[cfg(feature = "your_feature")]
76+
pub fn register_your_extension() {
77+
unsafe {
78+
sqlite3_auto_extension(Some(core::mem::transmute(
79+
sqlite3_your_extension_init as *const (),
80+
)));
81+
}
82+
}
83+
```
84+
85+
### Usage
86+
87+
Users can now use your extension by enabling the feature and registering it at startup:
88+
89+
```toml
90+
[dependencies]
91+
sqlite-wasm-rs = { version = "...", features = ["uuid"] }
92+
```
93+
94+
```rust
95+
fn main() {
96+
sqlite_wasm_rs::register_uuid_extension();
97+
98+
// Open database and use uuid functions...
99+
}
100+
```

0 commit comments

Comments
 (0)