SQLite3 bindings for Arc. Zero configuration — just import and use.
import "github.com/arc-language/sqlite3"
git clone https://github.com/arc-language/sqlite3
cd sqlite3
arc build main.ax -o main
./mainnamespace main
import c "libc"
import "github.com/arc-language/sqlite3"
extern c {
func printf(*byte, ...) int32
}
func main() {
let (db, rc) = sqlite3.open("myapp.db")
if rc != sqlite3.SQLITE_OK {
printf("failed: %s\n", db.errmsg())
return
}
defer db.close()
db.exec("CREATE TABLE IF NOT EXISTS items (id INTEGER PRIMARY KEY, name TEXT)")
let (ins, _) = db.prepare("INSERT INTO items (name) VALUES (?)")
defer ins.finalize()
ins.bind_text(1, "widget", 6)
ins.step()
let (sel, _) = db.prepare("SELECT id, name FROM items")
defer sel.finalize()
for sel.step() == sqlite3.SQLITE_ROW {
printf("id=%d name=%s\n", sel.column_int(0), sel.column_text(1))
}
}
db.ax — constants and raw C extern declarations
db_handle.ax — DB struct: open / close / exec / prepare
stmt.ax — Stmt struct: step / reset / finalize / column metadata
stmt_bind.ax — bind_int / bind_float / bind_text / bind_blob / bind_null
stmt_column.ax — column_int / column_float / column_text / column_blob
main.ax — usage example
| Function | Signature | Description |
|---|---|---|
open |
(path: *byte) -> (DB, int32) |
Open or create a database file |
open_v2 |
(path: *byte, flags: int32) -> (DB, int32) |
Open with explicit flags |
close |
(self db: *DB) -> int32 |
Close the database connection |
exec |
(self db: *DB, sql: *byte) -> int32 |
Execute SQL with no result rows |
prepare |
(self db: *DB, sql: *byte) -> (Stmt, int32) |
Compile SQL into a prepared statement |
errmsg |
(self db: *DB) -> *byte |
Get last error message |
errcode |
(self db: *DB) -> int32 |
Get last error code |
changes |
(self db: *DB) -> int32 |
Number of rows affected by last write |
last_insert_rowid |
(self db: *DB) -> int64 |
Rowid of last INSERT operation |
| Function | Signature | Description |
|---|---|---|
step |
(self s: *Stmt) -> int32 |
Advance to next row (SQLITE_ROW or SQLITE_DONE) |
reset |
(self s: *Stmt) -> int32 |
Rewind statement for re-execution |
finalize |
(self s: *Stmt) -> int32 |
Destroy the prepared statement |
clear_bindings |
(self s: *Stmt) -> int32 |
Unbind all parameters |
bind_parameter_count |
(self s: *Stmt) -> int32 |
Number of ? placeholders |
| Function | Signature | Description |
|---|---|---|
bind_int |
(self s: *Stmt, idx: int32, val: int64) -> int32 |
Bind an integer value |
bind_float |
(self s: *Stmt, idx: int32, val: float64) -> int32 |
Bind a floating-point value |
bind_text |
(self s: *Stmt, idx: int32, val: *byte, len: int32) -> int32 |
Bind a text string (copied internally) |
bind_blob |
(self s: *Stmt, idx: int32, data: *void, len: int32) -> int32 |
Bind raw bytes (copied internally) |
bind_null |
(self s: *Stmt, idx: int32) -> int32 |
Bind NULL value |
| Function | Signature | Description |
|---|---|---|
column_int |
(self s: *Stmt, idx: int32) -> int64 |
Read integer column |
column_float |
(self s: *Stmt, idx: int32) -> float64 |
Read floating-point column |
column_text |
(self s: *Stmt, idx: int32) -> *byte |
Read text column |
column_blob |
(self s: *Stmt, idx: int32) -> *void |
Read blob column |
column_bytes |
(self s: *Stmt, idx: int32) -> int32 |
Byte length of column value |
column_type |
(self s: *Stmt, idx: int32) -> int32 |
SQLite type of column value |
column_name |
(self s: *Stmt, idx: int32) -> *byte |
Column name from schema |
column_is_null |
(self s: *Stmt, idx: int32) -> bool |
Check if column is NULL |
Result Codes
SQLITE_OK 0 // Successful result
SQLITE_ERROR 1 // Generic error
SQLITE_BUSY 5 // Database is locked
SQLITE_ROW 100 // Step has another row ready
SQLITE_DONE 101 // Step has finished executing
Open Flags
SQLITE_OPEN_READWRITE 0x00000002 // Open for reading and writing
SQLITE_OPEN_CREATE 0x00000004 // Create file if it doesn't exist
Data Types
SQLITE_INTEGER 1
SQLITE_FLOAT 2
SQLITE_TEXT 3
SQLITE_BLOB 4
SQLITE_NULL 5
Always pair close and finalize with defer for automatic cleanup:
let (db, _) = sqlite3.open("app.db")
defer db.close()
let (stmt, _) = db.prepare("SELECT * FROM users")
defer stmt.finalize()
Call reset before re-executing a prepared statement with new bindings:
ins.bind_text(1, "Alice", 5)
ins.step()
ins.reset()
ins.bind_text(1, "Bob", 3)
ins.step()
ins.reset()
Use column_type or column_is_null before reading columns:
if sel.column_is_null(2) {
printf(" score is NULL\n")
} else {
printf(" score=%.1f\n", sel.column_float(2))
}
Use open_v2 with explicit flags for read-only operations:
let (db, _) = sqlite3.open_v2("data.db", sqlite3.SQLITE_OPEN_READWRITE)
defer db.close()
MIT