feat: ADR-0035 4e — ALTER TABLE add/drop/rename column
Advanced-only `alter` entry word; ALTER TABLE <T> ADD COLUMN <col> <type> [constraints] | DROP COLUMN <col> | RENAME COLUMN <old> TO <new> -> SqlAlterTable, runtime-decomposed to the existing column executors (do_add_column / do_drop_column / do_rename_column) — one undo step each, no new worker layer. The COLUMN keyword is required (reserves bare RENAME TO for 4h, ADD CONSTRAINT for 4g). - ADD COLUMN takes NOT NULL / UNIQUE / DEFAULT / CHECK (no PK / inline REFERENCES). do_add_column extended to consume the SQL raw-text default_sql / check_sql (sql_expr is validate-only, the 4a.2 mechanism), reaching parity with CREATE TABLE's column constraints. - Drop/rename column refuse a column any CHECK references — table-level AND column-level (incl. a column's own self-check on rename) — the 4a.3 deferral, detected up-front by tokenizing the raw CHECK text (skipping string literals). In the shared executors, so it guards both the simple and SQL surfaces and fixes a latent rename-drift bug that desynced the stored CHECK text and broke rebuild. - SQL DROP COLUMN refuses an index-covered column (no --cascade SQL spelling — matches SQLite + the simple default). - The column executors and do_add_index gained an internal-__rdbms_* guard (refuse as "no such table"), closing a pre-existing exposure on both surfaces. (do_change_column_type / do_add_constraint / do_add_relationship are a tracked follow-up.) - `alter` is advanced-only; AlterTableAction::AddColumn is boxed (clippy::large_enum_variant). Docs: ADR-0035 status + §13 4e; ADR README; requirements.md Q1. Plan: docs/plans/20260525-adr-0035-sql-ddl-4e.md. Tests: 1854 passing / 0 failing / 0 skipped / 1 ignored; clippy clean.
This commit is contained in:
@@ -3,14 +3,15 @@
|
||||
## Status
|
||||
|
||||
Accepted. Design agreed with the user (2026-05-24); the approach is
|
||||
**validated end-to-end by sub-phases 4a / 4a.2 / 4a.3 / 4b / 4c / 4d**
|
||||
(`CREATE TABLE` with column- and table-level constraints and foreign
|
||||
keys, `DROP TABLE [IF EXISTS]`, and `CREATE [UNIQUE] INDEX` /
|
||||
`DROP INDEX [IF EXISTS]`, implemented 2026-05-25 — plans
|
||||
**validated end-to-end by sub-phases 4a / 4a.2 / 4a.3 / 4b / 4c / 4d /
|
||||
4e** (`CREATE TABLE` with column- and table-level constraints and foreign
|
||||
keys, `DROP TABLE [IF EXISTS]`, `CREATE [UNIQUE] INDEX` /
|
||||
`DROP INDEX [IF EXISTS]`, and `ALTER TABLE` add/drop/rename column,
|
||||
implemented 2026-05-25 — plans
|
||||
`docs/plans/20260524-adr-0035-sql-ddl-4a.md`, `…-4a2.md`, `…-4a3.md`,
|
||||
`docs/plans/20260525-adr-0035-sql-ddl-4b.md`, `…-4c.md`, `…-4d.md`), so
|
||||
the decision is accepted while the remaining sub-phases (**4e–4i**, §13)
|
||||
continue. This is **Phase 4** of the ADR-0030 roadmap (the
|
||||
`docs/plans/20260525-adr-0035-sql-ddl-4b.md`, `…-4c.md`, `…-4d.md`,
|
||||
`…-4e.md`), so the decision is accepted while the remaining sub-phases
|
||||
(**4f–4i**, §13) continue. This is **Phase 4** of the ADR-0030 roadmap (the
|
||||
advanced-mode SQL surface), the peer of ADR-0031 (expression grammar),
|
||||
ADR-0032 (`SELECT`), and ADR-0033 (DML). It **clarifies ADR-0030 §4**
|
||||
on how DDL is represented and executed.
|
||||
@@ -401,13 +402,39 @@ ADR-0033's structure:
|
||||
Simple-mode `add unique index` stays deferred. `create`/`drop` each
|
||||
gain a *second* advanced node, exercising the all-candidates dispatch
|
||||
(`decide` tries every advanced candidate).
|
||||
- **4e — `ALTER TABLE` add/drop/rename column.** Drop/rename column
|
||||
must guard against a **table-level CHECK that references the column**
|
||||
(4a.3): today the rebuild rejects it cleanly via the engine (the
|
||||
rebuilt table's `CHECK` names a missing column), leaving the table
|
||||
intact — 4e adds the up-front detection (parsing column references
|
||||
out of the raw CHECK text in `__rdbms_playground_table_checks`) so the
|
||||
refusal is deliberate; the friendly wording itself is **H1** work.
|
||||
- **4e — `ALTER TABLE` add/drop/rename column.** *(Implemented
|
||||
2026-05-25 — plan `docs/plans/20260525-adr-0035-sql-ddl-4e.md`.)*
|
||||
`alter` is a new advanced-**only** entry word (like `select`/`with`);
|
||||
`ALTER TABLE <T> ADD COLUMN <col> <type> [NOT NULL|UNIQUE|DEFAULT|
|
||||
CHECK] | DROP COLUMN <col> | RENAME COLUMN <old> TO <new>` →
|
||||
`SqlAlterTable { AlterTableAction }`, **runtime-decomposed** to the
|
||||
existing `do_add_column` / `do_drop_column` / `do_rename_column` (one
|
||||
undo step each) — no new worker layer. The `COLUMN` keyword is
|
||||
required (reserves bare `RENAME TO` for 4h, `ADD CONSTRAINT` for 4g);
|
||||
ADD COLUMN takes column constraints only (no PK / inline REFERENCES).
|
||||
**`do_add_column` was extended** to consume the SQL raw-text
|
||||
`default_sql` / `check_sql` (DEFAULT/CHECK; `sql_expr` is validate-only
|
||||
— the 4a.2 mechanism), so ADD COLUMN reaches parity with `CREATE
|
||||
TABLE`'s column constraints. Drop/rename column now **refuse a column a
|
||||
CHECK references** — the 4a.3 deferral, extended (user-confirmed) to
|
||||
**both table-level and column-level CHECKs** — detected up-front by
|
||||
tokenizing the raw CHECK text (`check_references_column`, skipping
|
||||
string literals); for RENAME the column's *own* column-level CHECK
|
||||
counts (it drifts too), for DROP it does not (it drops with the
|
||||
column). This lives in the shared executors, so it guards **both** the
|
||||
simple `drop/rename column` and the SQL surface, fixing a latent
|
||||
rename-drift bug (a native rename rewrites the live CHECK but leaves the
|
||||
stored text — table-level in `__rdbms_playground_table_checks` or
|
||||
column-level in `__rdbms_playground_columns` — stale, breaking a later
|
||||
rebuild). SQL
|
||||
`DROP COLUMN` over an index-covered column is **refused** (no
|
||||
`--cascade` SQL spelling — matches SQLite + the simple default;
|
||||
user-confirmed). The shared column executors (and `do_add_index`) also
|
||||
gained an internal-`__rdbms_*`-table guard (refuse as "no such table"),
|
||||
closing a pre-existing exposure on both surfaces (user-confirmed). The
|
||||
friendly wording of the CHECK-guard refusal is **H1**. *(The broader
|
||||
internal-table guard on `do_change_column_type` / `do_add_constraint` /
|
||||
`do_add_relationship` is a tracked follow-up.)*
|
||||
- **4f — `ALTER TABLE … ALTER COLUMN TYPE`** (the §7 conversion
|
||||
model + the lossy-with-note path).
|
||||
- **4g — `ALTER TABLE` add/drop constraint, add foreign key.**
|
||||
|
||||
Reference in New Issue
Block a user