Explainer
- SQLite allows you to create custom virtual tables which allow you to query an external data source using SQL, lowering the bar to entry and homogenizing your data sources
- In the past we’ve looked at creating virtual tables in golang, and here we do something similar in rust.
- One notable improvement here is the inclusion of a loadable extension.
- In most examples I could find (such as mattn go-sqlite3), the virtual table you create is only available within the SQLite connection that is created in your application
- This is not ideal as we would like potential third parties to be able to simply load our vtab into their own (local) install of sqlite, using the
sqlite3command - In other words, we dont want to have to ship a golang/rust executable, we want to ship a shared object. This is what an SQLite Run-Time Loadable Extension does
- https://www.sqlite.org/loadext.html
- There is an example in rusqlite: https://github.com/rusqlite/rusqlite/blob/master/examples/loadable_extension.rs
Setup: Dependencies
- In
Cargo.toml:
[dependencies]
rusqlite = { version = "0.31.0", features = ["vtab", "loadable_extension", "trace"] }
[lib]
name = "demo"
crate-type = ["cdylib"] #this is important as the default `rlib` wont work
- We are creating a shared library, so no
main.rsis needed. instead, create alib.rsfile in thesrcfolder instead
Step 1 – Creating the VTab
- The rusqlite documentation has the bare-bones procedure already:
- Write implementation of
VTabandVTabCursortraits. - Create an instance of the
Modulestructure specialized forVTabimpl. from step 1. - Register your
Modulestructure usingConnection::create_module. - Run a
CREATE VIRTUAL TABLEcommand that specifies the new module in theUSINGclause.
- Write implementation of
- This is where the following references come in handy:
- I started from the below:
https://github.com/rusqlite/rusqlite/blob/master/tests/vtab.rs - Then to flesh it out a bit more: https://github.com/rusqlite/rusqlite/blob/master/src/vtab/csvtab.rs
- I started from the below:
Step 2 – loadable extension
- Once we have our vtab defined above, we need to make it available to the
sqlite3commandsqlite3has the.loadcommand which lets you load runtime extensions like our vtab
- When
.loadis executed, sqlite looks for a specific function within our shared object. Unless otherwise specified this will default tosqlite3_extension_init, so this is the first function we need to define:
- In line 10 above, not that if we get a successful connection to the DB, we hand off to the
extension_initfunction which we define right after - A lot of this is made super easy due to the bridging provided by rusqlite
Step 3 – build and test
cargo build --libsqlite3.load /full/path/to/demo.so
Using the vtab in your rust program
What if we need to use our vtab not as a loadable extenstion, but as part of our rust program? The process remains the same as above, using just step 1. Step 2 is not required. Instead:
- Create
main.rs
References
- Rusqlite Vtab test: https://github.com/rusqlite/rusqlite/blob/master/tests/vtab.rs
- Rusqlite CSV Vtab: https://github.com/rusqlite/rusqlite/blob/master/src/vtab/csvtab.rs
- Rusqlite Loadable Extension: https://github.com/rusqlite/rusqlite/blob/master/examples/loadable_extension.rs