SQLite-loadable-rs: A framework for building SQLite Extensions in Rust
observablehq.com
observablehq.com
Direct GitHub link: https://github.com/asg017/sqlite-loadable-rs
A soon-to-be-released sqlite-loadable extension that's the fasted CSV parser for SQLite, and rivals DuckDB's parser at non-analytical queries: https://github.com/asg017/sqlite-xsv
A regular expression extension in Rust, the fastest SQLite regex implementation: https://github.com/asg017/sqlite-regex
And in the near future, expect more extensions for postgres, parquet, XML, S3, image manipulation, and more!
In the sqlite-xsv VTab::open impl for XsvTable [0], you pass a &'vtab XsvTable to XsvCursor. But the means that if open is called again, to create a second cursor, then a `&mut XsvTable` and a `&XsvTable` reference exist at the same time, which is unsafe. Note that sqlite-xsv doesn't actually keep the `&XsvTable`, so it's fine, but it serves as an example where a safety problem could surface.
The same problem also applies to VTabWriteable::update. The fix is to make both of these methods receive an immutable reference and force implementors to use interior mutability. Note this isn't hypothetical, it's actually unsafe, and would appear if you had a unit test that implemented a writable virtual table backed by a rust data structure, and attempted to iterate and update at the same time.
I have an as-yet-unpublished code base that experiments with this. It's not published yet because it doesn't cover everything I want to and I'm trying to avoid publishing something where the API might have to break. My goals are explicitly safety first, performance second. https://github.com/CGamesPlay/sqlite3_ext
[0] https://github.com/asg017/sqlite-xsv/blob/main/src/xsv.rs#L9...
Please consider GIS/spatial extension. SpatiaLite is pretty bad, for example the KNN feature is deprecated and the replacement has not yet made it to a release yet.
I’ve used it frequently for prototyping, but the dialect is different enough from Postgres, that I usually switch over pretty early. But for production, it seems people are really advancing it as a solution for applications, which doesn’t fit with the “When To Use” guide on the website. https://www.sqlite.org/whentouse.html
- Application file format
- Websites
- Server-side database
Under not recommended they essentially say, very high volume and highly concurrent access.
But... actual guidance as to how to use it there is still pretty thin on the ground!
Short version: use WAL mode (which is not the default). Only send writes from a single process (maybe via a queue). Run your own load tests before you go live. Don't use it if you're going to want to horizontally scale to handle more than 1,000 requests/second or so (though vertically scaling will probably work really well).
I'd love to see more useful written material about this. I hope to provide more myself at some point.
Here are some notes I wrote a few months ago: https://simonwillison.net/2022/Oct/23/datasette-gunicorn/
I think it's still very relevant. I mean you have service XYZ replicated two times behind a load balancer, how do you use SQLite out of the box? You can't, you have to use one of those service that will proxy / queue queries, so then why even trying to use SQLite.
The fact that it's just a file on disk make it a bad solution for a lot of simple use cases.
Most small to medium web applications can handle:
- Only being reliable for 99.99% of the time (using a single cloud VM where the cloud provides the hardware level failover).
- Scaling up instead of out (adding CPU, RAM and faster disk).
depending on your use case, using multiple writer processes can be fine, e.g. multiple writer processes storing periodic metrics (once per minute) into a single sqlite database. the occasional "database is locked" error (it does happen a few times a day) is handled by simply returning and trying again at the next interval. that's fine for this particular use case - the metrics for the last interval are just delayed a bit.
rqlite offers horizontal and vertical real scalability, but only vertical for writes. See https://rqlite.io/docs/guides/performance/
Last week saw a similar project in rust to built Postgres extensions
Hope I can play something interesting during vacations
The first thing I'd try is to use crate-type = ["staticlib"] to compile the sqlite extension to a static .a file (cargo build --target wasm32-unknown-unknown), and compile sqlite to a staticlib separately then link them together into a .wasm file and run wasm-opt & friends on that.
There might be some configuration needed to let the extension know the sqlite functions its calling will be linked together later, but that should all be possible. Maybe with some whack-a-mole of wading through compiler versions and build flags and whatnot.
The workflow is basically prototype your virtual tables in python and then write some optimized code in a lower level language later. Just an idea for those interested.
Does SQLite's virtual table API support writes?