initial commit
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
.koka
|
||||
.vscode
|
||||
koka-test.sqlite3
|
||||
27
README.md
Normal file
27
README.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# sqlite
|
||||
|
||||
Koka binding for [SQLite3](https://www.sqlite.org/index.html).
|
||||
|
||||
This package uses the SQLite3 standard amalgamation, version 3.51.2.
|
||||
The following compile-time options are enabled:
|
||||
|
||||
```
|
||||
#define SQLITE_DQS 0
|
||||
#define SQLITE_DEFAULT_MEMSTATUS 0
|
||||
#define SQLITE_LIKE_DOESNT_MATCH_BLOBS
|
||||
#define SQLITE_OMIT_AUTOINIT
|
||||
#define SQLITE_STRICT_SUBTYPE 1
|
||||
#define SQLITE_ENABLE_CARRAY
|
||||
#define SQLITE_ENABLE_COLUMN_METADATA
|
||||
#define SQLITE_ENABLE_DBSTAT_VTAB
|
||||
#define SQLITE_ENABLE_FTS5
|
||||
#define SQLITE_ENABLE_GEOPOLY
|
||||
#define SQLITE_ENABLE_HIDDEN_COLUMNS
|
||||
#define SQLITE_ENABLE_ICU
|
||||
#define SQLITE_ENABLE_MATH_FUNCTIONS
|
||||
#define SQLITE_ENABLE_NORMALIZE
|
||||
#define SQLITE_ENABLE_PERCENTILE
|
||||
#define SQLITE_ENABLE_RTREE
|
||||
#define SQLITE_ENABLE_SESSION
|
||||
#define SQLITE_SOUNDEX
|
||||
```
|
||||
49
sqlite/capi.kk
Normal file
49
sqlite/capi.kk
Normal file
@@ -0,0 +1,49 @@
|
||||
// Minimal SQLite3 C API wrapper.
|
||||
// This module is for internal use and should not be used directly.
|
||||
module sqlite/capi
|
||||
|
||||
pub import std/num/int32
|
||||
|
||||
extern import
|
||||
c file "sqlite-define.c"
|
||||
extern import
|
||||
c file "sqlite3.c"
|
||||
extern import
|
||||
c file "sqlite-inline.c"
|
||||
|
||||
extern make-sqlite-ok(): int32
|
||||
c inline "SQLITE_OK"
|
||||
pub val int32/sqlite-ok: int32 = make-sqlite-ok()
|
||||
|
||||
pub extern initialize(): int32
|
||||
c inline "sqlite3_initialize()"
|
||||
|
||||
pub extern shutdown(): int32
|
||||
c inline "sqlite3_shutdown()"
|
||||
|
||||
pub extern errstr(x: int32): string
|
||||
c "kk_sqlite3_errstr"
|
||||
|
||||
pub extern extended-errcode(^db: any): int32
|
||||
c "kk_sqlite3_extended_errcode"
|
||||
|
||||
pub extern error-offset(^db: any): int
|
||||
c "kk_sqlite3_error_offset"
|
||||
|
||||
pub extern open-v2(^filename: string, flags: int32, ^vfs: string): (any, int32)
|
||||
c "kk_sqlite3_open_v2"
|
||||
|
||||
pub extern close(^db: any): int32
|
||||
c "kk_sqlite3_close"
|
||||
|
||||
pub extern prepare-v3(^db: any, ^sql: sslice, flags: int32): (any, sslice, int32)
|
||||
c "kk_sqlite3_prepare_v3"
|
||||
|
||||
pub extern finalize(^stmt: any): int32
|
||||
c "kk_sqlite3_finalize"
|
||||
|
||||
pub extern step(^stmt: any): int32
|
||||
c "kk_sqlite3_step"
|
||||
|
||||
pub extern reset(^stmt: any): int32
|
||||
c "kk_sqlite3_reset"
|
||||
20
sqlite/sqlite-define.c
Normal file
20
sqlite/sqlite-define.c
Normal file
@@ -0,0 +1,20 @@
|
||||
// Rather than requiring every importer to manage defines,
|
||||
// set some here and include the SQLite3 amalgamation.
|
||||
#define SQLITE_DQS 0
|
||||
#define SQLITE_DEFAULT_MEMSTATUS 0
|
||||
#define SQLITE_LIKE_DOESNT_MATCH_BLOBS
|
||||
#define SQLITE_OMIT_AUTOINIT
|
||||
#define SQLITE_STRICT_SUBTYPE 1
|
||||
#define SQLITE_ENABLE_CARRAY
|
||||
#define SQLITE_ENABLE_COLUMN_METADATA
|
||||
#define SQLITE_ENABLE_DBSTAT_VTAB
|
||||
#define SQLITE_ENABLE_FTS5
|
||||
#define SQLITE_ENABLE_GEOPOLY
|
||||
// #define SQLITE_ENABLE_HIDDEN_COLUMNS
|
||||
// #define SQLITE_ENABLE_ICU
|
||||
#define SQLITE_ENABLE_MATH_FUNCTIONS
|
||||
#define SQLITE_ENABLE_NORMALIZE
|
||||
#define SQLITE_ENABLE_PERCENTILE
|
||||
#define SQLITE_ENABLE_RTREE
|
||||
#define SQLITE_ENABLE_SESSION
|
||||
#define SQLITE_SOUNDEX
|
||||
83
sqlite/sqlite-inline.c
Normal file
83
sqlite/sqlite-inline.c
Normal file
@@ -0,0 +1,83 @@
|
||||
#include <kklib.h>
|
||||
#include <sqlite3.h>
|
||||
|
||||
static inline sqlite3 *borrow_db(kk_box_t cref, kk_context_t *_ctx) {
|
||||
return (sqlite3 *)kk_cptr_unbox_borrowed(cref, _ctx);
|
||||
}
|
||||
|
||||
kk_string_t kk_sqlite3_errstr(int32_t x, kk_context_t *_ctx) {
|
||||
const char *s = sqlite3_errstr((int)x);
|
||||
if (s == NULL) {
|
||||
return kk_string_empty();
|
||||
}
|
||||
return kk_string_alloc_from_utf8(s, _ctx);
|
||||
}
|
||||
|
||||
int32_t kk_sqlite3_extended_errcode(kk_box_t cref, kk_context_t *_ctx) {
|
||||
sqlite3 *db = borrow_db(cref, _ctx);
|
||||
return (int32_t)sqlite3_extended_errcode(db);
|
||||
}
|
||||
|
||||
kk_integer_t kk_sqlite3_error_offset(kk_box_t cref, kk_context_t *_ctx) {
|
||||
sqlite3 *db = borrow_db(cref, _ctx);
|
||||
int r = sqlite3_error_offset(db);
|
||||
return kk_integer_from_int(r, _ctx);
|
||||
}
|
||||
|
||||
kk_std_core_types__tuple2 kk_sqlite3_open_v2(kk_string_t filename, int32_t flags, kk_string_t vfs, kk_context_t *_ctx) {
|
||||
kk_ssize_t vfs_len = 0;
|
||||
const char *name = kk_string_cbuf_borrow(filename, NULL, _ctx);
|
||||
const char *v = kk_string_cbuf_borrow(vfs, &vfs_len, _ctx);
|
||||
sqlite3 *db = NULL;
|
||||
int r = sqlite3_open_v2(name, &db, (int)flags, vfs_len != 0 ? v : NULL);
|
||||
return kk_std_core_types__new_Tuple2(kk_box_box(kk_cptr_box(db, _ctx), _ctx), kk_int32_box((int32_t)r, _ctx), _ctx);
|
||||
}
|
||||
|
||||
int32_t kk_sqlite3_close(kk_box_t cref, kk_context_t *_ctx) {
|
||||
sqlite3 *db = borrow_db(cref, _ctx);
|
||||
return (int32_t)sqlite3_close(db);
|
||||
}
|
||||
|
||||
kk_std_core_types__tuple3 kk_sqlite3_prepare_v3(kk_box_t cref, kk_std_core_sslice__sslice sql, int32_t flags, kk_context_t *_ctx) {
|
||||
kk_box_t fst, snd, thd;
|
||||
sqlite3 *db = borrow_db(cref, _ctx);
|
||||
|
||||
kk_intx_t sql_start = kk_integer_clamp_borrow(sql.start, _ctx);
|
||||
kk_intx_t sql_len = kk_integer_clamp_borrow(sql.len, _ctx);
|
||||
// TODO(zephyr): instead of borrowing and then duping to construct left,
|
||||
// check whether we can replace the reference
|
||||
const char *sql_bytes = kk_string_cbuf_borrow(sql.str, NULL, _ctx) + sql_start;
|
||||
|
||||
sqlite3_stmt *stmt = NULL;
|
||||
const char *left_bytes = NULL;
|
||||
int r = sqlite3_prepare_v3(db, sql_bytes, (int)sql_len, flags, &stmt, &left_bytes);
|
||||
|
||||
kk_std_core_sslice__sslice left = {
|
||||
.str = kk_string_dup(sql.str, _ctx),
|
||||
.start = kk_integer_from_int(sql_start + (left_bytes - sql_bytes), _ctx),
|
||||
.len = kk_integer_from_int(sql_len - (left_bytes - sql_bytes), _ctx),
|
||||
};
|
||||
fst = kk_box_box(kk_cptr_box(stmt, _ctx), _ctx);
|
||||
snd = kk_std_core_sslice__sslice_box(left, _ctx);
|
||||
thd = kk_int32_box((int32_t)r, _ctx);
|
||||
return kk_std_core_types__new_Tuple3(fst, snd, thd, _ctx);
|
||||
}
|
||||
|
||||
static inline sqlite3_stmt *borrow_stmt(kk_box_t cref, kk_context_t *_ctx) {
|
||||
return (sqlite3_stmt *)kk_cptr_unbox_borrowed(cref, _ctx);
|
||||
}
|
||||
|
||||
int32_t kk_sqlite3_finalize(kk_box_t cref, kk_context_t *_ctx) {
|
||||
sqlite3_stmt *stmt = borrow_stmt(cref, _ctx);
|
||||
return (int32_t)sqlite3_finalize(stmt);
|
||||
}
|
||||
|
||||
int32_t kk_sqlite3_step(kk_box_t cref, kk_context_t *_ctx) {
|
||||
sqlite3_stmt *stmt = borrow_stmt(cref, _ctx);
|
||||
return (int32_t)sqlite3_step(stmt);
|
||||
}
|
||||
|
||||
int32_t kk_sqlite3_reset(kk_box_t cref, kk_context_t *_ctx) {
|
||||
sqlite3_stmt *stmt = borrow_stmt(cref, _ctx);
|
||||
return (int32_t)sqlite3_reset(stmt);
|
||||
}
|
||||
432
sqlite/sqlite-result.kk
Normal file
432
sqlite/sqlite-result.kk
Normal file
@@ -0,0 +1,432 @@
|
||||
module sqlite/sqlite-result
|
||||
|
||||
import sqlite/capi
|
||||
|
||||
// Result codes returned from SQLite3 C API routines.
|
||||
pub type sqlite-result
|
||||
Ok
|
||||
Row
|
||||
Done
|
||||
Error-Code(code: sqlite-error, pos: int)
|
||||
Ok-Load-Permanently
|
||||
|
||||
// Error result codes.
|
||||
//
|
||||
// The base variants correspond to the primary result codes.
|
||||
// With the exception of `SQLITE_OK_LOAD_PERMANENTLY`, extended result codes
|
||||
// are represented by an additional argument to the primary result code's constructor.
|
||||
// All error codes carry the field for such arguments, even if there is no
|
||||
// extended result code associated with it, so that wildcard pattern matches
|
||||
// do not need to update if new extended result codes are added in the future.
|
||||
pub type sqlite-error
|
||||
Error(ext: maybe<ext-error>)
|
||||
Internal(ext: maybe<ext-internal>)
|
||||
Perm(ext: maybe<ext-perm>)
|
||||
Abort(ext: maybe<ext-abort>)
|
||||
Busy(ext: maybe<ext-busy>)
|
||||
Locked(ext: maybe<ext-locked>)
|
||||
No-Mem(ext: maybe<ext-no-mem>)
|
||||
Read-Only(ext: maybe<ext-read-only>)
|
||||
Interrupt(ext: maybe<ext-interrupt>)
|
||||
IO-Err(ext: maybe<ext-io-err>)
|
||||
Corrupt(ext: maybe<ext-corrupt>)
|
||||
Not-Found(ext: maybe<ext-not-found>)
|
||||
Full(ext: maybe<ext-full>)
|
||||
Cant-Open(ext: maybe<ext-cant-open>)
|
||||
Protocol(ext: maybe<ext-protocol>)
|
||||
Schema(ext: maybe<ext-schema>)
|
||||
Too-Big(ext: maybe<ext-too-big>)
|
||||
Constraint(ext: maybe<ext-constraint>)
|
||||
Mismatch(ext: maybe<ext-mismatch>)
|
||||
Misuse(ext: maybe<ext-misuse>)
|
||||
No-LFS(ext: maybe<ext-no-lfs>)
|
||||
Auth(ext: maybe<ext-auth>)
|
||||
Range(ext: maybe<ext-range>)
|
||||
Not-A-DB(ext: maybe<ext-not-a-db>)
|
||||
Notice(ext: maybe<ext-notice>)
|
||||
Warning(ext: maybe<ext-warning>)
|
||||
// Empty(ext: maybe<ext-empty>) // unused
|
||||
// Format(ext: maybe<ext-format>) // unused
|
||||
|
||||
// Extended result codes for the `ERROR` primary result code.
|
||||
pub type ext-error
|
||||
Error-Missing-Coll-Seq
|
||||
Error-Retry
|
||||
Error-Snapshot
|
||||
|
||||
// Extended result codes for the `INTERNAL` primary result code.
|
||||
pub type ext-internal
|
||||
|
||||
// Extended result codes for the `PERM` primary result code.
|
||||
pub type ext-perm
|
||||
|
||||
// Extended result codes for the `ABORT` primary result code.
|
||||
pub type ext-abort
|
||||
Abort-Rollback
|
||||
|
||||
// Extended result codes for the `BUSY` primary result code.
|
||||
pub type ext-busy
|
||||
Busy-Recovery
|
||||
Busy-Snapshot
|
||||
Busy-Timeout
|
||||
|
||||
// Extended result codes for the `LOCKED` primary result code.
|
||||
pub type ext-locked
|
||||
Locked-Shared-Cache
|
||||
Locked-VTab
|
||||
|
||||
// Extended result codes for the `NOMEM` primary result code.
|
||||
pub type ext-no-mem
|
||||
|
||||
// Extended result codes for the `READONLY` primary result code.
|
||||
pub type ext-read-only
|
||||
Read-Only-Recovery
|
||||
Read-Only-Cant-Lock
|
||||
Read-Only-Rollback
|
||||
Read-Only-DB-Moved
|
||||
Read-Only-Cant-Init
|
||||
Read-Only-Directory
|
||||
|
||||
// Extended result codes for the `INTERRUPT` primary result code.
|
||||
pub type ext-interrupt
|
||||
|
||||
// Extended result codes for the `IOERR` primary result code.
|
||||
pub type ext-io-err
|
||||
IO-Err-Read
|
||||
IO-Err-Short-Read
|
||||
IO-Err-Write
|
||||
IO-Err-Fsync
|
||||
IO-Err-Dir-Fsync
|
||||
IO-Err-Truncate
|
||||
IO-Err-Fstat
|
||||
IO-Err-Unlock
|
||||
IO-Err-Read-Lock
|
||||
IO-Err-Delete
|
||||
IO-Err-No-Mem
|
||||
IO-Err-Access
|
||||
IO-Err-Check-Reserved-Lock
|
||||
IO-Err-Lock
|
||||
IO-Err-Close
|
||||
IO-Err-Shm-Open
|
||||
IO-Err-Shm-Size
|
||||
IO-Err-Shm-Map
|
||||
IO-Err-Seek
|
||||
IO-Err-Delete-No-Ent
|
||||
IO-Err-Mmap
|
||||
IO-Err-Get-Temp-Path
|
||||
IO-Err-Convpath
|
||||
IO-Err-Vnode
|
||||
IO-Err-Auth
|
||||
IO-Err-Begin-Atomic
|
||||
IO-Err-Commit-Atomic
|
||||
IO-Err-Rollback-Atomic
|
||||
IO-Err-Data
|
||||
IO-Err-Corrupt-FS
|
||||
// IO-Err-Blocked // unused
|
||||
// IO-Err-Dir-Close // unused
|
||||
// IO-Err-Shm-Lock // unused
|
||||
|
||||
// Extended result codes for the `CORRUPT` primary result code.
|
||||
pub type ext-corrupt
|
||||
Corrupt-Vtab
|
||||
Corrupt-Sequence
|
||||
Corrupt-Index
|
||||
|
||||
// Extended result codes for the `NOTFOUND` primary result code.
|
||||
pub type ext-not-found
|
||||
|
||||
// Extended result codes for the `FULL` primary result code.
|
||||
pub type ext-full
|
||||
|
||||
// Extended result codes for the `CANTOPEN` primary result code.
|
||||
pub type ext-cant-open
|
||||
Cant-Open-Isdir
|
||||
Cant-Open-Fullpath
|
||||
Cant-Open-Convpath
|
||||
Cant-Open-DirtyWAL
|
||||
Cant-Open-Symlink
|
||||
// Cant-Open-Notempdir // unused
|
||||
|
||||
// Extended result codes for the `PROTOCOL` primary result code.
|
||||
pub type ext-protocol
|
||||
|
||||
// Extended result codes for the `SCHEMA` primary result code.
|
||||
pub type ext-schema
|
||||
|
||||
// Extended result codes for the `TOOBIG` primary result code.
|
||||
pub type ext-too-big
|
||||
|
||||
// Extended result codes for the `CONSTRAINT` primary result code.
|
||||
pub type ext-constraint
|
||||
Constraint-Check
|
||||
Constraint-Commithook
|
||||
Constraint-Foreignkey
|
||||
Constraint-Function
|
||||
Constraint-Notnull
|
||||
Constraint-Primarykey
|
||||
Constraint-Trigger
|
||||
Constraint-Unique
|
||||
Constraint-VTab
|
||||
Constraint-Rowid
|
||||
Constraint-Pinned
|
||||
Constraint-Datatype
|
||||
|
||||
// Extended result codes for the `MISMATCH` primary result code.
|
||||
pub type ext-mismatch
|
||||
|
||||
// Extended result codes for the `MISUSE` primary result code.
|
||||
pub type ext-misuse
|
||||
|
||||
// Extended result codes for the `NOLFS` primary result code.
|
||||
pub type ext-no-lfs
|
||||
|
||||
// Extended result codes for the `AUTH` primary result code.
|
||||
pub type ext-auth
|
||||
Auth-User
|
||||
|
||||
// Extended result codes for the `RANGE` primary result code.
|
||||
pub type ext-range
|
||||
|
||||
// Extended result codes for the `NOTADB` primary result code.
|
||||
pub type ext-not-a-db
|
||||
|
||||
// Extended result codes for the `NOTICE` primary result code.
|
||||
pub type ext-notice
|
||||
Notice-Recover-WAL
|
||||
Notice-Recover-Rollback
|
||||
|
||||
// Extended result codes for the `WARNING` primary result code.
|
||||
pub type ext-warning
|
||||
Warning-Autoindex
|
||||
|
||||
// Convert an SQLite3 result to its integer value.
|
||||
pub fun int32(r: sqlite-result): int32
|
||||
match r
|
||||
Ok -> 0.int32
|
||||
Row -> 100.int32
|
||||
Done -> 101.int32
|
||||
Error-Code(err, _) -> match err
|
||||
Error(Nothing) -> 1.int32
|
||||
Error(Just(Error-Missing-Coll-Seq)) -> 257.int32
|
||||
Error(Just(Error-Retry)) -> 513.int32
|
||||
Error(Just(Error-Snapshot)) -> 769.int32
|
||||
Internal(_) -> 2.int32
|
||||
Perm(_) -> 3.int32
|
||||
Abort(Nothing) -> 4.int32
|
||||
Abort(Just(Abort-Rollback)) -> 516.int32
|
||||
Busy(Nothing) -> 5.int32
|
||||
Busy(Just(Busy-Recovery)) -> 261.int32
|
||||
Busy(Just(Busy-Snapshot)) -> 517.int32
|
||||
Busy(Just(Busy-Timeout)) -> 773.int32
|
||||
Locked(Nothing) -> 6.int32
|
||||
Locked(Just(Locked-Shared-Cache)) -> 262.int32
|
||||
Locked(Just(Locked-VTab)) -> 518.int32
|
||||
No-Mem(_) -> 7.int32
|
||||
Read-Only(Nothing) -> 8.int32
|
||||
Read-Only(Just(Read-Only-Recovery)) -> 264.int32
|
||||
Read-Only(Just(Read-Only-Cant-Lock)) -> 520.int32
|
||||
Read-Only(Just(Read-Only-Rollback)) -> 776.int32
|
||||
Read-Only(Just(Read-Only-DB-Moved)) -> 1032.int32
|
||||
Read-Only(Just(Read-Only-Cant-Init)) -> 1288.int32
|
||||
Read-Only(Just(Read-Only-Directory)) -> 1544.int32
|
||||
Interrupt(_) -> 9.int32
|
||||
IO-Err(Nothing) -> 10.int32
|
||||
IO-Err(Just(IO-Err-Read)) -> 266.int32
|
||||
IO-Err(Just(IO-Err-Short-Read)) -> 522.int32
|
||||
IO-Err(Just(IO-Err-Write)) -> 778.int32
|
||||
IO-Err(Just(IO-Err-Fsync)) -> 1034.int32
|
||||
IO-Err(Just(IO-Err-Dir-Fsync)) -> 1290.int32
|
||||
IO-Err(Just(IO-Err-Truncate)) -> 1546.int32
|
||||
IO-Err(Just(IO-Err-Fstat)) -> 1802.int32
|
||||
IO-Err(Just(IO-Err-Unlock)) -> 2058.int32
|
||||
IO-Err(Just(IO-Err-Read-Lock)) -> 2314.int32
|
||||
IO-Err(Just(IO-Err-Delete)) -> 2570.int32
|
||||
IO-Err(Just(IO-Err-No-Mem)) -> 3082.int32
|
||||
IO-Err(Just(IO-Err-Access)) -> 3338.int32
|
||||
IO-Err(Just(IO-Err-Check-Reserved-Lock)) -> 3594.int32
|
||||
IO-Err(Just(IO-Err-Lock)) -> 3850.int32
|
||||
IO-Err(Just(IO-Err-Close)) -> 4106.int32
|
||||
IO-Err(Just(IO-Err-Shm-Open)) -> 4618.int32
|
||||
IO-Err(Just(IO-Err-Shm-Size)) -> 4874.int32
|
||||
IO-Err(Just(IO-Err-Shm-Map)) -> 5386.int32
|
||||
IO-Err(Just(IO-Err-Seek)) -> 5642.int32
|
||||
IO-Err(Just(IO-Err-Delete-No-Ent)) -> 5898.int32
|
||||
IO-Err(Just(IO-Err-Mmap)) -> 6154.int32
|
||||
IO-Err(Just(IO-Err-Get-Temp-Path)) -> 6410.int32
|
||||
IO-Err(Just(IO-Err-Convpath)) -> 6666.int32
|
||||
IO-Err(Just(IO-Err-Vnode)) -> 6922.int32
|
||||
IO-Err(Just(IO-Err-Auth)) -> 7178.int32
|
||||
IO-Err(Just(IO-Err-Begin-Atomic)) -> 7434.int32
|
||||
IO-Err(Just(IO-Err-Commit-Atomic)) -> 7690.int32
|
||||
IO-Err(Just(IO-Err-Rollback-Atomic)) -> 7946.int32
|
||||
IO-Err(Just(IO-Err-Data)) -> 8202.int32
|
||||
IO-Err(Just(IO-Err-Corrupt-FS)) -> 8458.int32
|
||||
Corrupt(Nothing) -> 11.int32
|
||||
Corrupt(Just(Corrupt-Vtab)) -> 267.int32
|
||||
Corrupt(Just(Corrupt-Sequence)) -> 523.int32
|
||||
Corrupt(Just(Corrupt-Index)) -> 779.int32
|
||||
Not-Found(_) -> 12.int32
|
||||
Full(_) -> 13.int32
|
||||
Cant-Open(Nothing) -> 14.int32
|
||||
Cant-Open(Just(Cant-Open-Isdir)) -> 526.int32
|
||||
Cant-Open(Just(Cant-Open-Fullpath)) -> 782.int32
|
||||
Cant-Open(Just(Cant-Open-Convpath)) -> 1038.int32
|
||||
Cant-Open(Just(Cant-Open-DirtyWAL)) -> 1294.int32
|
||||
Cant-Open(Just(Cant-Open-Symlink)) -> 1550.int32
|
||||
Protocol(_) -> 15.int32
|
||||
Schema(_) -> 17.int32
|
||||
Too-Big(_) -> 18.int32
|
||||
Constraint(Nothing) -> 19.int32
|
||||
Constraint(Just(Constraint-Check)) -> 275.int32
|
||||
Constraint(Just(Constraint-Commithook)) -> 531.int32
|
||||
Constraint(Just(Constraint-Foreignkey)) -> 787.int32
|
||||
Constraint(Just(Constraint-Function)) -> 1043.int32
|
||||
Constraint(Just(Constraint-Notnull)) -> 1299.int32
|
||||
Constraint(Just(Constraint-Primarykey)) -> 1555.int32
|
||||
Constraint(Just(Constraint-Trigger)) -> 1811.int32
|
||||
Constraint(Just(Constraint-Unique)) -> 2067.int32
|
||||
Constraint(Just(Constraint-VTab)) -> 2323.int32
|
||||
Constraint(Just(Constraint-Rowid)) -> 2579.int32
|
||||
Constraint(Just(Constraint-Pinned)) -> 2835.int32
|
||||
Constraint(Just(Constraint-Datatype)) -> 3091.int32
|
||||
Mismatch(_) -> 20.int32
|
||||
Misuse(_) -> 21.int32
|
||||
No-LFS(_) -> 21.int32
|
||||
Auth(Nothing) -> 23.int32
|
||||
Auth(Just(Auth-User)) -> 279.int32
|
||||
Range(_) -> 25.int32
|
||||
Not-A-DB(_) -> 26.int32
|
||||
Notice(Nothing) -> 27.int32
|
||||
Notice(Just(Notice-Recover-WAL)) -> 283.int32
|
||||
Notice(Just(Notice-Recover-Rollback)) -> 539.int32
|
||||
Warning(Nothing) -> 28.int32
|
||||
Warning(Just(Warning-Autoindex)) -> 284.int32
|
||||
Ok-Load-Permanently -> 256.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
|
||||
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)
|
||||
100 -> Row
|
||||
101 -> Done
|
||||
v -> throw("invalid SQLite3 result code " ++ v.show, ExnRange)
|
||||
|
||||
// Convert an SQLite result to its corresponding primary 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)
|
||||
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)
|
||||
265952
sqlite/sqlite3.c
Normal file
265952
sqlite/sqlite3.c
Normal file
File diff suppressed because it is too large
Load Diff
13968
sqlite/sqlite3.h
Normal file
13968
sqlite/sqlite3.h
Normal file
File diff suppressed because it is too large
Load Diff
116
sqlite/sqlite3.kk
Normal file
116
sqlite/sqlite3.kk
Normal file
@@ -0,0 +1,116 @@
|
||||
// Low level wrapper around a modern subset of the SQLite3 API.
|
||||
//
|
||||
// Using this module involves manual resource management.
|
||||
//
|
||||
module sqlite/sqlite3
|
||||
|
||||
import sqlite/capi
|
||||
pub import sqlite/sqlite-result
|
||||
|
||||
// Helper to convert error codes returned directly from SQLite3 to the
|
||||
// corresponding objects.
|
||||
fun trusted-result(r: int32, pos: int = -1): sqlite-result
|
||||
with final ctl throw-exn(exn) impossible(exn.message)
|
||||
r.sqlite-result(pos)
|
||||
|
||||
// Database handle. An sqlite3 object is obtained by calling one of `open`,
|
||||
// `open-existing`, or `read-only` and must be `close`d once all use is finished.
|
||||
abstract struct sqlite3
|
||||
cref: any
|
||||
|
||||
// Get the result code and position of the last operation.
|
||||
pub fun last-result(db: sqlite3): sqlite-result
|
||||
capi/extended-errcode(db.cref).trusted-result(capi/error-offset(db.cref))
|
||||
|
||||
///////////// System lifetime /////////////
|
||||
|
||||
// NOTE(zephyr): sqlite3/initialize has the qualifier on its name because
|
||||
// type inference doesn't know whether to select this one or the capi function
|
||||
// when constructing startup-initialized below, and there's no way to specify
|
||||
// this one without the qualifier.
|
||||
// This is probably a Koka bug.
|
||||
|
||||
// Initialize SQLite3.
|
||||
// This function is automatically called during program initialization;
|
||||
// see `startup-initialized`.
|
||||
// If there is a call to `shutdown`, then there must be another call to
|
||||
// `initialize` before the next use of any other SQLite3 function.
|
||||
pub fun sqlite3/initialize(): sqlite-result
|
||||
capi/initialize().trusted-result
|
||||
|
||||
// Release resources held by SQLite3.
|
||||
// There must not be any `sqlite3` object which is not closed.
|
||||
pub fun sqlite3/shutdown(): sqlite-result
|
||||
capi/shutdown().trusted-result
|
||||
|
||||
// The result of initializing SQLite3 during program startup.
|
||||
pub val startup-initialized = sqlite3/initialize()
|
||||
|
||||
///////////// Database lifetime /////////////
|
||||
|
||||
// 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.
|
||||
|
||||
fun open-raw(name: db-name, base-flags: int32, sync-mode: sync-mode, vfs: string): (sqlite3, sqlite-result)
|
||||
val flags = match sync-mode
|
||||
Single-Thread -> base-flags.or(0x02000000.i32) // | EXRESCODE
|
||||
Multi-Thread -> base-flags.or(0x02008000.i32) // | EXRESCODE | NOMUTEX
|
||||
Serialized -> base-flags.or(0x02010000.i32) // | EXRESCODE | FULLMUTEX
|
||||
val (db, r) = match name
|
||||
Filename(path) -> capi/open-v2(path, flags, vfs)
|
||||
URI(uri) -> capi/open-v2(uri, flags.or(0x00000040.i32), vfs) // | URI
|
||||
Memory-Shared(name) -> capi/open-v2("file:" ++ name ++ "?mode=memory&cache=shared", flags.or(0x000200C0.i32), vfs) // | URI | SHAREDCACHE | MEMORY
|
||||
Memory -> capi/open-v2(":memory:", flags.or(0x00000080.i32), vfs) // | MEMORY
|
||||
(Sqlite3(db), r.trusted-result)
|
||||
|
||||
// Open or create a database in read-write mode.
|
||||
pub fun open(name: db-name, sync-mode: sync-mode = Serialized, vfs: string = ""): (sqlite3, sqlite-result)
|
||||
open-raw(name, 6.i32, sync-mode, vfs)
|
||||
|
||||
// Open an existing database in read-write mode.
|
||||
pub fun open-existing(name: db-name, sync-mode: sync-mode = Serialized, vfs: string = ""): (sqlite3, sqlite-result)
|
||||
open-raw(name, 2.i32, sync-mode, vfs)
|
||||
|
||||
// Open a database in read-only mode.
|
||||
pub fun read-only(name: db-name, sync-mode: sync-mode = Serialized, vfs: string = ""): (sqlite3, sqlite-result)
|
||||
open-raw(name, 1.i32, sync-mode, vfs)
|
||||
|
||||
pub fun close(db: sqlite3): sqlite-result
|
||||
capi/close(db.cref).trusted-result
|
||||
|
||||
///////////// Statements /////////////
|
||||
|
||||
// Prepared SQL statement.
|
||||
// Corresponds to `sqlite3_stmt *` in the C API.
|
||||
abstract struct statement
|
||||
cref: any
|
||||
|
||||
pub fun prepare(db: sqlite3, sql: sslice, persistent: bool = False, disable-vtab: bool = False, disable-log: bool = False): either<sqlite-result, (statement, sslice)>
|
||||
val flags = 0.i32
|
||||
.or(persistent.int32 * 0x01.i32)
|
||||
.or(disable-vtab.int32 * 0x04.i32)
|
||||
.or(disable-log.int32 * 0x10.i32)
|
||||
val (stmt, left, r) = capi/prepare-v3(db.cref, sql, flags)
|
||||
if r == int32/sqlite-ok then
|
||||
Right((Statement(stmt), left))
|
||||
else
|
||||
Left(r.trusted-result(capi/error-offset(db.cref)))
|
||||
|
||||
pub fun statement/finalize(stmt: statement): sqlite-result
|
||||
capi/finalize(stmt.cref).trusted-result
|
||||
|
||||
pub fun statement/step(stmt: statement): sqlite-result
|
||||
capi/step(stmt.cref).trusted-result
|
||||
|
||||
pub fun statement/reset(stmt: statement): sqlite-result
|
||||
capi/reset(stmt.cref).trusted-result
|
||||
17
test.nix.sh
Executable file
17
test.nix.sh
Executable file
@@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env nix-shell
|
||||
#! nix-shell -i bash --pure
|
||||
#! nix-shell -p sqlite koka
|
||||
#! nix-shell -I https://github.com/NixOS/nixpkgs/archive/e764fc9a405871f1f6ca3d1394fb422e0a0c3951.tar.gz
|
||||
|
||||
set -e
|
||||
|
||||
koka -e --ccincdir=./sqlite test/test.kk
|
||||
|
||||
RESULT=$(sqlite3 koka-test.sqlite3 'SELECT * FROM koka')
|
||||
if [[ "$RESULT" != "value inserted from koka" ]]; then
|
||||
echo "FAIL"
|
||||
echo "want: value inserted from koka"
|
||||
echo " got: $RESULT"
|
||||
else
|
||||
echo "PASS"
|
||||
fi
|
||||
27
test/test.kk
Normal file
27
test/test.kk
Normal file
@@ -0,0 +1,27 @@
|
||||
module test
|
||||
|
||||
import sqlite/sqlite3
|
||||
|
||||
// TODO(zephyr): For now, we're just doing a very basic test to estimate whether
|
||||
// I'm doing Koka FFI correctly. An actual test suite would be excellent.
|
||||
|
||||
fun stmt(db: sqlite3, text: string)
|
||||
println(text)
|
||||
match db.prepare(text.slice)
|
||||
Left(r-prep) -> println(" prepare result: " ++ r-prep.show)
|
||||
Right((stmt, rest)) ->
|
||||
println(" prepare remainder: " ++ rest.show)
|
||||
val r-step = stmt.step
|
||||
println(" step result: " ++ r-step.show)
|
||||
val r-fin = stmt.finalize
|
||||
println(" finalize result: " ++ r-fin.show)
|
||||
|
||||
pub fun main()
|
||||
println("initialize result: " ++ startup-initialized.show)
|
||||
val (db, r-open) = open(Filename("koka-test.sqlite3"))
|
||||
println("open result: " ++ r-open.show)
|
||||
stmt(db, "DROP TABLE IF EXISTS koka; -- reset previous test runs")
|
||||
stmt(db, "CREATE TABLE koka(v TEXT NOT NULL)")
|
||||
stmt(db, "INSERT INTO koka VALUES ('value inserted from koka');")
|
||||
val r-close = db.close
|
||||
println("close result: " ++ r-close.show)
|
||||
Reference in New Issue
Block a user