File tree Expand file tree Collapse file tree 8 files changed +88
-0
lines changed
Expand file tree Collapse file tree 8 files changed +88
-0
lines changed Original file line number Diff line number Diff line change @@ -387,6 +387,9 @@ pub struct Update {
387387 pub output : Option < OutputClause > ,
388388 /// SQLite-specific conflict resolution clause
389389 pub or : Option < SqliteOnConflict > ,
390+ /// ORDER BY (MySQL extension for single-table UPDATE)
391+ /// See <https://dev.mysql.com/doc/refman/8.4/en/update.html>
392+ pub order_by : Vec < OrderByExpr > ,
390393 /// LIMIT
391394 pub limit : Option < Expr > ,
392395}
@@ -434,6 +437,11 @@ impl Display for Update {
434437 f. write_str ( "RETURNING" ) ?;
435438 indented_list ( f, returning) ?;
436439 }
440+ if !self . order_by . is_empty ( ) {
441+ SpaceOrNewline . fmt ( f) ?;
442+ f. write_str ( "ORDER BY" ) ?;
443+ indented_list ( f, & self . order_by ) ?;
444+ }
437445 if let Some ( limit) = & self . limit {
438446 SpaceOrNewline . fmt ( f) ?;
439447 write ! ( f, "LIMIT {limit}" ) ?;
Original file line number Diff line number Diff line change @@ -952,6 +952,7 @@ impl Spanned for Update {
952952 returning,
953953 output,
954954 or : _,
955+ order_by,
955956 limit,
956957 } = self ;
957958
@@ -963,6 +964,7 @@ impl Spanned for Update {
963964 . chain ( selection. iter ( ) . map ( |i| i. span ( ) ) )
964965 . chain ( returning. iter ( ) . flat_map ( |i| i. iter ( ) . map ( |k| k. span ( ) ) ) )
965966 . chain ( output. iter ( ) . map ( |i| i. span ( ) ) )
967+ . chain ( order_by. iter ( ) . map ( |i| i. span ( ) ) )
966968 . chain ( limit. iter ( ) . map ( |i| i. span ( ) ) ) ,
967969 )
968970 }
Original file line number Diff line number Diff line change @@ -520,6 +520,16 @@ pub trait Dialect: Debug + Any {
520520 false
521521 }
522522
523+ /// Returns true if the dialect supports `ORDER BY` in `UPDATE` statements.
524+ ///
525+ /// ```sql
526+ /// UPDATE foo SET bar = false WHERE foo = true ORDER BY foo ASC;
527+ /// ```
528+ /// See <https://dev.mysql.com/doc/refman/8.4/en/update.html>
529+ fn supports_update_order_by ( & self ) -> bool {
530+ false
531+ }
532+
523533 /// Returns true if the dialect supports an `EXCEPT` clause following a
524534 /// wildcard in a select list.
525535 ///
Original file line number Diff line number Diff line change @@ -179,6 +179,11 @@ impl Dialect for MySqlDialect {
179179 true
180180 }
181181
182+ /// See: <https://dev.mysql.com/doc/refman/8.4/en/update.html>
183+ fn supports_update_order_by ( & self ) -> bool {
184+ true
185+ }
186+
182187 fn supports_data_type_signed_suffix ( & self ) -> bool {
183188 true
184189 }
Original file line number Diff line number Diff line change @@ -17745,6 +17745,13 @@ impl<'a> Parser<'a> {
1774517745 } else {
1774617746 None
1774717747 };
17748+ let order_by = if self.dialect.supports_update_order_by()
17749+ && self.parse_keywords(&[Keyword::ORDER, Keyword::BY])
17750+ {
17751+ self.parse_comma_separated(Parser::parse_order_by_expr)?
17752+ } else {
17753+ vec![]
17754+ };
1774817755 let limit = if self.parse_keyword(Keyword::LIMIT) {
1774917756 Some(self.parse_expr()?)
1775017757 } else {
@@ -17760,6 +17767,7 @@ impl<'a> Parser<'a> {
1776017767 returning,
1776117768 output,
1776217769 or,
17770+ order_by,
1776317771 limit,
1776417772 }
1776517773 .into())
Original file line number Diff line number Diff line change @@ -535,6 +535,7 @@ fn parse_update_set_from() {
535535 returning: None,
536536 output: None,
537537 or: None,
538+ order_by: vec![],
538539 limit: None
539540 })
540541 );
@@ -554,6 +555,7 @@ fn parse_update_with_table_alias() {
554555 selection,
555556 returning,
556557 or: None,
558+ order_by: _,
557559 limit: None,
558560 optimizer_hints,
559561 update_token: _,
Original file line number Diff line number Diff line change @@ -2707,6 +2707,7 @@ fn parse_update_with_joins() {
27072707 selection,
27082708 returning,
27092709 or : None ,
2710+ order_by : _,
27102711 limit : None ,
27112712 optimizer_hints,
27122713 update_token : _,
@@ -2784,6 +2785,57 @@ fn parse_update_with_joins() {
27842785 }
27852786}
27862787
2788+ #[ test]
2789+ fn parse_update_with_order_by ( ) {
2790+ let sql = "UPDATE foo SET bar = false WHERE foo = true ORDER BY foo ASC" ;
2791+ match mysql ( ) . verified_stmt ( sql) {
2792+ Statement :: Update ( Update { order_by, .. } ) => {
2793+ assert_eq ! (
2794+ vec![ OrderByExpr {
2795+ expr: Expr :: Identifier ( Ident {
2796+ value: "foo" . to_owned( ) ,
2797+ quote_style: None ,
2798+ span: Span :: empty( ) ,
2799+ } ) ,
2800+ options: OrderByOptions {
2801+ asc: Some ( true ) ,
2802+ nulls_first: None ,
2803+ } ,
2804+ with_fill: None ,
2805+ } ] ,
2806+ order_by
2807+ ) ;
2808+ }
2809+ _ => unreachable ! ( ) ,
2810+ }
2811+ }
2812+
2813+ #[ test]
2814+ fn parse_update_with_order_by_and_limit ( ) {
2815+ let sql = "UPDATE foo SET bar = false WHERE foo = true ORDER BY foo ASC LIMIT 10" ;
2816+ match mysql ( ) . verified_stmt ( sql) {
2817+ Statement :: Update ( Update { order_by, limit, .. } ) => {
2818+ assert_eq ! (
2819+ vec![ OrderByExpr {
2820+ expr: Expr :: Identifier ( Ident {
2821+ value: "foo" . to_owned( ) ,
2822+ quote_style: None ,
2823+ span: Span :: empty( ) ,
2824+ } ) ,
2825+ options: OrderByOptions {
2826+ asc: Some ( true ) ,
2827+ nulls_first: None ,
2828+ } ,
2829+ with_fill: None ,
2830+ } ] ,
2831+ order_by
2832+ ) ;
2833+ assert_eq ! ( Some ( Expr :: value( number( "10" ) ) ) , limit) ;
2834+ }
2835+ _ => unreachable ! ( ) ,
2836+ }
2837+ }
2838+
27872839#[ test]
27882840fn parse_delete_with_order_by ( ) {
27892841 let sql = "DELETE FROM customers ORDER BY id DESC" ;
Original file line number Diff line number Diff line change @@ -497,6 +497,7 @@ fn parse_update_tuple_row_values() {
497497 from: None ,
498498 returning: None ,
499499 output: None ,
500+ order_by: vec![ ] ,
500501 limit: None ,
501502 update_token: AttachedToken :: empty( )
502503 } )
You can’t perform that action at this time.
0 commit comments