sqlite3-parser: separate boxed Update struct

This commit is contained in:
Jussi Saurio
2025-02-09 12:51:08 +02:00
parent 575b484740
commit af920a317c
4 changed files with 65 additions and 25 deletions

View File

@@ -66,10 +66,13 @@ impl Stmt {
} => column_count(returning),
Self::Pragma(..) => ColumnCount::Dynamic,
Self::Select(s) => s.column_count(),
Self::Update {
returning: Some(returning),
..
} => column_count(returning),
Self::Update(update) => {
let Update { returning, .. } = &**update;
match returning {
Some(returning) => column_count(returning),
None => ColumnCount::None,
}
}
_ => ColumnCount::None,
}
}
@@ -173,11 +176,18 @@ impl Stmt {
Err(custom_err!("0 values for {} columns", columns.len()))
}
},
Self::Update {
order_by: Some(_),
limit: None,
..
} => Err(custom_err!("ORDER BY without LIMIT on UPDATE")),
Self::Update(update) => {
let Update {
order_by, limit, ..
} = &**update;
if let Some(_) = order_by {
if limit.is_none() {
return Err(custom_err!("ORDER BY without LIMIT on UPDATE"));
}
}
Ok(())
}
_ => Ok(()),
}
}

View File

@@ -466,18 +466,19 @@ impl ToTokens for Stmt {
name.to_tokens(s)
}
Self::Select(select) => select.to_tokens(s),
Self::Update {
with,
or_conflict,
tbl_name,
indexed,
sets,
from,
where_clause,
returning,
order_by,
limit,
} => {
Self::Update(update) => {
let Update {
with,
or_conflict,
tbl_name,
indexed,
sets,
from,
where_clause,
returning,
order_by,
limit,
} = &**update;
if let Some(with) = with {
with.to_tokens(s)?;
}

View File

@@ -223,6 +223,11 @@ pub enum Stmt {
/// `SELECT`
Select(Box<Select>),
/// `UPDATE`
Update(Box<Update>),
/// `VACUUM`: database name, into expr
Vacuum(Option<Name>, Option<Expr>),
}
/// `CREATE TRIGGER
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CreateTrigger {
@@ -245,6 +250,30 @@ pub struct CreateTrigger {
/// statements
pub commands: Vec<TriggerCmd>,
}
/// `UPDATE` clause
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Update {
/// CTE
pub with: Option<With>,
/// `OR`
pub or_conflict: Option<ResolveType>,
/// table name
pub tbl_name: QualifiedName,
/// `INDEXED`
pub indexed: Option<Indexed>,
/// `SET` assignments
pub sets: Vec<Set>,
/// `FROM`
pub from: Option<FromClause>,
/// `WHERE` clause
pub where_clause: Option<Box<Expr>>,
/// `RETURNING`
pub returning: Option<Vec<ResultColumn>>,
/// `ORDER BY`
pub order_by: Option<Vec<SortedColumn>>,
/// `LIMIT`
pub limit: Option<Box<Limit>>,
}
/// SQL expression

View File

@@ -790,15 +790,15 @@ where_opt_ret(A) ::= WHERE expr(X) RETURNING selcollist(Y).
cmd ::= with(C) UPDATE orconf(R) xfullname(X) indexed_opt(I) SET setlist(Y) from(F)
where_opt_ret(W) orderby_opt(O) limit_opt(L). {
let (where_clause, returning) = W;
self.ctx.stmt = Some(Stmt::Update { with: C, or_conflict: R, tbl_name: X, indexed: I, sets: Y, from: F,
where_clause: where_clause.map(Box::new), returning, order_by: O, limit: L });
self.ctx.stmt = Some(Stmt::Update(Box::new(Update{ with: C, or_conflict: R, tbl_name: X, indexed: I, sets: Y, from: F,
where_clause: where_clause.map(Box::new), returning, order_by: O, limit: L })));
}
%else
cmd ::= with(C) UPDATE orconf(R) xfullname(X) indexed_opt(I) SET setlist(Y) from(F)
where_opt_ret(W). {
let (where_clause, returning) = W;
self.ctx.stmt = Some(Stmt::Update { with: C, or_conflict: R, tbl_name: X, indexed: I, sets: Y, from: F,
where_clause: where_clause.map(Box::new), returning, order_by: None, limit: None });
self.ctx.stmt = Some(Stmt::Update(Box::new(Update{ with: C, or_conflict: R, tbl_name: X, indexed: I, sets: Y, from: F,
where_clause: where_clause.map(Box::new), returning, order_by: None, limit: None })));
}
%endif