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:
+11
-1
@@ -312,6 +312,14 @@ pub enum Command {
|
||||
listed_columns: Vec<String>,
|
||||
row_source: String,
|
||||
},
|
||||
/// A SQL `UPDATE` validated by the walker (ADR-0033 §2,
|
||||
/// advanced mode). Grammar-as-text: the worker executes `sql`
|
||||
/// and re-persists `target_table`'s CSV (ADR-0030 §11).
|
||||
/// `RETURNING` (3g) is added by the sub-phase that reads it.
|
||||
SqlUpdate {
|
||||
sql: String,
|
||||
target_table: String,
|
||||
},
|
||||
/// App-lifecycle command (per ADR-0003). These work in both
|
||||
/// simple and advanced modes; the dispatcher branches on the
|
||||
/// `Command::App(...)` variant before mode-specific routing.
|
||||
@@ -608,6 +616,7 @@ impl Command {
|
||||
Self::Explain { .. } => "explain",
|
||||
Self::Select { .. } => "select",
|
||||
Self::SqlInsert { .. } => "insert into",
|
||||
Self::SqlUpdate { .. } => "update",
|
||||
Self::App(app) => match app {
|
||||
AppCommand::Quit => "quit",
|
||||
AppCommand::Help => "help",
|
||||
@@ -677,7 +686,8 @@ impl Command {
|
||||
Self::Select { .. } => "",
|
||||
// A SQL `INSERT` carries its parsed target table (for
|
||||
// CSV re-persistence and ok-summary subject).
|
||||
Self::SqlInsert { target_table, .. } => target_table,
|
||||
Self::SqlInsert { target_table, .. }
|
||||
| Self::SqlUpdate { target_table, .. } => target_table,
|
||||
// App commands aren't tied to schema entities — the
|
||||
// verb is the most identifying thing. The
|
||||
// display_subject override below provides a richer
|
||||
|
||||
Reference in New Issue
Block a user