commit e84153de97a14dc5227b415cdd4577a044ec0b73 from: Omar Polo date: Sun Dec 31 09:48:45 2023 UTC import sqlite module Still very WIP (much like everything else...) but I like how it's coming. commit - efbc6291524c83d55010c44b32b07eda0f06059e commit + e84153de97a14dc5227b415cdd4577a044ec0b73 blob - /dev/null blob + 0a7a7c5a753b4131d9718194754a7cc1ac97e78f (mode 644) --- /dev/null +++ sqlite3/errors.ha @@ -0,0 +1,52 @@ +// This is free and unencumbered software released into the public domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +def sqlite_ok: int = 0; +def sqlite_row: int = 100; +def sqlite_done: int = 101; + +export type sqlite_error = !void; +export type sqlite_internal = !void; +export type sqlite_perm = !void; +export type sqlite_abort = !void; +export type sqlite_busy = !void; +export type sqlite_locked = !void; +// ... +export type sqlite_unknown_error = !void; + +export type unknown_parameter = !void; + +export type error = !(sqlite_error | sqlite_internal | sqlite_perm | + sqlite_abort | sqlite_busy | sqlite_locked | + sqlite_unknown_error); + +export fn strerror(err: error) str = { + return ""; +}; + +fn code2err(code: int) error = { + switch (code) { + case 1 => return sqlite_error; + case => return sqlite_unknown_error; + }; +}; blob - /dev/null blob + 9d2a989972eac004d8e9c43de1fa2e2dfa20ff4a (mode 644) --- /dev/null +++ sqlite3/sqlite3.ha @@ -0,0 +1,246 @@ +// This is free and unencumbered software released into the public domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +use strings; +use types; +use types::c; + +export type sqlite3 = *opaque; +export type statement = *opaque; + +export def OPEN_READONLY: int = 0x00000001; +export def OPEN_READWRITE: int = 0x00000002; +export def OPEN_CREATE: int = 0x00000004; +export def OPEN_DELETEONCLOSE: int = 0x00000008; // VFS only +export def OPEN_EXCLUSIVE: int = 0x00000010; // VFS only +export def OPEN_AUTOPROXY: int = 0x00000020; // VFS only +export def OPEN_URI: int = 0x00000040; +// ... +export def OPEN_NOMUTEX: int = 0x00008000; +// .. +export def OPEN_WAL: int = 0x00080000; // VFS only +export def OPEN_NOFOLLOW: int = 0x01000000; +export def OPEN_EXRESCODE: int = 0x02000000; + +export def def_open_flags = OPEN_READWRITE | OPEN_CREATE | OPEN_WAL | + OPEN_URI | OPEN_NOMUTEX; + +@symbol("sqlite3_open_v2") fn libsqlite3_open_v2( + filename: *const c::char, + sqlite3: *opaque, + flags: int, + vfs: nullable *const c::char, +) int; + +// XXX vfs support? +export fn open(filename: const str, flags: int...) (sqlite3 | error) = { + let f = if (len(flags) == 0) def_open_flags else flags[0]; + + let path = c::fromstr(filename); + defer free(path); + + let addr: uintptr = 0; + let ret = libsqlite3_open_v2(path, &addr: *opaque, f, null); + if (ret == sqlite_ok) { + return (addr: *opaque): sqlite3; + }; + return code2err(ret); +}; + +@symbol("sqlite3_close_v2") fn libsqlite3_close_v2(sqlite3: *opaque) int; + +export fn close(db: sqlite3) (void | error) = { + let ret = libsqlite3_close_v2(db: *opaque); + if (ret != sqlite_ok) { + return code2err(ret); + }; +}; + +@symbol("sqlite3_prepare_v2") fn libsqlite3_prepare_v2( + sqlite3: *opaque, + sql: *const c::char, + nbyte: int, + stmt: *opaque, + tail: nullable *opaque, +) int; + +export fn prepare(db: sqlite3, sql: const str) (statement | error) = { + let s = c::fromstr(sql); + defer free(s); + + let stmt: uintptr = 0; + let ret = libsqlite3_prepare_v2(db: *opaque, s, -1, &stmt: *opaque, + null); + if (ret == sqlite_ok) { + return stmt: statement; + }; + return code2err(ret); +}; + +// XXX missing +// sqlite3_bind_blob +// sqlite3_bind_blob64 +// sqlite3_bind_double + +@symbol("sqlite3_bind_parameter_index") fn libsqlite3_bind_parameter_index( + stmt: *opaque, + name: *const c::char, +) int; + +fn bind_parameter_index(stmt: statement, col: (str | int)) (int | error) = { + let name = match (col) { + case let n: int => return n; + case let n: str => yield n; + }; + + let n = c::fromstr(name); + defer free(n); + + let ret = libsqlite3_bind_parameter_index(stmt: *opaque, n); + if (ret == 0) { + return sqlite_error; + }; + + return ret; +}; + +@symbol("sqlite3_bind_int") fn libsqlite3_bind_int( + stmt: *opaque, + col: int, + val: int, +) int; + +export fn bind_int(stmt: statement, col: (str | int), v: int) (void | error) = { + let n = bind_parameter_index(stmt, col)?; + let ret = libsqlite3_bind_int(stmt: *opaque, n, v); + if (ret != sqlite_ok) { + return code2err(ret); + }; +}; + +@symbol("sqlite3_bind_null") fn libsqlite3_bind_null( + stmt: *opaque, + col: int, +) int; + +export fn bind_null(stmt: statement, col: (str | int)) (void | error) = { + let n = bind_parameter_index(stmt, col)?; + let ret = libsqlite3_bind_null(stmt: *opaque, n); + if (ret != sqlite_ok) { + return code2err(ret); + }; +}; + +fn freecstr(s: *opaque) void = free(s: *c::char); + +@symbol("sqlite3_bind_text") fn libsqlite3_bind_text( + stmt: *opaque, + col: int, + val: *const c::char, + bytelen: int, + freefn: *fn(*opaque) void +) int; + +export fn bind_text(stmt: statement, col: (str | int), v: str) (void | error) = { + let n = bind_parameter_index(stmt, col)?; + + let s = c::fromstr(v); + // free'd via the callback + + let ret = libsqlite3_bind_text(stmt: *opaque, n, s, -1, &freecstr); + if (ret != sqlite_ok) { + return code2err(ret); + }; +}; + +export fn bind( + stmt: statement, + col: (str | int), + val: (int | void | str), +) (void | error) = { + match (val) { + case let v: int => return bind_int(stmt, col, v); + case let v: void => return bind_null(stmt, col); + case let v: str => return bind_text(stmt, col, v); + }; +}; + +@symbol("sqlite3_step") fn libsqlite3_step(stmt: *opaque) int; + +export fn step(stmt: statement) (bool | error) = { + let ret = libsqlite3_step(stmt: *opaque); + switch (ret) { + case sqlite_row => return true; + case sqlite_done => return false; + case => return code2err(ret); + }; +}; + +@symbol("sqlite3_column_text") fn libsqlite3_column_text( + stmt: *opaque, + col: int, +) *const c::char; + +export fn column_text(stmt: statement, col: int) const str = { + let s = libsqlite3_column_text(stmt: *opaque, col); + if (s == null) { + return ""; + }; + return c::tostr_unsafe(s); +}; + +@symbol("sqlite3_column_int") fn libsqlite3_column_int( + stmt: *opaque, + col: int, +) int; + +export fn column_int(stmt: statement, col: int) int = { + return libsqlite3_column_int(stmt: *opaque, col); +}; + +@symbol("sqlite3_finalize") fn libsqlite3_finalize(stmt: *opaque) int; + +export fn finalize(stmt: statement) (void | error) = { + let ret = libsqlite3_finalize(stmt: *opaque); + if (ret != sqlite_ok) { + return code2err(ret); + }; +}; + +@symbol("sqlite3_reset") fn libsqlite3_reset(stmt: *opaque) int; + +export fn reset(stmt: statement) (void | error) = { + let ret = libsqlite3_reset(stmt: *opaque); + if (ret != sqlite_ok) { + return code2err(ret); + }; +}; + +@symbol("sqlite3_clear_bindings") fn libsqlite3_clear_bindings(stmt: *opaque) int; + +export fn clear_bindings(stmt: statement) (void | error) = { + let ret = libsqlite3_clear_bindings(stmt: *opaque); + if (ret != sqlite_ok) { + return code2err(ret); + }; +};