sqlite is part of the program: #import c unit replaces the Makefile cc build
src/db/sqlite.sx declares the vendored amalgamation as a named '#import c' unit (pinned defines + -O2 + #source); every #foreign binding resolves against it with UNPREFIXED sqlite3_* names. sx compiles the unit through its content-addressed object cache — once per checkout — links the objects into 'sx build' binaries, and loads them as a priority symbol target under 'sx run', so the OS libsqlite3 can never shadow the vendored copy (the version pin in sqlite_smoke proves it). Retired: the Makefile vendor targets (cc -> .a + jit/.dylib), the GENERATED dist_sqlite3_* rename.h (the JIT no longer resolves program-owned symbols through the process images, so the rename's reason is gone), and the -L plumbing in make build + tests/run.sh. make test 22/22; otool -L build/dist carries no libsqlite3.
This commit is contained in:
BIN
.sx-cache/c-11a77f91b0e34902.o
Normal file
BIN
.sx-cache/c-11a77f91b0e34902.o
Normal file
Binary file not shown.
BIN
.sx-cache/c-532fd2a7a0245e62.o
Normal file
BIN
.sx-cache/c-532fd2a7a0245e62.o
Normal file
Binary file not shown.
47
Makefile
47
Makefile
@@ -9,48 +9,23 @@ BUILD_DIR := build
|
||||
# Programs compiled by `make build`: the smoke program and the `dist`
|
||||
# product entry point. Further entry points under src/ get added here as
|
||||
# they land.
|
||||
#
|
||||
# The vendored SQLite (vendor/sqlite/) is part of the PROGRAM, not the
|
||||
# build system: src/db/sqlite.sx declares it as a named `#import c` unit
|
||||
# (pinned defines + -O2 + #source), so sx compiles and links it through
|
||||
# its content-addressed object cache (.sx-cache/) — once per checkout.
|
||||
# `sx build` links the unit's objects into the binary; `sx run` loads
|
||||
# them as a priority symbol target the OS libsqlite3 cannot shadow.
|
||||
SMOKE := tests/smoke.sx
|
||||
DIST := src/dist.sx
|
||||
|
||||
# Vendored SQLite (vendor/sqlite/README.md): one amalgamation, two build
|
||||
# products in two DIRECTORIES — the macOS linker prefers a dylib over an
|
||||
# archive in the same -L directory, and `sx build` must link the static
|
||||
# copy while `sx run` (the test runner) dlopens the dylib.
|
||||
#
|
||||
# rename.h is GENERATED from the bindings: every `dist_sqlite3_*` symbol
|
||||
# named in src/db/sqlite.sx gets a #define, so the rename list and the
|
||||
# bound surface cannot drift (see the README for why renaming exists).
|
||||
VENDOR_DIR := $(BUILD_DIR)/vendor
|
||||
SQLITE_SRC := vendor/sqlite/sqlite3.c
|
||||
SQLITE_DEFS := -DSQLITE_DQS=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 \
|
||||
-DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_SHARED_CACHE \
|
||||
-DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_ENABLE_COLUMN_METADATA \
|
||||
-include $(VENDOR_DIR)/rename.h
|
||||
|
||||
$(VENDOR_DIR)/rename.h: src/db/sqlite.sx
|
||||
@mkdir -p $(VENDOR_DIR)
|
||||
@{ echo '/* GENERATED by make from src/db/sqlite.sx — do not edit. */'; \
|
||||
grep -o '"dist_sqlite3_[a-z0-9_]*"' src/db/sqlite.sx | tr -d '"' | sort -u | \
|
||||
sed 's/^dist_\(.*\)/#define \1 dist_\1/'; } > $@
|
||||
|
||||
$(VENDOR_DIR)/libsqlite3.a: $(SQLITE_SRC) vendor/sqlite/sqlite3.h $(VENDOR_DIR)/rename.h
|
||||
@mkdir -p $(VENDOR_DIR)
|
||||
cc $(SQLITE_DEFS) -O2 -c $(SQLITE_SRC) -o $(VENDOR_DIR)/sqlite3.o
|
||||
ar rcs $@ $(VENDOR_DIR)/sqlite3.o
|
||||
|
||||
$(VENDOR_DIR)/jit/libsqlite3.dylib: $(SQLITE_SRC) vendor/sqlite/sqlite3.h $(VENDOR_DIR)/rename.h
|
||||
@mkdir -p $(VENDOR_DIR)/jit
|
||||
cc $(SQLITE_DEFS) -O2 -dynamiclib $(SQLITE_SRC) -o $@
|
||||
|
||||
.PHONY: build test publish-example vendor clean
|
||||
|
||||
vendor: $(VENDOR_DIR)/libsqlite3.a $(VENDOR_DIR)/jit/libsqlite3.dylib
|
||||
.PHONY: build test publish-example clean
|
||||
|
||||
# Compile the product sources (and the smoke program) without running.
|
||||
build: vendor
|
||||
build:
|
||||
@mkdir -p $(BUILD_DIR)
|
||||
$(SX) build -o $(BUILD_DIR)/smoke $(SMOKE)
|
||||
$(SX) build -o $(BUILD_DIR)/dist $(DIST) -L $(VENDOR_DIR)
|
||||
$(SX) build -o $(BUILD_DIR)/dist $(DIST)
|
||||
|
||||
# Run the test runner over every tests/**/*.sx. Exits non-zero on any
|
||||
# failure. Depends on `build` so the CLI acceptance test (tests/cli_*.sx)
|
||||
@@ -67,4 +42,4 @@ publish-example: build
|
||||
./$(BUILD_DIR)/dist ci publish --manifest examples/dist.json --local-store .sx-tmp/publish-example --json
|
||||
|
||||
clean:
|
||||
@rm -rf $(BUILD_DIR)
|
||||
@rm -rf $(BUILD_DIR) .sx-cache
|
||||
|
||||
228
src/db/sqlite.sx
228
src/db/sqlite.sx
@@ -2,15 +2,17 @@
|
||||
// sqlite.sx — sx bindings over the VENDORED SQLite amalgamation
|
||||
// (vendor/sqlite/, see its README for version + upgrade notes).
|
||||
//
|
||||
// `#library "sqlite3"` resolves to the vendored build products under
|
||||
// build/vendor/ (never the OS copy): `sx build` links the static
|
||||
// archive via `-L build/vendor`; `sx run` dlopens the dylib via
|
||||
// `-L build/vendor/jit` (tests/run.sh). Every bound symbol is renamed
|
||||
// `dist_sqlite3_*` in the vendored build — `build/vendor/rename.h` is
|
||||
// GENERATED by the Makefile from THIS FILE's `#foreign` names, so the
|
||||
// rename list and the bindings cannot drift. tests/sqlite_smoke.sx pins
|
||||
// `sqlite3_libversion()` to the vendored version so a silent fallback
|
||||
// to the system library fails the suite.
|
||||
// The amalgamation is part of THIS program: the named `#import c`
|
||||
// unit below compiles vendor/sqlite/sqlite3.c with the pinned options
|
||||
// (through sx's content-addressed object cache, so it compiles once
|
||||
// per checkout, not once per run) and every `#foreign sqlib` decl
|
||||
// binds against it. Under `sx run` the unit's dylib is a PRIORITY
|
||||
// symbol-search target consulted before the process images, so the OS
|
||||
// libsqlite3 (loaded into the compiler via CoreServices) can never
|
||||
// shadow the vendored copy; under `sx build` the unit's objects link
|
||||
// directly into the binary. tests/sqlite_smoke.sx pins
|
||||
// `sqlite3_libversion()` to the vendored version so any fallback
|
||||
// fails the suite.
|
||||
//
|
||||
// COVERAGE — the full practical C API, ONE variant per function (the
|
||||
// modern/64-bit form where duplicates exist; `bind_text`/`bind_blob`
|
||||
@@ -24,7 +26,7 @@
|
||||
// * the sqlite3_value_* family + bind/column_value — only
|
||||
// meaningful with user-defined functions (callbacks, above);
|
||||
// * varargs APIs (sqlite3_config, db_config, log, mprintf) —
|
||||
// configuration happens via compile-time defines in the Makefile;
|
||||
// configuration happens via the unit's compile-time defines;
|
||||
// * UTF-16 variants (we are UTF-8 only), the mutex/VFS layer
|
||||
// (built SQLITE_THREADSAFE=0), sessions/snapshots/vtabs/loadable
|
||||
// extensions (not compiled in), deprecated API (compiled out via
|
||||
@@ -49,124 +51,134 @@
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
sqlib :: #library "sqlite3";
|
||||
sqlib :: #import c {
|
||||
#define "SQLITE_DQS=0";
|
||||
#define "SQLITE_THREADSAFE=0";
|
||||
#define "SQLITE_DEFAULT_MEMSTATUS=0";
|
||||
#define "SQLITE_OMIT_DEPRECATED";
|
||||
#define "SQLITE_OMIT_SHARED_CACHE";
|
||||
#define "SQLITE_LIKE_DOESNT_MATCH_BLOBS";
|
||||
#define "SQLITE_ENABLE_COLUMN_METADATA";
|
||||
#flags "-O2";
|
||||
#source "../../vendor/sqlite/sqlite3.c";
|
||||
};
|
||||
|
||||
// ── FFI: connection lifecycle ─────────────────────────────────────────
|
||||
sqlite3_open :: (path: cstring, out_db: *usize) -> i32 #foreign sqlib "dist_sqlite3_open";
|
||||
sqlite3_open_v2 :: (path: cstring, out_db: *usize, flags: i32, vfs: usize) -> i32 #foreign sqlib "dist_sqlite3_open_v2";
|
||||
sqlite3_close :: (db: usize) -> i32 #foreign sqlib "dist_sqlite3_close";
|
||||
sqlite3_close_v2 :: (db: usize) -> i32 #foreign sqlib "dist_sqlite3_close_v2";
|
||||
sqlite3_open :: (path: cstring, out_db: *usize) -> i32 #foreign sqlib "sqlite3_open";
|
||||
sqlite3_open_v2 :: (path: cstring, out_db: *usize, flags: i32, vfs: usize) -> i32 #foreign sqlib "sqlite3_open_v2";
|
||||
sqlite3_close :: (db: usize) -> i32 #foreign sqlib "sqlite3_close";
|
||||
sqlite3_close_v2 :: (db: usize) -> i32 #foreign sqlib "sqlite3_close_v2";
|
||||
|
||||
// ── FFI: errors ───────────────────────────────────────────────────────
|
||||
sqlite3_errcode :: (db: usize) -> i32 #foreign sqlib "dist_sqlite3_errcode";
|
||||
sqlite3_extended_errcode :: (db: usize) -> i32 #foreign sqlib "dist_sqlite3_extended_errcode";
|
||||
sqlite3_errmsg :: (db: usize) -> ?cstring #foreign sqlib "dist_sqlite3_errmsg";
|
||||
sqlite3_errstr :: (code: i32) -> ?cstring #foreign sqlib "dist_sqlite3_errstr";
|
||||
sqlite3_error_offset :: (db: usize) -> i32 #foreign sqlib "dist_sqlite3_error_offset";
|
||||
sqlite3_extended_result_codes :: (db: usize, onoff: i32) -> i32 #foreign sqlib "dist_sqlite3_extended_result_codes";
|
||||
sqlite3_errcode :: (db: usize) -> i32 #foreign sqlib "sqlite3_errcode";
|
||||
sqlite3_extended_errcode :: (db: usize) -> i32 #foreign sqlib "sqlite3_extended_errcode";
|
||||
sqlite3_errmsg :: (db: usize) -> ?cstring #foreign sqlib "sqlite3_errmsg";
|
||||
sqlite3_errstr :: (code: i32) -> ?cstring #foreign sqlib "sqlite3_errstr";
|
||||
sqlite3_error_offset :: (db: usize) -> i32 #foreign sqlib "sqlite3_error_offset";
|
||||
sqlite3_extended_result_codes :: (db: usize, onoff: i32) -> i32 #foreign sqlib "sqlite3_extended_result_codes";
|
||||
|
||||
// ── FFI: connection state & control ───────────────────────────────────
|
||||
sqlite3_busy_timeout :: (db: usize, ms: i32) -> i32 #foreign sqlib "dist_sqlite3_busy_timeout";
|
||||
sqlite3_interrupt :: (db: usize) #foreign sqlib "dist_sqlite3_interrupt";
|
||||
sqlite3_is_interrupted :: (db: usize) -> i32 #foreign sqlib "dist_sqlite3_is_interrupted";
|
||||
sqlite3_get_autocommit :: (db: usize) -> i32 #foreign sqlib "dist_sqlite3_get_autocommit";
|
||||
sqlite3_txn_state :: (db: usize, schema: cstring) -> i32 #foreign sqlib "dist_sqlite3_txn_state";
|
||||
sqlite3_db_filename :: (db: usize, db_name: cstring) -> ?cstring #foreign sqlib "dist_sqlite3_db_filename";
|
||||
sqlite3_db_readonly :: (db: usize, db_name: cstring) -> i32 #foreign sqlib "dist_sqlite3_db_readonly";
|
||||
sqlite3_db_cacheflush :: (db: usize) -> i32 #foreign sqlib "dist_sqlite3_db_cacheflush";
|
||||
sqlite3_db_release_memory :: (db: usize) -> i32 #foreign sqlib "dist_sqlite3_db_release_memory";
|
||||
sqlite3_last_insert_rowid :: (db: usize) -> i64 #foreign sqlib "dist_sqlite3_last_insert_rowid";
|
||||
sqlite3_set_last_insert_rowid :: (db: usize, rowid: i64) #foreign sqlib "dist_sqlite3_set_last_insert_rowid";
|
||||
sqlite3_changes64 :: (db: usize) -> i64 #foreign sqlib "dist_sqlite3_changes64";
|
||||
sqlite3_total_changes64 :: (db: usize) -> i64 #foreign sqlib "dist_sqlite3_total_changes64";
|
||||
sqlite3_limit :: (db: usize, id: i32, new_val: i32) -> i32 #foreign sqlib "dist_sqlite3_limit";
|
||||
sqlite3_exec :: (db: usize, sql: cstring, cb: usize, arg: usize, errmsg: usize) -> i32 #foreign sqlib "dist_sqlite3_exec";
|
||||
sqlite3_table_column_metadata :: (db: usize, db_name: cstring, table: cstring, column: cstring, out_data_type: *usize, out_coll_seq: *usize, out_not_null: *i32, out_primary_key: *i32, out_autoinc: *i32) -> i32 #foreign sqlib "dist_sqlite3_table_column_metadata";
|
||||
sqlite3_busy_timeout :: (db: usize, ms: i32) -> i32 #foreign sqlib "sqlite3_busy_timeout";
|
||||
sqlite3_interrupt :: (db: usize) #foreign sqlib "sqlite3_interrupt";
|
||||
sqlite3_is_interrupted :: (db: usize) -> i32 #foreign sqlib "sqlite3_is_interrupted";
|
||||
sqlite3_get_autocommit :: (db: usize) -> i32 #foreign sqlib "sqlite3_get_autocommit";
|
||||
sqlite3_txn_state :: (db: usize, schema: cstring) -> i32 #foreign sqlib "sqlite3_txn_state";
|
||||
sqlite3_db_filename :: (db: usize, db_name: cstring) -> ?cstring #foreign sqlib "sqlite3_db_filename";
|
||||
sqlite3_db_readonly :: (db: usize, db_name: cstring) -> i32 #foreign sqlib "sqlite3_db_readonly";
|
||||
sqlite3_db_cacheflush :: (db: usize) -> i32 #foreign sqlib "sqlite3_db_cacheflush";
|
||||
sqlite3_db_release_memory :: (db: usize) -> i32 #foreign sqlib "sqlite3_db_release_memory";
|
||||
sqlite3_last_insert_rowid :: (db: usize) -> i64 #foreign sqlib "sqlite3_last_insert_rowid";
|
||||
sqlite3_set_last_insert_rowid :: (db: usize, rowid: i64) #foreign sqlib "sqlite3_set_last_insert_rowid";
|
||||
sqlite3_changes64 :: (db: usize) -> i64 #foreign sqlib "sqlite3_changes64";
|
||||
sqlite3_total_changes64 :: (db: usize) -> i64 #foreign sqlib "sqlite3_total_changes64";
|
||||
sqlite3_limit :: (db: usize, id: i32, new_val: i32) -> i32 #foreign sqlib "sqlite3_limit";
|
||||
sqlite3_exec :: (db: usize, sql: cstring, cb: usize, arg: usize, errmsg: usize) -> i32 #foreign sqlib "sqlite3_exec";
|
||||
sqlite3_table_column_metadata :: (db: usize, db_name: cstring, table: cstring, column: cstring, out_data_type: *usize, out_coll_seq: *usize, out_not_null: *i32, out_primary_key: *i32, out_autoinc: *i32) -> i32 #foreign sqlib "sqlite3_table_column_metadata";
|
||||
|
||||
// ── FFI: statements ───────────────────────────────────────────────────
|
||||
sqlite3_prepare_v2 :: (db: usize, sql: [*]u8, nbyte: i32, out_stmt: *usize, out_tail: usize) -> i32 #foreign sqlib "dist_sqlite3_prepare_v2";
|
||||
sqlite3_prepare_v3 :: (db: usize, sql: [*]u8, nbyte: i32, prep_flags: u32, out_stmt: *usize, out_tail: usize) -> i32 #foreign sqlib "dist_sqlite3_prepare_v3";
|
||||
sqlite3_step :: (stmt: usize) -> i32 #foreign sqlib "dist_sqlite3_step";
|
||||
sqlite3_reset :: (stmt: usize) -> i32 #foreign sqlib "dist_sqlite3_reset";
|
||||
sqlite3_finalize :: (stmt: usize) -> i32 #foreign sqlib "dist_sqlite3_finalize";
|
||||
sqlite3_clear_bindings :: (stmt: usize) -> i32 #foreign sqlib "dist_sqlite3_clear_bindings";
|
||||
sqlite3_sql :: (stmt: usize) -> ?cstring #foreign sqlib "dist_sqlite3_sql";
|
||||
sqlite3_expanded_sql :: (stmt: usize) -> ?cstring #foreign sqlib "dist_sqlite3_expanded_sql";
|
||||
sqlite3_stmt_busy :: (stmt: usize) -> i32 #foreign sqlib "dist_sqlite3_stmt_busy";
|
||||
sqlite3_stmt_readonly :: (stmt: usize) -> i32 #foreign sqlib "dist_sqlite3_stmt_readonly";
|
||||
sqlite3_stmt_isexplain :: (stmt: usize) -> i32 #foreign sqlib "dist_sqlite3_stmt_isexplain";
|
||||
sqlite3_stmt_explain :: (stmt: usize, mode: i32) -> i32 #foreign sqlib "dist_sqlite3_stmt_explain";
|
||||
sqlite3_stmt_status :: (stmt: usize, op: i32, reset: i32) -> i32 #foreign sqlib "dist_sqlite3_stmt_status";
|
||||
sqlite3_db_handle :: (stmt: usize) -> usize #foreign sqlib "dist_sqlite3_db_handle";
|
||||
sqlite3_next_stmt :: (db: usize, stmt: usize) -> usize #foreign sqlib "dist_sqlite3_next_stmt";
|
||||
sqlite3_prepare_v2 :: (db: usize, sql: [*]u8, nbyte: i32, out_stmt: *usize, out_tail: usize) -> i32 #foreign sqlib "sqlite3_prepare_v2";
|
||||
sqlite3_prepare_v3 :: (db: usize, sql: [*]u8, nbyte: i32, prep_flags: u32, out_stmt: *usize, out_tail: usize) -> i32 #foreign sqlib "sqlite3_prepare_v3";
|
||||
sqlite3_step :: (stmt: usize) -> i32 #foreign sqlib "sqlite3_step";
|
||||
sqlite3_reset :: (stmt: usize) -> i32 #foreign sqlib "sqlite3_reset";
|
||||
sqlite3_finalize :: (stmt: usize) -> i32 #foreign sqlib "sqlite3_finalize";
|
||||
sqlite3_clear_bindings :: (stmt: usize) -> i32 #foreign sqlib "sqlite3_clear_bindings";
|
||||
sqlite3_sql :: (stmt: usize) -> ?cstring #foreign sqlib "sqlite3_sql";
|
||||
sqlite3_expanded_sql :: (stmt: usize) -> ?cstring #foreign sqlib "sqlite3_expanded_sql";
|
||||
sqlite3_stmt_busy :: (stmt: usize) -> i32 #foreign sqlib "sqlite3_stmt_busy";
|
||||
sqlite3_stmt_readonly :: (stmt: usize) -> i32 #foreign sqlib "sqlite3_stmt_readonly";
|
||||
sqlite3_stmt_isexplain :: (stmt: usize) -> i32 #foreign sqlib "sqlite3_stmt_isexplain";
|
||||
sqlite3_stmt_explain :: (stmt: usize, mode: i32) -> i32 #foreign sqlib "sqlite3_stmt_explain";
|
||||
sqlite3_stmt_status :: (stmt: usize, op: i32, reset: i32) -> i32 #foreign sqlib "sqlite3_stmt_status";
|
||||
sqlite3_db_handle :: (stmt: usize) -> usize #foreign sqlib "sqlite3_db_handle";
|
||||
sqlite3_next_stmt :: (db: usize, stmt: usize) -> usize #foreign sqlib "sqlite3_next_stmt";
|
||||
|
||||
// ── FFI: binding ──────────────────────────────────────────────────────
|
||||
sqlite3_bind_parameter_count :: (stmt: usize) -> i32 #foreign sqlib "dist_sqlite3_bind_parameter_count";
|
||||
sqlite3_bind_parameter_index :: (stmt: usize, name: cstring) -> i32 #foreign sqlib "dist_sqlite3_bind_parameter_index";
|
||||
sqlite3_bind_parameter_name :: (stmt: usize, idx: i32) -> ?cstring #foreign sqlib "dist_sqlite3_bind_parameter_name";
|
||||
sqlite3_bind_text :: (stmt: usize, idx: i32, text: [*]u8, n: i32, destructor: isize) -> i32 #foreign sqlib "dist_sqlite3_bind_text";
|
||||
sqlite3_bind_blob :: (stmt: usize, idx: i32, data: [*]u8, n: i32, destructor: isize) -> i32 #foreign sqlib "dist_sqlite3_bind_blob";
|
||||
sqlite3_bind_double :: (stmt: usize, idx: i32, v: f64) -> i32 #foreign sqlib "dist_sqlite3_bind_double";
|
||||
sqlite3_bind_int64 :: (stmt: usize, idx: i32, v: i64) -> i32 #foreign sqlib "dist_sqlite3_bind_int64";
|
||||
sqlite3_bind_null :: (stmt: usize, idx: i32) -> i32 #foreign sqlib "dist_sqlite3_bind_null";
|
||||
sqlite3_bind_zeroblob64 :: (stmt: usize, idx: i32, n: u64) -> i32 #foreign sqlib "dist_sqlite3_bind_zeroblob64";
|
||||
sqlite3_bind_parameter_count :: (stmt: usize) -> i32 #foreign sqlib "sqlite3_bind_parameter_count";
|
||||
sqlite3_bind_parameter_index :: (stmt: usize, name: cstring) -> i32 #foreign sqlib "sqlite3_bind_parameter_index";
|
||||
sqlite3_bind_parameter_name :: (stmt: usize, idx: i32) -> ?cstring #foreign sqlib "sqlite3_bind_parameter_name";
|
||||
sqlite3_bind_text :: (stmt: usize, idx: i32, text: [*]u8, n: i32, destructor: isize) -> i32 #foreign sqlib "sqlite3_bind_text";
|
||||
sqlite3_bind_blob :: (stmt: usize, idx: i32, data: [*]u8, n: i32, destructor: isize) -> i32 #foreign sqlib "sqlite3_bind_blob";
|
||||
sqlite3_bind_double :: (stmt: usize, idx: i32, v: f64) -> i32 #foreign sqlib "sqlite3_bind_double";
|
||||
sqlite3_bind_int64 :: (stmt: usize, idx: i32, v: i64) -> i32 #foreign sqlib "sqlite3_bind_int64";
|
||||
sqlite3_bind_null :: (stmt: usize, idx: i32) -> i32 #foreign sqlib "sqlite3_bind_null";
|
||||
sqlite3_bind_zeroblob64 :: (stmt: usize, idx: i32, n: u64) -> i32 #foreign sqlib "sqlite3_bind_zeroblob64";
|
||||
|
||||
// ── FFI: result columns ───────────────────────────────────────────────
|
||||
sqlite3_column_blob :: (stmt: usize, icol: i32) -> ?*u8 #foreign sqlib "dist_sqlite3_column_blob";
|
||||
sqlite3_column_double :: (stmt: usize, icol: i32) -> f64 #foreign sqlib "dist_sqlite3_column_double";
|
||||
sqlite3_column_int64 :: (stmt: usize, icol: i32) -> i64 #foreign sqlib "dist_sqlite3_column_int64";
|
||||
sqlite3_column_text :: (stmt: usize, icol: i32) -> ?*u8 #foreign sqlib "dist_sqlite3_column_text";
|
||||
sqlite3_column_bytes :: (stmt: usize, icol: i32) -> i32 #foreign sqlib "dist_sqlite3_column_bytes";
|
||||
sqlite3_column_type :: (stmt: usize, icol: i32) -> i32 #foreign sqlib "dist_sqlite3_column_type";
|
||||
sqlite3_column_count :: (stmt: usize) -> i32 #foreign sqlib "dist_sqlite3_column_count";
|
||||
sqlite3_column_name :: (stmt: usize, icol: i32) -> ?cstring #foreign sqlib "dist_sqlite3_column_name";
|
||||
sqlite3_column_decltype :: (stmt: usize, icol: i32) -> ?cstring #foreign sqlib "dist_sqlite3_column_decltype";
|
||||
sqlite3_column_database_name :: (stmt: usize, icol: i32) -> ?cstring #foreign sqlib "dist_sqlite3_column_database_name";
|
||||
sqlite3_column_table_name :: (stmt: usize, icol: i32) -> ?cstring #foreign sqlib "dist_sqlite3_column_table_name";
|
||||
sqlite3_column_origin_name :: (stmt: usize, icol: i32) -> ?cstring #foreign sqlib "dist_sqlite3_column_origin_name";
|
||||
sqlite3_data_count :: (stmt: usize) -> i32 #foreign sqlib "dist_sqlite3_data_count";
|
||||
sqlite3_column_blob :: (stmt: usize, icol: i32) -> ?*u8 #foreign sqlib "sqlite3_column_blob";
|
||||
sqlite3_column_double :: (stmt: usize, icol: i32) -> f64 #foreign sqlib "sqlite3_column_double";
|
||||
sqlite3_column_int64 :: (stmt: usize, icol: i32) -> i64 #foreign sqlib "sqlite3_column_int64";
|
||||
sqlite3_column_text :: (stmt: usize, icol: i32) -> ?*u8 #foreign sqlib "sqlite3_column_text";
|
||||
sqlite3_column_bytes :: (stmt: usize, icol: i32) -> i32 #foreign sqlib "sqlite3_column_bytes";
|
||||
sqlite3_column_type :: (stmt: usize, icol: i32) -> i32 #foreign sqlib "sqlite3_column_type";
|
||||
sqlite3_column_count :: (stmt: usize) -> i32 #foreign sqlib "sqlite3_column_count";
|
||||
sqlite3_column_name :: (stmt: usize, icol: i32) -> ?cstring #foreign sqlib "sqlite3_column_name";
|
||||
sqlite3_column_decltype :: (stmt: usize, icol: i32) -> ?cstring #foreign sqlib "sqlite3_column_decltype";
|
||||
sqlite3_column_database_name :: (stmt: usize, icol: i32) -> ?cstring #foreign sqlib "sqlite3_column_database_name";
|
||||
sqlite3_column_table_name :: (stmt: usize, icol: i32) -> ?cstring #foreign sqlib "sqlite3_column_table_name";
|
||||
sqlite3_column_origin_name :: (stmt: usize, icol: i32) -> ?cstring #foreign sqlib "sqlite3_column_origin_name";
|
||||
sqlite3_data_count :: (stmt: usize) -> i32 #foreign sqlib "sqlite3_data_count";
|
||||
|
||||
// ── FFI: incremental blob I/O ─────────────────────────────────────────
|
||||
sqlite3_blob_open :: (db: usize, db_name: cstring, table: cstring, column: cstring, rowid: i64, flags: i32, out_blob: *usize) -> i32 #foreign sqlib "dist_sqlite3_blob_open";
|
||||
sqlite3_blob_reopen :: (blob: usize, rowid: i64) -> i32 #foreign sqlib "dist_sqlite3_blob_reopen";
|
||||
sqlite3_blob_close :: (blob: usize) -> i32 #foreign sqlib "dist_sqlite3_blob_close";
|
||||
sqlite3_blob_bytes :: (blob: usize) -> i32 #foreign sqlib "dist_sqlite3_blob_bytes";
|
||||
sqlite3_blob_read :: (blob: usize, buf: [*]u8, n: i32, offset: i32) -> i32 #foreign sqlib "dist_sqlite3_blob_read";
|
||||
sqlite3_blob_write :: (blob: usize, buf: [*]u8, n: i32, offset: i32) -> i32 #foreign sqlib "dist_sqlite3_blob_write";
|
||||
sqlite3_blob_open :: (db: usize, db_name: cstring, table: cstring, column: cstring, rowid: i64, flags: i32, out_blob: *usize) -> i32 #foreign sqlib "sqlite3_blob_open";
|
||||
sqlite3_blob_reopen :: (blob: usize, rowid: i64) -> i32 #foreign sqlib "sqlite3_blob_reopen";
|
||||
sqlite3_blob_close :: (blob: usize) -> i32 #foreign sqlib "sqlite3_blob_close";
|
||||
sqlite3_blob_bytes :: (blob: usize) -> i32 #foreign sqlib "sqlite3_blob_bytes";
|
||||
sqlite3_blob_read :: (blob: usize, buf: [*]u8, n: i32, offset: i32) -> i32 #foreign sqlib "sqlite3_blob_read";
|
||||
sqlite3_blob_write :: (blob: usize, buf: [*]u8, n: i32, offset: i32) -> i32 #foreign sqlib "sqlite3_blob_write";
|
||||
|
||||
// ── FFI: online backup ────────────────────────────────────────────────
|
||||
sqlite3_backup_init :: (dst: usize, dst_name: cstring, src: usize, src_name: cstring) -> usize #foreign sqlib "dist_sqlite3_backup_init";
|
||||
sqlite3_backup_step :: (bk: usize, n_page: i32) -> i32 #foreign sqlib "dist_sqlite3_backup_step";
|
||||
sqlite3_backup_finish :: (bk: usize) -> i32 #foreign sqlib "dist_sqlite3_backup_finish";
|
||||
sqlite3_backup_remaining :: (bk: usize) -> i32 #foreign sqlib "dist_sqlite3_backup_remaining";
|
||||
sqlite3_backup_pagecount :: (bk: usize) -> i32 #foreign sqlib "dist_sqlite3_backup_pagecount";
|
||||
sqlite3_backup_init :: (dst: usize, dst_name: cstring, src: usize, src_name: cstring) -> usize #foreign sqlib "sqlite3_backup_init";
|
||||
sqlite3_backup_step :: (bk: usize, n_page: i32) -> i32 #foreign sqlib "sqlite3_backup_step";
|
||||
sqlite3_backup_finish :: (bk: usize) -> i32 #foreign sqlib "sqlite3_backup_finish";
|
||||
sqlite3_backup_remaining :: (bk: usize) -> i32 #foreign sqlib "sqlite3_backup_remaining";
|
||||
sqlite3_backup_pagecount :: (bk: usize) -> i32 #foreign sqlib "sqlite3_backup_pagecount";
|
||||
|
||||
// ── FFI: serialization ────────────────────────────────────────────────
|
||||
sqlite3_serialize :: (db: usize, schema: cstring, out_size: *i64, flags: u32) -> ?*u8 #foreign sqlib "dist_sqlite3_serialize";
|
||||
sqlite3_deserialize :: (db: usize, schema: cstring, data: usize, sz_db: i64, sz_buf: i64, flags: u32) -> i32 #foreign sqlib "dist_sqlite3_deserialize";
|
||||
sqlite3_serialize :: (db: usize, schema: cstring, out_size: *i64, flags: u32) -> ?*u8 #foreign sqlib "sqlite3_serialize";
|
||||
sqlite3_deserialize :: (db: usize, schema: cstring, data: usize, sz_db: i64, sz_buf: i64, flags: u32) -> i32 #foreign sqlib "sqlite3_deserialize";
|
||||
|
||||
// ── FFI: library utilities ────────────────────────────────────────────
|
||||
sqlite3_libversion :: () -> ?cstring #foreign sqlib "dist_sqlite3_libversion";
|
||||
sqlite3_libversion_number :: () -> i32 #foreign sqlib "dist_sqlite3_libversion_number";
|
||||
sqlite3_sourceid :: () -> ?cstring #foreign sqlib "dist_sqlite3_sourceid";
|
||||
sqlite3_threadsafe :: () -> i32 #foreign sqlib "dist_sqlite3_threadsafe";
|
||||
sqlite3_compileoption_used :: (name: cstring) -> i32 #foreign sqlib "dist_sqlite3_compileoption_used";
|
||||
sqlite3_compileoption_get :: (n: i32) -> ?cstring #foreign sqlib "dist_sqlite3_compileoption_get";
|
||||
sqlite3_complete :: (sql: cstring) -> i32 #foreign sqlib "dist_sqlite3_complete";
|
||||
sqlite3_free :: (p: usize) #foreign sqlib "dist_sqlite3_free";
|
||||
sqlite3_malloc64 :: (n: u64) -> usize #foreign sqlib "dist_sqlite3_malloc64";
|
||||
sqlite3_msize :: (p: usize) -> u64 #foreign sqlib "dist_sqlite3_msize";
|
||||
sqlite3_memory_used :: () -> i64 #foreign sqlib "dist_sqlite3_memory_used";
|
||||
sqlite3_memory_highwater :: (reset: i32) -> i64 #foreign sqlib "dist_sqlite3_memory_highwater";
|
||||
sqlite3_release_memory :: (n: i32) -> i32 #foreign sqlib "dist_sqlite3_release_memory";
|
||||
sqlite3_soft_heap_limit64 :: (n: i64) -> i64 #foreign sqlib "dist_sqlite3_soft_heap_limit64";
|
||||
sqlite3_hard_heap_limit64 :: (n: i64) -> i64 #foreign sqlib "dist_sqlite3_hard_heap_limit64";
|
||||
sqlite3_randomness :: (n: i32, buf: [*]u8) #foreign sqlib "dist_sqlite3_randomness";
|
||||
sqlite3_sleep :: (ms: i32) -> i32 #foreign sqlib "dist_sqlite3_sleep";
|
||||
sqlite3_stricmp :: (a: cstring, b: cstring) -> i32 #foreign sqlib "dist_sqlite3_stricmp";
|
||||
sqlite3_strnicmp :: (a: cstring, b: cstring, n: i32) -> i32 #foreign sqlib "dist_sqlite3_strnicmp";
|
||||
sqlite3_strglob :: (glob: cstring, s: cstring) -> i32 #foreign sqlib "dist_sqlite3_strglob";
|
||||
sqlite3_strlike :: (like: cstring, s: cstring, esc: u32) -> i32 #foreign sqlib "dist_sqlite3_strlike";
|
||||
sqlite3_libversion :: () -> ?cstring #foreign sqlib "sqlite3_libversion";
|
||||
sqlite3_libversion_number :: () -> i32 #foreign sqlib "sqlite3_libversion_number";
|
||||
sqlite3_sourceid :: () -> ?cstring #foreign sqlib "sqlite3_sourceid";
|
||||
sqlite3_threadsafe :: () -> i32 #foreign sqlib "sqlite3_threadsafe";
|
||||
sqlite3_compileoption_used :: (name: cstring) -> i32 #foreign sqlib "sqlite3_compileoption_used";
|
||||
sqlite3_compileoption_get :: (n: i32) -> ?cstring #foreign sqlib "sqlite3_compileoption_get";
|
||||
sqlite3_complete :: (sql: cstring) -> i32 #foreign sqlib "sqlite3_complete";
|
||||
sqlite3_free :: (p: usize) #foreign sqlib "sqlite3_free";
|
||||
sqlite3_malloc64 :: (n: u64) -> usize #foreign sqlib "sqlite3_malloc64";
|
||||
sqlite3_msize :: (p: usize) -> u64 #foreign sqlib "sqlite3_msize";
|
||||
sqlite3_memory_used :: () -> i64 #foreign sqlib "sqlite3_memory_used";
|
||||
sqlite3_memory_highwater :: (reset: i32) -> i64 #foreign sqlib "sqlite3_memory_highwater";
|
||||
sqlite3_release_memory :: (n: i32) -> i32 #foreign sqlib "sqlite3_release_memory";
|
||||
sqlite3_soft_heap_limit64 :: (n: i64) -> i64 #foreign sqlib "sqlite3_soft_heap_limit64";
|
||||
sqlite3_hard_heap_limit64 :: (n: i64) -> i64 #foreign sqlib "sqlite3_hard_heap_limit64";
|
||||
sqlite3_randomness :: (n: i32, buf: [*]u8) #foreign sqlib "sqlite3_randomness";
|
||||
sqlite3_sleep :: (ms: i32) -> i32 #foreign sqlib "sqlite3_sleep";
|
||||
sqlite3_stricmp :: (a: cstring, b: cstring) -> i32 #foreign sqlib "sqlite3_stricmp";
|
||||
sqlite3_strnicmp :: (a: cstring, b: cstring, n: i32) -> i32 #foreign sqlib "sqlite3_strnicmp";
|
||||
sqlite3_strglob :: (glob: cstring, s: cstring) -> i32 #foreign sqlib "sqlite3_strglob";
|
||||
sqlite3_strlike :: (like: cstring, s: cstring, esc: u32) -> i32 #foreign sqlib "sqlite3_strlike";
|
||||
|
||||
// ── Result codes (primary; full set) ──────────────────────────────────
|
||||
SQLITE_OK :: 0;
|
||||
|
||||
11
tests/run.sh
11
tests/run.sh
@@ -8,15 +8,14 @@
|
||||
#
|
||||
# Locate the compiler via SX (overridable); defaults to the sibling sx repo.
|
||||
#
|
||||
# `-L build/vendor/jit` lets the JIT dlopen the VENDORED libsqlite3.dylib
|
||||
# (built by `make build`) instead of falling back to the OS copy — the
|
||||
# version assert in tests/sqlite_smoke.sx depends on it.
|
||||
# The vendored SQLite needs no flags here: src/db/sqlite.sx declares it
|
||||
# as a `#import c` unit, so `sx run` compiles (cached) and loads it as a
|
||||
# priority symbol target — the version assert in tests/sqlite_smoke.sx
|
||||
# proves the OS copy never shadows it.
|
||||
set -u
|
||||
|
||||
SX="${SX:-/Users/agra/projects/sx/zig-out/bin/sx}"
|
||||
TESTS_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
||||
REPO_DIR=$(CDPATH= cd -- "$TESTS_DIR/.." && pwd)
|
||||
SX_RUN_FLAGS="-L $REPO_DIR/build/vendor/jit"
|
||||
|
||||
pass=0
|
||||
fail=0
|
||||
@@ -26,7 +25,7 @@ fail=0
|
||||
# pass/fail counters survive).
|
||||
for t in $(find "$TESTS_DIR" -name '*.sx' -type f | sort); do
|
||||
name=${t#"$TESTS_DIR"/}
|
||||
if "$SX" run "$t" $SX_RUN_FLAGS >/dev/null 2>&1; then
|
||||
if "$SX" run "$t" >/dev/null 2>&1; then
|
||||
printf ' %-44s ok\n' "$name"
|
||||
pass=$((pass + 1))
|
||||
else
|
||||
|
||||
40
vendor/sqlite/README.md
vendored
40
vendor/sqlite/README.md
vendored
@@ -7,26 +7,21 @@
|
||||
`sqlite3ext.h` dropped — no shell, no loadable extensions)
|
||||
- License: public domain (<https://sqlite.org/copyright.html>)
|
||||
|
||||
`make build` compiles this into `build/vendor/libsqlite3.a` (statically
|
||||
linked into the `dist` binary via `-L build/vendor`) and
|
||||
`build/vendor/jit/libsqlite3.dylib` (dlopen'd by `sx run`, which is how
|
||||
`make test` executes the test programs). The two locations are separate
|
||||
on purpose: the macOS linker prefers a dylib over an archive in the same
|
||||
search directory, and the AOT binary must link the static copy.
|
||||
`tests/sqlite_smoke.sx` asserts `sqlite3_libversion()` equals the version
|
||||
above, so a fallback to the OS libsqlite3 fails loudly in both modes.
|
||||
|
||||
## Symbol renaming
|
||||
|
||||
The sx JIT resolves `#foreign` symbols via `dlsym(RTLD_DEFAULT)`, which
|
||||
searches every image already loaded into the process — the OS libsqlite3
|
||||
is usually among them and wins by load order. So every API function the
|
||||
bindings use is renamed `dist_sqlite3_*` in the vendored build: those
|
||||
symbols exist ONLY here, making resolution unambiguous in both JIT and
|
||||
AOT modes. The rename header is GENERATED by `make` into
|
||||
`build/vendor/rename.h` from the `#foreign` names in
|
||||
`src/db/sqlite.sx` — the bindings file is the single source of truth,
|
||||
and the rename list cannot drift from it.
|
||||
The amalgamation is part of the program, not the build system:
|
||||
`src/db/sqlite.sx` declares it as a named `#import c` unit carrying the
|
||||
pinned compile options (`SQLITE_DQS=0`, `SQLITE_THREADSAFE=0`,
|
||||
`SQLITE_DEFAULT_MEMSTATUS=0`, `SQLITE_OMIT_DEPRECATED`,
|
||||
`SQLITE_OMIT_SHARED_CACHE`, `SQLITE_LIKE_DOESNT_MATCH_BLOBS`,
|
||||
`SQLITE_ENABLE_COLUMN_METADATA`, `-O2`), and every `#foreign sqlib`
|
||||
binding resolves against that unit. sx compiles the unit through its
|
||||
content-addressed object cache (`.sx-cache/`), so the 250k-line source
|
||||
builds once per checkout — `sx build` links the objects into the
|
||||
binary, `sx run` loads them as a PRIORITY symbol-search target ahead of
|
||||
the process images, which is why the OS libsqlite3 (a different
|
||||
version, loaded into the compiler process by CoreServices) can never
|
||||
shadow this copy. `tests/sqlite_smoke.sx` asserts
|
||||
`sqlite3_libversion()` equals the version above, so any fallback fails
|
||||
loudly in both modes.
|
||||
|
||||
## Bound surface
|
||||
|
||||
@@ -42,5 +37,6 @@ variants, and subsystems this build omits (mutex/VFS under
|
||||
`SQLITE_THREADSAFE=0`, sessions/snapshots/vtabs, deprecated API).
|
||||
|
||||
To upgrade: replace `sqlite3.c`/`sqlite3.h` with a newer amalgamation,
|
||||
update this file and the version constant in `tests/sqlite_smoke.sx`, and
|
||||
run `make clean test`.
|
||||
update this file and the version constant in `tests/sqlite_smoke.sx`,
|
||||
and run `make clean test` (the object cache keys on the source bytes,
|
||||
so the new amalgamation recompiles automatically).
|
||||
|
||||
Reference in New Issue
Block a user