Module: Sqlite

Defined in:
lib/tep/sqlite.rb

Overview

Tep::SQLite -- a thin wrapper around the system libsqlite3 for spinel-AOT'd apps. Uses tep_sqlite.c (compiled to tep_sqlite.o) as a stable C ABI surface, exposed via spinel's ffi_func DSL.

Why not the sqlite3 gem? It's a CRuby-MRI native extension (loadable .so/.bundle), which spinel can't link -- spinel produces a single static binary with everything resolved at compile time. The C-shim approach (same pattern as tep's HTTP server in sphttp.c) replaces "load a gem at runtime" with "link a .o at compile time."

Usage

db = Tep::SQLite.new
db.open("./app.db")
db.exec("CREATE TABLE IF NOT EXISTS notes (id INTEGER PRIMARY KEY, body TEXT)")

# Parameterised insert: prepare once, bind, step, finalize.
db.prepare("INSERT INTO notes (body) VALUES (?)")
db.bind_str(1, "hello")
db.step
db.finalize
id = db.last_rowid

# Single-row, single-column read.
body = db.first_str("SELECT body FROM notes WHERE id = ?", id.to_s)

# Iterating rows.
db.prepare("SELECT id, body FROM notes ORDER BY id")
while db.step == 1
puts db.col_int(0).to_s + ": " + db.col_str(1)
end
db.finalize

Constraints

  • One in-flight cursor per process (the prepare/step/finalize trio shares a single C-side sqlite3_stmt *). Nesting one query inside another's loop will overwrite the parent cursor. The framework runs handlers serially per worker so this is fine for "one DB call per request".
  • Columns are read as either str or int. Floats / blobs / NULL aren't first-class -- a NULL column returns "" (str) or 0 (int).
  • The C side caps a single col_str result at 64 KiB. Large blobs would truncate.

All FFI plumbing lives at the top level (parallel to Sock) so spinel's name resolver finds it from anywhere in the Tep tree.