Files
rdbms-playground/docs/adr
claude@clouddev1 555149da3c docs: ADR-0033 — SQL DML grammar (INSERT / UPDATE / DELETE)
Phase 3 of ADR-0030's SQL-surface roadmap. Status: Proposed.

Statement shapes (§1): single- and multi-row INSERT, INSERT…SELECT
(recursing through ADR-0032's SQL_SELECT_COMPOUND), UPDATE with
SET assignment list, DELETE, all three optionally followed by
RETURNING projection_list. Full UPSERT (ON CONFLICT … DO NOTHING /
DO UPDATE with the SQLite/PostgreSQL `excluded` pseudo-table)
on INSERT.

Dispatch (§2): SQL-first / DSL-fallback in Advanced mode via
Choice(SQL_shape, DSL_shape) per shared entry word. Requires a
new walker capability — Node::Guard(fn), a zero-byte-consumption
gating node — landed as the first sub-phase's work (R1 mitigation
budgeted).

Execution (§10): three typed Command variants (SqlInsert /
SqlUpdate / SqlDelete) carrying target_table, listed_columns,
and a returning: bool flag. Worker handlers know per-kind
specialisations: shortid auto-fill (§6, parity with DSL),
cascade summary (§7, WHERE byte-range injection into pre-count
subqueries), DataResult routing on RETURNING (§5).

Diagnostics (§8): three new keys (insert_arity_mismatch ERROR,
auto_column_overridden WARNING, not_null_missing WARNING) with
positive + negative test requirements.

OOS list (§13): DEFAULT VALUES (seed feature), SQLite OR-prefixes,
UPDATE FROM, WITH-prefixed DML, indexed-by hints,
multi-statement batches.

Implementation notes: eleven phased sub-phases (3a–3k) each with
explicit exit gates + written DA gates. Ordering puts Node::Guard
scaffolding (3a) FIRST so the dispatch mechanism is proven before
DML grammar lands on top.

Initial DA review (Initial DA review section) recorded seven
critiques that were resolved before status moved to Proposed; a
second-pass DA surfaced an eighth (Node::Guard wasn't an
existing walker capability) and added it to §2 + sub-phase 3a's
scope.
2026-05-20 22:35:34 +00:00
..

Architecture Decision Records

This directory contains the project's ADRs, recorded per ADR-0000.

Index

  • ADR-0000 — Record architecture decisions
  • ADR-0001 — Language and TUI framework
  • ADR-0002 — Database engine
  • ADR-0003 — Input modes and command dispatch
  • ADR-0004 — Project file format
  • ADR-0005 — Column type vocabulary
  • ADR-0006 — Undo snapshots and replay log
  • ADR-0007 — Sharing and export
  • ADR-0008 — Testing approach
  • ADR-0009 — DSL command syntax conventions
  • ADR-0010 — Database access via a dedicated worker thread
  • ADR-0011 — Foreign-key column type compatibility
  • ADR-0012 — Internal metadata for user-facing column types
  • ADR-0013 — Relationships, naming, and the rebuild-table strategy
  • ADR-0014 — Data operations, value literals, and the auto-show pattern
  • ADR-0015 — Project storage runtime
  • ADR-0016 — Pretty table rendering for data and structure views
  • ADR-0017 — Column type-change compatibility
  • ADR-0018 — Auto-fill contracts for serial and shortid columns
  • ADR-0019 — Friendly error layer (H1) and i18n message catalog
  • ADR-0020 — Tokenization layer for the DSL parser
  • ADR-0021 — Parser-as-source-of-truth for H1a (per-command usage in parse errors)
  • ADR-0022 — Ambient typing assistance: colour, hint panel, completion (I3 + I4)
  • ADR-0023 — Unified declarative grammar tree — direction (superseded for execution detail by ADR-0024)
  • ADR-0024 — Unified grammar tree: execution planAccepted, the executable spec — implemented (Phases AF; Phase F shipped "minimal", parser.rs retained as the router — see the ADR's Phase F implementation note)
  • ADR-0025 — IndexesAccepted, add index / drop index, persistence, rebuild-table preservation, and items-list display (C3 index portion + S2)
  • ADR-0026 — Complex WHERE expressionsAccepted, stratified recursive expression grammar (AND/OR/NOT, comparisons, LIKE, IS NULL, IN, BETWEEN) for update / delete / show data filters; show data gains where + limit; adds the Subgrammar node and a recursive Expr AST (C5a)
  • ADR-0027 — Input-field validity indicatorAccepted, a debounced [ERR] / [WRN] marker at the input row's right edge, backed by a walker diagnostics-severity model (parse-outcome + schema-existence); advisory, never blocks submission (S6); Amendment 1 adds a LIKE-on-numeric-column WARNING
  • ADR-0028 — Query plans (EXPLAIN QUERY PLAN)Accepted, an explain prefix command over show data / update / delete; an annotated, span-styled plan tree; introduces the OutputLine styled-runs mechanism (ADR-0016's deferred per-span styling) (QA1 / QA2)
  • ADR-0029 — Column constraints (NOT NULL / UNIQUE / CHECK / DEFAULT)Accepted, the four column-level constraints declared in the column-spec suffix (create table / add column) and modified on existing columns via add constraint … / drop constraint …; a pre-flight dry-run guards populated columns; CHECK reuses the ADR-0026 expression grammar via Subgrammar (C3)
  • ADR-0030 — Advanced mode: the standard-SQL surfaceAccepted, SQL added as grammar within the unified grammar tree (ADR-0024), not a separate batch parser — so SQL gets the same completion / highlighting / hints / parse-errors as the DSL; mode gates the SQL forms; DDL routes through the typed Command executor (metadata + type vocabulary preserved), DML and SELECT execute as validated SQL; engine-neutral posture, the DSL→SQL teaching echo; supersedes ADR-0001's sqlparser-rs reservation; phased plan (Q1 / Q2 / Q4)
  • ADR-0031 — The SQL expression grammarAccepted, the stratified SQL expression grammar fragment commissioned by ADR-0030 §3: a single precedence ladder (OR/AND/NOT, the comparison/LIKE/IN/BETWEEN/IS NULL predicate set, arithmetic incl. ||, function calls, CASE) — the superset of ADR-0026's DSL WHERE grammar, authored as a parallel fragment so simple mode is untouched; pure validation, builds no AST (consumers run/store SQL as text per ADR-0030 §4/§6); reuses ADR-0026's Subgrammar recursion + depth cap unchanged; subquery expressions and qualified column refs deferred to ADR-0030 Phase 2
  • ADR-0032 — The full SQL SELECT grammarAccepted, the Phase-2 grammar commissioned by ADR-0030 §3: full SELECT with INNER/LEFT/RIGHT/FULL OUTER/CROSS joins, GROUP BY/HAVING, all four set ops (UNION/UNION ALL/INTERSECT/EXCEPT), WITH and WITH RECURSIVE CTEs, LIMIT … OFFSET, DISTINCT, t.*, and bare-alias projection (lifting Phase-1 §4.2); additive extensions to ADR-0031's sql_expr for scalar subqueries, IN (SELECT …), [NOT] EXISTS, and qualified column refs (redeeming ADR-0031 §7 OOS-1/OOS-2); grammar-recursion via Subgrammar(&SQL_SELECT_COMPOUND) reuses ADR-0026's MAX_SUBGRAMMAR_DEPTH = 64 cap unchanged; softens ADR-0030 §8's "ambient assistance comes for free" claim: completion scope needs new WalkContext accumulators (a from_scope_stack of ScopeFrames holding from_scope / cte_bindings / projection_aliases), a new walker node variant Node::ScopedSubgrammar(&Node) as the push/pop trigger (existing Node::Subgrammar unchanged so DSL Expr and sql_expr recursion are unaffected), qualified-prefix completion narrowing, body-projection-derived CTE column resolution (so SELECT * and explicit-projection CTE bodies both yield real column completion past cte_alias.|), and a post-walk fixup pass that re-resolves projection-list identifier highlighting/validity once FROM is parsed (the projection-before-FROM problem); classifies every Phase-2 validation case against ADR-0027's ERROR/WARNING guideline (§11): five new diagnostic.* keys for parse-time-detectable cases (unknown qualifier, ambiguous column, projection-alias misplaced, CTE/compound arity mismatch) plus eight engine.* translation keys; a MatchedPath-walking predicate-warnings variant that closes the Phase-1 gap where SQL WHERE expressions emitted no LIKE-on-numeric / = NULL / type-mismatch warnings (ADR-0027 Amendment 1 finally extends to the SQL surface); adds a worker-side post-prepare type-resolution pass via engine column-origin metadata so bare column refs recover their playground type (partially lifting Phase-1 §4.5, the bool→0/1 case) — Cargo.toml gains column_metadata to rusqlite features (verified against pinned 0.39.0); __rdbms_* rejection extended to every new table-source slot; Amendment 1 narrows §12's resolution rule from a grammar-side structural classification to "trust the engine's column-origin metadata verbatim" after an empirical probe showed origin metadata follows through non-recursive CTEs, scalar subqueries, derived tables, set ops, and joins — the one structural exception is recursive CTE result columns, which return None and stay typeless; Amendment 2 records that §10.6's "rewrite the highlight class" prescription is realised via the two-pass schema-existence diagnostic + the renderer's diagnostic-overlay path (no separate per-byte rewrite step needed; no new HighlightClass variant), and that the projection-before-FROM completion narrowing has been improved by an src/completion.rs look-ahead probe when the leading walk's from_scope is empty but the full input parses
  • ADR-0033 — The full SQL DML grammar (INSERT / UPDATE / DELETE)Proposed, the Phase-3 grammar commissioned by ADR-0030 §3: single- and multi-row INSERT (incl. INSERT … SELECT recursing through ADR-0032's SQL_SELECT_COMPOUND), UPDATE with SET assignment list, DELETE, all three optionally followed by RETURNING projection_list, plus full ON CONFLICT … DO NOTHING / DO UPDATE UPSERT on INSERT; fixes the DSL-vs-SQL dispatch architecture for shared entry words (insert/update/delete): SQL-first / DSL-fallback in Advanced mode via a Choice(SQL_shape, DSL_shape) per shape, gated by a new walker capability Node::Guard(fn) — a zero-byte-consumption gating node that fails the enclosing Seq with a ValidationError; carries Command::SqlInsert / SqlUpdate / SqlDelete variants and do_sql_* worker handlers each of which knows the target table (for re-persistence) and the returning: bool flag (for DataResult routing); shortid auto-fill mirrors the DSL do_insert mechanism via worker post-fill; SQL DELETE produces the same per-relationship cascade summary the DSL DELETE does (ADR-0014 parity), with the WHERE-clause source bytes re-injected into per-child pre-count subqueries; three new walker diagnostics (insert_arity_mismatch ERROR, auto_column_overridden WARNING, not_null_missing WARNING) with positive + negative tests each; OOS list explicitly carves out DEFAULT VALUES (the project's planned seed feature), SQLite-specific OR REPLACE / OR IGNORE / OR ABORT / OR FAIL / OR ROLLBACK prefixes, UPDATE FROM multi-table updates, and WITH-prefixed DML; the excluded keyword inside ON CONFLICT DO UPDATE is a deliberate carve-out from ADR-0030 §7's engine-neutral posture (no standard-SQL UPSERT spelling exists that SQLite and PostgreSQL share); eleven phased sub-phases each with explicit exit gates + written DA gate, opening with Node::Guard mechanism scaffolding before any DML grammar lands; initial DA review recorded seven critiques that were resolved before status moved to Proposed