Sqlite3FFI
struct Sqlite3FFIRuntime-loaded SQLite FFI: dlopen + dlsym for all C entry-points.
Loads libsqlite3 at construction via OwnedDLHandle and resolves
every function pointer once. All opaque pointer arguments (sqlite3*,
sqlite3_stmt*) are represented as Int (64-bit on all supported
platforms), matching the C ABI on x86-64 and arm64 without requiring
Pointer type annotations.
Construct this exactly once per process -- reach it through
sqlite_ffi(), which returns a borrow of the _Global instance.
RTLD.NODELETE additionally makes dlclose a no-op, so the library
image stays resident (and its VFS state, WAL locks and shared-memory
mappings intact) for the process lifetime.
Because _dl_sym copies each symbol's address out into a plain
function value, calls do not borrow the handle; the handle only has to
outlive them, which the _Global guarantees.
Example::
ref ffi = sqlite_ffi()
var db = ffi.open(":memory:")
ffi.exec(db, "CREATE TABLE t (x INTEGER)")
_ = ffi.close(db)
Implements Movable
__init__
def __init__(out self, lib_path: String = "") Load libsqlite3 and resolve all function pointers.
- Args
lib_path: Explicit path to the library. If empty, the soname is looked up by_dlopen.open_library:$CONDA_PREFIX/lib, next to the executable and in its../lib, then the dynamic linker's search path (the build environment's lib via the binary's rpath, then the system), so it works with or without$CONDA_PREFIX.
Raises Error: If the library cannot be opened (the message names every
place searched and says to set CONDA_PREFIX) or a symbol
is missing.
open
def open(self, filename: String) -> Int Open or create a SQLite database file.
Uses a List[Int] as the output buffer for the sqlite3**
argument (same pattern as simdjson FFI for output pointer args).
Passes an explicit null-terminated copy of filename (same
pattern as exec) to avoid the Mojo String quirk where
reused heap buffers may contain stale bytes after the logical
string end.
- Args
filename: File path or:memory:for an in-memory database.
Raises Error: If sqlite3_open returns a non-zero code.
close
def close(self, db: Int) -> Int32 Close the database connection.
- Args
db:sqlite3handle.
errmsg
def errmsg(self, db: Int) -> String Return the most recent error message for the connection.
- Args
db:sqlite3handle.
exec
def exec(self, db: Int, sql: String) Execute one or more SQL statements with no result rows.
sqlite3_exec reads until a null byte, so we build an explicit
List[UInt8] copy of sql and append a 0 byte before calling
into C. String.unsafe_ptr() returns a read-only pointer in this
Mojo version, so we cannot patch the null byte in-place. The copy
eliminates the Mojo String quirk where reused heap buffers may
contain stale bytes after the logical string end.
- Args
db:sqlite3handle.sql: Semicolon-separated SQL text (DDL, DML, PRAGMA, etc.).
Raises Error: If sqlite3_exec returns a non-zero code.
prepare_v2
def prepare_v2(self, db: Int, sql: String) -> Int Compile SQL text into a prepared statement.
Uses a List[Int] as the output buffer for the sqlite3_stmt**
argument.
Passes len(sql) as the explicit byte count to
sqlite3_prepare_v2 (instead of -1) so SQLite never reads
beyond the valid bytes. This avoids a Mojo String quirk where
reused heap buffers may contain stale bytes after the logical
string end, which with nByte = -1 causes spurious parse errors
(e.g. near "NTEGER": syntax error).
- Args
db:sqlite3handle.sql: A single SQL statement (without trailing semicolon).
Raises Error: If compilation fails.
step
def step(self, stmt: Int) -> Int32 Advance a prepared statement by one step.
- Args
stmt:sqlite3_stmthandle.
reset
def reset(self, stmt: Int) -> Int32 Reset a prepared statement for re-execution.
- Args
stmt:sqlite3_stmthandle.
finalize
def finalize(self, stmt: Int) Destroy a prepared statement and free its resources.
- Args
stmt:sqlite3_stmthandle.
bind_int
def bind_int(self, stmt: Int, idx: Int, val: Int) Bind an integer value to a statement parameter (1-based index).
Wraps sqlite3_bind_int64.
- Args
stmt:sqlite3_stmthandle.idx: Parameter index (1-based).val: Integer value.
Raises Error: On binding failure.
bind_double
def bind_double(self, stmt: Int, idx: Int, val: Float64) Bind a floating-point value to a statement parameter.
- Args
stmt:sqlite3_stmthandle.idx: Parameter index (1-based).val: Float64 value.
Raises Error: On binding failure.
bind_text
def bind_text(self, stmt: Int, idx: Int, val: String) Bind a text value to a statement parameter (SQLITE_TRANSIENT copy).
Passes the explicit byte length (len(v)) to sqlite3_bind_text
instead of -1 to avoid the Mojo String null-termination quirk
where reused buffers may contain stale bytes after the logical end.
- Args
stmt:sqlite3_stmthandle.idx: Parameter index (1-based).val: String value (copied by SQLite).
Raises Error: On binding failure.
bind_null
def bind_null(self, stmt: Int, idx: Int) Bind SQL NULL to a statement parameter.
- Args
stmt:sqlite3_stmthandle.idx: Parameter index (1-based).
Raises Error: On binding failure.
column_count
def column_count(self, stmt: Int) -> Int Return the number of columns in the current result row.
- Args
stmt:sqlite3_stmthandle.
changes
def changes(self, db: Int) -> Int Return the rows inserted, updated or deleted by the most recent statement.
- Args
db:sqlite3handle.
total_changes
def total_changes(self, db: Int) -> Int Return rows changed by all statements since the connection opened.
- Args
db:sqlite3handle.
last_insert_rowid
def last_insert_rowid(self, db: Int) -> Int Return the rowid of the most recent successful INSERT.
- Args
db:sqlite3handle.
column_type
def column_type(self, stmt: Int, col: Int) -> Int Return the SQLite type code of a column value (0-based index).
- Args
stmt:sqlite3_stmthandle.col: Column index (0-based).
column_int
def column_int(self, stmt: Int, col: Int) -> Int Read an integer column value (0-based index).
- Args
stmt:sqlite3_stmthandle.col: Column index (0-based).
column_double
def column_double(self, stmt: Int, col: Int) -> Float64 Read a floating-point column value (0-based index).
- Args
stmt:sqlite3_stmthandle.col: Column index (0-based).
column_text
def column_text(self, stmt: Int, col: Int) -> String Read a text column value (0-based index).
- Args
stmt:sqlite3_stmthandle.col: Column index (0-based).