f62cccec55
explain now wraps the advanced SQL commands — select, with (CTE), insert, update, delete — in addition to the DSL show data/update/ delete it already covered, rendering through the same plan tree (ADR-0039, closing the ADR-0030 OOS-2 gap). Implemented as a second Advanced `explain` CommandNode under the shared entry word, reusing the established shared-word dispatch (SQL-first, DSL-fallback) rather than new grammar machinery. build_explain_sql slices the inner SQL off the source and reuses the existing SQL builders; do_explain_plan runs EXPLAIN QUERY PLAN over the carried text verbatim (never executes, so safe for destructive verbs). Advanced explain update/delete now route through SQL with an identical plan; DSL-explain tests pinned to simple mode. Help and usage text now list the advanced explain forms.
114 lines
5.5 KiB
Markdown
114 lines
5.5 KiB
Markdown
# ADR-0039: EXPLAIN over advanced-mode SQL queries
|
|
|
|
## Status
|
|
|
|
**Accepted** — decision recorded 2026-05-27. **Implemented 2026-05-30**
|
|
(issue #7; see Implementation below). **Supersedes ADR-0030 §13 OOS-2.**
|
|
|
|
## Context
|
|
|
|
ADR-0028 gave the DSL `explain` command: a prefix over `show data` /
|
|
`update` / `delete` that runs `EXPLAIN QUERY PLAN` and renders an
|
|
annotated, span-styled plan tree. ADR-0030 §13 **OOS-2** excluded
|
|
"`EXPLAIN` of advanced-mode SQL queries."
|
|
|
|
On readback (2026-05-27) that exclusion is a **deferred** out-of-scope
|
|
item, not a **rejected** one (see ADR-0000's out-of-scope discipline):
|
|
its own wording — *"the DSL `explain` still works for what it already
|
|
wraps"* — shows it was "not included in this surface," never "undesirable
|
|
for teaching." There was no pedagogical argument against it; it simply
|
|
fell outside the Phase-4/5 SQL-surface scope. It surfaced while
|
|
characterising advanced-mode `explain` (briefly suspected a bug; it was
|
|
OOS-2 behaving exactly as written).
|
|
|
|
Letting a learner see the plan for the SQL they *wrote* is a natural
|
|
extension of ADR-0028's intent, so OOS-2 is lifted.
|
|
|
|
## Decision
|
|
|
|
`explain` works over advanced-mode SQL queries — the SQL commands
|
|
`Select` / `SqlInsert` / `SqlUpdate` / `SqlDelete` — in addition to the
|
|
DSL `ShowData` / `Update` / `Delete` it already wraps (ADR-0028). It runs
|
|
`EXPLAIN QUERY PLAN` over the command's validated SQL text and renders
|
|
through the **existing ADR-0028 plan tree**. Advanced mode only (the SQL
|
|
commands are advanced-only); the DSL `explain` stays available in both
|
|
modes, unchanged. **Supersedes ADR-0030 §13 OOS-2.**
|
|
|
|
## Design sketch (deferred to the build)
|
|
|
|
- **Grammar.** The `explain` inner gains the SQL statement shapes in
|
|
advanced mode, alongside the DSL trio — mirroring how `explain` already
|
|
wraps the DSL nodes, here wrapping the SQL command shapes.
|
|
- **Execution.** Run `EXPLAIN QUERY PLAN` over the carried SQL text (the
|
|
`Sql*` / `Select` commands already hold validated text); reuse
|
|
ADR-0028's plan capture + renderer. `EXPLAIN QUERY PLAN` never executes
|
|
the statement, so explaining a destructive SQL command is safe — the
|
|
same property ADR-0028 already relies on.
|
|
- **Mode.** SQL inner only in advanced mode; DSL inner in both, unchanged.
|
|
|
|
Built test-first when picked up.
|
|
|
|
## Implementation (2026-05-30)
|
|
|
|
Built as designed, with the mode-gating and DSL/SQL disambiguation
|
|
handled by the **existing shared-entry-word dispatch** rather than any
|
|
new grammar machinery:
|
|
|
|
- **Two `explain` CommandNodes under one entry word.** The original
|
|
`data::EXPLAIN` (`Simple`, DSL inner) is unchanged. A new
|
|
`data::EXPLAIN_SQL` (`Advanced`) carries `EXPLAIN_SQL_SHAPE` — a
|
|
`Choice` over `select` / `with` / `insert` / `update` / `delete`,
|
|
each `[Word, Subgrammar(&SQL_*_SHAPE)]` reusing the standalone SQL
|
|
command shapes. Both register under `explain` in `REGISTRY`, exactly
|
|
mirroring the `insert`/`update`/`delete` shared-word pattern
|
|
(ADR-0033 §2). The walker's `decide` then does all the work: advanced
|
|
mode tries `EXPLAIN_SQL` first and falls back to the DSL `EXPLAIN`
|
|
when no SQL branch matches (`explain show data …`, or a DSL-only
|
|
`--all-rows`); simple mode reaches only the DSL node. **`with` (CTE)
|
|
is included** — it builds a `Command::Select`, in scope per the
|
|
decision's AST naming.
|
|
- **Rejected `DynamicSubgrammar` mode-gating.** A factory reading
|
|
`ctx.mode` would be memoised wrongly: the dynamic-resolution cache
|
|
key omits `mode`, so a node resolved in one mode would be served back
|
|
in the other. The two-CommandNode route avoids this and stays on the
|
|
established dispatch path.
|
|
- **Clean inner SQL.** `build_explain_sql` slices the inner SQL text
|
|
from the source starting at the inner entry keyword's span (so the
|
|
carried text excludes `explain`), then delegates to the existing
|
|
`build_select` / `build_sql_*` builders. Their metadata extraction
|
|
(target table, etc.) reads the path by role, which is offset-
|
|
independent, so wrapping is transparent.
|
|
- **Execution.** `do_explain_plan` gains arms for
|
|
`Select` / `SqlInsert` / `SqlUpdate` / `SqlDelete` that run
|
|
`EXPLAIN QUERY PLAN` over the carried SQL text verbatim, no bound
|
|
params (grammar-as-text). `display_sql` is the user's text as written
|
|
(the DSL path canonicalises only because it *synthesises* SQL). The
|
|
ADR-0028 renderer is reused unchanged.
|
|
- **Behaviour note.** In advanced mode `explain update …` /
|
|
`explain delete …` now route through the SQL path (previously the
|
|
DSL inner). The plan is identical (§6/§7 parity), and the SQL grammar
|
|
accepts the full SQL syntax the DSL grammar rejected. DSL-explain
|
|
tests were pinned to simple mode; advanced SQL wrapping has its own
|
|
tests.
|
|
|
|
## Out of scope
|
|
|
|
- **EXPLAIN of DDL** (`CREATE` / `ALTER` / `DROP`). `EXPLAIN QUERY PLAN`
|
|
applies to `SELECT` / `INSERT` / `UPDATE` / `DELETE`; DDL has no query
|
|
plan. *(Deferred — may be revisited if a useful rendering emerges; per
|
|
ADR-0000's out-of-scope discipline, this is deferred, not rejected.)*
|
|
|
|
## Consequences
|
|
|
|
- A self-contained feature, orthogonal to the DSL → SQL echo (ADR-0038):
|
|
the echo renders SQL *from* DSL commands; this explains SQL the user
|
|
*wrote*. They share nothing but the plan renderer's lineage.
|
|
- One OOS item in ADR-0030 §13 is now superseded; the rest stand.
|
|
|
|
## See also
|
|
|
|
- ADR-0028 — the DSL `explain` and the span-styled plan tree this reuses.
|
|
- ADR-0030 §13 — OOS-2, superseded here.
|
|
- ADR-0032 / ADR-0033 — the SQL `SELECT` / DML this explains.
|
|
- ADR-0000 — the out-of-scope discipline that reframed OOS-2 as deferred.
|