Compare commits

1 Commits

Author SHA1 Message Date
5b77973a43 in progress switch to using effects 2026-03-19 11:19:44 -04:00
3 changed files with 309 additions and 114 deletions

View File

@@ -15,6 +15,26 @@ extern make-sqlite-ok(): int32
c inline "SQLITE_OK"
pub val int32/sqlite-ok: int32 = make-sqlite-ok()
extern make-sqlite-open-readonly(): int32 { c inline "SQLITE_OPEN_READONLY" }
extern make-sqlite-open-readwrite(): int32 { c inline "SQLITE_OPEN_READWRITE" }
extern make-sqlite-open-readwritecreate(): int32 { c inline "SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE" }
pub val int32/open-readonly = make-sqlite-open-readonly()
pub val int32/open-readwrite = make-sqlite-open-readwrite()
pub val int32/open-readwritecreate = make-sqlite-open-readwritecreate()
extern make-sqlite-open-uri(): int32 { c inline "SQLITE_OPEN_URI" }
extern make-sqlite-open-sharedcache(): int32 { c inline "SQLITE_OPEN_SHAREDCACHE" }
extern make-sqlite-open-memory(): int32 { c inline "SQLITE_OPEN_MEMORY" }
extern make-sqlite-open-exrescode(): int32 { c inline "SQLITE_OPEN_EXRESCODE" }
extern make-sqlite-open-nomutex(): int32 { c inline "SQLITE_OPEN_NOMUTEX" }
extern make-sqlite-open-fullmutex(): int32 { c inline "SQLITE_OPEN_FULLMUTEX" }
pub val int32/open-uri = make-sqlite-open-uri()
pub val int32/open-sharedcache = make-sqlite-open-sharedcache()
pub val int32/open-memory = make-sqlite-open-memory()
pub val int32/open-exrescode = make-sqlite-open-exrescode()
pub val int32/open-nomutex = make-sqlite-open-nomutex()
pub val int32/open-fullmutex = make-sqlite-open-fullmutex()
pub extern initialize(): int32
c inline "sqlite3_initialize()"
@@ -53,15 +73,16 @@ pub extern column-count(^stmt: any): int
pub extern column-type(^stmt: any, col: int32): int32
c "kk_sqlite3_column_type"
extern make-sqlite-integer(): int32 { c inline "SQLITE_INTEGER" }
pub val int32/integer = make-sqlite-integer()
extern make-sqlite-float(): int32 { c inline "SQLITE_FLOAT" }
pub val int32/float = make-sqlite-float()
extern make-sqlite-blob(): int32 { c inline "SQLITE_BLOB" }
pub val int32/blob = make-sqlite-blob()
extern make-sqlite-null(): int32 { c inline "SQLITE_NULL" }
pub val int32/null = make-sqlite-null()
extern make-sqlite-text(): int32 { c inline "SQLITE_TEXT" }
pub val int32/integer = make-sqlite-integer()
pub val int32/float = make-sqlite-float()
pub val int32/blob = make-sqlite-blob()
pub val int32/null = make-sqlite-null()
pub val int32/text = make-sqlite-text()
//TODO(zephyr): waiting on a proper bytes type in koka

167
sqlite/effective.kk Normal file
View File

@@ -0,0 +1,167 @@
// High-level SQLite3 API.
//
// This module uses effects to enforce safety invariants;
// it is not possible to retain a statement beyond the lifetime of a database.
module sqlite/effective
import std/core/undiv
import std/num/int32
import std/num/int64
import sqlite/capi
import sqlite/sqlite-result
// Throw an `:ExnSqlite3` if a result code is not `SQLITE_OK` or `SQLITE_OK_LOAD_PERMANENTLY`.
// `:r` must be a result code produced by SQLite3 and must not be `SQLITE_ROW` or `SQLITE_DONE`.
fun trusted-check-ok(r: int32, msg: string, ?kk-file-line: string): exn ()
// Explicitly check for SQLITE_OK first on the assumption that the single
// i32 comparison for the common case is cheaper than the match to convert to
// the Koka type.
if r != capi/int32/sqlite-ok then
val r' = try(fn() r.sqlite-result, fn(exn) impossible(exn.message))
match r'
Error-Code(code) -> throw(msg, ExnSqlite3(code))
Ok -> impossible("got ok after explicit check for ok")
Row -> impossible("SQLITE_ROW")
Done -> impossible("SQLITE_DONE")
// Ok-Load-Permanently is an uncommon case, but it's still a variety of ok.
Ok-Load-Permanently -> ()
named scoped effect database<s::S>
fun prepare-stmt(sql: sslice, ?persistent: bool, ?disable-vtab: bool, ?disable-log: bool): (any, sslice)
fun with-db(name: db-name, base-flags: int32, sync-mode: sync-mode, vfs: string, action: forall<s> (ev<database<s>>) -> <database<s>,exn|e> a): <exn|e> a
val flags = match sync-mode
Single-Thread -> base-flags.or(open-exrescode)
Multi-Thread -> base-flags.or(open-exrescode).or(open-nomutex)
Serialized -> base-flags.or(open-exrescode).or(open-fullmutex)
val (conn, r) = match name
Filename(path) -> capi/open-v2(path, flags, vfs)
URI(uri) -> capi/open-v2(uri, flags.or(open-uri), vfs)
Memory-Shared(name) -> capi/open-v2("file:" ++ name ++ "?mode=memory&cache=shared", flags.or(open-uri).or(open-sharedcache).or(open-memory), vfs)
Memory -> capi/open-v2(":memory:", flags.or(open-memory), vfs)
r.trusted-check-ok("opening database")
with finally
capi/close(conn).trusted-check-ok("closing database")
with db <- named handler
fun prepare-stmt(sql: sslice, persistent: bool, disable-vtab: bool, disable-log: bool)
val flags' = 0.i32
.or(persistent.int32 * 0x01.i32)
.or(disable-vtab.int32 * 0x04.i32)
.or(disable-log.int32 * 0x10.i32)
val (stmt, rest, r') = capi/prepare-v3(conn, sql, flags')
if r' != capi/int32/sqlite-ok then
val rr = try(fn() r'.sqlite-result, fn(exn) impossible(exn.message))
match rr
Error-Code(code) -> throw("preparing statement", ExnPrepare(code, sql, capi/error-offset(conn)))
t -> impossible(t.show)
(stmt, rest)
action(db)
// Modes that can be used to name a database to be opened.
pub type db-name
Filename(path: string)
URI(uri: string)
Memory-Shared(name: string) // in-memory database with shared cache
Memory
// Synchronization modes in which to open a database.
pub type sync-mode
Single-Thread // No concurrent use is safe.
Multi-Thread // The database is thread-safe, but connections are not.
Serialized // The database and connections are always thread-safe.
// Open or create a database in read-write mode.
//
// Once `:action` returns, the database is closed automatically.
// Exceptions are thrown on error when opening or closing the database.
pub fun open(name: db-name, sync-mode: sync-mode = Serialized, vfs: string = "", action: forall<s> (ev<database<s>>) -> <database<s>,exn|e> a): <exn|e> a
with-db(name, capi/int32/open-readwritecreate, sync-mode, vfs, action)
// Open an existing database in read-write mode.
//
// Once `:action` returns, the database is closed automatically.
// Exceptions are thrown on error when opening or closing the database.
pub fun open-existing(name: db-name, sync-mode: sync-mode = Serialized, vfs: string = "", action: forall<s> (ev<database<s>>) -> <database<s>,exn|e> a): <exn|e> a
with-db(name, capi/int32/open-readwrite, sync-mode, vfs, action)
// Open a database in read-only mode.
//
// Once `:action` returns, the database is closed automatically.
// Exceptions are thrown on error when opening or closing the databse.
pub fun read-only(name: db-name, sync-mode: sync-mode = Serialized, vfs: string = "", action: forall<s> (ev<database<s>>) -> <database<s>,exn|e> a): <exn|e> a
with-db(name, capi/int32/open-readonly, sync-mode, vfs, action)
named scoped effect statement<r::S> in database<s>
fun stmt-reset(): ()
fun bind(bind: list<sql-value>, bind-named: list<(string, sql-value)>): ()
fun stmt-step(): int32
// Create a prepared statement.
//
// Once `:action` returns, the statement is finalized automatically,
// which can cause an exception to be thrown.
pub fun prepare(db: ev<database<s>>, sql: sslice, persistent: bool = False, disable-vtab: bool = False, disable-log: bool = False, action: forall<r> (ev<statement<r>>, sslice) -> <database<s>,statement<r>,exn|e> a): <database<s>,exn|e> a
val (cref, rest) = db.prepare-stmt(sql)
with finally
capi/finalize(cref).trusted-check-ok("finalizing statement")
with stmt <- named handler
fun stmt-reset() capi/reset(cref).trusted-check-ok("resetting statement")
fun bind(bind, bind-named) cref.set-params
fun stmt-step() capi/step(cref)
action(stmt, rest)
pub type sql-value
// Blob(x: bytes)
Float(x: float64)
Integer(x: int64)
Text(x: string)
Null
fun set-params(stmt: any, ?bind: list<sql-value>, ?bind-named: list<(string, sql-value)>): exn ()
bind.foreach-indexed() fn(i, v)
val r = match v
Float(x) -> capi/bind-double(stmt, int32(i+1), x)
Integer(x) -> capi/bind-int64(stmt, int32(i+1), x)
Text(x) -> capi/bind-text(stmt, int32(i+1), x)
Null -> capi/bind-null(stmt, int32(i+1))
r.trusted-check-ok("binding parameter " ++ show(i+1)) // TODO(zephyr): lazy?
bind-named.foreach() fn((name, v))
val i = capi/parameter-index(stmt, name)
if i == 0.i32 then throw("no parameter named " ++ name.show, ExnRange)
val r = match v
Float(x) -> capi/bind-double(stmt, i, x)
Integer(x) -> capi/bind-int64(stmt, i, x)
Text(x) -> capi/bind-text(stmt, i, x)
Null -> capi/bind-null(stmt, i)
r.trusted-check-ok("binding parameter " ++ name.show)
named scoped effect row<r::S> in statement<s>
fun num-column(): int
fun column(col: int): sql-value
// fun blob(col: int): bytes
fun float64(col: int): float64
fun int(col: int): int
fun text(col: int): string
fun null(col: int): bool
fun with-row(stmt: any, action: forall<r> (ev<row<r>>) -> <row<r>|e> a): e a
with r <- named handler
fun num-column()
capi/column-count(stmt)
fun column(col)
val t = capi/column-type(stmt, col.int32)
if t == capi/int32/integer then Integer(capi/column-integer(stmt, col.int32).int64)
else if t == capi/int32/float then Float(capi/column-double(stmt, col.int32))
// else if t == capi/int32/blob then Blob(capi/column-blob(stmt, col.int32))
else if t == capi/int32/text then Text(capi/column-text(stmt, col.int32))
// If the DB gives us something unimaginable, pretend it's nothing.
else Null
fun float64(col)
capi/column-double(stmt, col.int32)
fun int(col)
capi/column-integer(stmt, col.int32)
fun text(col)
capi/column-text(stmt, col.int32)
fun null(col)
capi/column-type(stmt, col.int32) == capi/int32/null
action(r)

View File

@@ -7,7 +7,7 @@ pub type sqlite-result
Ok
Row
Done
Error-Code(code: sqlite-error, pos: int)
Error-Code(code: sqlite-error)
Ok-Load-Permanently
// Error result codes.
@@ -205,7 +205,7 @@ pub fun int32(r: sqlite-result): int32
Ok -> 0.int32
Row -> 100.int32
Done -> 101.int32
Error-Code(err, _) -> match err
Error-Code(err) -> match err
Error(Nothing) -> 1.int32
Error(Just(Error-Missing-Coll-Seq)) -> 257.int32
Error(Just(Error-Retry)) -> 513.int32
@@ -305,105 +305,105 @@ pub fun int32(r: sqlite-result): int32
// Get the SQLite result corresponding to a result code from the C API.
// Throws an exception if `r` does not correspond to a valid result.
pub fun int32/sqlite-result(r: int32, pos: int = -1): exn sqlite-result
pub fun int32/sqlite-result(r: int32): exn sqlite-result
match r.int
0 -> Ok
256 -> Ok-Load-Permanently
1 -> Error-Code(Error(Nothing), pos)
257 -> Error-Code(Error(Just(Error-Missing-Coll-Seq)), pos)
513 -> Error-Code(Error(Just(Error-Retry)), pos)
769 -> Error-Code(Error(Just(Error-Snapshot)), pos)
2 -> Error-Code(Internal(Nothing), pos)
3 -> Error-Code(Perm(Nothing), pos)
4 -> Error-Code(Abort(Nothing), pos)
516 -> Error-Code(Abort(Just(Abort-Rollback)), pos)
5 -> Error-Code(Busy(Nothing), pos)
261 -> Error-Code(Busy(Just(Busy-Recovery)), pos)
517 -> Error-Code(Busy(Just(Busy-Snapshot)), pos)
773 -> Error-Code(Busy(Just(Busy-Timeout)), pos)
6 -> Error-Code(Locked(Nothing), pos)
262 -> Error-Code(Locked(Just(Locked-Shared-Cache)), pos)
518 -> Error-Code(Locked(Just(Locked-VTab)), pos)
7 -> Error-Code(No-Mem(Nothing), pos)
8 -> Error-Code(Read-Only(Nothing), pos)
264 -> Error-Code(Read-Only(Just(Read-Only-Recovery)), pos)
520 -> Error-Code(Read-Only(Just(Read-Only-Cant-Lock)), pos)
776 -> Error-Code(Read-Only(Just(Read-Only-Rollback)), pos)
1032 -> Error-Code(Read-Only(Just(Read-Only-DB-Moved)), pos)
1288 -> Error-Code(Read-Only(Just(Read-Only-Cant-Init)), pos)
1544 -> Error-Code(Read-Only(Just(Read-Only-Directory)), pos)
9 -> Error-Code(Interrupt(Nothing), pos)
10 -> Error-Code(IO-Err(Nothing), pos)
266 -> Error-Code(IO-Err(Just(IO-Err-Read)), pos)
522 -> Error-Code(IO-Err(Just(IO-Err-Short-Read)), pos)
778 -> Error-Code(IO-Err(Just(IO-Err-Write)), pos)
1034 -> Error-Code(IO-Err(Just(IO-Err-Fsync)), pos)
1290 -> Error-Code(IO-Err(Just(IO-Err-Dir-Fsync)), pos)
1546 -> Error-Code(IO-Err(Just(IO-Err-Truncate)), pos)
1802 -> Error-Code(IO-Err(Just(IO-Err-Fstat)), pos)
2058 -> Error-Code(IO-Err(Just(IO-Err-Unlock)), pos)
2314 -> Error-Code(IO-Err(Just(IO-Err-Read-Lock)), pos)
2570 -> Error-Code(IO-Err(Just(IO-Err-Delete)), pos)
3082 -> Error-Code(IO-Err(Just(IO-Err-No-Mem)), pos)
3338 -> Error-Code(IO-Err(Just(IO-Err-Access)), pos)
3594 -> Error-Code(IO-Err(Just(IO-Err-Check-Reserved-Lock)), pos)
3850 -> Error-Code(IO-Err(Just(IO-Err-Lock)), pos)
4106 -> Error-Code(IO-Err(Just(IO-Err-Close)), pos)
4618 -> Error-Code(IO-Err(Just(IO-Err-Shm-Open)), pos)
4874 -> Error-Code(IO-Err(Just(IO-Err-Shm-Size)), pos)
5386 -> Error-Code(IO-Err(Just(IO-Err-Shm-Map)), pos)
5642 -> Error-Code(IO-Err(Just(IO-Err-Seek)), pos)
5898 -> Error-Code(IO-Err(Just(IO-Err-Delete-No-Ent)), pos)
6154 -> Error-Code(IO-Err(Just(IO-Err-Mmap)), pos)
6410 -> Error-Code(IO-Err(Just(IO-Err-Get-Temp-Path)), pos)
6666 -> Error-Code(IO-Err(Just(IO-Err-Convpath)), pos)
6922 -> Error-Code(IO-Err(Just(IO-Err-Vnode)), pos)
7178 -> Error-Code(IO-Err(Just(IO-Err-Auth)), pos)
7434 -> Error-Code(IO-Err(Just(IO-Err-Begin-Atomic)), pos)
7690 -> Error-Code(IO-Err(Just(IO-Err-Commit-Atomic)), pos)
7946 -> Error-Code(IO-Err(Just(IO-Err-Rollback-Atomic)), pos)
8202 -> Error-Code(IO-Err(Just(IO-Err-Data)), pos)
8458 -> Error-Code(IO-Err(Just(IO-Err-Corrupt-FS)), pos)
11 -> Error-Code(Corrupt(Nothing), pos)
267 -> Error-Code(Corrupt(Just(Corrupt-Vtab)), pos)
523 -> Error-Code(Corrupt(Just(Corrupt-Sequence)), pos)
779 -> Error-Code(Corrupt(Just(Corrupt-Index)), pos)
12 -> Error-Code(Not-Found(Nothing), pos)
13 -> Error-Code(Full(Nothing), pos)
14 -> Error-Code(Cant-Open(Nothing), pos)
526 -> Error-Code(Cant-Open(Just(Cant-Open-Isdir)), pos)
782 -> Error-Code(Cant-Open(Just(Cant-Open-Fullpath)), pos)
1038 -> Error-Code(Cant-Open(Just(Cant-Open-Convpath)), pos)
1294 -> Error-Code(Cant-Open(Just(Cant-Open-DirtyWAL)), pos)
1550 -> Error-Code(Cant-Open(Just(Cant-Open-Symlink)), pos)
15 -> Error-Code(Protocol(Nothing), pos)
17 -> Error-Code(Schema(Nothing), pos)
18 -> Error-Code(Too-Big(Nothing), pos)
19 -> Error-Code(Constraint(Nothing), pos)
275 -> Error-Code(Constraint(Just(Constraint-Check)), pos)
531 -> Error-Code(Constraint(Just(Constraint-Commithook)), pos)
787 -> Error-Code(Constraint(Just(Constraint-Foreignkey)), pos)
1043 -> Error-Code(Constraint(Just(Constraint-Function)), pos)
1299 -> Error-Code(Constraint(Just(Constraint-Notnull)), pos)
1555 -> Error-Code(Constraint(Just(Constraint-Primarykey)), pos)
1811 -> Error-Code(Constraint(Just(Constraint-Trigger)), pos)
2067 -> Error-Code(Constraint(Just(Constraint-Unique)), pos)
2323 -> Error-Code(Constraint(Just(Constraint-VTab)), pos)
2579 -> Error-Code(Constraint(Just(Constraint-Rowid)), pos)
2835 -> Error-Code(Constraint(Just(Constraint-Pinned)), pos)
3091 -> Error-Code(Constraint(Just(Constraint-Datatype)), pos)
20 -> Error-Code(Mismatch(Nothing), pos)
21 -> Error-Code(Misuse(Nothing), pos)
21 -> Error-Code(No-LFS(Nothing), pos)
23 -> Error-Code(Auth(Nothing), pos)
279 -> Error-Code(Auth(Just(Auth-User)), pos)
25 -> Error-Code(Range(Nothing), pos)
26 -> Error-Code(Not-A-DB(Nothing), pos)
27 -> Error-Code(Notice(Nothing), pos)
283 -> Error-Code(Notice(Just(Notice-Recover-WAL)), pos)
539 -> Error-Code(Notice(Just(Notice-Recover-Rollback)), pos)
28 -> Error-Code(Warning(Nothing), pos)
284 -> Error-Code(Warning(Just(Warning-Autoindex)), pos)
1 -> Error-Code(Error(Nothing))
257 -> Error-Code(Error(Just(Error-Missing-Coll-Seq)))
513 -> Error-Code(Error(Just(Error-Retry)))
769 -> Error-Code(Error(Just(Error-Snapshot)))
2 -> Error-Code(Internal(Nothing))
3 -> Error-Code(Perm(Nothing))
4 -> Error-Code(Abort(Nothing))
516 -> Error-Code(Abort(Just(Abort-Rollback)))
5 -> Error-Code(Busy(Nothing))
261 -> Error-Code(Busy(Just(Busy-Recovery)))
517 -> Error-Code(Busy(Just(Busy-Snapshot)))
773 -> Error-Code(Busy(Just(Busy-Timeout)))
6 -> Error-Code(Locked(Nothing))
262 -> Error-Code(Locked(Just(Locked-Shared-Cache)))
518 -> Error-Code(Locked(Just(Locked-VTab)))
7 -> Error-Code(No-Mem(Nothing))
8 -> Error-Code(Read-Only(Nothing))
264 -> Error-Code(Read-Only(Just(Read-Only-Recovery)))
520 -> Error-Code(Read-Only(Just(Read-Only-Cant-Lock)))
776 -> Error-Code(Read-Only(Just(Read-Only-Rollback)))
1032 -> Error-Code(Read-Only(Just(Read-Only-DB-Moved)))
1288 -> Error-Code(Read-Only(Just(Read-Only-Cant-Init)))
1544 -> Error-Code(Read-Only(Just(Read-Only-Directory)))
9 -> Error-Code(Interrupt(Nothing))
10 -> Error-Code(IO-Err(Nothing))
266 -> Error-Code(IO-Err(Just(IO-Err-Read)))
522 -> Error-Code(IO-Err(Just(IO-Err-Short-Read)))
778 -> Error-Code(IO-Err(Just(IO-Err-Write)))
1034 -> Error-Code(IO-Err(Just(IO-Err-Fsync)))
1290 -> Error-Code(IO-Err(Just(IO-Err-Dir-Fsync)))
1546 -> Error-Code(IO-Err(Just(IO-Err-Truncate)))
1802 -> Error-Code(IO-Err(Just(IO-Err-Fstat)))
2058 -> Error-Code(IO-Err(Just(IO-Err-Unlock)))
2314 -> Error-Code(IO-Err(Just(IO-Err-Read-Lock)))
2570 -> Error-Code(IO-Err(Just(IO-Err-Delete)))
3082 -> Error-Code(IO-Err(Just(IO-Err-No-Mem)))
3338 -> Error-Code(IO-Err(Just(IO-Err-Access)))
3594 -> Error-Code(IO-Err(Just(IO-Err-Check-Reserved-Lock)))
3850 -> Error-Code(IO-Err(Just(IO-Err-Lock)))
4106 -> Error-Code(IO-Err(Just(IO-Err-Close)))
4618 -> Error-Code(IO-Err(Just(IO-Err-Shm-Open)))
4874 -> Error-Code(IO-Err(Just(IO-Err-Shm-Size)))
5386 -> Error-Code(IO-Err(Just(IO-Err-Shm-Map)))
5642 -> Error-Code(IO-Err(Just(IO-Err-Seek)))
5898 -> Error-Code(IO-Err(Just(IO-Err-Delete-No-Ent)))
6154 -> Error-Code(IO-Err(Just(IO-Err-Mmap)))
6410 -> Error-Code(IO-Err(Just(IO-Err-Get-Temp-Path)))
6666 -> Error-Code(IO-Err(Just(IO-Err-Convpath)))
6922 -> Error-Code(IO-Err(Just(IO-Err-Vnode)))
7178 -> Error-Code(IO-Err(Just(IO-Err-Auth)))
7434 -> Error-Code(IO-Err(Just(IO-Err-Begin-Atomic)))
7690 -> Error-Code(IO-Err(Just(IO-Err-Commit-Atomic)))
7946 -> Error-Code(IO-Err(Just(IO-Err-Rollback-Atomic)))
8202 -> Error-Code(IO-Err(Just(IO-Err-Data)))
8458 -> Error-Code(IO-Err(Just(IO-Err-Corrupt-FS)))
11 -> Error-Code(Corrupt(Nothing))
267 -> Error-Code(Corrupt(Just(Corrupt-Vtab)))
523 -> Error-Code(Corrupt(Just(Corrupt-Sequence)))
779 -> Error-Code(Corrupt(Just(Corrupt-Index)))
12 -> Error-Code(Not-Found(Nothing))
13 -> Error-Code(Full(Nothing))
14 -> Error-Code(Cant-Open(Nothing))
526 -> Error-Code(Cant-Open(Just(Cant-Open-Isdir)))
782 -> Error-Code(Cant-Open(Just(Cant-Open-Fullpath)))
1038 -> Error-Code(Cant-Open(Just(Cant-Open-Convpath)))
1294 -> Error-Code(Cant-Open(Just(Cant-Open-DirtyWAL)))
1550 -> Error-Code(Cant-Open(Just(Cant-Open-Symlink)))
15 -> Error-Code(Protocol(Nothing))
17 -> Error-Code(Schema(Nothing))
18 -> Error-Code(Too-Big(Nothing))
19 -> Error-Code(Constraint(Nothing))
275 -> Error-Code(Constraint(Just(Constraint-Check)))
531 -> Error-Code(Constraint(Just(Constraint-Commithook)))
787 -> Error-Code(Constraint(Just(Constraint-Foreignkey)))
1043 -> Error-Code(Constraint(Just(Constraint-Function)))
1299 -> Error-Code(Constraint(Just(Constraint-Notnull)))
1555 -> Error-Code(Constraint(Just(Constraint-Primarykey)))
1811 -> Error-Code(Constraint(Just(Constraint-Trigger)))
2067 -> Error-Code(Constraint(Just(Constraint-Unique)))
2323 -> Error-Code(Constraint(Just(Constraint-VTab)))
2579 -> Error-Code(Constraint(Just(Constraint-Rowid)))
2835 -> Error-Code(Constraint(Just(Constraint-Pinned)))
3091 -> Error-Code(Constraint(Just(Constraint-Datatype)))
20 -> Error-Code(Mismatch(Nothing))
21 -> Error-Code(Misuse(Nothing))
21 -> Error-Code(No-LFS(Nothing))
23 -> Error-Code(Auth(Nothing))
279 -> Error-Code(Auth(Just(Auth-User)))
25 -> Error-Code(Range(Nothing))
26 -> Error-Code(Not-A-DB(Nothing))
27 -> Error-Code(Notice(Nothing))
283 -> Error-Code(Notice(Just(Notice-Recover-WAL)))
539 -> Error-Code(Notice(Just(Notice-Recover-Rollback)))
28 -> Error-Code(Warning(Nothing))
284 -> Error-Code(Warning(Just(Warning-Autoindex)))
100 -> Row
101 -> Done
v -> throw("invalid SQLite3 result code " ++ v.show, ExnRange)
@@ -412,21 +412,28 @@ pub fun int32/sqlite-result(r: int32, pos: int = -1): exn sqlite-result
// E.g., `Constraint(Just(Constraint-Unique))` is converted to `Constraint(Nothing)`.
pub fun primary(r: sqlite-result): sqlite-result
match r
Error-Code(Error(Just(_)), pos) -> Error-Code(Error(Nothing), pos)
Error-Code(Abort(Just(_)), pos) -> Error-Code(Abort(Nothing), pos)
Error-Code(Busy(Just(_)), pos) -> Error-Code(Busy(Nothing), pos)
Error-Code(Locked(Just(_)), pos) -> Error-Code(Locked(Nothing), pos)
Error-Code(Read-Only(Just(_)), pos) -> Error-Code(Read-Only(Nothing), pos)
Error-Code(IO-Err(Just(_)), pos) -> Error-Code(IO-Err(Nothing), pos)
Error-Code(Corrupt(Just(_)), pos) -> Error-Code(Corrupt(Nothing), pos)
Error-Code(Cant-Open(Just(_)), pos) -> Error-Code(Cant-Open(Nothing), pos)
Error-Code(Constraint(Just(_)), pos) -> Error-Code(Constraint(Nothing), pos)
Error-Code(Auth(Just(_)), pos) -> Error-Code(Auth(Nothing), pos)
Error-Code(Notice(Just(_)), pos) -> Error-Code(Notice(Nothing), pos)
Error-Code(Warning(Just(_)), pos) -> Error-Code(Warning(Nothing), pos)
Error-Code(Error(Just(_))) -> Error-Code(Error(Nothing))
Error-Code(Abort(Just(_))) -> Error-Code(Abort(Nothing))
Error-Code(Busy(Just(_))) -> Error-Code(Busy(Nothing))
Error-Code(Locked(Just(_))) -> Error-Code(Locked(Nothing))
Error-Code(Read-Only(Just(_))) -> Error-Code(Read-Only(Nothing))
Error-Code(IO-Err(Just(_))) -> Error-Code(IO-Err(Nothing))
Error-Code(Corrupt(Just(_))) -> Error-Code(Corrupt(Nothing))
Error-Code(Cant-Open(Just(_))) -> Error-Code(Cant-Open(Nothing))
Error-Code(Constraint(Just(_))) -> Error-Code(Constraint(Nothing))
Error-Code(Auth(Just(_))) -> Error-Code(Auth(Nothing))
Error-Code(Notice(Just(_))) -> Error-Code(Notice(Nothing))
Error-Code(Warning(Just(_))) -> Error-Code(Warning(Nothing))
Ok-Load-Permanently -> Ok
r -> r
// Get the message corresponding to a result code.
pub fun show(r: sqlite-result): string
capi/errstr(r.int32)
pub extend type exception-info
// Generic exceptions from SQLite3.
ExnSqlite3(code: sqlite-error)
// Exceptions from preparing SQL statements.
// The error may not be due to the SQL text, and therefore the `:pos` may be `-1`.
ExnPrepare(code: sqlite-error, stmt: sslice, pos: int)