# Behavior traces — sqlite/sqlite

> Canonical page: https://codevetter.com/unpack/sqlite/behavior-traces

# Behavior traces — sqlite/sqlite

Scanned commit fde3a84dddf35f4c19797c8afad04a44c596f4d8 (2026-09-21). Generated by codevetter codevetter 1.12.0 on 2026-09-22.

Three flows carry most of the system's weight: library startup and connection open; the prepare/step/finalize query cycle including automatic recompilation on schema change; and the CLI's REPL loop from argv parsing through dot-command dispatch to statement execution. A fourth, the durability path, is worth tracing separately because commit behavior forks sharply between rollback-journal and WAL mode. Each trace below names the actual functions in call order as read from the sources.
- Connection open trace: `sqlite3_open_v2` → `openDatabase` → `sqlite3_initialize` → mutex decision → flag masking → `sqlite3MallocZero(sizeof(sqlite3))` → `sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE)` → `sqlite3_mutex_enter` → `db->eOpenState = SQLITE_STATE_BUSY` → … → `setupLookaside` → `sqlite3_wal_autocheckpoint` → `opendb_out` label, which closes and nulls the handle on OOM or marks it `SQLITE_STATE_SICK` on other errors. — [src/main.c#L3388-L3470](https://github.com/sqlite/sqlite/blob/fde3a84dddf35f4c19797c8afad04a44c596f4d8/src/main.c#L3388-L3470) [src/main.c#L3700-L3752](https://github.com/sqlite/sqlite/blob/fde3a84dddf35f4c19797c8afad04a44c596f4d8/src/main.c#L3700-L3752)
- Prepare trace: `sqlite3_prepare_v2` → `sqlite3LockAndPrepare(db, zSql, nBytes, SQLITE_PREPARE_SAVESQL, 0, …)` → `sqlite3_mutex_enter(db->mutex)` → `sqlite3BtreeEnterAll(db)` → `sqlite3Prepare` (which memsets the `Parse` header/tail, links `sParse.pOuterParse`, and runs the parser) → retry loop → `sqlite3BtreeLeaveAll` → `sqlite3ApiExit` → `db->busyHandler.nBusy = 0`. — [src/prepare.c#L700-L745](https://github.com/sqlite/sqlite/blob/fde3a84dddf35f4c19797c8afad04a44c596f4d8/src/prepare.c#L700-L745) [src/prepare.c#L854-L900](https://github.com/sqlite/sqlite/blob/fde3a84dddf35f4c19797c8afad04a44c596f4d8/src/prepare.c#L854-L900) [src/prepare.c#L955-L972](https://github.com/sqlite/sqlite/blob/fde3a84dddf35f4c19797c8afad04a44c596f4d8/src/prepare.c#L955-L972)
- `SQLITE_PREPARE_PERSISTENT` changes allocation strategy mid-prepare: `sqlite3Prepare` increments `sParse.disableLookaside` and invokes `DisableLookaside` so long-lived statements do not pin lookaside slabs. — [src/prepare.c#L734-L740](https://github.com/sqlite/sqlite/blob/fde3a84dddf35f4c19797c8afad04a44c596f4d8/src/prepare.c#L734-L740)
- Step trace: `sqlite3_step` → `vdbeSafetyNotNull` → `sqlite3_mutex_enter` → inner `sqlite3Step` → (READY state) reset interrupt flag, bump `db->nVdbeActive`/`nVdbeWrite`/`nVdbeRead`, set `p->pc = 0`, move to `VDBE_RUN_STATE` → `sqlite3VdbeExec` (or `sqlite3VdbeList` when explaining) → on `SQLITE_DONE` with autocommit, `doWalCallbacks(db)`. — [src/vdbeapi.c#L838-L950](https://github.com/sqlite/sqlite/blob/fde3a84dddf35f4c19797c8afad04a44c596f4d8/src/vdbeapi.c#L838-L950) [src/vdbeapi.c#L980-L1000](https://github.com/sqlite/sqlite/blob/fde3a84dddf35f4c19797c8afad04a44c596f4d8/src/vdbeapi.c#L980-L1000)
- Auto-reset trace: when `sqlite3_step` is called on a statement already in `VDBE_HALT_STATE`, `sqlite3Step` calls `sqlite3_reset()` and `goto restart_step` — behavior introduced in 3.7.0, with `SQLITE_OMIT_AUTORESET` restoring the pre-3.6.23 `SQLITE_MISUSE` return. — [src/vdbeapi.c#L887-L917](https://github.com/sqlite/sqlite/blob/fde3a84dddf35f4c19797c8afad04a44c596f4d8/src/vdbeapi.c#L887-L917)
- Schema-change recovery trace: `sqlite3_step` loops while `sqlite3Step` returns `SQLITE_SCHEMA` (bounded by `SQLITE_MAX_SCHEMA_RETRY`), calling `sqlite3Reprepare(v)` → `sqlite3LockAndPrepare` on the saved SQL → `sqlite3VdbeSwap` → `sqlite3TransferBindings` → `sqlite3VdbeResetStepResult` → `sqlite3VdbeFinalize` of the throwaway VM, so bound parameters survive recompilation. — [src/vdbeapi.c#L980-L1000](https://github.com/sqlite/sqlite/blob/fde3a84dddf35f4c19797c8afad04a44c596f4d8/src/vdbeapi.c#L980-L1000) [src/prepare.c#L904-L940](https://github.com/sqlite/sqlite/blob/fde3a84dddf35f4c19797c8afad04a44c596f4d8/src/prepare.c#L904-L940)
- VDBE entry trace: `sqlite3VdbeExec` asserts `VDBE_RUN_STATE`, takes B-Tree mutexes via `sqlite3VdbeEnter` when `p->lockMask` is non-zero, computes `nProgressLimit` from `db->nProgressOps`, checks `db->u1.isInterrupted` (jumping to `abort_due_to_interrupt`), then enters the opcode loop incrementing `nVmStep` per instruction. — [src/vdbe.c#L902-L1000](https://github.com/sqlite/sqlite/blob/fde3a84dddf35f4c19797c8afad04a44c596f4d8/src/vdbe.c#L902-L1000)
- CLI startup trace: `main()` → `setvbuf(stderr,…,_IONBF)` → `isatty(0)`/`isatty(1)` to set `stdin_is_interactive`/`stdout_is_console` → `atexit(abnormalExit)` → optional `SQLITE_DEBUG_BREAK` debugger attach → `signal(SIGINT, interrupt_handler)`, `SIGTERM`/`SIGHUP` → `sqlite3_sourceid()` vs `SQLITE_SOURCE_ID` mismatch check that exits 1. — [src/shell.c.in#L14020-L14105](https://github.com/sqlite/sqlite/blob/fde3a84dddf35f4c19797c8afad04a44c596f4d8/src/shell.c.in#L14020-L14105)
- `main_init()` runs before any SQLite use and configures the library globally: `sqlite3_config(SQLITE_CONFIG_LOG, shellLog, p)`, `verify_uninitialized()`, `sqlite3_config(SQLITE_CONFIG_URI, 1)` and `sqlite3_config(SQLITE_CONFIG_MULTITHREAD)` — so the CLI runs in multithread (not serialized) mode with URI filenames enabled. — [src/shell.c.in#L13874-L13900](https://github.com/sqlite/sqlite/blob/fde3a84dddf35f4c19797c8afad04a44c596f4d8/src/shell.c.in#L13874-L13900)
- REPL trace: `process_input` → `one_input_line` → whitespace/`.`/`#` classification → `do_meta_command` for dot-commands (return code 2 means exit) → otherwise append to `zSql` → `sqlite3_complete` gate → `runOneSqlLine` → `shell_exec` → `sqlite3_prepare_v2`/step loop → QRF render. — [src/shell.c.in#L13473-L13565](https://github.com/sqlite/sqlite/blob/fde3a84dddf35f4c19797c8afad04a44c596f4d8/src/shell.c.in#L13473-L13565) [src/shell.c.in#L13354-L13370](https://github.com/sqlite/sqlite/blob/fde3a84dddf35f4c19797c8afad04a44c596f4d8/src/shell.c.in#L13354-L13370) [src/shell.c.in#L3807-L3860](https://github.com/sqlite/sqlite/blob/fde3a84dddf35f4c19797c8afad04a44c596f4d8/src/shell.c.in#L3807-L3860)
- Startup also sources `~/.sqliterc` through the same `process_input` path unless `-noinit` was given, and exits 1 on error when `bail_on_error` is set — meaning the rc file is executed with full dot-command privileges before the user's first keystroke. — [src/shell.c.in#L13745-L13755](https://github.com/sqlite/sqlite/blob/fde3a84dddf35f4c19797c8afad04a44c596f4d8/src/shell.c.in#L13745-L13755)
- Lazy-open trace: the shell does not open a database at startup; every dot-command that needs one calls `open_db(p, 0)` first (over 25 call sites), which is what makes `sqlite3` usable with no arguments and then `.open` later. — [src/shell.c.in#L5069-L5075](https://github.com/sqlite/sqlite/blob/fde3a84dddf35f4c19797c8afad04a44c596f4d8/src/shell.c.in#L5069-L5075) [src/shell.c.in#L9976-L11130](https://github.com/sqlite/sqlite/blob/fde3a84dddf35f4c19797c8afad04a44c596f4d8/src/shell.c.in#L9976-L11130)
- Commit trace (WAL): `sqlite3BtreeCommitPhaseOne` → `sqlite3PagerCommitPhaseOne` → `pagerFlushOnCommit` check → `sqlite3PcacheDirtyList` → `pagerWalFrames` → `sqlite3PcacheCleanAll`, then `sqlite3BtreeCommitPhaseTwo` → `sqlite3PagerCommitPhaseTwo`. — [src/btree.c#L4343](https://github.com/sqlite/sqlite/blob/fde3a84dddf35f4c19797c8afad04a44c596f4d8/src/btree.c#L4343) [src/btree.c#L4432](https://github.com/sqlite/sqlite/blob/fde3a84dddf35f4c19797c8afad04a44c596f4d8/src/btree.c#L4432) [src/pager.c#L6551-L6580](https://github.com/sqlite/sqlite/blob/fde3a84dddf35f4c19797c8afad04a44c596f4d8/src/pager.c#L6551-L6580) [src/pager.c#L6764](https://github.com/sqlite/sqlite/blob/fde3a84dddf35f4c19797c8afad04a44c596f4d8/src/pager.c#L6764)
- Commit trace (rollback journal): the same `sqlite3PagerCommitPhaseOne` falls into the non-WAL branch where `syncJournal()` and `pager_write_pagelist()` do the durable work, optionally short-circuited by `SQLITE_ENABLE_BATCH_ATOMIC_WRITE` when the device reports `SQLITE_IOCAP_BATCH_ATOMIC` and no super-journal is involved. — [src/pager.c#L6580-L6620](https://github.com/sqlite/sqlite/blob/fde3a84dddf35f4c19797c8afad04a44c596f4d8/src/pager.c#L6580-L6620) [src/pager.c#L4340](https://github.com/sqlite/sqlite/blob/fde3a84dddf35f4c19797c8afad04a44c596f4d8/src/pager.c#L4340) [src/pager.c#L4483](https://github.com/sqlite/sqlite/blob/fde3a84dddf35f4c19797c8afad04a44c596f4d8/src/pager.c#L4483)

Every claim links to its cited files at the pinned commit. Citations identify source evidence; they do not establish runtime correctness. Independent CodeVetter scan — not reviewed by upstream maintainers.

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
