diff --git a/src/ast/mod.rs b/src/ast/mod.rs index d21f83574..93f44e1b6 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -3238,6 +3238,8 @@ pub enum Statement { returning: Option>, /// SQLite-specific conflict resolution clause or: Option, + /// LIMIT + limit: Option, }, /// ```sql /// DELETE @@ -4810,6 +4812,7 @@ impl fmt::Display for Statement { selection, returning, or, + limit, } => { f.write_str("UPDATE ")?; if let Some(or) = or { @@ -4843,6 +4846,10 @@ impl fmt::Display for Statement { f.write_str("RETURNING")?; indented_list(f, returning)?; } + if let Some(limit) = limit { + SpaceOrNewline.fmt(f)?; + write!(f, "LIMIT {limit}")?; + } Ok(()) } Statement::Delete(delete) => delete.fmt(f), diff --git a/src/ast/spans.rs b/src/ast/spans.rs index e6e601c33..9705a0076 100644 --- a/src/ast/spans.rs +++ b/src/ast/spans.rs @@ -378,6 +378,7 @@ impl Spanned for Statement { selection, returning, or: _, + limit: _, } => union_spans( core::iter::once(table.span()) .chain(assignments.iter().map(|i| i.span())) diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 78ce6de6d..d7a07d385 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -15152,6 +15152,11 @@ impl<'a> Parser<'a> { } else { None }; + let limit = if self.parse_keyword(Keyword::LIMIT) { + Some(self.parse_expr()?) + } else { + None + }; Ok(Statement::Update { table, assignments, @@ -15159,6 +15164,7 @@ impl<'a> Parser<'a> { selection, returning, or, + limit, }) } diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index d71449d92..06d9cf14b 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -515,6 +515,7 @@ fn parse_update_set_from() { }), returning: None, or: None, + limit: None } ); @@ -533,6 +534,7 @@ fn parse_update_with_table_alias() { selection, returning, or: None, + limit: None, } => { assert_eq!( TableWithJoins { diff --git a/tests/sqlparser_mysql.rs b/tests/sqlparser_mysql.rs index 2b8d4b5ee..0dcf7c0d3 100644 --- a/tests/sqlparser_mysql.rs +++ b/tests/sqlparser_mysql.rs @@ -2516,6 +2516,7 @@ fn parse_update_with_joins() { selection, returning, or: None, + limit: None, } => { assert_eq!( TableWithJoins { diff --git a/tests/sqlparser_sqlite.rs b/tests/sqlparser_sqlite.rs index 06496f0ce..114aca03a 100644 --- a/tests/sqlparser_sqlite.rs +++ b/tests/sqlparser_sqlite.rs @@ -485,7 +485,8 @@ fn parse_update_tuple_row_values() { joins: vec![], }, from: None, - returning: None + returning: None, + limit: None } ); } @@ -592,6 +593,23 @@ fn test_regexp_operator() { sqlite().verified_only_select(r#"SELECT count(*) FROM messages WHERE msg_text REGEXP '\d+'"#); } +#[test] +fn test_update_delete_limit() { + match sqlite().verified_stmt("UPDATE foo SET bar = 1 LIMIT 99") { + Statement::Update { limit, .. } => { + assert_eq!(limit, Some(Expr::value(number("99")))); + } + _ => unreachable!(), + } + + match sqlite().verified_stmt("DELETE FROM foo LIMIT 99") { + Statement::Delete(Delete { limit, .. }) => { + assert_eq!(limit, Some(Expr::value(number("99")))); + } + _ => unreachable!(), + } +} + fn sqlite() -> TestedDialects { TestedDialects::new(vec![Box::new(SQLiteDialect {})]) }