@@ -334,6 +334,108 @@ pub enum SelectFlavor {
334334 FromFirstNoSelect ,
335335}
336336
337+ /// MySQL-specific SELECT modifiers that appear after the SELECT keyword.
338+ ///
339+ /// These modifiers affect query execution and optimization. They can appear in any order after
340+ /// SELECT and before the column list, can be repeated, and can be interleaved with
341+ /// DISTINCT/DISTINCTROW/ALL:
342+ ///
343+ /// ```sql
344+ /// SELECT
345+ /// [ALL | DISTINCT | DISTINCTROW]
346+ /// [HIGH_PRIORITY]
347+ /// [STRAIGHT_JOIN]
348+ /// [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT]
349+ /// [SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS]
350+ /// select_expr [, select_expr] ...
351+ /// ```
352+ ///
353+ /// See [MySQL SELECT](https://dev.mysql.com/doc/refman/8.4/en/select.html).
354+ #[ derive( Debug , Clone , PartialEq , PartialOrd , Eq , Ord , Hash , Default ) ]
355+ #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
356+ #[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
357+ pub struct SelectModifiers {
358+ /// `HIGH_PRIORITY` gives the SELECT higher priority than statements that update a table.
359+ ///
360+ /// <https://dev.mysql.com/doc/refman/8.4/en/select.html>
361+ pub high_priority : bool ,
362+ /// `STRAIGHT_JOIN` forces the optimizer to join tables in the order listed in the FROM clause.
363+ ///
364+ /// <https://dev.mysql.com/doc/refman/8.4/en/select.html>
365+ pub straight_join : bool ,
366+ /// `SQL_SMALL_RESULT` hints that the result set is small, using in-memory temp tables.
367+ ///
368+ /// <https://dev.mysql.com/doc/refman/8.4/en/select.html>
369+ pub sql_small_result : bool ,
370+ /// `SQL_BIG_RESULT` hints that the result set is large, using disk-based temp tables.
371+ ///
372+ /// <https://dev.mysql.com/doc/refman/8.4/en/select.html>
373+ pub sql_big_result : bool ,
374+ /// `SQL_BUFFER_RESULT` forces the result to be put into a temporary table to release locks early.
375+ ///
376+ /// <https://dev.mysql.com/doc/refman/8.4/en/select.html>
377+ pub sql_buffer_result : bool ,
378+ /// `SQL_NO_CACHE` tells MySQL not to cache the query result. (Deprecated in 8.4+.)
379+ ///
380+ /// <https://dev.mysql.com/doc/refman/8.4/en/select.html>
381+ pub sql_no_cache : bool ,
382+ /// `SQL_CALC_FOUND_ROWS` tells MySQL to calculate the total number of rows. (Deprecated in 8.0.17+.)
383+ ///
384+ /// - [MySQL SELECT modifiers](https://dev.mysql.com/doc/refman/8.4/en/select.html)
385+ /// - [`FOUND_ROWS()`](https://dev.mysql.com/doc/refman/8.4/en/information-functions.html#function_found-rows)
386+ pub sql_calc_found_rows : bool ,
387+ }
388+
389+ impl fmt:: Display for SelectModifiers {
390+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
391+ if self . high_priority {
392+ f. write_str ( " HIGH_PRIORITY" ) ?;
393+ }
394+ if self . straight_join {
395+ f. write_str ( " STRAIGHT_JOIN" ) ?;
396+ }
397+ if self . sql_small_result {
398+ f. write_str ( " SQL_SMALL_RESULT" ) ?;
399+ }
400+ if self . sql_big_result {
401+ f. write_str ( " SQL_BIG_RESULT" ) ?;
402+ }
403+ if self . sql_buffer_result {
404+ f. write_str ( " SQL_BUFFER_RESULT" ) ?;
405+ }
406+ if self . sql_no_cache {
407+ f. write_str ( " SQL_NO_CACHE" ) ?;
408+ }
409+ if self . sql_calc_found_rows {
410+ f. write_str ( " SQL_CALC_FOUND_ROWS" ) ?;
411+ }
412+ Ok ( ( ) )
413+ }
414+ }
415+
416+ impl SelectModifiers {
417+ /// Returns true if any of the modifiers are set.
418+ pub fn is_any_set ( & self ) -> bool {
419+ // Using irrefutable destructuring to catch fields added in the future
420+ let Self {
421+ high_priority,
422+ straight_join,
423+ sql_small_result,
424+ sql_big_result,
425+ sql_buffer_result,
426+ sql_no_cache,
427+ sql_calc_found_rows,
428+ } = self ;
429+ * high_priority
430+ || * straight_join
431+ || * sql_small_result
432+ || * sql_big_result
433+ || * sql_buffer_result
434+ || * sql_no_cache
435+ || * sql_calc_found_rows
436+ }
437+ }
438+
337439/// A restricted variant of `SELECT` (without CTEs/`ORDER BY`), which may
338440/// appear either as the only body item of a `Query`, or as an operand
339441/// to a set operation like `UNION`.
@@ -350,6 +452,10 @@ pub struct Select {
350452 pub optimizer_hint : Option < OptimizerHint > ,
351453 /// `SELECT [DISTINCT] ...`
352454 pub distinct : Option < Distinct > ,
455+ /// MySQL-specific SELECT modifiers.
456+ ///
457+ /// See [MySQL SELECT](https://dev.mysql.com/doc/refman/8.4/en/select.html).
458+ pub select_modifiers : Option < SelectModifiers > ,
353459 /// MSSQL syntax: `TOP (<N>) [ PERCENT ] [ WITH TIES ]`
354460 pub top : Option < Top > ,
355461 /// Whether the top was located before `ALL`/`DISTINCT`
@@ -442,6 +548,10 @@ impl fmt::Display for Select {
442548 }
443549 }
444550
551+ if let Some ( ref select_modifiers) = self . select_modifiers {
552+ select_modifiers. fmt ( f) ?;
553+ }
554+
445555 if !self . projection . is_empty ( ) {
446556 indented_list ( f, & self . projection ) ?;
447557 }
@@ -3351,8 +3461,14 @@ impl fmt::Display for NonBlock {
33513461#[ derive( Debug , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
33523462#[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
33533463#[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
3354- /// `DISTINCT` or `DISTINCT ON (...)` modifiers for `SELECT` lists.
3464+ /// `ALL`, ` DISTINCT`, or `DISTINCT ON (...)` modifiers for `SELECT` lists.
33553465pub enum Distinct {
3466+ /// `ALL` (keep duplicate rows)
3467+ ///
3468+ /// Generally this is the default if omitted, but omission should be represented as
3469+ /// `None::<Option<Distinct>>`
3470+ All ,
3471+
33563472 /// `DISTINCT` (remove duplicate rows)
33573473 Distinct ,
33583474
@@ -3363,6 +3479,7 @@ pub enum Distinct {
33633479impl fmt:: Display for Distinct {
33643480 fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
33653481 match self {
3482+ Distinct :: All => write ! ( f, "ALL" ) ,
33663483 Distinct :: Distinct => write ! ( f, "DISTINCT" ) ,
33673484 Distinct :: On ( col_names) => {
33683485 let col_names = display_comma_separated ( col_names) ;
0 commit comments