---
phase: 04-query-interface
plan: "02"
type: execute
wave: 2
depends_on:
  - "04-01"
files_modified:
  - src/query/explain.rs
  - src/query/mod.rs
  - src/lib.rs
autonomous: true
requirements:
  - QUERY-04

must_haves:
  truths:
    - "FROM explain_semantic_view('orders', dimensions := ['region'], metrics := ['total_revenue']) returns formatted output with semantic view metadata, pretty-printed SQL, and DuckDB EXPLAIN plan"
    - "The expanded SQL in EXPLAIN output has SELECT/FROM/WHERE/GROUP BY on separate lines"
    - "EXPLAIN output includes a metadata header with view name, dimensions, and metrics"
  artifacts:
    - path: "src/query/explain.rs"
      provides: "ExplainSemanticViewVTab implementing VTab for EXPLAIN output"
      contains: "ExplainSemanticViewVTab"
    - path: "src/query/mod.rs"
      provides: "Updated module declarations including explain"
      contains: "pub mod explain"
    - path: "src/lib.rs"
      provides: "Updated entrypoint registering explain_semantic_view"
      contains: "explain_semantic_view"
  key_links:
    - from: "src/query/explain.rs"
      to: "src/expand.rs"
      via: "expand() call to generate SQL for display"
      pattern: "expand\\("
    - from: "src/query/explain.rs"
      to: "src/query/table_function.rs"
      via: "Shared QueryState for catalog + connection access"
      pattern: "QueryState"
    - from: "src/lib.rs"
      to: "src/query/explain.rs"
      via: "register_table_function_with_extra_info for explain function"
      pattern: "explain_semantic_view"
---

<objective>
Implement `explain_semantic_view()` table function that returns formatted EXPLAIN output including metadata, pretty-printed expanded SQL, and DuckDB's EXPLAIN plan.

Purpose: QUERY-04 requires users to see the expanded SQL for debugging and transparency. Since standard `EXPLAIN` on a table function only shows DuckDB's physical plan, a dedicated function provides the three-part output users need.

Output: A working `explain_semantic_view` table function returning VARCHAR rows with metadata header, formatted SQL, and DuckDB EXPLAIN plan.
</objective>

<execution_context>
@/Users/paul/.claude/get-shit-done/workflows/execute-plan.md
@/Users/paul/.claude/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/04-query-interface/04-RESEARCH.md
@.planning/phases/04-query-interface/04-01-SUMMARY.md
@src/query/table_function.rs
@src/query/error.rs
@src/expand.rs
@src/lib.rs
</context>

<tasks>

<task type="auto">
  <name>Task 1: Implement explain_semantic_view table function</name>
  <files>
    src/query/explain.rs
    src/query/mod.rs
    src/lib.rs
  </files>
  <action>
Create `src/query/explain.rs` implementing `ExplainSemanticViewVTab` as a table function that returns formatted EXPLAIN output.

**Function signature:** `explain_semantic_view(view_name VARCHAR, dimensions := LIST(VARCHAR), metrics := LIST(VARCHAR))`
Same signature as `semantic_query` -- positional view_name + named list params.

**Output schema:** Single VARCHAR column named `explain_output`. Each row is one line of the formatted output.

**bind() implementation:**
1. Extract parameters exactly like `semantic_query` (view_name positional, dimensions/metrics named lists)
2. Look up definition from CatalogState; error if not found (reuse QueryError::ViewNotFound)
3. Call `expand()` to get the expanded SQL
4. Pretty-print the expanded SQL (it is already multi-line from expand(), but ensure SELECT/FROM/WHERE/GROUP BY are on separate lines with consistent indentation)
5. Build the three-part output per CONTEXT.md:

**Part 1 -- Metadata header:**
```
-- Semantic View: {view_name}
-- Dimensions: {dim1, dim2, ...}
-- Metrics: {met1, met2, ...}
```

**Part 2 -- Expanded SQL:**
```
-- Expanded SQL:
{pretty-printed SQL}
```
The SQL from expand() is already formatted multi-line. No additional formatting library needed -- hand-rolled is fine per Claude's Discretion.

**Part 3 -- DuckDB EXPLAIN plan:**
Execute `EXPLAIN {expanded_sql}` via raw FFI on the stored connection, capture the result text, and include it:
```
-- DuckDB Plan:
{explain output from DuckDB}
```
If EXPLAIN execution fails (e.g., tables don't exist yet), include a note: `-- DuckDB Plan: (not available -- {error})`

6. Store all output lines in BindData as `Vec<String>`
7. Declare one result column: `bind.add_result_column("explain_output", LogicalTypeHandle::from(LogicalTypeId::Varchar))`

**func() implementation:**
- Iterate over stored lines from BindData, write each line as one row to the output chunk
- Set done flag when all lines emitted
- Handle chunked output if lines exceed chunk size (unlikely but correct)

**InitData:** `AtomicBool` done flag + current row index (AtomicUsize or similar)

**mod.rs update:** Add `pub mod explain;`

**lib.rs update:** Register `explain_semantic_view` table function in the entrypoint using the same `QueryState` as `semantic_query`:
```rust
con.register_table_function_with_extra_info::<ExplainSemanticViewVTab, _>(
    "explain_semantic_view",
    &query_state,
)?;
```

**SQL pretty-printing:** The expand() output already uses newlines and indentation. For the EXPLAIN output, simply emit it as-is. If needed, add 2-space indent for readability. This is hand-rolled per Claude's Discretion (no library needed).

**Feature gate:** All code behind `#[cfg(feature = "extension")]` like the rest of the query module.
  </action>
  <verify>
    <automated>cd /Users/paul/Documents/Dev/Personal/duckdb-semantic-views && cargo build --no-default-features --features extension 2>&1 | tail -10</automated>
    <manual>Load extension in DuckDB, define a view, run `FROM explain_semantic_view('view_name', dimensions := ['region'], metrics := ['total'])` and verify three-part output appears</manual>
  </verify>
  <done>explain_semantic_view table function is registered and returns three-part formatted output: metadata header (view name, dimensions, metrics), pretty-printed expanded SQL, and DuckDB's EXPLAIN plan. Output uses standard SQL comment prefixes for metadata lines.</done>
</task>

</tasks>

<verification>
1. `cargo build --no-default-features --features extension` succeeds
2. `just test-sql` passes (no regression in existing tests)
3. Manual test:
   ```sql
   LOAD 'build/release/extension/semantic_views/semantic_views.duckdb_extension';
   CREATE TABLE orders (region VARCHAR, amount DECIMAL(10,2));
   INSERT INTO orders VALUES ('EMEA', 100), ('APAC', 200);
   SELECT define_semantic_view('test', '{"base_table":"orders","dimensions":[{"name":"region","expr":"region"}],"metrics":[{"name":"total","expr":"sum(amount)"}]}');
   FROM explain_semantic_view('test', dimensions := ['region'], metrics := ['total']);
   ```
   Output shows metadata header, expanded SQL with CTE, and DuckDB physical plan.
</verification>

<success_criteria>
- `explain_semantic_view` function is registered and callable
- Output contains metadata header with view name, dimensions, metrics
- Output contains pretty-printed expanded SQL with SELECT/FROM/WHERE/GROUP BY on separate lines
- Output contains DuckDB's EXPLAIN plan (or graceful fallback message if plan unavailable)
- Extension compiles and loads without error
</success_criteria>

<output>
After completion, create `.planning/phases/04-query-interface/04-02-SUMMARY.md`
</output>
