grammar+db: 3e — SQL UPDATE grammar + execution (ADR-0033 §2)
New src/dsl/grammar/sql_update.rs: SQL_UPDATE_SHAPE =
<table> SET col = sql_expr (',' …)* [WHERE sql_expr] [';'], the
__rdbms_* target rejection, and the shared sql_expr on both the
assignment RHS and the predicate. No --all-rows rail — a SQL
UPDATE without WHERE runs as written (ADR-0030 §12). Reuses
sql_select::WHERE_CLAUSE (now pub(crate)) so the predicate
diagnostics are identical. The target uses the shared `table_name`
ident role (not a bespoke one) so the Phase-2 schema-existence and
predicate-warning passes collect it as a scope binding and check
the SET / WHERE columns for free — a bespoke role left them
unchecked (the cross-cut tests caught this).
Command::SqlUpdate { sql, target_table }; Request::RunSqlUpdate +
do_sql_update (execute validated SQL via execute_with_fk_enrichment,
re-persist the target CSV, append history.log). 3e surfaces the
affected-row count only; precise row output is RETURNING (3g), so
the update-success render skips a column-less data set rather than
showing a misleading "(no rows)" band. Behind the dev `sql_update`
entry word until 3j.
Tests: grammar accept/reject; integration (single/multi-col,
no-WHERE all-rows, sql_expr in SET, scalar subquery in SET,
zero-match success, history); walker cross-cut (unknown SET column
→ unknown_column, `= NULL` in WHERE → eq_null warning); app-level
render-guard both ways (column-less → count only; with columns →
table renders). 1524 green, clippy clean.
This commit is contained in:
@@ -3933,6 +3933,30 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sql_update_unknown_set_column_is_error() {
|
||||
// ADR-0033 sub-phase 3e cross-cut: the schema-existence
|
||||
// pass fires on the SET assignment column.
|
||||
let schema = schema_with("t", &[("id", Type::Int), ("v", Type::Text)]);
|
||||
let diags = diag_keys("sql_update t set nonexistent = 1 where id = 1", &schema);
|
||||
assert!(
|
||||
diags.iter().any(|d| d.contains("no such column")),
|
||||
"expected unknown_column on the SET column; got {diags:?}",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sql_update_eq_null_in_where_warns() {
|
||||
// ADR-0033 sub-phase 3e cross-cut: the predicate-warning
|
||||
// pass fires on `= NULL` in an UPDATE's WHERE.
|
||||
let schema = schema_with("t", &[("id", Type::Int), ("v", Type::Int)]);
|
||||
let diags = diag_keys("sql_update t set v = 1 where v = NULL", &schema);
|
||||
assert!(
|
||||
diags.iter().any(|d| d.contains("IS NULL")),
|
||||
"expected eq_null warning on the WHERE; got {diags:?}",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cte_name_is_valid_table_source() {
|
||||
let schema = schema_with("base", &[("id", Type::Int)]);
|
||||
|
||||
Reference in New Issue
Block a user