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:
@@ -301,6 +301,15 @@ pub enum Command {
|
||||
unique: bool,
|
||||
if_not_exists: bool,
|
||||
},
|
||||
/// Advanced-mode SQL `ALTER TABLE <table> <action>` (ADR-0035 §4,
|
||||
/// sub-phase 4e). `alter` is advanced-only. Each action maps to an
|
||||
/// existing column executor — the runtime decomposes it to
|
||||
/// `add_column` / `drop_column` / `rename_column` (one undo step
|
||||
/// each). 4f/4g/4h extend [`AlterTableAction`].
|
||||
SqlAlterTable {
|
||||
table: String,
|
||||
action: AlterTableAction,
|
||||
},
|
||||
/// Add a column-level constraint to an existing column
|
||||
/// (ADR-0029 §2.2). Applied through the rebuild-table
|
||||
/// primitive after a §5 dry-run guards populated columns.
|
||||
@@ -705,6 +714,25 @@ pub enum IndexSelector {
|
||||
Columns { table: String, columns: Vec<String> },
|
||||
}
|
||||
|
||||
/// The action of an advanced-mode `ALTER TABLE` (ADR-0035 §4). Sub-phase
|
||||
/// 4e carries the column actions; 4f/4g/4h add `AlterColumnType`,
|
||||
/// `AddConstraint`/`AddForeignKey`/`DropConstraint`, and `RenameTo`.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum AlterTableAction {
|
||||
/// `ADD COLUMN <name> <type> [NOT NULL] [UNIQUE] [DEFAULT …]
|
||||
/// [CHECK …]` — column constraints only (no PK / inline REFERENCES;
|
||||
/// those are create-table / 4g). Reuses `do_add_column`. Boxed so
|
||||
/// the large `ColumnSpec` doesn't bloat the enum (and `Command` /
|
||||
/// `Action` that embed it) — `clippy::large_enum_variant`.
|
||||
AddColumn(Box<ColumnSpec>),
|
||||
/// `DROP COLUMN <name>` — reuses `do_drop_column` (cascade = false:
|
||||
/// an index-covered column is refused, matching SQLite + the
|
||||
/// simple-mode default; there is no `--cascade` SQL spelling).
|
||||
DropColumn { column: String },
|
||||
/// `RENAME COLUMN <old> TO <new>` — reuses `do_rename_column`.
|
||||
RenameColumn { old: String, new: String },
|
||||
}
|
||||
|
||||
impl std::fmt::Display for IndexSelector {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
@@ -735,6 +763,7 @@ impl Command {
|
||||
Self::DropIndex { .. } => "drop index",
|
||||
Self::SqlDropIndex { .. } => "drop index",
|
||||
Self::SqlCreateIndex { .. } => "create index",
|
||||
Self::SqlAlterTable { .. } => "alter table",
|
||||
Self::AddConstraint { .. } => "add constraint",
|
||||
Self::DropConstraint { .. } => "drop constraint",
|
||||
Self::ShowTable { .. } => "show table",
|
||||
@@ -813,6 +842,7 @@ impl Command {
|
||||
// `DropIndex` / `SqlDropTable` fallback).
|
||||
Self::SqlDropIndex { name, .. } => name,
|
||||
Self::SqlCreateIndex { table, .. } => table,
|
||||
Self::SqlAlterTable { table, .. } => table,
|
||||
// Replay isn't tied to a single table; the path is
|
||||
// the most identifying thing for log output.
|
||||
Self::Replay { path } => path,
|
||||
|
||||
Reference in New Issue
Block a user