UDF in the libSQL database
libSQL is a fork of the popular SQLite database. One of the key enhancements libSQL brings is UDF (User Defined Functions) support. Through Wasm-based UDFs, users can add their own processing logic to the database, and then process the data in and out of the database on the fly. libSQL uses WasmEdge to run these UDFs. In this article, I will show you how.
Prerequisites
First, you will need to install WasmEdge runtime.
Next, install the latest libSQL or build it from source.
git clone https://github.com/libsql/libsql
cd libsql
./configure --enable-wasm-runtime-wasmedge
make
The encrypt and decrypt example
Build the encrypt and decrypt example into wasm. Since WasmEdge supports WASI functions here, we will use the wasm32-wasi
target.
git clone https://github.com/libsql/libsql_bindgen
cd libsql_bindgen/examples/encrypt_decrypt
cargo build --target wasm32-wasi --release
Then, we can build a SQL file for creating the encrypt
function in a libSQL database.
export FUNC_NAME='encrypt'
echo "DROP FUNCTION IF EXISTS ${FUNC_NAME};" >> create_${FUNC_NAME}_udf.sql
echo -n "CREATE FUNCTION ${FUNC_NAME} LANGUAGE wasm AS X'" >> create_${FUNC_NAME}_udf.sql
xxd -p ../../target/wasm32-wasi/release/libsql_encrypt_decrypt.wasm | tr -d "\n" >> create_${FUNC_NAME}_udf.sql
echo "';" >> create_${FUNC_NAME}_udf.sql
Create another SQL file for the decrypt
function.
export FUNC_NAME='decrypt'
echo "DROP FUNCTION IF EXISTS ${FUNC_NAME};" >> create_${FUNC_NAME}_udf.sql
echo -n "CREATE FUNCTION ${FUNC_NAME} LANGUAGE wasm AS X'" >> create_${FUNC_NAME}_udf.sql
xxd -p ../../target/wasm32-wasi/release/libsql_encrypt_decrypt.wasm | tr -d "\n" >> create_${FUNC_NAME}_udf.sql
echo "';" >> create_${FUNC_NAME}_udf.sql
Now, you can add those UDFs to a libSQL instance.
./libsql
libsql> .init_wasm_func_table
libsql> .read create_encrypt_udf.sql
libsql> .read create_decrypt_udf.sql
Finally, you can create a table and test it.
libsql>
CREATE TABLE secrets(secret);
INSERT INTO secrets (secret) VALUES (encrypt('my secret value: 1', 's3cretp4ss'));
INSERT INTO secrets (secret) VALUES (encrypt('my even more secret value: 2', 's3cretp4ss'));
INSERT INTO secrets (secret) VALUES (encrypt('classified value: 3', 's3cretp4ss'));
SELECT secret, decrypt(secret, 'wrong-pass') from secrets;
secret decrypt(secret, 'wrong-pass')
-------------------------------------------- -----------------------------
IyTvoTEnh9a/f6+pac3rLPToP9DkWqS7CEW8tan3mbQ= [ACCESS DENIED]
bUQ4fEe6hPnsMx8ABOZO97CMr/wouGTByfUCEmFVZTs= [ACCESS DENIED]
o+m1w7UdoxBZxLumNW0VoMKSMFaC4o8N5uknAQZ/yFY= [ACCESS DENIED]
SELECT secret, decrypt(secret, 's3cretp4ss') from secrets;
secret decrypt(secret, 's3cretp4ss')
-------------------------------------------- -----------------------------
IyTvoTEnh9a/f6+pac3rLPToP9DkWqS7CEW8tan3mbQ= my secret value: 1
bUQ4fEe6hPnsMx8ABOZO97CMr/wouGTByfUCEmFVZTs= my even more secret value: 2
o+m1w7UdoxBZxLumNW0VoMKSMFaC4o8N5uknAQZ/yFY= classified value: 3