Skip to content

Commit fd2aae3

Browse files
authored
Merge 'Allow registering and executing WebAssembly functions' from Piotr Sarna (#45)
This series implements a mechanism for registering and running Wasm functions. The current runtime of choice is wasmtime and its libwasmtime.so library with C bindings (but a switch to Rust should be considered, because that's the native language of wasmtime and the only interface which offers all of its features). It operates on a very crude ABI (ref:#16), where ints and doubles are passed to/from WebAssembly as is, and for strings/blobs/null it passes a pointer to a structure: string: [1 byte for type specification][data] blob: [1 byte for type specification][4 bytes of size][data] null: [1 byte for type specification] The way it's implemented now is twofold: There's an internal run_wasm function, capable of running WebAssembly and translating the parameter types from and to the Wasm module A dynamic lookup table, currently a regular SQL table: CREATE TABLE libsql_wasm_func_table(name text PRIMARY KEY, body text). The table can be initialized from C code by calling libsql_try_initialize_wasm_func_table() or from shell by using a .init_wasm_func_table command. After creating and filling the new meta-table, when a function call is used in a statement, e.g. SELECT id, fib(id) FROM t, and function fib is neither built-in nor user-defined, it will be looked up in the table. If found, its body will be assumed to hold valid WebAssembly code, compiled and run. In order to enable WebAssembly integration, run configure with ./configure --enable-wasm-runtime parameter. A few examples WebAssembly-based user-defined functions coded in Rust can be found here: https://github.com/psarna/libsql_bindgen Here's an inline demo for testing purposes, with a WebAssembly fibonacci sequence already compiled from Rust and copied in-place: ``` .init_wasm_func_table CREATE FUNCTION fib LANGUAGE wasm AS ' (module (type (;0;) (func (param i64) (result i64))) (func $fib (type 0) (param i64) (result i64) (local i64) i64.const 0 local.set 1 block ;; label = @1 local.get 0 i64.const 2 i64.lt_u br_if 0 (;@1;) i64.const 0 local.set 1 loop ;; label = @2 local.get 0 i64.const -1 i64.add call $fib local.get 1 i64.add local.set 1 local.get 0 i64.const -2 i64.add local.tee 0 i64.const 1 i64.gt_u br_if 0 (;@2;) end end local.get 0 local.get 1 i64.add) (memory (;0;) 16) (global $__stack_pointer (mut i32) (i32.const 1048576)) (global (;1;) i32 (i32.const 1048576)) (global (;2;) i32 (i32.const 1048576)) (export "memory" (memory 0)) (export "fib" (func $fib))) '; CREATE TABLE IF NOT EXISTS example(id int PRIMARY KEY); INSERT OR REPLACE INTO example(id) VALUES (7); INSERT OR REPLACE INTO example(id) VALUES (8); INSERT OR REPLACE INTO example(id) VALUES (9); SELECT id, fib(id) FROM example; ``` This series also comes with syntactic sugar for registering and deregistering Wasm functions dynamically via SQL: CREATE FUNCTION and DROP FUNCTION: Fixes #18 Fixes #17
2 parents 9128aba + 101c471 commit fd2aae3

28 files changed

Lines changed: 8770 additions & 2382 deletions

.github/workflows/maketestwasm.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
name: Makefile CI with Wasm enabled
2+
3+
on:
4+
push:
5+
branches: [ "main" ]
6+
pull_request:
7+
branches: [ "main" ]
8+
9+
jobs:
10+
build:
11+
12+
runs-on: ubuntu-latest
13+
14+
steps:
15+
- uses: actions/checkout@v3
16+
17+
- name: get TCL
18+
run: sudo apt-get install -y tcl8.6-dev
19+
20+
- name: configure with Wasm
21+
run: ./configure --enable-wasm-runtime-dynamic
22+
23+
- name: make the library generally available
24+
run: sudo ln -s $(pwd)/.libs/libwblibsql.so /usr/lib/libwblibsql.so && ls -lsh /usr/lib
25+
26+
- name: Run tests
27+
run: make test
28+
29+
- name: Run Rust tests with Wasm
30+
run: make rusttestwasm

Dockerfile-wasm-udf

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# This Dockerfile can be used to test the WebAssembly udf build
2+
# of libSQL.
3+
# Build with `docker build -t libsql-wasm-udf -f Dockerfile-wasm-udf`
4+
# Run e.g. with `docker run -it libsql-wasm-udf`
5+
# or with `docker run -it -v.:/home/libsql/playground libsql-wasm-udf ./sqlite3 playground/db.sql`
6+
# for an interactive session with the database being preserved on host in the db.sql file.
7+
8+
FROM rust:slim-buster
9+
10+
WORKDIR /home/libsql
11+
ADD src src
12+
ADD ext ext
13+
ADD tool tool
14+
15+
RUN apt-get update
16+
RUN apt-get install -y tcl8.6-dev build-essential autoconf
17+
18+
#I'm sorry for that
19+
RUN ln -s /bin/grep /usr/bin/grep
20+
RUN ln -s /bin/sed /usr/bin/sed
21+
RUN ln -sf /bin/bash /bin/sh
22+
23+
COPY manifest manifest.uuid VERSION configure.ac Makefile.in \
24+
libtool sqlite3.pc.in sqlite_cfg.h.in install-sh config.guess config.sub ltmain.sh .
25+
26+
RUN autoconf
27+
RUN ./configure --enable-wasm-runtime
28+
RUN make sqlite3

Makefile.in

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,13 @@ LIBREADLINE = @TARGET_READLINE_LIBS@
6666
#
6767
TCC += -DSQLITE_THREADSAFE=@SQLITE_THREADSAFE@
6868

69+
# Optional WebAssembly runtime library
70+
#
71+
TARGET_OPT_WASM_RUNTIME_LINK = @TARGET_OPT_WASM_RUNTIME_LINK@
72+
6973
# Any target libraries which libsqlite must be linked against
7074
#
71-
TLIBS = @LIBS@ $(LIBS)
75+
TLIBS = @LIBS@ $(LIBS) $(TARGET_OPT_WASM_RUNTIME_LINK)
7276

7377
# Flags controlling use of the in memory btree implementation
7478
#
@@ -776,7 +780,13 @@ mptest: mptester$(TEXE)
776780
cp fts5.c fts5.h tsrc
777781
touch .target_source
778782

779-
sqlite3.c: .target_source $(TOP)/tool/mksqlite3c.tcl
783+
libwblibsql.so: $(TOP)/src/rust/wasmtime-bindings/src/lib.rs
784+
( mkdir -p .libs && cd $(TOP)/src/rust/wasmtime-bindings/ && cargo build --release && cp target/release/libwblibsql.so $(TOP)/.libs/ )
785+
786+
libwblibsql.a: $(TOP)/src/rust/wasmtime-bindings/src/lib.rs
787+
( mkdir -p .libs && cd $(TOP)/src/rust/wasmtime-bindings/ && cargo build --release && cp target/release/libwblibsql.a $(TOP)/.libs/ )
788+
789+
sqlite3.c: .target_source $(TOP)/tool/mksqlite3c.tcl @OPT_WASM_RUNTIME_LIB@
780790
$(TCLSH_CMD) $(TOP)/tool/mksqlite3c.tcl $(AMALGAMATION_LINE_MACROS)
781791
cp tsrc/sqlite3ext.h .
782792
cp $(TOP)/ext/session/sqlite3session.h .
@@ -1318,6 +1328,9 @@ quicktest: ./testfixture$(TEXE)
13181328
rusttest: sqlite3.h libsqlite3.la
13191329
( cd test/rust_suite; LD_LIBRARY_PATH=../../.libs cargo test )
13201330

1331+
rusttestwasm: sqlite3.h libsqlite3.la
1332+
( cd test/rust_suite; LD_LIBRARY_PATH=../../.libs cargo test --features udf )
1333+
13211334
# This is the common case. Run many tests that do not take too long,
13221335
# including fuzzcheck, sqlite3_analyzer, and sqldiff tests.
13231336
#

0 commit comments

Comments
 (0)