sqlite bindings: honest C integer widths on the wrappers

The wrapper surface previously widened every integer to i64. Wrappers
now carry SQLite's own widths: i32 where the C API says int (result
codes, counts, indexes, byte sizes), u32/u64 where it says unsigned
(prepare flags, strlike escape, zeroblob64), i64 only for the genuinely
64-bit APIs (rowids, changes64, memory accounting, serialize sizes).
sx converts implicitly in both directions, so call sites are unchanged.
This commit is contained in:
agra
2026-06-12 15:43:29 +03:00
parent b5b8ab092b
commit 3747c40e90

View File

@@ -41,6 +41,10 @@
// views pass without copying — and `column_text`/`column_blob`/
// `serialize` return `?*u8` + explicit byte counts, never `cstring`:
// their payloads may carry interior NULs that a strlen would truncate.
// Integer widths are SQLite's own, on the wrappers too: `i32` where
// the C API says `int` (result codes, counts, indexes, byte sizes),
// `u32`/`u64` where it says unsigned, and `i64` only for the genuinely
// 64-bit APIs (rowids, changes64, memory accounting, serialize sizes).
// =====================================================================
#import "modules/std.sx";
@@ -322,8 +326,8 @@ sq_copy_bytes :: (p: ?*u8, n: i64) -> string {
sqlite_version :: () -> string {
return sq_from_cstr(sqlite3_libversion());
}
sqlite_version_number :: () -> i64 {
return xx sqlite3_libversion_number();
sqlite_version_number :: () -> i32 {
return sqlite3_libversion_number();
}
sqlite_sourceid :: () -> string {
return sq_from_cstr(sqlite3_sourceid());
@@ -335,26 +339,27 @@ sqlite_compileoption_used :: (name: string) -> bool {
return sqlite3_compileoption_used(to_cstring(name)) != 0;
}
// The n'th compile option ("" past the end).
sqlite_compileoption_get :: (n: i64) -> string {
return sq_from_cstr(sqlite3_compileoption_get(xx n));
sqlite_compileoption_get :: (n: i32) -> string {
return sq_from_cstr(sqlite3_compileoption_get(n));
}
// Human text for a result code (static storage; copied anyway).
sqlite_errstr :: (code: i64) -> string {
return sq_from_cstr(sqlite3_errstr(xx code));
sqlite_errstr :: (code: i32) -> string {
return sq_from_cstr(sqlite3_errstr(code));
}
// True iff `sql` ends in a complete SQL statement.
sqlite_complete :: (sql: string) -> bool {
return sqlite3_complete(to_cstring(sql)) != 0;
}
// `n` bytes from SQLite's CSPRNG.
sqlite_randomness :: (n: i64) -> string {
raw : [*]u8 = xx context.allocator.alloc_bytes(n + 1);
sqlite3_randomness(xx n, raw);
raw[n] = 0;
return string.{ ptr = raw, len = n };
sqlite_randomness :: (n: i32) -> string {
len : i64 = n;
raw : [*]u8 = xx context.allocator.alloc_bytes(len + 1);
sqlite3_randomness(n, raw);
raw[len] = 0;
return string.{ ptr = raw, len = len };
}
sqlite_sleep :: (ms: i64) -> i64 {
return xx sqlite3_sleep(xx ms);
sqlite_sleep :: (ms: i32) -> i32 {
return sqlite3_sleep(ms);
}
// memory_used/highwater read 0 in this build: SQLITE_DEFAULT_MEMSTATUS=0.
sqlite_memory_used :: () -> i64 {
@@ -363,8 +368,8 @@ sqlite_memory_used :: () -> i64 {
sqlite_memory_highwater :: (reset: bool) -> i64 {
return sqlite3_memory_highwater(if reset then 1 else 0);
}
sqlite_release_memory :: (n: i64) -> i64 {
return xx sqlite3_release_memory(xx n);
sqlite_release_memory :: (n: i32) -> i32 {
return sqlite3_release_memory(n);
}
sqlite_soft_heap_limit :: (n: i64) -> i64 {
return sqlite3_soft_heap_limit64(n);
@@ -377,11 +382,11 @@ sqlite_hard_heap_limit :: (n: i64) -> i64 {
sqlite_strglob :: (glob: string, s: string) -> bool {
return sqlite3_strglob(to_cstring(glob), to_cstring(s)) == 0;
}
sqlite_strlike :: (like: string, s: string, esc: i64) -> bool {
return sqlite3_strlike(to_cstring(like), to_cstring(s), xx esc) == 0;
sqlite_strlike :: (like: string, s: string, esc: u32) -> bool {
return sqlite3_strlike(to_cstring(like), to_cstring(s), esc) == 0;
}
sqlite_stricmp :: (a: string, b: string) -> i64 {
return xx sqlite3_stricmp(to_cstring(a), to_cstring(b));
sqlite_stricmp :: (a: string, b: string) -> i32 {
return sqlite3_stricmp(to_cstring(a), to_cstring(b));
}
// ── prepared statements ───────────────────────────────────────────────
@@ -393,34 +398,34 @@ SqliteStmt :: struct {
db: usize;
// ── binding ──
bind_text :: (self: *SqliteStmt, idx: i64, s: string) -> !SqliteErr {
rc := sqlite3_bind_text(self.handle, xx idx, s.ptr, xx s.len, SQLITE_TRANSIENT);
bind_text :: (self: *SqliteStmt, idx: i32, s: string) -> !SqliteErr {
rc := sqlite3_bind_text(self.handle, idx, s.ptr, xx s.len, SQLITE_TRANSIENT);
if rc != SQLITE_OK { raise error.Bind; }
return;
}
bind_blob :: (self: *SqliteStmt, idx: i64, bytes: string) -> !SqliteErr {
rc := sqlite3_bind_blob(self.handle, xx idx, bytes.ptr, xx bytes.len, SQLITE_TRANSIENT);
bind_blob :: (self: *SqliteStmt, idx: i32, bytes: string) -> !SqliteErr {
rc := sqlite3_bind_blob(self.handle, idx, bytes.ptr, xx bytes.len, SQLITE_TRANSIENT);
if rc != SQLITE_OK { raise error.Bind; }
return;
}
bind_double :: (self: *SqliteStmt, idx: i64, v: f64) -> !SqliteErr {
rc := sqlite3_bind_double(self.handle, xx idx, v);
bind_double :: (self: *SqliteStmt, idx: i32, v: f64) -> !SqliteErr {
rc := sqlite3_bind_double(self.handle, idx, v);
if rc != SQLITE_OK { raise error.Bind; }
return;
}
bind_int64 :: (self: *SqliteStmt, idx: i64, v: i64) -> !SqliteErr {
rc := sqlite3_bind_int64(self.handle, xx idx, v);
bind_int64 :: (self: *SqliteStmt, idx: i32, v: i64) -> !SqliteErr {
rc := sqlite3_bind_int64(self.handle, idx, v);
if rc != SQLITE_OK { raise error.Bind; }
return;
}
bind_null :: (self: *SqliteStmt, idx: i64) -> !SqliteErr {
rc := sqlite3_bind_null(self.handle, xx idx);
bind_null :: (self: *SqliteStmt, idx: i32) -> !SqliteErr {
rc := sqlite3_bind_null(self.handle, idx);
if rc != SQLITE_OK { raise error.Bind; }
return;
}
// Reserve an `n`-byte zero-filled blob (fill it via SqliteBlob I/O).
bind_zeroblob :: (self: *SqliteStmt, idx: i64, n: i64) -> !SqliteErr {
rc := sqlite3_bind_zeroblob64(self.handle, xx idx, xx n);
bind_zeroblob :: (self: *SqliteStmt, idx: i32, n: u64) -> !SqliteErr {
rc := sqlite3_bind_zeroblob64(self.handle, idx, n);
if rc != SQLITE_OK { raise error.Bind; }
return;
}
@@ -429,25 +434,25 @@ SqliteStmt :: struct {
}
// ── parameters ──
parameter_count :: (self: *SqliteStmt) -> i64 {
return xx sqlite3_bind_parameter_count(self.handle);
parameter_count :: (self: *SqliteStmt) -> i32 {
return sqlite3_bind_parameter_count(self.handle);
}
// 1-based index of a named parameter (":name" / "@name" / "?N"), 0 if absent.
parameter_index :: (self: *SqliteStmt, name: string) -> i64 {
return xx sqlite3_bind_parameter_index(self.handle, to_cstring(name));
parameter_index :: (self: *SqliteStmt, name: string) -> i32 {
return sqlite3_bind_parameter_index(self.handle, to_cstring(name));
}
// The name of parameter `idx` ("" for nameless `?` parameters).
parameter_name :: (self: *SqliteStmt, idx: i64) -> string {
return sq_from_cstr(sqlite3_bind_parameter_name(self.handle, xx idx));
parameter_name :: (self: *SqliteStmt, idx: i32) -> string {
return sq_from_cstr(sqlite3_bind_parameter_name(self.handle, idx));
}
// ── execution ──
// SQLITE_ROW / SQLITE_DONE on success; anything else raises with the
// detail left in the connection's errmsg.
step :: (self: *SqliteStmt) -> (i64, !SqliteErr) {
step :: (self: *SqliteStmt) -> (i32, !SqliteErr) {
rc := sqlite3_step(self.handle);
if rc != SQLITE_ROW and rc != SQLITE_DONE { raise error.Step; }
return xx rc;
return rc;
}
reset :: (self: *SqliteStmt) {
sqlite3_reset(self.handle);
@@ -458,49 +463,49 @@ SqliteStmt :: struct {
}
// ── columns (copies into context.allocator; NULL reads as ""/0) ──
column_int64 :: (self: *SqliteStmt, icol: i64) -> i64 {
return sqlite3_column_int64(self.handle, xx icol);
column_int64 :: (self: *SqliteStmt, icol: i32) -> i64 {
return sqlite3_column_int64(self.handle, icol);
}
column_double :: (self: *SqliteStmt, icol: i64) -> f64 {
return sqlite3_column_double(self.handle, xx icol);
column_double :: (self: *SqliteStmt, icol: i32) -> f64 {
return sqlite3_column_double(self.handle, icol);
}
column_text :: (self: *SqliteStmt, icol: i64) -> string {
p := sqlite3_column_text(self.handle, xx icol);
n := sqlite3_column_bytes(self.handle, xx icol);
column_text :: (self: *SqliteStmt, icol: i32) -> string {
p := sqlite3_column_text(self.handle, icol);
n := sqlite3_column_bytes(self.handle, icol);
return sq_copy_bytes(p, xx n);
}
column_blob :: (self: *SqliteStmt, icol: i64) -> string {
p := sqlite3_column_blob(self.handle, xx icol);
n := sqlite3_column_bytes(self.handle, xx icol);
column_blob :: (self: *SqliteStmt, icol: i32) -> string {
p := sqlite3_column_blob(self.handle, icol);
n := sqlite3_column_bytes(self.handle, icol);
return sq_copy_bytes(p, xx n);
}
column_bytes :: (self: *SqliteStmt, icol: i64) -> i64 {
return xx sqlite3_column_bytes(self.handle, xx icol);
column_bytes :: (self: *SqliteStmt, icol: i32) -> i32 {
return sqlite3_column_bytes(self.handle, icol);
}
column_type :: (self: *SqliteStmt, icol: i64) -> i64 {
return xx sqlite3_column_type(self.handle, xx icol);
column_type :: (self: *SqliteStmt, icol: i32) -> i32 {
return sqlite3_column_type(self.handle, icol);
}
column_count :: (self: *SqliteStmt) -> i64 {
return xx sqlite3_column_count(self.handle);
column_count :: (self: *SqliteStmt) -> i32 {
return sqlite3_column_count(self.handle);
}
column_name :: (self: *SqliteStmt, icol: i64) -> string {
return sq_from_cstr(sqlite3_column_name(self.handle, xx icol));
column_name :: (self: *SqliteStmt, icol: i32) -> string {
return sq_from_cstr(sqlite3_column_name(self.handle, icol));
}
// The declared type from the schema ("" for expressions).
column_decltype :: (self: *SqliteStmt, icol: i64) -> string {
return sq_from_cstr(sqlite3_column_decltype(self.handle, xx icol));
column_decltype :: (self: *SqliteStmt, icol: i32) -> string {
return sq_from_cstr(sqlite3_column_decltype(self.handle, icol));
}
column_database_name :: (self: *SqliteStmt, icol: i64) -> string {
return sq_from_cstr(sqlite3_column_database_name(self.handle, xx icol));
column_database_name :: (self: *SqliteStmt, icol: i32) -> string {
return sq_from_cstr(sqlite3_column_database_name(self.handle, icol));
}
column_table_name :: (self: *SqliteStmt, icol: i64) -> string {
return sq_from_cstr(sqlite3_column_table_name(self.handle, xx icol));
column_table_name :: (self: *SqliteStmt, icol: i32) -> string {
return sq_from_cstr(sqlite3_column_table_name(self.handle, icol));
}
column_origin_name :: (self: *SqliteStmt, icol: i64) -> string {
return sq_from_cstr(sqlite3_column_origin_name(self.handle, xx icol));
column_origin_name :: (self: *SqliteStmt, icol: i32) -> string {
return sq_from_cstr(sqlite3_column_origin_name(self.handle, icol));
}
data_count :: (self: *SqliteStmt) -> i64 {
return xx sqlite3_data_count(self.handle);
data_count :: (self: *SqliteStmt) -> i32 {
return sqlite3_data_count(self.handle);
}
// ── introspection ──
@@ -522,11 +527,11 @@ SqliteStmt :: struct {
return sqlite3_stmt_readonly(self.handle) != 0;
}
// 0 = normal, 1 = EXPLAIN, 2 = EXPLAIN QUERY PLAN.
isexplain :: (self: *SqliteStmt) -> i64 {
return xx sqlite3_stmt_isexplain(self.handle);
isexplain :: (self: *SqliteStmt) -> i32 {
return sqlite3_stmt_isexplain(self.handle);
}
status :: (self: *SqliteStmt, op: i64, reset: bool) -> i64 {
return xx sqlite3_stmt_status(self.handle, xx op, if reset then 1 else 0);
status :: (self: *SqliteStmt, op: i32, reset: bool) -> i32 {
return sqlite3_stmt_status(self.handle, op, if reset then 1 else 0);
}
}
@@ -557,9 +562,9 @@ Sqlite :: struct {
return Sqlite.{ handle = h };
}
open_v2 :: (path: string, flags: i64) -> (Sqlite, !SqliteErr) {
open_v2 :: (path: string, flags: i32) -> (Sqlite, !SqliteErr) {
h : usize = 0;
rc := sqlite3_open_v2(to_cstring(path), @h, xx flags, 0);
rc := sqlite3_open_v2(to_cstring(path), @h, flags, 0);
if rc != SQLITE_OK {
if h != 0 { sqlite3_close(h); }
raise error.Open;
@@ -594,9 +599,9 @@ Sqlite :: struct {
}
// prepare with SQLITE_PREPARE_* flags (e.g. PERSISTENT for the
// statement cache a storage layer keeps hot).
prepare_v3 :: (self: *Sqlite, sql: string, flags: i64) -> (SqliteStmt, !SqliteErr) {
prepare_v3 :: (self: *Sqlite, sql: string, flags: u32) -> (SqliteStmt, !SqliteErr) {
sh : usize = 0;
rc := sqlite3_prepare_v3(self.handle, sql.ptr, xx sql.len, xx flags, @sh, 0);
rc := sqlite3_prepare_v3(self.handle, sql.ptr, xx sql.len, flags, @sh, 0);
if rc != SQLITE_OK { raise error.Prepare; }
return SqliteStmt.{ handle = sh, db = self.handle };
}
@@ -605,23 +610,23 @@ Sqlite :: struct {
errmsg :: (self: *Sqlite) -> string {
return sq_from_cstr(sqlite3_errmsg(self.handle));
}
errcode :: (self: *Sqlite) -> i64 {
return xx sqlite3_errcode(self.handle);
errcode :: (self: *Sqlite) -> i32 {
return sqlite3_errcode(self.handle);
}
extended_errcode :: (self: *Sqlite) -> i64 {
return xx sqlite3_extended_errcode(self.handle);
extended_errcode :: (self: *Sqlite) -> i32 {
return sqlite3_extended_errcode(self.handle);
}
// Byte offset of the most recent error's token in its SQL, -1 if n/a.
error_offset :: (self: *Sqlite) -> i64 {
return xx sqlite3_error_offset(self.handle);
error_offset :: (self: *Sqlite) -> i32 {
return sqlite3_error_offset(self.handle);
}
extended_result_codes :: (self: *Sqlite, on: bool) {
sqlite3_extended_result_codes(self.handle, if on then 1 else 0);
}
// ── state & control ──
busy_timeout :: (self: *Sqlite, ms: i64) {
sqlite3_busy_timeout(self.handle, xx ms);
busy_timeout :: (self: *Sqlite, ms: i32) {
sqlite3_busy_timeout(self.handle, ms);
}
interrupt :: (self: *Sqlite) {
sqlite3_interrupt(self.handle);
@@ -633,15 +638,15 @@ Sqlite :: struct {
return sqlite3_get_autocommit(self.handle) != 0;
}
// SQLITE_TXN_NONE / _READ / _WRITE for the "main" schema.
txn_state :: (self: *Sqlite) -> i64 {
return xx sqlite3_txn_state(self.handle, to_cstring("main"));
txn_state :: (self: *Sqlite) -> i32 {
return sqlite3_txn_state(self.handle, to_cstring("main"));
}
db_filename :: (self: *Sqlite) -> string {
return sq_from_cstr(sqlite3_db_filename(self.handle, to_cstring("main")));
}
// 1 readonly, 0 read-write, -1 no such database name.
db_readonly :: (self: *Sqlite) -> i64 {
return xx sqlite3_db_readonly(self.handle, to_cstring("main"));
db_readonly :: (self: *Sqlite) -> i32 {
return sqlite3_db_readonly(self.handle, to_cstring("main"));
}
cacheflush :: (self: *Sqlite) {
sqlite3_db_cacheflush(self.handle);
@@ -663,8 +668,8 @@ Sqlite :: struct {
}
// Set a SQLITE_LIMIT_* runtime limit; answers the PRIOR value.
// new_val < 0 reads without changing.
limit :: (self: *Sqlite, id: i64, new_val: i64) -> i64 {
return xx sqlite3_limit(self.handle, xx id, xx new_val);
limit :: (self: *Sqlite, id: i32, new_val: i32) -> i32 {
return sqlite3_limit(self.handle, id, new_val);
}
// Schema introspection for one column of "main".`table`.
@@ -731,18 +736,19 @@ SqliteBlob :: struct {
if rc != SQLITE_OK { raise error.Blob; }
return;
}
bytes :: (self: *SqliteBlob) -> i64 {
return xx sqlite3_blob_bytes(self.handle);
bytes :: (self: *SqliteBlob) -> i32 {
return sqlite3_blob_bytes(self.handle);
}
read :: (self: *SqliteBlob, offset: i64, n: i64) -> (string, !SqliteErr) {
raw : [*]u8 = xx context.allocator.alloc_bytes(n + 1);
rc := sqlite3_blob_read(self.handle, raw, xx n, xx offset);
read :: (self: *SqliteBlob, offset: i32, n: i32) -> (string, !SqliteErr) {
len : i64 = n;
raw : [*]u8 = xx context.allocator.alloc_bytes(len + 1);
rc := sqlite3_blob_read(self.handle, raw, n, offset);
if rc != SQLITE_OK { raise error.Blob; }
raw[n] = 0;
return string.{ ptr = raw, len = n };
raw[len] = 0;
return string.{ ptr = raw, len = len };
}
write :: (self: *SqliteBlob, offset: i64, data: string) -> !SqliteErr {
rc := sqlite3_blob_write(self.handle, data.ptr, xx data.len, xx offset);
write :: (self: *SqliteBlob, offset: i32, data: string) -> !SqliteErr {
rc := sqlite3_blob_write(self.handle, data.ptr, xx data.len, offset);
if rc != SQLITE_OK { raise error.Blob; }
return;
}
@@ -767,19 +773,19 @@ SqliteBackup :: struct {
}
// Copy up to `n` pages (-1 = all remaining). SQLITE_OK = more to do,
// SQLITE_DONE = complete; BUSY/LOCKED are retryable per the C API.
step :: (self: *SqliteBackup, n: i64) -> i64 {
return xx sqlite3_backup_step(self.handle, xx n);
step :: (self: *SqliteBackup, n: i32) -> i32 {
return sqlite3_backup_step(self.handle, n);
}
remaining :: (self: *SqliteBackup) -> i64 {
return xx sqlite3_backup_remaining(self.handle);
remaining :: (self: *SqliteBackup) -> i32 {
return sqlite3_backup_remaining(self.handle);
}
pagecount :: (self: *SqliteBackup) -> i64 {
return xx sqlite3_backup_pagecount(self.handle);
pagecount :: (self: *SqliteBackup) -> i32 {
return sqlite3_backup_pagecount(self.handle);
}
finish :: (self: *SqliteBackup) -> i64 {
finish :: (self: *SqliteBackup) -> i32 {
rc := sqlite3_backup_finish(self.handle);
self.handle = 0;
return xx rc;
return rc;
}
}