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:
claude@clouddev1
2026-05-25 19:49:13 +00:00
parent 701217d29f
commit bbc2e34b33
17 changed files with 1294 additions and 55 deletions
+2
View File
@@ -175,6 +175,7 @@ pub const KEYS_AND_PLACEHOLDERS: &[(&str, &[&str])] = &[
("help.ddl.sql_drop_table", &[]),
("help.ddl.sql_create_index", &[]),
("help.ddl.sql_drop_index", &[]),
("help.ddl.sql_alter_table", &[]),
// Advanced-mode SQL CREATE TABLE / DROP TABLE no-op notes (ADR-0035 §4).
("ddl.create_skipped_exists", &["name"]),
("ddl.drop_skipped_absent", &["name"]),
@@ -255,6 +256,7 @@ pub const KEYS_AND_PLACEHOLDERS: &[(&str, &[&str])] = &[
("parse.usage.sql_drop_table", &[]),
("parse.usage.sql_create_index", &[]),
("parse.usage.sql_drop_index", &[]),
("parse.usage.sql_alter_table", &[]),
("parse.usage.delete", &[]),
("parse.usage.drop_column", &[]),
("parse.usage.drop_constraint", &[]),
+8
View File
@@ -270,6 +270,10 @@ help:
— create an index (advanced SQL)
sql_drop_index: |-
drop index [if exists] <name> — remove an index (advanced SQL)
sql_alter_table: |-
alter table <T> add column <col> <type> [not null] [unique] [default …] [check …]
alter table <T> drop column <col>
alter table <T> rename column <old> to <new> — change a table's columns (advanced SQL)
drop: |-
drop table <T> — remove a table
drop column [from] [table] <T>: <col> [--cascade] — remove a column
@@ -465,6 +469,10 @@ parse:
sql_drop_table: "drop table [if exists] <Name>"
sql_create_index: "create [unique] index [if not exists] [<Name>] on <Table> (<col>[, ...])"
sql_drop_index: "drop index [if exists] <Name>"
sql_alter_table: |-
alter table <Table> add column <Name> <Type> [not null] [unique] [default <expr>] [check (<expr>)]
alter table <Table> drop column <Name>
alter table <Table> rename column <Old> to <New>
drop_table: "drop table <Name>"
drop_column: "drop column [from] [table] <Table>: <Name>"
drop_relationship: |-