explain: explain command end to end (ADR-0028 steps 2–3)

Add the `explain` prefix command — `explain show data`,
`explain update`, `explain delete` — from grammar through to a
rendered plan tree.

- Grammar: an `EXPLAIN` CommandNode whose shape is a Choice over
  the three explainable query shapes, referenced (not
  duplicated) through `Subgrammar`. `Command::Explain { query:
  Box<Self> }`; `build_show_data` is extracted so the role-based
  builders serve both standalone and explain-wrapped commands.
- Worker: SQL construction is split out of do_query_data /
  do_update / do_delete into `build_*_sql`, so EXPLAIN QUERY
  PLAN runs the exact same statement. `Request::ExplainPlan` /
  `do_explain_plan` capture the plan; `QueryPlan` / `ExplainRow`
  carry it back. EXPLAIN QUERY PLAN never executes, so
  explaining update/delete changes nothing.
- Display SQL: the executed statement with `?N` parameters
  inlined as standard-SQL literals via a quote-aware scan.
- Render: `render_explain_plan` draws the box-drawing plan tree
  (plain output; ADR-0028 step 4 adds the styled tree).
- Catalog: `parse.usage.explain` and the `help.data.explain`
  entry, so `explain` shows up in the in-app `help` listing.

1151 tests pass (+18); clippy clean.
This commit is contained in:
claude@clouddev1
2026-05-19 12:38:02 +00:00
parent c1fcf28e04
commit d17addddd7
11 changed files with 836 additions and 67 deletions
+2
View File
@@ -151,6 +151,7 @@ pub const KEYS_AND_PLACEHOLDERS: &[(&str, &[&str])] = &[
("help.data.update", &[]),
("help.data.delete", &[]),
("help.data.replay", &[]),
("help.data.explain", &[]),
// ---- Hint panel ambient typing assistance (ADR-0022 §6) ----
("hint.ambient_complete", &[]),
(
@@ -214,6 +215,7 @@ pub const KEYS_AND_PLACEHOLDERS: &[(&str, &[&str])] = &[
("parse.usage.drop_index", &[]),
("parse.usage.drop_relationship", &[]),
("parse.usage.drop_table", &[]),
("parse.usage.explain", &[]),
("parse.usage.insert", &[]),
("parse.usage.rename_column", &[]),
("parse.usage.export", &[]),
+8
View File
@@ -281,6 +281,10 @@ help:
replay <path> — run each non-blank, non-`#`-comment line of <path>
as a command. Stops at the first error (no rollback);
relative paths resolve under the project directory.
explain: |-
explain show data <T> | explain update <T> ... | explain delete from <T> ...
— show how the database would run a query, without
running it (safe even for update / delete)
# Type reference, appended after the command list.
types_reference: |
Types: text, int, real, decimal, bool, date, datetime, blob, serial, shortid
@@ -440,6 +444,10 @@ parse:
insert: "insert into <Table> [(<col>[, ...])] [values] (<value>[, ...])"
update: "update <Table> set <col>=<value>[, ...] (where <col>=<value> | --all-rows)"
delete: "delete from <Table> (where <col>=<value> | --all-rows)"
explain: |-
explain show data <Table> [where <expr>] [limit <n>]
explain update <Table> set <col>=<value>[, ...] (where <expr> | --all-rows)
explain delete from <Table> (where <expr> | --all-rows)
replay: "replay <path> | replay '<path with spaces>'"
# App-lifecycle commands (per ADR-0003, surfaced through
# the parser so they participate in usage templates +