Explorar el Código

docs: save SQLite binding test inventory and session

Eric Streit hace 1 día
padre
commit
5683cf5fed
Se han modificado 2 ficheros con 342 adiciones y 0 borrados
  1. 178 0
      bindings/sqlite3/TEST-INVENTORY.md
  2. 164 0
      docs/session-2026-10-26-sqlite-binding.md

+ 178 - 0
bindings/sqlite3/TEST-INVENTORY.md

@@ -0,0 +1,178 @@
+# SQLite binding — test inventory
+
+Date: 2026-10-26
+
+This note records which existing tests are useful for hardening the V3
+SQLite binding under `bindings/sqlite3`, and which APIs they would drive.
+
+## Sources scanned
+
+| Source | Count | Notes |
+|---|---:|---|
+| `bindings/sqlite3/tests` | 8 | Current V3 tests: smoke, prepared, scalar, errors, BLOB, connection, callback, hooks |
+| sibling `m2SQLITE/tests` | 7 | Original GNU Modula-2 binding tests; closest existing coverage |
+| sibling `m2SQLITE/sqlite-master/test` | 1,195 `.test` files | Upstream SQLite TCL regression suite; useful as a specification |
+| `compiler/tests` | 806 files | Compiler/ABI tests; not SQLite-specific, but several guard binding prerequisites |
+
+The upstream SQLite tests are TCL-based and cannot run directly against
+the V3 binding.  Port individual `do_test` scenarios, not the test
+harness.
+
+## Current V3 binding tests
+
+- `SQLiteSmoke.mod`
+- `SQLitePrepared.mod`
+- `SQLiteScalar.mod`
+- `SQLiteErrors.mod`
+- `SQLiteBlob.mod`
+- `SQLiteConnection.mod`
+- `SQLiteCallback.mod`
+- `SQLiteHooks.mod`
+
+## Original m2SQLITE tests
+
+| Test | Useful coverage | Status in V3 binding |
+|---|---|---|
+| `test_prepare.mod` | `bind_parameter_count/index`, named parameters, 64-bit bind, scalar round trip | **High priority.** Missing parameter-introspection APIs |
+| `test_func.mod` | scalar/aggregate UDFs, auxdata, numeric type, `result_value`, 64-bit text/blob, zeroblob, error paths | Missing several callback/result APIs |
+| `test_blob.mod` | read-only BLOB write error, reopen, backup API, backup to file | BLOB happy path covered; read-only/error and backup not covered |
+| `test_codes.mod` | extended constraint codes (unique/not-null/PK/FK), `get_table` | Only PK/unique constants; missing not-null/FK constants and `get_table` |
+| `test_exec.mod` | exec, change counters, rowid, error capture | Already covered by current V3 tests |
+| `test_open.mod` | `open` / `open_v2` / close and `errcode` | Already covered by current V3 tests |
+| `test_version.mod` | `sqlite3_libversion*` | Missing version APIs |
+
+## Upstream SQLite tests worth mining
+
+### Highest priority
+
+| File | Interesting cases | What it drives |
+|---|---|---|
+| `bind.test` | `bind-1.*` named params/unbound NULL/reset; `bind-9.*` high parameter numbers; `bind-10.*` parameter index/name; 32/64/double/NULL/text/UTF-16/clear sections | `sqlite3_bind_parameter_count/name/index`; reset/reuse; long 64-bit values |
+| `incrblob.test` | sections `incrblob-3.*` read-only write, `4.*` bad row/table/column/type opens, `7.*` handle invalidation | BLOB error paths and boundary behavior |
+| `types.test`, `types2.test`, `types3.test` | storage classes, affinity, integer/real/text conversions | `column_type`, numeric columns, bound values |
+| `null.test`, `nulls1.test`, `nulls2.test` | NULL in expressions, comparisons, result types | `bind_null`, `column_type`, `value_type` |
+| `auth.test` | deny at prepare, `SQLITE_IGNORE` for reads, action arguments, authorizer replacement | authorizer arguments and return semantics |
+| `busy.test`, `busy2.test` | lock contention, busy handler invocation, timeout | actual busy-handler behavior (current test only registers one) |
+| `progress.test` | callback count, nonzero return aborts query, nested query from callback | progress callback return handling |
+| `trace.test`, `trace2.test`, `trace3.test` | statement/profile/row/close masks and callback arguments | trace masks beyond `SQLiteTraceStmt` |
+
+### Medium priority
+
+| File | Interesting cases | What it drives |
+|---|---|---|
+| `func.test` … `func9.test` | function arg counts, NULLs, destructors, auxdata, aggregates, result types | aggregate/auxdata APIs, more result writers |
+| `errors`/`errmsg.test` | error text and error offsets | `sqlite3_error_offset`, error-message behavior |
+| `fkey1.test` … `fkey9.test` | foreign-key and not-null constraint codes | missing extended-code constants |
+| `openv2.test`, `uri.test`, `uri2.test` | open flags, URI filenames, read-only opens | `open_v2` flags and URI behavior |
+| `limit.test`, `limit2.test` | `sqlite3_limit` | connection limits |
+| `trans.test`, `trans2.test`, `trans3.test`, `rollback.test` | transaction boundaries and hooks | commit/rollback hook ordering |
+| `backup.test`, `backup2.test`, `backup4.test`, `backup5.test` | online backup and incremental backup | backup API |
+| `attach.test`, `attach2.test` | multiple attached databases | BLOB `zDb` values, future helpers |
+
+### Later / not useful yet
+
+- `malloc*`, `*fault*`, `*ioerr*`: SQLite fault-injection harness.
+- `wal*`, `shared*`, `lock*`: pager/WAL/concurrency internals.
+- `window*`, `collat*`: APIs not exposed by the V3 binding yet.
+- `select*`, `expr*`, `alter*`, `vacuum*`: SQL engine behavior, not binding behavior.
+- `session`, `rbu`, `rtree`, `fts`: extension APIs.
+
+## Compiler tests that matter as binding prerequisites
+
+These are not SQLite tests, but they exercise compiler/ABI features the
+binding relies on and should remain in the main gate:
+
+- `compiler/tests/t_callback.mod` — top-level C callbacks
+- `compiler/tests/cabi_scalars_prog.mod` — scalar C ABI
+- `compiler/tests/cstr_prog.mod` — C strings
+- `compiler/tests/cstruct_layout_prog.mod` — C record layout
+- `compiler/tests/t_open_row_adr.mod` — `ADR` behavior
+- `compiler/tests/t_libc2.mod` — raw C buffers
+- `compiler/tests/t_byte.mod`, `t_real.mod`, `t_long.mod` — byte/REAL/LONGINT widths
+
+## Recommended next test additions
+
+### 1. `SQLiteParams.mod` — best next test
+
+Port from `m2SQLITE/tests/test_prepare.mod` and `bind.test`.
+
+Add APIs:
+
+- `sqlite3_bind_parameter_count`
+- `sqlite3_bind_parameter_name`
+- `sqlite3_bind_parameter_index`
+
+Cases:
+
+- anonymous `?` parameters
+- named `:name`, `@name`, `$name` parameters
+- repeated named parameters
+- unbound parameters read back as NULL
+- `reset` and rebind reuse
+- `clear_bindings`
+- `LONGINT` value such as `9000000001`
+
+### 2. Extend `SQLiteBlob.mod`
+
+Port from `incrblob-3.*`, `incrblob-4.*` and `test_blob.mod`.
+
+Cases:
+
+- write to a read-only handle returns `SQLiteReadOnly`
+- close after a read-only write error
+- open nonexistent row/table/column
+- open integer/real/NULL column as BLOB
+- read/write outside bounds
+- reopen behavior
+- handle invalidation after a write to the same table
+
+### 3. Extend `SQLiteHooks.mod`
+
+Port from `progress.test` and `auth.test`.
+
+Cases:
+
+- progress callback returns nonzero and aborts the query
+- progress callback with `nOps = 0` disabled
+- authorizer `SQLiteAuthIgnore` on `SQLITE_READ` returns NULL
+- authorizer action arguments
+- busy handler actually invoked by a second connection
+
+### 4. Extended-code tests
+
+Port from `m2SQLITE/tests/test_codes.mod`.
+
+Add constants and tests for:
+
+- `SQLiteConstraintNotNull` = 1299
+- `SQLiteConstraintForeignKey` = 787
+- `SQLiteConstraintCheck` = 275
+- optionally trigger, rowid and datatype constraints
+
+### 5. Later slices
+
+- aggregate functions + auxdata (`test_func.mod`, `func*.test`)
+- backup API (`test_blob.mod`, `backup*.test`)
+- version/sourceid/threadsafe (`test_version.mod`)
+- `sqlite3_get_table` / `free_table`
+- statement metadata (`sqlite3_sql`, `expanded_sql`, `stmt_readonly`, `stmt_busy`)
+- limits, autocommit and error offsets
+
+## Related session note
+
+See `docs/session-2026-10-26-sqlite-binding.md` for the binding work
+completed in this session and the current verification state.
+
+## Porting caveats
+
+- Replace m2SQLITE's `libc.printf`/`HALT` style with the V3 test convention:
+  set `ExitCode := 42` on success.
+- m2SQLITE's `SQLiteUtils` helpers do not exist in the V3 binding; call
+  the raw `SQLite` procedures directly.
+- For a raw C pointer to a V3 array, use `ADR(a[0])`, not `ADR(a)`.
+- V3 string literals in the current compiler can be truncated for long
+  SQL text.  Keep individual literals short, or build the SQL through a
+  character buffer/concatenation.  Adjacent string literal concatenation
+  is not supported.
+- The upstream tests are specifications, not a runnable harness for this
+  binding.

+ 164 - 0
docs/session-2026-10-26-sqlite-binding.md

@@ -0,0 +1,164 @@
+# Session save — 2026-10-26 (SQLite binding)
+
+## Where we are
+
+The V3 SQLite binding under `bindings/sqlite3` now covers the core
+connection, statement, scalar, BLOB, callback and hook APIs.
+
+Binding code is committed through:
+
+```text
+9dd2a80 bindings: add SQLite connection hooks
+9df09ae bindings: add SQLite callback support
+0f235a1 bindings: add SQLite BLOB and connection APIs
+5d5faa1 bindings: add SQLite scalar and error APIs
+f40a026 bindings: add SQLite showcase
+ae7ce54 bindings: add SQLite prepared statements
+d3be70c bindings: add SQLite open/exec/close smoke test
+```
+
+The binding tests and showcase pass.  The compiler gate is **323/323**.
+`master` is one commit ahead of `origin/master` at the time of writing.
+
+## What this session added
+
+### Connection and scalar layer
+
+- `sqlite3_open_v2`, `close_v2`, open flags
+- `sqlite3_bind_int64`, `bind_double`, `bind_null`
+- `sqlite3_reset`, `clear_bindings`
+- `sqlite3_column_count`, `data_count`, `column_type`, `column_bytes`
+- `sqlite3_column_int64`, `double`, `name`, `decltype`
+- error APIs and `sqlite3_exec` `VAR errmsg`
+- result-code and storage-class constants
+
+### BLOB layer
+
+- `sqlite3_bind_blob`, `bind_zeroblob`
+- `sqlite3_column_blob`
+- `sqlite3_blob_open`, `blob_close`, `blob_read`, `blob_write`,
+  `blob_bytes`, `blob_reopen`
+- `sqlite3_changes`, `total_changes`, `last_insert_rowid`
+
+### Callbacks
+
+- `sqlite3_exec` row callbacks (`char **argv` / `char **colNames`)
+- `sqlite3_create_function_v2`
+- `sqlite3_value_*` and `sqlite3_result_*` scalar families
+- `SQLiteArrayAt` to index C pointer arrays
+- user data and context DB handle
+
+### Connection hooks
+
+- `sqlite3_busy_timeout`, `busy_handler`, `interrupt`
+- `sqlite3_progress_handler`
+- `sqlite3_trace_v2`
+- `sqlite3_update_hook`
+- `sqlite3_commit_hook`, `rollback_hook`
+- `sqlite3_set_authorizer`
+- `sqlite3_db_handle`
+- `SQLiteOp*`, `SQLiteAuth*`, `SQLiteTrace*` constants
+
+## Tests
+
+Current binding tests in `bindings/sqlite3/tests`:
+
+- `SQLiteSmoke.mod` — open/exec/close
+- `SQLitePrepared.mod` — prepared insert/select
+- `SQLiteScalar.mod` — scalar types and column metadata
+- `SQLiteErrors.mod` — errcode/errmsg/extended codes/free
+- `SQLiteBlob.mod` — bind/column/incremental BLOB, zeroblob
+- `SQLiteConnection.mod` — open_v2/close_v2/changes/rowid/read-only
+- `SQLiteCallback.mod` — exec callbacks and scalar UDFs
+- `SQLiteHooks.mod` — busy/progress/trace/update/commit/rollback/auth
+
+Showcase output remains:
+
+```text
+1: Ada
+2: Grace
+```
+
+## Key decisions and gotchas
+
+- Opaque SQLite handles stay `ADDRESS`; no by-value struct ABI.
+- `sqlite3_exec` takes `VAR errmsg : ADDRESS`; non-NIL messages are
+  caller-owned and freed with `sqlite3_free`.
+- `SQLiteTransient()` supplies `SQLITE_TRANSIENT`; bound text/BLOB data
+  is copied by SQLite.
+- For raw C buffers from V3 arrays, use `ADR(a[0])`, not `ADR(a)`.
+  `ADR(a)` points at the V3 array descriptor.
+- Callbacks must be top-level V3 procedures; nested procedures still
+  carry a hidden frame link and are not C-callable.
+- `sqlite3_update_hook` / `commit_hook` return the previous hook
+  pointer; assign it to an `ADDRESS`.
+- `sqlite3_set_authorizer` returns `SQLiteAuthOk`,
+  `SQLiteAuthDeny` or `SQLiteAuthIgnore`.
+- Compiler observation: a long V3 string literal used as SQL text was
+  truncated (61 bytes generated).  Keep SQL literals short or build
+  longer SQL through buffers; adjacent string literal concatenation is
+  not supported by V3.
+
+## Test-inventory analysis
+
+The full analysis is saved at:
+
+```text
+bindings/sqlite3/TEST-INVENTORY.md
+```
+
+Sources examined:
+
+- sibling `m2SQLITE/tests` — 7 original GNU Modula-2 binding tests
+- sibling `m2SQLITE/sqlite-master/test` — 1,195 upstream SQLite tests
+- `compiler/tests` — 806 compiler/ABI tests, not SQLite-specific
+
+Highest-value items identified:
+
+1. `m2SQLITE/tests/test_prepare.mod` + upstream `bind.test` —
+   parameter count/name/index, unbound parameters as NULL, reset/reuse,
+   64-bit values.
+2. `incrblob*.test` + `m2SQLITE/tests/test_blob.mod` — read-only BLOB
+   writes, invalid opens, bounds, handle invalidation, backup.
+3. `m2SQLITE/tests/test_codes.mod` — not-null/foreign-key/check
+   extended codes, `get_table`.
+4. `test_func.mod` / upstream `func*.test` — aggregates, auxdata,
+   more result writers and error paths.
+5. `auth.test`, `busy.test`, `progress.test`, `trace.test` — deeper
+   hook semantics.
+
+## Recommended next slice
+
+Add:
+
+- `sqlite3_bind_parameter_count`
+- `sqlite3_bind_parameter_name`
+- `sqlite3_bind_parameter_index`
+
+with a new `SQLiteParams.mod` ported from `test_prepare.mod` and
+`bind.test`.  This is the smallest high-value gap in the current
+binding.
+
+Then extend BLOB and hook tests with the upstream error/abort cases.
+
+## Resume commands
+
+```sh
+cd bindings/sqlite3
+./run.sh
+
+cd ../../compiler
+./run_tests.sh        # expect 323/323
+```
+
+## Remaining API gaps
+
+- statement parameter introspection
+- extended constraint codes beyond PK/unique
+- aggregates and auxdata
+- backup API
+- `sqlite3_get_table` / `free_table`
+- library version/source id/threadsafe
+- statement metadata (`sql`, `expanded_sql`, `readonly`, `busy`)
+- limits, autocommit and error offsets
+- extension loading and WAL/checkpoint helpers