---
phase: 27-alias-based-query-expansion
plan: 02
type: execute
wave: 1
depends_on: []
files_modified:
  - src/parse.rs
  - test/sql/phase16_parser.test
  - test/sql/phase19_parser_hook_validation.test
  - test/sql/phase20_extended_ddl.test
  - test/sql/phase21_error_reporting.test
  - test/sql/TEST_LIST
autonomous: true
requirements: [CLN-01]

must_haves:
  truths:
    - "The old paren-body DDL syntax (CREATE SEMANTIC VIEW name (tables := [...], ...)) is rejected at parse time"
    - "The AS-body DDL syntax (CREATE SEMANTIC VIEW name AS TABLES (...) ...) continues to work"
    - "DROP, DESCRIBE, SHOW semantic view commands continue to work"
    - "Old sqllogictest files using paren-body syntax are deleted or rewritten to use AS-body syntax"
  artifacts:
    - path: "src/parse.rs"
      provides: "Parse module with paren-body code path removed"
    - path: "test/sql/phase20_extended_ddl.test"
      provides: "Extended DDL tests rewritten to use AS-body syntax"
  key_links:
    - from: "src/parse.rs::validate_create_body"
      to: "src/body_parser.rs::parse_keyword_body"
      via: "rewrite_ddl_keyword_body dispatch"
      pattern: "rewrite_ddl_keyword_body"
---

<objective>
Remove the old paren-body `:=`/struct-literal DDL parsing code from parse.rs and update or delete all sqllogictest files that used the old syntax.

Purpose: CLN-01 removes dead code for a DDL syntax that is no longer supported. The AS-body keyword syntax (Phase 25) is the only path forward. All parser-hook test files that use `CREATE SEMANTIC VIEW name (tables := [...])` must be deleted or rewritten. The function-based DDL tests (phase2_ddl.test, phase4_query.test) are unaffected -- they call `create_semantic_view()` as a table function, not the parser hook.
Output: Clean parse.rs with no paren-body path; all test files use AS-body or function-based syntax.
</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/27-alias-based-query-expansion/27-RESEARCH.md

<interfaces>
<!-- Key types and contracts the executor needs. Extracted from codebase. -->

From src/parse.rs -- functions to DELETE (CLN-01):
```rust
// Lines ~162-215: DELETE -- parses paren-body "name (body)" format
fn parse_create_body(trimmed: &str, prefix_len: usize) -> Result<(&str, &str), String> { ... }

// Lines ~218-233: DELETE -- delegates to parse_create_body
pub fn parse_ddl_text(query: &str) -> Result<(&str, &str), String> { ... }

// Lines ~402-433: DELETE -- only called from validate_clauses
fn validate_brackets(body: &str, body_offset: usize) -> Result<(), ParseError> { ... }

// Lines ~437-494: DELETE -- only called from validate_clauses
fn scan_clause_keywords(body: &str, body_offset: usize) -> Result<Vec<String>, ParseError> { ... }

// Lines ~506-544: DELETE -- only called from validate_create_body paren-body branch
pub fn validate_clauses(body: &str, body_offset: usize, _original_query: &str) -> Result<(), ParseError> { ... }
```

From src/parse.rs -- code to MODIFY:
```rust
// rewrite_ddl() lines ~258-283: The CREATE branch (line 270) calls parse_create_body.
// After CLN-01, CREATE forms no longer go through rewrite_ddl (they go through
// validate_create_body -> rewrite_ddl_keyword_body). But rewrite_ddl is still called
// for Drop/Describe/Show forms (lines 624, 630). Remove the CREATE match arm from
// rewrite_ddl, or remove rewrite_ddl entirely and inline the Drop/Describe/Show
// logic into validate_and_rewrite.

// extract_ddl_name() lines ~294-312: The CREATE branch (line 303) calls parse_create_body.
// After removing parse_create_body, update extract_ddl_name to handle CREATE forms
// differently: extract name from AS-body syntax (find the name between prefix and "AS"
// or "("). Alternatively, parse the name directly without parse_create_body.

// validate_create_body() lines ~638-716: Remove lines 689-715 (the paren-body branch).
// After the AS-body check (line 686), if !is_as_body, return an error:
// "Expected 'AS' after view name. Old paren-body syntax is no longer supported."
```

From src/parse.rs -- Rust unit tests to DELETE:
```
- parse_ddl_text tests (lines ~1334-1393): All test parse_ddl_text which is being deleted
- rewrite_ddl CREATE tests (lines ~1125-1157, 1394-1427): Tests that pass paren-body DDL
- validate_clauses tests (lines ~1613-1740): All test validate_clauses which is being deleted
- validate_and_rewrite paren-body tests (lines ~1434-1446, 1454-1524, 1547-1592):
  Tests that use paren-body syntax. KEEP tests for Drop/Describe/Show (lines 1528-1540).
  KEEP tests for AS-body syntax.
```

From src/parse.rs -- what to KEEP:
```rust
pub fn validate_and_rewrite(query: &str) -> Result<Option<String>, ParseError>;  // Main entry point
fn validate_create_body(...) -> Result<Option<String>, ParseError>;  // KEEP, modify
fn rewrite_ddl_keyword_body(...) -> Result<Option<String>, ParseError>;  // KEEP (AS-body path)
pub fn detect_ddl_prefix(input: &str) -> Option<(DdlKind, usize)>;  // KEEP
fn extract_name_only(trimmed: &str, prefix_len: usize) -> Result<String, String>;  // KEEP
pub fn extract_ddl_name(query: &str) -> Result<Option<String>, String>;  // KEEP, modify
```

Old sqllogictest files to handle:
- phase16_parser.test (104 lines): DELETE entirely -- tests parser-hook paren-body DDL
- phase19_parser_hook_validation.test (144 lines): DELETE entirely -- tests paren-body validation across all 7 DDL forms
- phase20_extended_ddl.test (311 lines): REWRITE to AS-body syntax -- tests CREATE OR REPLACE, IF NOT EXISTS, DROP, DESCRIBE, SHOW which are still valid
- phase21_error_reporting.test (158 lines): REWRITE error cases to AS-body syntax where applicable, delete paren-body-specific error tests

Files that are UNAFFECTED (function-based DDL, not parser hook):
- phase2_ddl.test: Uses create_semantic_view() function call -- KEEP as-is
- phase4_query.test: Uses create_semantic_view() function call -- KEEP as-is
- phase2_restart.test: Uses create_semantic_view() function call, excluded from TEST_LIST -- KEEP as-is
- phase25_keyword_body.test: Uses AS-body syntax -- KEEP as-is
- phase26_join_resolution.test: Uses AS-body syntax -- KEEP as-is
</interfaces>
</context>

<tasks>

<task type="auto">
  <name>Task 1: Remove paren-body code path from parse.rs</name>
  <files>src/parse.rs</files>
  <action>
    Delete and modify the following in src/parse.rs:

    **DELETE these functions entirely:**
    1. `parse_create_body()` (~lines 162-215) -- paren-body name/body extractor
    2. `parse_ddl_text()` (~lines 218-233) -- thin wrapper around parse_create_body
    3. `validate_brackets()` (~lines 402-433) -- only called from validate_clauses
    4. `scan_clause_keywords()` (~lines 437-494) -- only called from validate_clauses
    5. `validate_clauses()` (~lines 506-544) -- only called from paren-body branch
    6. `check_close_bracket()` helper (~lines 373-397) -- only called from validate_brackets

    **MODIFY `validate_create_body()`:**
    - After the AS-body check (currently line 686 `return rewrite_ddl_keyword_body(...)`), the remaining code (lines 689-715) handles paren-body. Replace lines 689-715 with an error:
    ```rust
    // Paren-body syntax (tables := [...]) is no longer supported (CLN-01).
    Err(ParseError {
        message: "Expected 'AS' keyword after view name. The old paren-body syntax (tables := [...]) is no longer supported. Use: CREATE SEMANTIC VIEW name AS TABLES (...) DIMENSIONS (...) METRICS (...)".to_string(),
        position: Some(trim_offset + plen + (trimmed_no_semi.len() - plen - after_prefix.len()) + name_end),
    })
    ```

    **MODIFY `rewrite_ddl()`:**
    - The CREATE match arm (lines 269-273) calls `parse_create_body`. Since CREATE forms now always go through `validate_create_body -> rewrite_ddl_keyword_body`, `rewrite_ddl`'s CREATE arm is dead code for the validation path. However, `rewrite_ddl` may still be called directly from tests.
    - Option A (preferred): Remove the CREATE arm from `rewrite_ddl()`, making it handle only Drop/DropIfExists/Describe/Show. Rename it to something like `rewrite_ddl_name_only` for clarity, or keep the name. Update the match to return an error for CREATE forms: `Err("CREATE forms must use validate_and_rewrite".to_string())`
    - Option B: Delete `rewrite_ddl()` entirely, inline the Drop/Describe/Show logic into `validate_and_rewrite`. This is cleaner but more invasive.
    - Choose Option A for minimal risk.

    **MODIFY `extract_ddl_name()`:**
    - The CREATE arm (lines 302-305) calls `parse_create_body`. Replace with direct name extraction: after the DDL prefix, trim whitespace and take the next word up to whitespace, '(', or end of string. This is the same logic already in `validate_create_body` (lines 653-656) -- extract it.
    - Simplest: copy the name extraction from validate_create_body into extract_ddl_name's CREATE arm.

    **DELETE these Rust unit tests:**
    - All `parse_ddl_text` tests (~lines 1334-1393): `test_parse_ddl_text_*`
    - All `rewrite_ddl` tests that pass paren-body CREATE DDL (~lines 1120-1157, 1394-1427). KEEP tests for DROP/DESCRIBE/SHOW.
    - All `validate_clauses` tests (~lines 1613-1740): `test_validate_clauses_*`
    - All `validate_and_rewrite` tests that use paren-body syntax. KEEP: `test_validate_and_rewrite_not_ours`, `test_validate_and_rewrite_drop`, `test_validate_and_rewrite_show`, `test_validate_and_rewrite_describe`, `test_validate_and_rewrite_drop_if_exists`. Also KEEP any AS-body tests.
    - Add a new test: `test_validate_and_rewrite_rejects_paren_body` that confirms `validate_and_rewrite("CREATE SEMANTIC VIEW x (tables := [...])")` returns Err with "no longer supported" message.
    - Update `CLAUSE_KEYWORDS` constant: if it was only used by `scan_clause_keywords` and `suggest_clause_keyword`, check if `suggest_clause_keyword` has other callers. If only `scan_clause_keywords` called it, delete both. But `suggest_clause_keyword` is also used by body_parser -- grep first.

    **Safety checks before deletion:**
    - `grep -n 'validate_clauses\|validate_brackets\|scan_clause_keywords\|parse_create_body\|parse_ddl_text\|check_close_bracket' src/` to confirm no callers outside parse.rs
    - `grep -n 'suggest_clause_keyword\|CLAUSE_KEYWORDS' src/` to check if they have callers outside deleted functions

    After all deletions, run `cargo test` to catch any compilation errors from missing references.
  </action>
  <verify>
    <automated>cd /Users/paul/Documents/Dev/Personal/duckdb-semantic-views && cargo test -- parse</automated>
  </verify>
  <done>parse_create_body, parse_ddl_text, validate_brackets, scan_clause_keywords, validate_clauses, and check_close_bracket are deleted. validate_create_body returns error for non-AS-body syntax. rewrite_ddl no longer handles CREATE forms. extract_ddl_name works without parse_create_body. All remaining parse tests pass.</done>
</task>

<task type="auto">
  <name>Task 2: Delete or rewrite old sqllogictest files using paren-body DDL</name>
  <files>test/sql/phase16_parser.test, test/sql/phase19_parser_hook_validation.test, test/sql/phase20_extended_ddl.test, test/sql/phase21_error_reporting.test, test/sql/TEST_LIST</files>
  <action>
    Handle each old sqllogictest file:

    **1. DELETE `phase16_parser.test`** (104 lines)
    - Tests the original Phase 16 parser hook with paren-body syntax
    - Coverage is superseded by phase25_keyword_body.test (AS-body) and phase27_qualified_refs.test
    - Remove from TEST_LIST

    **2. DELETE `phase19_parser_hook_validation.test`** (144 lines)
    - Tests 7 DDL form validation with paren-body syntax
    - Phase 25 keyword body test already covers all 7 forms with AS-body syntax
    - Remove from TEST_LIST

    **3. REWRITE `phase20_extended_ddl.test`** (311 lines)
    - This file tests CREATE OR REPLACE, IF NOT EXISTS, DROP, DROP IF EXISTS, DESCRIBE, SHOW
    - These DDL verbs are still supported -- only the body syntax changed
    - Rewrite all `CREATE SEMANTIC VIEW name (tables := [...], ...)` to use AS-body syntax:
      ```sql
      CREATE SEMANTIC VIEW name AS
        TABLES (alias AS physical_table PRIMARY KEY (id))
        DIMENSIONS (alias.dim_name AS expr)
        METRICS (alias.metric_name AS agg_expr);
      ```
    - Keep the test structure (setup tables, DDL operations, assertions, cleanup)
    - Use phase-prefixed table names if not already present (they use sv_test)
    - Update the file header comment to note it was rewritten for AS-body syntax

    **4. REWRITE `phase21_error_reporting.test`** (158 lines)
    - This file tests error messages and caret positioning for malformed DDL
    - Error test cases for paren-body-specific errors (missing `:=`, bracket validation, unknown clause keywords) should be DELETED -- those error paths no longer exist
    - Error test cases for general DDL errors (missing view name, near-miss detection) should be KEPT and updated if needed
    - Add a new error test: confirm that paren-body syntax produces a clear "no longer supported" error:
      ```
      statement error
      CREATE SEMANTIC VIEW err_test (tables := [...])
      ----
      no longer supported
      ```
    - Keep any AS-body error tests that already exist

    **5. Update TEST_LIST:**
    - Remove phase16_parser.test
    - Remove phase19_parser_hook_validation.test
    - Keep phase20_extended_ddl.test (rewritten)
    - Keep phase21_error_reporting.test (rewritten)

    After rewriting, run `just build && just test-sql` to confirm all sqllogictest files pass.
  </action>
  <verify>
    <automated>cd /Users/paul/Documents/Dev/Personal/duckdb-semantic-views && just build && just test-sql</automated>
  </verify>
  <done>phase16_parser.test and phase19_parser_hook_validation.test deleted. phase20_extended_ddl.test and phase21_error_reporting.test rewritten to use AS-body syntax. TEST_LIST updated. All sqllogictest files pass.</done>
</task>

</tasks>

<verification>
- `cargo test` passes (all Rust unit + prop tests)
- `just build && just test-sql` passes (all sqllogictest files)
- `grep -rn "parse_create_body\|parse_ddl_text\|validate_clauses\|scan_clause_keywords\|validate_brackets" src/parse.rs` returns only comments (no function definitions or calls)
- `grep -l "tables :=" test/sql/*.test` returns only function-based DDL test files (phase2_ddl.test, phase4_query.test), NOT parser-hook paren-body tests
- phase16_parser.test and phase19_parser_hook_validation.test do not exist
- `validate_and_rewrite("CREATE SEMANTIC VIEW x (tables := [...])")` returns Err
</verification>

<success_criteria>
- CLN-01: All paren-body DDL parsing code (scan_clause_keywords, validate_clauses, validate_brackets, parse_create_body, parse_ddl_text) is deleted from parse.rs
- validate_create_body rejects non-AS syntax with a clear error message
- All 7 DDL verbs continue to work with AS-body syntax (verified by rewritten phase20 test)
- Error reporting tests updated for AS-body syntax (verified by rewritten phase21 test)
- Full test suite passes via `just test-all`
</success_criteria>

<output>
After completion, create `.planning/phases/27-alias-based-query-expansion/27-02-SUMMARY.md`
</output>
