← board

C: sqlite SQL exec reports corrupt sqlite_master during schema parse

Resolution

Done 2026-06-28. The self-compiled SQLite unity driver now executes:

open=0
exec=0
close=0

The richer test/csqlite_extended_test.c also completes table creation, index creation, inserts, selects, transaction update/delete, aggregate COUNT/SUM/AVG, and close. The last crash on the path was not schema corruption; it was the inline nested aggregate pointer-field bug fixed under bugfix-cfront-sqlite3-crash-vdbecursor-layout.md.

Symptom

The self-compiled SQLite amalgamation now opens and closes :memory: cleanly. The current probe:

sqlite3_exec(db, "CREATE TABLE t(id INTEGER, name TEXT);", 0, 0, 0);

now reaches VDBE execution but still fails before SQLITE_OK. As of the latest 2026-06-28 run it returns SQLITE_ERROR (1) with:

unrecognized token: "#"

GDB breakpoint at corruptSchema shows the schema row is otherwise sensible:

argv[0] = "table"
argv[1] = "sqlite_master"
argv[2] = "sqlite_master"
argv[3] = "1"
argv[4] = "CREATE TABLE x(type text,name text,tbl_name text,rootpage int,sql text)"
zExtra  = ""

Earlier reductions below describe the previous SQLITE_CORRUPT and VDBE crash states.

2026-06-28 update

The original SQLITE_CORRUPT return was reduced to two C frontend bugs and is no longer the current failure:

Further reduction cleared two more SQLite blockers:

With these fixes, the public sqlite3_exec(... CREATE TABLE ...) advances past schema parsing, SELECT expansion, and column-array construction. It then hit a segfault inside sqlite3VdbeExec: OP_OpenRead did not allocate cursor 0, so the following OP_Rewind dereferenced p->apCsr[0] == NULL.

That VDBE crash was a C switch-lowering bug: SQLite has legal case labels inside the compound block for case OP_ReopenIdx: { ... case OP_OpenRead: ... }. Switch lowering only scanned top-level switch-body statements, so nested case OP_OpenRead / case OP_OpenWrite labels emitted body labels but no dispatch tests. Guard: test/cswitch_nested_case_block_b127.c.

With nested switch labels fixed, the clean libc-free probe now reports:

open=0
exec=1
exec-msg=unrecognized token: "#"
close=0

The next reduction should identify where that # token enters the SQL text or token stream.

Acceptance