feat: advanced ALTER COLUMN SET/DROP NOT NULL & DEFAULT, SET DATA TYPE (ADR-0035 Am2)

The standard-first ALTER COLUMN constraint gap-fill advanced mode lacked:

- ALTER COLUMN <c> SET DATA TYPE <ty> — ISO canonical synonym for the
  PostgreSQL TYPE shorthand (same AlterColumnType action + executor).
- SET NOT NULL / DROP NOT NULL — reuse the ADR-0029 do_add_constraint /
  do_drop_constraint executors (dry-run + internal-table guards free).
- SET DEFAULT <expr> / DROP DEFAULT — SET DEFAULT uses a dedicated
  raw-SQL executor (do_set_column_default); sql_expr yields no typed
  Value, so it can't go through do_add_constraint. DROP DEFAULT reuses
  do_drop_constraint.

Grammar: AT_ALTER_COLUMN gains a tail Choice (type / set / drop), reusing
SQL_TYPE and the CREATE TABLE DEFAULT_NODES; builder dispatch routes the
new column-attribute forms; runtime decomposes to the executors.

ADR-0035 Am2 corrected in-place: SET DEFAULT decomposes to
do_set_column_default, not do_add_constraint (Value-based) — found during
build.

Tests (test-first): 6 parse + 7 Tier-3 execution via run_replay. Suite
1962/0/1; clippy clean.
This commit is contained in:
claude@clouddev1
2026-05-27 21:03:14 +00:00
parent 9f15f386d5
commit 338dc8a4cf
7 changed files with 550 additions and 10 deletions
+21 -1
View File
@@ -33,7 +33,7 @@ use crate::db::{
Database, DbError, DeleteResult, DropColumnResult, DropIndexOutcome, DropOutcome, InsertResult,
QueryPlan, TableDescription, UpdateResult,
};
use crate::dsl::command::TableConstraint;
use crate::dsl::command::{Constraint, ConstraintKind, TableConstraint};
use crate::dsl::{AlterTableAction, ChangeColumnMode, Command, ColumnSpec};
use crate::dsl::walker::Severity;
use crate::event::AppEvent;
@@ -2185,6 +2185,26 @@ async fn execute_command_typed(
.change_column_type(table, column, ty, ChangeColumnMode::ForceConversion, src)
.await
.map(CommandOutcome::ChangeColumn),
// ADR-0035 Amendment 2: ALTER COLUMN constraint gap-fill.
// SET/DROP NOT NULL and DROP DEFAULT reuse the ADR-0029
// executors; SET DEFAULT needs the raw-SQL path (sql_expr has
// no typed Value).
AlterTableAction::SetColumnNotNull { column } => database
.add_constraint(table, column, Constraint::NotNull, src)
.await
.map(|d| CommandOutcome::Schema(Some(d))),
AlterTableAction::DropColumnNotNull { column } => database
.drop_constraint(table, column, ConstraintKind::NotNull, src)
.await
.map(|d| CommandOutcome::Schema(Some(d))),
AlterTableAction::SetColumnDefault { column, default_sql } => database
.set_column_default(table, column, default_sql, src)
.await
.map(|d| CommandOutcome::Schema(Some(d))),
AlterTableAction::DropColumnDefault { column } => database
.drop_constraint(table, column, ConstraintKind::Default, src)
.await
.map(|d| CommandOutcome::Schema(Some(d))),
// `ADD [CONSTRAINT <name>] (CHECK | UNIQUE | FOREIGN KEY)`
// (ADR-0035 §4g) — each reuses an existing low-level executor
// (the FK via the relationship machinery `add 1:n