java-topology/tools/tickets/defects/sqlite-0001.md
russell@unturf.com db29a08762 undefect. CWE-407 — 92 sites, 42 ecosystems
B&W print-friendly diagrams + tinkerpop-0001 + wave-3 proof sections.
Squash of 94 local commits onto remote master.
2026-03-26 19:48:18 -04:00

46 lines
1.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
id: sqlite-0001
repo: sqlite/sqlite
severity: MEDIUM
status: PATCHED
created: 2026-03-23
---
## Defect
**File:** `src/trigger.c:792` (`checkColumnOverlap`)
**Pattern:** `sqlite3IdListIndex(pIdList, pEList->a[e].zEName)` inside `for(e=0; e<pEList->nExpr; e++)`
**Complexity:** O(|SET_cols| × |trigger_cols|) per DML trigger check
**Language:** C
## Description
`checkColumnOverlap` determines whether any column in an UPDATE's SET clause (`pEList`)
matches any column listed in a trigger's WHEN-columns list (`pIdList`). It does this
by looping over each column in the SET clause and calling `sqlite3IdListIndex()` — a
linear scan through the IdList — for each one.
`sqlite3IdListIndex` is a sequential name-comparison loop (O(|pIdList|)). The outer
`for` loop is O(|pEList->nExpr|). Combined: O(|SET_cols| × |trigger_cols|).
This function is called by `triggersReallyExist()` which runs on **every INSERT, UPDATE,
and DELETE** to determine which triggers fire. For a table with W trigger-watched columns
and an UPDATE with S SET columns, each DML statement triggers O(S × W) comparisons.
At S=W=50 (wide table with a full-column UPDATE trigger), this is 2,500 string comparisons
per DML statement.
## Fix
**Replace:** Linear scan via `sqlite3IdListIndex` for each SET column
**With:** Build a case-insensitive hash set over `pIdList->a[i].zName` before the loop;
check O(1) per SET column via hash lookup.
**Data structure:** SQLite's `sqlite3HashInsert`/`sqlite3HashFind` (already used in the
codebase) keyed on column name string.
## Work required
- [ ] Patch in `defects/sqlite/patch/`
- [ ] Unit test — asserts exact comparison counts before/after (in `defects/sqlite/unit/`)
- [ ] Integration test — UPDATE on table with W=10,20,50 trigger-watched columns (in `defects/sqlite/integration/`)
- [ ] Benchmark — timing before/after on 10,000 UPDATE statements (in `defects/sqlite/bench/`)
- [ ] White paper section — `whitepaper/vectors/database/sqlite.rst`