Skip to main content

qusql_parse/
select.rs

1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License at
4//
5// http://www.apache.org/licenses/LICENSE-2.0
6//
7// Unless required by applicable law or agreed to in writing, software
8// distributed under the License is distributed on an "AS IS" BASIS,
9// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10// See the License for the specific language governing permissions and
11// limitations under the License.
12use alloc::{borrow::Cow, boxed::Box, vec::Vec};
13
14use crate::QualifiedName;
15use crate::qualified_name::parse_qualified_name_unreserved;
16use crate::{
17    DataType, Identifier, SString, Span, Spanned, Statement,
18    data_type::{DataTypeContext, parse_data_type},
19    expression::{Expression, PRIORITY_MAX, parse_expression_unreserved},
20    keywords::{Keyword, Restrict},
21    lexer::{StringType, Token},
22    parser::{ParseError, Parser},
23    span::OptSpanned,
24    statement::parse_compound_query,
25};
26
27/// Value in select
28#[derive(Debug, Clone)]
29pub struct SelectExpr<'a> {
30    /// Value to select
31    pub expr: Expression<'a>,
32    /// Optional name to give value if specified
33    pub as_: Option<Identifier<'a>>,
34}
35
36impl<'a> Spanned for SelectExpr<'a> {
37    fn span(&self) -> Span {
38        self.expr.join_span(&self.as_)
39    }
40}
41
42pub(crate) fn parse_select_expr<'a>(
43    parser: &mut Parser<'a, '_>,
44) -> Result<SelectExpr<'a>, ParseError> {
45    let expr = parse_expression_unreserved(parser, PRIORITY_MAX)?;
46    let reserved = parser.reserved();
47    let as_ = if parser.skip_keyword(Keyword::AS).is_some() {
48        Some(parser.consume_plain_identifier_unreserved()?)
49    } else {
50        let is_implicit_alias = match &parser.token {
51            Token::Ident(_, kw) => !kw.restricted(reserved),
52            Token::String(_, StringType::DoubleQuoted) => parser.options.dialect.is_postgresql(),
53            _ => false,
54        };
55        if is_implicit_alias {
56            Some(parser.consume_plain_identifier_unreserved()?)
57        } else {
58            None
59        }
60    };
61    Ok(SelectExpr { expr, as_ })
62}
63
64/// Specification for join
65#[derive(Debug, Clone)]
66pub enum JoinSpecification<'a> {
67    /// On specification expression and span of "ON"
68    On(Expression<'a>, Span),
69    /// List of columns to joint using, and span of "USING"
70    Using(Vec<Identifier<'a>>, Span),
71}
72
73impl<'a> Spanned for JoinSpecification<'a> {
74    fn span(&self) -> Span {
75        match &self {
76            JoinSpecification::On(v, s) => s.join_span(v),
77            JoinSpecification::Using(v, s) => s.join_span(v),
78        }
79    }
80}
81
82/// Type of join
83#[derive(Debug, Clone)]
84pub enum JoinType {
85    Inner(Span),
86    Cross(Span),
87    Normal(Span),
88    Straight(Span),
89    Left(Span),
90    Right(Span),
91    FullOuter(Span),
92    Natural(Span),
93    NaturalInner(Span),
94    NaturalLeft(Span),
95    NaturalRight(Span),
96}
97impl Spanned for JoinType {
98    fn span(&self) -> Span {
99        match &self {
100            JoinType::Inner(v) => v.span(),
101            JoinType::Cross(v) => v.span(),
102            JoinType::Normal(v) => v.span(),
103            JoinType::Straight(v) => v.span(),
104            JoinType::Left(v) => v.span(),
105            JoinType::Right(v) => v.span(),
106            JoinType::FullOuter(v) => v.span(),
107            JoinType::Natural(v) => v.span(),
108            JoinType::NaturalInner(v) => v.span(),
109            JoinType::NaturalLeft(v) => v.span(),
110            JoinType::NaturalRight(v) => v.span(),
111        }
112    }
113}
114
115#[derive(Debug, Clone)]
116pub enum IndexHintUse {
117    Use(Span),
118    Ignore(Span),
119    Force(Span),
120}
121impl Spanned for IndexHintUse {
122    fn span(&self) -> Span {
123        match &self {
124            IndexHintUse::Use(v) => v.span(),
125            IndexHintUse::Ignore(v) => v.span(),
126            IndexHintUse::Force(v) => v.span(),
127        }
128    }
129}
130
131#[derive(Debug, Clone)]
132pub enum IndexHintType {
133    Index(Span),
134    Key(Span),
135}
136impl Spanned for IndexHintType {
137    fn span(&self) -> Span {
138        match &self {
139            IndexHintType::Index(v) => v.span(),
140            IndexHintType::Key(v) => v.span(),
141        }
142    }
143}
144
145#[derive(Debug, Clone)]
146pub enum IndexHintFor {
147    Join(Span),
148    OrderBy(Span),
149    GroupBy(Span),
150}
151impl Spanned for IndexHintFor {
152    fn span(&self) -> Span {
153        match &self {
154            IndexHintFor::Join(v) => v.span(),
155            IndexHintFor::OrderBy(v) => v.span(),
156            IndexHintFor::GroupBy(v) => v.span(),
157        }
158    }
159}
160
161#[derive(Debug, Clone)]
162pub struct IndexHint<'a> {
163    pub use_: IndexHintUse,
164    pub type_: IndexHintType,
165    pub for_: Option<(Span, IndexHintFor)>,
166    pub lparen: Span,
167    pub index_list: Vec<Identifier<'a>>,
168    pub rparen: Span,
169}
170
171impl<'a> Spanned for IndexHint<'a> {
172    fn span(&self) -> Span {
173        self.use_
174            .span()
175            .join_span(&self.type_)
176            .join_span(&self.for_)
177            .join_span(&self.lparen)
178            .join_span(&self.index_list)
179            .join_span(&self.rparen)
180    }
181}
182
183/// JSON_TABLE ON EMPTY/ERROR behavior
184#[derive(Debug, Clone)]
185pub enum JsonTableOnErrorEmpty<'a> {
186    /// DEFAULT value
187    Default(Expression<'a>),
188    /// ERROR
189    Error(Span),
190    /// NULL
191    Null(Span),
192}
193
194impl<'a> Spanned for JsonTableOnErrorEmpty<'a> {
195    fn span(&self) -> Span {
196        match self {
197            JsonTableOnErrorEmpty::Default(expr) => expr.span(),
198            JsonTableOnErrorEmpty::Error(s) => s.clone(),
199            JsonTableOnErrorEmpty::Null(s) => s.clone(),
200        }
201    }
202}
203
204/// JSON_TABLE column definition
205#[derive(Debug, Clone)]
206pub enum JsonTableColumn<'a> {
207    /// Regular column: name data_type PATH 'path' [options]
208    Column {
209        name: Identifier<'a>,
210        data_type: DataType<'a>,
211        path_span: Span,
212        path: Expression<'a>,
213        /// ON EMPTY clause
214        on_empty: Option<(JsonTableOnErrorEmpty<'a>, Span)>,
215        /// ON ERROR clause
216        on_error: Option<(JsonTableOnErrorEmpty<'a>, Span)>,
217    },
218    /// Ordinality column: name FOR ORDINALITY
219    Ordinality {
220        name: Identifier<'a>,
221        for_ordinality_span: Span,
222    },
223    /// Nested path: NESTED PATH 'path' COLUMNS (...)
224    Nested {
225        nested_span: Span,
226        path_span: Span,
227        path: Expression<'a>,
228        columns_span: Span,
229        columns: Vec<JsonTableColumn<'a>>,
230    },
231}
232
233impl<'a> Spanned for JsonTableColumn<'a> {
234    fn span(&self) -> Span {
235        match self {
236            JsonTableColumn::Column {
237                name,
238                data_type,
239                path_span,
240                path,
241                on_empty,
242                on_error,
243            } => name
244                .span()
245                .join_span(data_type)
246                .join_span(path_span)
247                .join_span(path)
248                .join_span(on_empty)
249                .join_span(on_error),
250            JsonTableColumn::Ordinality {
251                name,
252                for_ordinality_span,
253            } => name.span().join_span(for_ordinality_span),
254            JsonTableColumn::Nested {
255                nested_span,
256                path_span,
257                path,
258                columns_span,
259                columns,
260            } => nested_span
261                .join_span(path_span)
262                .join_span(path)
263                .join_span(columns_span)
264                .join_span(columns),
265        }
266    }
267}
268
269/// The name of a table-valued function in a FROM clause.
270///
271/// Well-known set-returning functions get their own variant so consumers can
272/// match on them without string comparison. Any other function name falls into
273/// `Other`.
274#[derive(Debug, Clone)]
275pub enum TableFunctionName<'a> {
276    /// `UNNEST(array, ...)` — expand one or more arrays into a set of rows
277    Unnest(Span),
278    /// `GENERATE_SERIES(start, stop [, step])` — generate a series of values
279    GenerateSeries(Span),
280    /// `STRING_TO_TABLE(str, delimiter)` — split a string into rows
281    StringToTable(Span),
282    /// Any other set-returning function (user-defined or less common builtins)
283    Other(QualifiedName<'a>),
284}
285
286impl<'a> Spanned for TableFunctionName<'a> {
287    fn span(&self) -> Span {
288        match self {
289            TableFunctionName::Unnest(s)
290            | TableFunctionName::GenerateSeries(s)
291            | TableFunctionName::StringToTable(s) => s.clone(),
292            TableFunctionName::Other(n) => n.span(),
293        }
294    }
295}
296
297/// Reference to table in select
298#[derive(Debug, Clone)]
299pub enum TableReference<'a> {
300    /// Reference to a table or view
301    Table {
302        /// Name of table to to select from
303        identifier: QualifiedName<'a>,
304        /// Span of "AS" if specified
305        as_span: Option<Span>,
306        /// Alias for table if specified
307        as_: Option<Identifier<'a>>,
308        /// Index hints
309        index_hints: Vec<IndexHint<'a>>,
310    },
311    /// Subquery
312    Query {
313        /// Query yielding table
314        query: Box<Statement<'a>>,
315        /// Span of "AS" if specified
316        as_span: Option<Span>,
317        /// Alias for table if specified
318        as_: Option<Identifier<'a>>,
319        /// Optional column list `(col1, col2, ...)` after the alias
320        col_list: Vec<Identifier<'a>>,
321    },
322    /// JSON_TABLE function
323    JsonTable {
324        /// Span of "JSON_TABLE"
325        json_table_span: Span,
326        /// JSON data expression
327        json_expr: Expression<'a>,
328        /// JSON path expression
329        path: Expression<'a>,
330        /// COLUMNS keyword span
331        columns_keyword_span: Span,
332        /// Column definitions
333        columns: Vec<JsonTableColumn<'a>>,
334        /// Span of "AS" if specified
335        as_span: Option<Span>,
336        /// Alias for table if specified
337        as_: Option<Identifier<'a>>,
338    },
339    /// Table-valued function call, e.g. `generate_series(1, 10)` or `unnest(arr) WITH ORDINALITY`
340    Function {
341        /// The function name
342        name: TableFunctionName<'a>,
343        /// Arguments passed to the function
344        args: Vec<Expression<'a>>,
345        /// Span of `WITH ORDINALITY` if present
346        with_ordinality: Option<Span>,
347        /// Span of "AS" if specified
348        as_span: Option<Span>,
349        /// Alias for the result set if specified
350        as_: Option<Identifier<'a>>,
351        /// Optional column alias list `(col1, col2, ...)` after the alias
352        col_list: Vec<Identifier<'a>>,
353    },
354    /// Join
355    Join {
356        /// What type of join is it
357        join: JoinType,
358        /// Left hand side of join
359        left: Box<TableReference<'a>>,
360        /// Right hand side of join
361        right: Box<TableReference<'a>>,
362        /// How to do the join if specified
363        specification: Option<JoinSpecification<'a>>,
364    },
365}
366
367impl<'a> Spanned for TableReference<'a> {
368    fn span(&self) -> Span {
369        match &self {
370            TableReference::Table {
371                identifier,
372                as_span,
373                as_,
374                index_hints,
375            } => identifier
376                .opt_join_span(as_span)
377                .opt_join_span(as_)
378                .opt_join_span(index_hints)
379                .expect("span of table"),
380            TableReference::Query {
381                query,
382                as_span,
383                as_,
384                col_list,
385            } => query.join_span(as_span).join_span(as_).join_span(col_list),
386            TableReference::JsonTable {
387                json_table_span,
388                json_expr,
389                path,
390                columns_keyword_span,
391                columns,
392                as_span,
393                as_,
394            } => json_table_span
395                .join_span(json_expr)
396                .join_span(path)
397                .join_span(columns_keyword_span)
398                .join_span(columns)
399                .join_span(as_span)
400                .join_span(as_),
401            TableReference::Function {
402                name,
403                args,
404                with_ordinality,
405                as_span,
406                as_,
407                col_list,
408            } => name
409                .span()
410                .join_span(args)
411                .join_span(with_ordinality)
412                .join_span(as_span)
413                .join_span(as_)
414                .join_span(col_list),
415            TableReference::Join {
416                join,
417                left,
418                right,
419                specification,
420            } => join
421                .join_span(left)
422                .join_span(right)
423                .join_span(specification),
424        }
425    }
426}
427
428pub(crate) fn parse_table_reference_inner<'a>(
429    parser: &mut Parser<'a, '_>,
430    additional_restrict: crate::keywords::Restrict,
431) -> Result<TableReference<'a>, ParseError> {
432    // TODO [LATERAL] table_subquery [AS] alias [(col_list)]
433    // if parser.skip_token(Token::LParen).is_some() {
434    //     let a = parse_table_reference(parser)?;
435    //     parser.consume_token(Token::RParen)?;
436    //     return Ok(a);
437    // }
438
439    match &parser.token {
440        Token::Ident(_, Keyword::LATERAL) => {
441            // LATERAL subquery/function
442            let lateral_span = parser.consume_keyword(Keyword::LATERAL)?;
443            parser.postgres_only(&lateral_span);
444            let query = parse_compound_query(parser)?;
445            let as_span = parser.skip_keyword(Keyword::AS);
446            let as_ = if as_span.is_some()
447                || (matches!(&parser.token, Token::Ident(_, k) if !k.restricted(parser.reserved() | additional_restrict)))
448            {
449                Some(
450                    parser.consume_plain_identifier_restrict(
451                        parser.reserved() | additional_restrict,
452                    )?,
453                )
454            } else {
455                None
456            };
457            Ok(TableReference::Query {
458                query: Box::new(query),
459                as_span: as_span
460                    .map(|s| lateral_span.join_span(&s))
461                    .or(Some(lateral_span)),
462                as_,
463                col_list: Vec::new(),
464            })
465        }
466        Token::Ident(_, Keyword::SELECT) | Token::LParen => {
467            // If the token after '(' is an identifier (table name) or another '('
468            // (for nested groups like ((t1 join t2) join t3)), rather than
469            // SELECT/VALUES/WITH, treat it as a MySQL parenthesized join group.
470            let is_join_group = matches!(parser.token, Token::LParen)
471                && !matches!(
472                    parser.peek(),
473                    Token::Ident(_, Keyword::SELECT | Keyword::VALUES | Keyword::WITH)
474                        | Token::LParen
475                );
476            if is_join_group {
477                parser.consume_token(Token::LParen)?;
478                let inner = parse_table_reference(parser, additional_restrict)?;
479                parser.consume_token(Token::RParen)?;
480                return Ok(inner);
481            }
482            let query = parse_compound_query(parser)?;
483            let as_span = parser.skip_keyword(Keyword::AS);
484            let as_ = if as_span.is_some()
485                || (matches!(&parser.token, Token::Ident(_, k) if !k.restricted(parser.reserved() | additional_restrict)))
486            {
487                Some(
488                    parser.consume_plain_identifier_restrict(
489                        parser.reserved() | additional_restrict,
490                    )?,
491                )
492            } else {
493                None
494            };
495            // Optional column list: AS alias (col1, col2, ...)
496            let mut col_list = Vec::new();
497            if as_.is_some() && matches!(parser.token, Token::LParen) {
498                parser.consume_token(Token::LParen)?;
499                loop {
500                    parser.recovered(
501                        "')' or ','",
502                        &|t| matches!(t, Token::RParen | Token::Comma),
503                        |parser| {
504                            col_list
505                                .push(parser.consume_plain_identifier_restrict(Restrict::EMPTY)?);
506                            Ok(())
507                        },
508                    )?;
509                    if parser.skip_token(Token::Comma).is_none() {
510                        break;
511                    }
512                }
513                parser.consume_token(Token::RParen)?;
514            };
515            Ok(TableReference::Query {
516                query: Box::new(query),
517                as_span,
518                as_,
519                col_list,
520            })
521        }
522        Token::Ident(_, _) => parse_table_reference_named(parser, additional_restrict),
523        Token::String(_, StringType::DoubleQuoted) if parser.options.dialect.is_postgresql() => {
524            parse_table_reference_named(parser, additional_restrict)
525        }
526        _ => parser.expected_failure("subquery or identifier"),
527    }
528}
529
530fn parse_table_reference_named<'a>(
531    parser: &mut Parser<'a, '_>,
532    additional_restrict: Restrict,
533) -> Result<TableReference<'a>, ParseError> {
534    if matches!(parser.token, Token::Ident(_, Keyword::JSON_TABLE))
535        && matches!(parser.peek(), Token::LParen)
536    {
537        let json_table_span = parser.consume_keyword(Keyword::JSON_TABLE)?;
538
539        parser.consume_token(Token::LParen)?;
540
541        // Parse JSON data expression (first argument)
542        let json_expr = parse_expression_unreserved(parser, PRIORITY_MAX)?;
543
544        // Expect comma
545        parser.consume_token(Token::Comma)?;
546
547        // Parse JSON path - just a simple string for now
548        let path = match &parser.token {
549            Token::String(s, _) => {
550                let val = *s;
551                let span = parser.consume();
552                Expression::String(Box::new(SString::new(Cow::Borrowed(val), span)))
553            }
554            _ => {
555                // Fall back to expression parsing
556                parse_expression_unreserved(parser, PRIORITY_MAX)?
557            }
558        };
559
560        // Parse COLUMNS clause (no comma before COLUMNS)
561        let columns_keyword_span = parser.consume_keyword(Keyword::COLUMNS)?;
562        parser.consume_token(Token::LParen)?;
563
564        let columns = parser.recovered(")", &|t| t == &Token::RParen, |parser| {
565            // Parse column definitions
566            parse_json_table_columns(parser)
567        })?;
568
569        parser.consume_token(Token::RParen)?;
570
571        // Closing parenthesis of JSON_TABLE
572        parser.consume_token(Token::RParen)?;
573
574        // Parse AS and alias
575        let as_span = parser.skip_keyword(Keyword::AS);
576        let as_ = if as_span.is_some()
577            || (matches!(&parser.token, Token::Ident(_, k) if !k.restricted(parser.reserved() | additional_restrict)))
578        {
579            Some(parser.consume_plain_identifier_unreserved()?)
580        } else {
581            None
582        };
583
584        return Ok(TableReference::JsonTable {
585            json_table_span,
586            json_expr,
587            path,
588            columns_keyword_span,
589            columns,
590            as_span,
591            as_,
592        });
593    }
594
595    // Snapshot the first token's keyword (if any) before consuming the qualified name,
596    // so we can build the correct TableFunctionName variant if this turns out to be a
597    // table-valued function call.
598    let first_kw = match &parser.token {
599        Token::Ident(_, kw) => Some(*kw),
600        _ => None,
601    };
602    let identifier = parse_qualified_name_unreserved(parser)?;
603
604    if matches!(parser.token, Token::LParen) {
605        // Table-valued function call (any set-returning function)
606        let func_name = if identifier.prefix.is_empty() {
607            match first_kw {
608                Some(Keyword::UNNEST) => TableFunctionName::Unnest(identifier.identifier.span),
609                Some(Keyword::GENERATE_SERIES) => {
610                    TableFunctionName::GenerateSeries(identifier.identifier.span)
611                }
612                Some(Keyword::STRING_TO_TABLE) => {
613                    TableFunctionName::StringToTable(identifier.identifier.span)
614                }
615                _ => TableFunctionName::Other(identifier),
616            }
617        } else {
618            TableFunctionName::Other(identifier)
619        };
620        parser.consume_token(Token::LParen)?;
621        let mut args = Vec::new();
622        if !matches!(parser.token, Token::RParen) {
623            loop {
624                parser.recovered(
625                    "')' or ','",
626                    &|t| matches!(t, Token::RParen | Token::Comma),
627                    |parser| {
628                        args.push(parse_expression_unreserved(parser, PRIORITY_MAX)?);
629                        Ok(())
630                    },
631                )?;
632                if parser.skip_token(Token::Comma).is_none() {
633                    break;
634                }
635            }
636        }
637        parser.consume_token(Token::RParen)?;
638        // WITH ORDINALITY is a general FROM-clause modifier supported by all SRFs
639        let with_ordinality = if let Some(with_span) = parser.skip_keyword(Keyword::WITH) {
640            let ord_span = parser.consume_keyword(Keyword::ORDINALITY)?;
641            Some(with_span.join_span(&ord_span))
642        } else {
643            None
644        };
645        let as_span = parser.skip_keyword(Keyword::AS);
646        let as_ = if as_span.is_some()
647            || (matches!(&parser.token, Token::Ident(_, k) if !k.restricted(parser.reserved() | additional_restrict)))
648        {
649            Some(parser.consume_plain_identifier_unreserved()?)
650        } else {
651            None
652        };
653        // Parse optional column alias list `alias(col1, col2, ...)` (PostgreSQL table-function syntax)
654        let col_list = if as_.is_some() && matches!(parser.token, Token::LParen) {
655            parser.consume_token(Token::LParen)?;
656            let mut cols = Vec::new();
657            loop {
658                parser.recovered(
659                    "')' or ','",
660                    &|t| matches!(t, Token::RParen | Token::Comma),
661                    |parser| {
662                        cols.push(parser.consume_plain_identifier_unreserved()?);
663                        Ok(())
664                    },
665                )?;
666                if parser.skip_token(Token::Comma).is_none() {
667                    break;
668                }
669            }
670            parser.consume_token(Token::RParen)?;
671            cols
672        } else {
673            Vec::new()
674        };
675        return Ok(TableReference::Function {
676            name: func_name,
677            args,
678            with_ordinality,
679            as_span,
680            as_,
681            col_list,
682        });
683    }
684
685    // TODO [PARTITION (partition_names)] [[AS] alias]
686    let as_span = parser.skip_keyword(Keyword::AS);
687    let as_ = if as_span.is_some()
688        || (matches!(&parser.token, Token::Ident(_, k) if !k.restricted(parser.reserved() | additional_restrict)))
689    {
690        Some(parser.consume_plain_identifier_restrict(parser.reserved() | additional_restrict)?)
691    } else {
692        None
693    };
694
695    let mut index_hints = Vec::new();
696    loop {
697        let use_ = match parser.token {
698            Token::Ident(_, Keyword::USE) => IndexHintUse::Use(parser.consume()),
699            Token::Ident(_, Keyword::IGNORE) => IndexHintUse::Ignore(parser.consume()),
700            Token::Ident(_, Keyword::FORCE) => IndexHintUse::Force(parser.consume()),
701            _ => break,
702        };
703        let type_ = match parser.token {
704            Token::Ident(_, Keyword::INDEX) => IndexHintType::Index(parser.consume()),
705            Token::Ident(_, Keyword::KEY) => IndexHintType::Key(parser.consume()),
706            _ => parser.expected_failure("'INDEX' or 'KEY'")?,
707        };
708        let for_ = if let Some(for_span) = parser.skip_keyword(Keyword::FOR) {
709            let v = match parser.token {
710                Token::Ident(_, Keyword::JOIN) => IndexHintFor::Join(parser.consume()),
711                Token::Ident(_, Keyword::GROUP) => {
712                    IndexHintFor::GroupBy(parser.consume_keywords(&[Keyword::GROUP, Keyword::BY])?)
713                }
714                Token::Ident(_, Keyword::ORDER) => {
715                    IndexHintFor::OrderBy(parser.consume_keywords(&[Keyword::ORDER, Keyword::BY])?)
716                }
717                _ => parser.expected_failure("'JOIN', 'GROUP BY' or 'ORDER BY'")?,
718            };
719            Some((for_span, v))
720        } else {
721            None
722        };
723        let lparen = parser.consume_token(Token::LParen)?;
724        let mut index_list = Vec::new();
725        loop {
726            parser.recovered(
727                "')' or ','",
728                &|t| matches!(t, Token::RParen | Token::Comma),
729                |parser| {
730                    index_list.push(parser.consume_plain_identifier_unreserved()?);
731                    Ok(())
732                },
733            )?;
734            if matches!(parser.token, Token::RParen) {
735                break;
736            }
737            parser.consume_token(Token::Comma)?;
738        }
739        let rparen = parser.consume_token(Token::RParen)?;
740        index_hints.push(IndexHint {
741            use_,
742            type_,
743            for_,
744            lparen,
745            index_list,
746            rparen,
747        })
748    }
749
750    if !index_hints.is_empty() && !parser.options.dialect.is_maria() {
751        parser.err(
752            "Index hints only supported by MariaDb",
753            &index_hints.opt_span().unwrap(),
754        );
755    }
756
757    Ok(TableReference::Table {
758        identifier,
759        as_span,
760        as_,
761        index_hints,
762    })
763}
764
765fn parse_json_table_columns<'a>(
766    parser: &mut Parser<'a, '_>,
767) -> Result<Vec<JsonTableColumn<'a>>, ParseError> {
768    let mut columns = Vec::new();
769
770    loop {
771        // Check for NESTED PATH
772        if let Some(nested_span) = parser.skip_keyword(Keyword::NESTED) {
773            let path_span = parser.consume_keyword(Keyword::PATH)?;
774            let path = match &parser.token {
775                Token::String(s, _) => {
776                    let val = *s;
777                    let span = parser.consume();
778                    Expression::String(Box::new(SString::new(Cow::Borrowed(val), span)))
779                }
780                _ => parse_expression_unreserved(parser, PRIORITY_MAX)?,
781            };
782            let columns_span = parser.consume_keyword(Keyword::COLUMNS)?;
783            parser.consume_token(Token::LParen)?;
784            let nested_columns = parser.recovered(")", &|t| t == &Token::RParen, |parser| {
785                parse_json_table_columns(parser)
786            })?;
787            parser.consume_token(Token::RParen)?;
788
789            columns.push(JsonTableColumn::Nested {
790                nested_span,
791                path_span,
792                path,
793                columns_span,
794                columns: nested_columns,
795            });
796        } else {
797            // Parse column name
798            let name = parser.consume_plain_identifier_unreserved()?;
799
800            // Check if this is FOR ORDINALITY
801            if let Some(for_span) = parser.skip_keyword(Keyword::FOR) {
802                let ordinality_span = parser.consume_keyword(Keyword::ORDINALITY)?;
803                let for_ordinality_span = for_span.join_span(&ordinality_span);
804
805                columns.push(JsonTableColumn::Ordinality {
806                    name,
807                    for_ordinality_span,
808                });
809            } else {
810                // Parse data type
811                let data_type = parse_data_type(parser, DataTypeContext::FunctionReturn)?;
812
813                // Check for EXISTS before PATH
814                let _ = parser.skip_keyword(Keyword::EXISTS);
815
816                // Parse PATH keyword and path expression
817                let path_span = parser.consume_keyword(Keyword::PATH)?;
818                let path = match &parser.token {
819                    Token::String(s, _) => {
820                        let val = *s;
821                        let span = parser.consume();
822                        Expression::String(Box::new(SString::new(Cow::Borrowed(val), span)))
823                    }
824                    _ => parse_expression_unreserved(parser, PRIORITY_MAX)?,
825                };
826
827                // Parse ON EMPTY and ON ERROR clauses
828                // These can appear in various orders: DEFAULT '...' ON EMPTY, ERROR ON ERROR, etc.
829                let mut on_empty = None;
830                let mut on_error = None;
831
832                loop {
833                    let behavior_start = parser.span.span().start;
834                    let behavior = match &parser.token {
835                        Token::Ident(_, Keyword::DEFAULT) => {
836                            parser.consume();
837                            // Parse the default value
838                            let default_val = parse_expression_unreserved(parser, PRIORITY_MAX)?;
839                            Some(JsonTableOnErrorEmpty::Default(default_val))
840                        }
841                        Token::Ident(_, Keyword::ERROR) => {
842                            let error_span = parser.consume();
843                            Some(JsonTableOnErrorEmpty::Error(error_span))
844                        }
845                        Token::Ident(_, Keyword::NULL) => {
846                            let null_span = parser.consume();
847                            Some(JsonTableOnErrorEmpty::Null(null_span))
848                        }
849                        _ => None,
850                    };
851
852                    if let Some(behavior) = behavior {
853                        parser.consume_keyword(Keyword::ON)?;
854                        let clause_end = parser.span.span().end;
855                        match &parser.token {
856                            Token::Ident(_, Keyword::EMPTY) => {
857                                parser.consume();
858                                let span = behavior_start..clause_end;
859                                on_empty = Some((behavior, span));
860                            }
861                            Token::Ident(_, Keyword::ERROR) => {
862                                parser.consume();
863                                let span = behavior_start..clause_end;
864                                on_error = Some((behavior, span));
865                            }
866                            _ => {
867                                // Not EMPTY or ERROR, emit an error
868                                parser.expected_failure("EMPTY or ERROR")?;
869                            }
870                        }
871                    } else {
872                        // No behavior keyword, we're done
873                        break;
874                    }
875                }
876
877                columns.push(JsonTableColumn::Column {
878                    name,
879                    data_type,
880                    path_span,
881                    path,
882                    on_empty,
883                    on_error,
884                });
885            }
886        }
887
888        // Check if there are more columns
889        if parser.skip_token(Token::Comma).is_none() {
890            break;
891        }
892
893        // Check if we've reached the end of the column list
894        if matches!(parser.token, Token::RParen) {
895            break;
896        }
897    }
898
899    Ok(columns)
900}
901
902pub(crate) fn parse_table_reference<'a>(
903    parser: &mut Parser<'a, '_>,
904    additional_restrict: crate::keywords::Restrict,
905) -> Result<TableReference<'a>, ParseError> {
906    let mut ans = parse_table_reference_inner(parser, additional_restrict)?;
907    loop {
908        let join = match parser.token {
909            Token::Ident(_, Keyword::FULL) => {
910                let full = parser.consume_keyword(Keyword::FULL)?;
911                parser.postgres_only(&full);
912                if let Some(outer) = parser.skip_keyword(Keyword::OUTER) {
913                    JoinType::FullOuter(
914                        full.join_span(&outer)
915                            .join_span(&parser.consume_keyword(Keyword::JOIN)?),
916                    )
917                } else {
918                    JoinType::FullOuter(full.join_span(&parser.consume_keyword(Keyword::JOIN)?))
919                }
920            }
921            Token::Ident(_, Keyword::INNER) => JoinType::Inner(
922                parser
923                    .consume_keyword(Keyword::INNER)?
924                    .join_span(&parser.consume_keyword(Keyword::JOIN)?),
925            ),
926            Token::Ident(_, Keyword::CROSS) => JoinType::Cross(
927                parser
928                    .consume_keyword(Keyword::CROSS)?
929                    .join_span(&parser.consume_keyword(Keyword::JOIN)?),
930            ),
931            Token::Ident(_, Keyword::JOIN) => {
932                JoinType::Normal(parser.consume_keyword(Keyword::JOIN)?)
933            }
934            Token::Ident(_, Keyword::STRAIGHT_JOIN) => {
935                JoinType::Straight(parser.consume_keyword(Keyword::STRAIGHT_JOIN)?)
936            }
937            Token::Ident(_, Keyword::LEFT) => {
938                let left = parser.consume_keyword(Keyword::LEFT)?;
939                if let Some(outer) = parser.skip_keyword(Keyword::OUTER) {
940                    JoinType::Left(
941                        left.join_span(&outer)
942                            .join_span(&parser.consume_keyword(Keyword::JOIN)?),
943                    )
944                } else {
945                    JoinType::Left(left.join_span(&parser.consume_keyword(Keyword::JOIN)?))
946                }
947            }
948            Token::Ident(_, Keyword::RIGHT) => {
949                let right = parser.consume_keyword(Keyword::RIGHT)?;
950                if let Some(outer) = parser.skip_keyword(Keyword::OUTER) {
951                    JoinType::Right(
952                        right
953                            .join_span(&outer)
954                            .join_span(&parser.consume_keyword(Keyword::JOIN)?),
955                    )
956                } else {
957                    JoinType::Right(right.join_span(&parser.consume_keyword(Keyword::JOIN)?))
958                }
959            }
960            Token::Ident(_, Keyword::NATURAL) => {
961                let natural = parser.consume_keyword(Keyword::NATURAL)?;
962                match &parser.token {
963                    Token::Ident(_, Keyword::INNER) => JoinType::NaturalInner(
964                        natural
965                            .join_span(&parser.consume_keywords(&[Keyword::INNER, Keyword::JOIN])?),
966                    ),
967                    Token::Ident(_, Keyword::LEFT) => {
968                        let left = parser.consume_keyword(Keyword::LEFT)?;
969                        if let Some(outer) = parser.skip_keyword(Keyword::OUTER) {
970                            JoinType::NaturalLeft(
971                                left.join_span(&outer)
972                                    .join_span(&parser.consume_keyword(Keyword::JOIN)?),
973                            )
974                        } else {
975                            JoinType::NaturalLeft(
976                                left.join_span(&parser.consume_keyword(Keyword::JOIN)?),
977                            )
978                        }
979                    }
980                    Token::Ident(_, Keyword::RIGHT) => {
981                        let right = parser.consume_keyword(Keyword::RIGHT)?;
982                        if let Some(outer) = parser.skip_keyword(Keyword::OUTER) {
983                            JoinType::NaturalRight(
984                                right
985                                    .join_span(&outer)
986                                    .join_span(&parser.consume_keyword(Keyword::JOIN)?),
987                            )
988                        } else {
989                            JoinType::NaturalRight(
990                                right.join_span(&parser.consume_keyword(Keyword::JOIN)?),
991                            )
992                        }
993                    }
994                    Token::Ident(_, Keyword::JOIN) => JoinType::Natural(
995                        natural.join_span(&parser.consume_keyword(Keyword::JOIN)?),
996                    ),
997                    _ => parser.expected_failure("'INNER', 'LEFT', 'RIGHT' or 'JOIN'")?,
998                }
999            }
1000            _ => break,
1001        };
1002
1003        let right = parse_table_reference_inner(parser, additional_restrict)?;
1004
1005        let specification = match &parser.token {
1006            Token::Ident(_, Keyword::ON) => {
1007                let on = parser.consume_keyword(Keyword::ON)?;
1008                let expr = parse_expression_unreserved(parser, PRIORITY_MAX)?;
1009                Some(JoinSpecification::On(expr, on))
1010            }
1011            Token::Ident(_, Keyword::USING) => {
1012                let using = parser.consume_keyword(Keyword::USING)?;
1013                let mut join_column_list = Vec::new();
1014                loop {
1015                    join_column_list.push(parser.consume_plain_identifier_unreserved()?);
1016                    if parser.skip_token(Token::Comma).is_none() {
1017                        break;
1018                    }
1019                }
1020                Some(JoinSpecification::Using(join_column_list, using))
1021            }
1022            _ => None,
1023        };
1024
1025        ans = TableReference::Join {
1026            join,
1027            left: Box::new(ans),
1028            right: Box::new(right),
1029            specification,
1030        };
1031    }
1032    Ok(ans)
1033}
1034
1035/// Flags specified after SELECT
1036#[derive(Debug, Clone)]
1037pub enum SelectFlag {
1038    All(Span),
1039    Distinct(Span),
1040    DistinctOn(Span),
1041    DistinctRow(Span),
1042    HighPriority(Span),
1043    StraightJoin(Span),
1044    SqlSmallResult(Span),
1045    SqlBigResult(Span),
1046    SqlBufferResult(Span),
1047    SqlNoCache(Span),
1048    SqlCalcFoundRows(Span),
1049}
1050
1051impl Spanned for SelectFlag {
1052    fn span(&self) -> Span {
1053        match &self {
1054            SelectFlag::All(v) => v.span(),
1055            SelectFlag::Distinct(v) => v.span(),
1056            SelectFlag::DistinctOn(v) => v.span(),
1057            SelectFlag::DistinctRow(v) => v.span(),
1058            SelectFlag::HighPriority(v) => v.span(),
1059            SelectFlag::StraightJoin(v) => v.span(),
1060            SelectFlag::SqlSmallResult(v) => v.span(),
1061            SelectFlag::SqlBigResult(v) => v.span(),
1062            SelectFlag::SqlBufferResult(v) => v.span(),
1063            SelectFlag::SqlNoCache(v) => v.span(),
1064            SelectFlag::SqlCalcFoundRows(v) => v.span(),
1065        }
1066    }
1067}
1068
1069/// Ordering direction
1070#[derive(Debug, Clone)]
1071pub enum OrderFlag {
1072    Asc(Span),
1073    Desc(Span),
1074    AscNullsFirst(Span),
1075    AscNullsLast(Span),
1076    DescNullsFirst(Span),
1077    DescNullsLast(Span),
1078    NullsFirst(Span),
1079    NullsLast(Span),
1080    None,
1081}
1082impl OptSpanned for OrderFlag {
1083    fn opt_span(&self) -> Option<Span> {
1084        match &self {
1085            OrderFlag::Asc(v) => v.opt_span(),
1086            OrderFlag::Desc(v) => v.opt_span(),
1087            OrderFlag::AscNullsFirst(v) => v.opt_span(),
1088            OrderFlag::AscNullsLast(v) => v.opt_span(),
1089            OrderFlag::DescNullsFirst(v) => v.opt_span(),
1090            OrderFlag::DescNullsLast(v) => v.opt_span(),
1091            OrderFlag::NullsFirst(v) => v.opt_span(),
1092            OrderFlag::NullsLast(v) => v.opt_span(),
1093            OrderFlag::None => None,
1094        }
1095    }
1096}
1097
1098/// Lock strength for locking
1099#[derive(Debug, Clone)]
1100pub enum LockStrength {
1101    Update(Span),
1102    Share(Span),
1103    NoKeyUpdate(Span),
1104    KeyShare(Span),
1105}
1106impl Spanned for LockStrength {
1107    fn span(&self) -> Span {
1108        match &self {
1109            LockStrength::Update(v) => v.span(),
1110            LockStrength::Share(v) => v.span(),
1111            LockStrength::NoKeyUpdate(v) => v.span(),
1112            LockStrength::KeyShare(v) => v.span(),
1113        }
1114    }
1115}
1116
1117#[derive(Debug, Clone)]
1118pub enum LockWait {
1119    NoWait(Span),
1120    SkipLocket(Span),
1121    Default,
1122}
1123impl OptSpanned for LockWait {
1124    fn opt_span(&self) -> Option<Span> {
1125        match &self {
1126            LockWait::NoWait(v) => v.opt_span(),
1127            LockWait::SkipLocket(v) => v.opt_span(),
1128            LockWait::Default => None,
1129        }
1130    }
1131}
1132
1133#[derive(Debug, Clone)]
1134pub struct Locking<'a> {
1135    /// Span of "FOR"
1136    pub for_span: Span,
1137    pub strength: LockStrength,
1138    pub of: Option<(Span, Vec<Identifier<'a>>)>,
1139    pub wait: LockWait,
1140}
1141impl<'a> Spanned for Locking<'a> {
1142    fn span(&self) -> Span {
1143        self.for_span
1144            .join_span(&self.strength)
1145            .join_span(&self.of)
1146            .join_span(&self.wait)
1147    }
1148}
1149
1150/// Representation of select Statement
1151///
1152/// ```
1153/// # use qusql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statement, Select, Statement, Issues};
1154/// # let options = ParseOptions::new().dialect(SQLDialect::MariaDB);
1155/// #
1156/// let sql = "SELECT f1,f2 FROM t1 WHERE f3<=10 AND f4='y'";
1157/// let mut issues = Issues::new(sql);
1158/// let stmt = parse_statement(sql, &mut issues, &options);
1159///
1160/// # assert!(issues.is_ok());
1161/// let s: Select = match stmt {
1162///     Some(Statement::Select(s)) => *s,
1163///     _ => panic!("We should get an select statement")
1164/// };
1165///
1166/// println!("{:#?}", s.where_);
1167///
1168/// let sql = "SELECT CAST(NULL AS CHAR)";
1169/// let stmt = parse_statement(sql, &mut issues, &options);
1170///
1171/// # assert!(issues.is_ok());
1172/// let s: Select = match stmt {
1173///     Some(Statement::Select(s)) => *s,
1174///     _ => panic!("We should get an select statement")
1175/// };
1176///
1177/// println!("{:#?}", s.where_);
1178///
1179/// let sql = "SELECT * FROM t1, d2.t2 FOR SHARE OF t1, t2 NOWAIT";
1180/// let stmt = parse_statement(sql, &mut issues, &options);
1181///
1182/// # assert!(issues.is_ok());
1183/// let s: Select = match stmt {
1184///     Some(Statement::Select(s)) => *s,
1185///     _ => panic!("We should get an select statement")
1186/// };
1187///
1188/// assert!(s.locking.is_some());
1189/// println!("{:#?}", s.locking);
1190/// ```
1191#[derive(Debug, Clone)]
1192pub struct Select<'a> {
1193    /// Span of "SELECT"
1194    pub select_span: Span,
1195    /// Flags specified after "SELECT"
1196    pub flags: Vec<SelectFlag>,
1197    /// List of values to select
1198    pub select_exprs: Vec<SelectExpr<'a>>,
1199    /// Span of "FROM"
1200    pub from_span: Option<Span>,
1201    /// List of tables to select from
1202    pub table_references: Option<Vec<TableReference<'a>>>,
1203    /// Where expression and span of "WHERE" if specified
1204    pub where_: Option<(Expression<'a>, Span)>,
1205    /// Span of "GROUP_BY" and group expression if specified
1206    pub group_by: Option<(Span, Vec<Expression<'a>>)>,
1207    /// Having expression and span of "HAVING" if specified
1208    pub having: Option<(Expression<'a>, Span)>,
1209    /// Span of window if specified
1210    pub window_span: Option<Span>,
1211    /// Span of "ORDER BY" and list of order expression and directions, if specified
1212    pub order_by: Option<(Span, Vec<(Expression<'a>, OrderFlag)>)>,
1213    /// Span of "LIMIT", offset and count expressions if specified
1214    pub limit: Option<(Span, Option<Expression<'a>>, Expression<'a>)>,
1215    /// PostgreSQL: DISTINCT ON (expr, ...) list
1216    pub distinct_on: Option<(Span, Vec<Expression<'a>>)>,
1217    /// PostgreSQL: OFFSET n [ROWS] (when no LIMIT is present)
1218    pub offset: Option<(Span, Expression<'a>)>,
1219    /// PostgreSQL: FETCH {FIRST|NEXT} n {ROW|ROWS} ONLY
1220    pub fetch: Option<(Span, Expression<'a>)>,
1221    /// Row locking clause
1222    pub locking: Option<Locking<'a>>,
1223}
1224
1225impl<'a> Spanned for Select<'a> {
1226    fn span(&self) -> Span {
1227        self.select_span
1228            .join_span(&self.flags)
1229            .join_span(&self.select_exprs)
1230            .join_span(&self.from_span)
1231            .join_span(&self.table_references)
1232            .join_span(&self.where_)
1233            .join_span(&self.group_by)
1234            .join_span(&self.having)
1235            .join_span(&self.window_span)
1236            .join_span(&self.order_by)
1237            .join_span(&self.limit)
1238            .join_span(&self.distinct_on)
1239            .join_span(&self.offset)
1240            .join_span(&self.fetch)
1241    }
1242}
1243
1244pub(crate) fn parse_select<'a>(parser: &mut Parser<'a, '_>) -> Result<Select<'a>, ParseError> {
1245    let select_span = parser.consume_keyword(Keyword::SELECT)?;
1246    let mut flags = Vec::new();
1247    let mut select_exprs = Vec::new();
1248
1249    loop {
1250        match &parser.token {
1251            Token::Ident(_, Keyword::ALL) => {
1252                flags.push(SelectFlag::All(parser.consume_keyword(Keyword::ALL)?))
1253            }
1254            Token::Ident(_, Keyword::DISTINCT) => {
1255                let distinct_span = parser.consume_keyword(Keyword::DISTINCT)?;
1256                // PostgreSQL: DISTINCT ON (expr, ...)
1257                if matches!(parser.token, Token::Ident(_, Keyword::ON)) {
1258                    flags.push(SelectFlag::DistinctOn(distinct_span));
1259                } else {
1260                    flags.push(SelectFlag::Distinct(distinct_span));
1261                }
1262            }
1263            Token::Ident(_, Keyword::DISTINCTROW) => flags.push(SelectFlag::DistinctRow(
1264                parser.consume_keyword(Keyword::DISTINCTROW)?,
1265            )),
1266            Token::Ident(_, Keyword::HIGH_PRIORITY) => flags.push(SelectFlag::HighPriority(
1267                parser.consume_keyword(Keyword::HIGH_PRIORITY)?,
1268            )),
1269            Token::Ident(_, Keyword::STRAIGHT_JOIN) => flags.push(SelectFlag::StraightJoin(
1270                parser.consume_keyword(Keyword::STRAIGHT_JOIN)?,
1271            )),
1272            Token::Ident(_, Keyword::SQL_SMALL_RESULT) => flags.push(SelectFlag::SqlSmallResult(
1273                parser.consume_keyword(Keyword::SQL_SMALL_RESULT)?,
1274            )),
1275            Token::Ident(_, Keyword::SQL_BIG_RESULT) => flags.push(SelectFlag::SqlBigResult(
1276                parser.consume_keyword(Keyword::SQL_BIG_RESULT)?,
1277            )),
1278            Token::Ident(_, Keyword::SQL_BUFFER_RESULT) => flags.push(SelectFlag::SqlBufferResult(
1279                parser.consume_keyword(Keyword::SQL_BUFFER_RESULT)?,
1280            )),
1281            Token::Ident(_, Keyword::SQL_NO_CACHE) => flags.push(SelectFlag::SqlNoCache(
1282                parser.consume_keyword(Keyword::SQL_NO_CACHE)?,
1283            )),
1284            Token::Ident(_, Keyword::SQL_CALC_FOUND_ROWS) => flags.push(
1285                SelectFlag::SqlCalcFoundRows(parser.consume_keyword(Keyword::SQL_CALC_FOUND_ROWS)?),
1286            ),
1287            _ => break,
1288        }
1289    }
1290
1291    // PostgreSQL: parse DISTINCT ON (expr, ...) if signaled by DistinctOn flag
1292    let distinct_on = if flags
1293        .last()
1294        .is_some_and(|f| matches!(f, SelectFlag::DistinctOn(_)))
1295    {
1296        let on_span = parser.consume_keyword(Keyword::ON)?;
1297        parser.postgres_only(&on_span);
1298        parser.consume_token(Token::LParen)?;
1299        let mut exprs = Vec::new();
1300        loop {
1301            parser.recovered(
1302                "')' or ','",
1303                &|t| matches!(t, Token::RParen | Token::Comma),
1304                |parser| {
1305                    exprs.push(parse_expression_unreserved(parser, PRIORITY_MAX)?);
1306                    Ok(())
1307                },
1308            )?;
1309            if parser.skip_token(Token::Comma).is_none() {
1310                break;
1311            }
1312        }
1313        parser.consume_token(Token::RParen)?;
1314        Some((on_span, exprs))
1315    } else {
1316        None
1317    };
1318
1319    loop {
1320        select_exprs.push(parse_select_expr(parser)?);
1321        if parser.skip_token(Token::Comma).is_none() {
1322            break;
1323        }
1324    }
1325
1326    // TODO [into_option]
1327
1328    let from_span = parser.skip_keyword(Keyword::FROM);
1329
1330    let table_references = if from_span.is_some() {
1331        let mut table_references = Vec::new();
1332        loop {
1333            table_references.push(parse_table_reference(parser, Restrict::EMPTY)?);
1334            if parser.skip_token(Token::Comma).is_none() {
1335                break;
1336            }
1337        }
1338        Some(table_references)
1339    } else {
1340        None
1341    };
1342
1343    // TODO PARTITION partition_list;
1344    let where_ = if let Some(span) = parser.skip_keyword(Keyword::WHERE) {
1345        Some((parse_expression_unreserved(parser, PRIORITY_MAX)?, span))
1346    } else {
1347        None
1348    };
1349
1350    let group_by = if let Some(group_span) = parser.skip_keyword(Keyword::GROUP) {
1351        let span = parser.consume_keyword(Keyword::BY)?.join_span(&group_span);
1352        let mut groups = Vec::new();
1353        loop {
1354            groups.push(parse_expression_unreserved(parser, PRIORITY_MAX)?);
1355            if parser.skip_token(Token::Comma).is_none() {
1356                break;
1357            }
1358        }
1359        // TODO [WITH ROLLUP]]
1360        Some((span, groups))
1361    } else {
1362        None
1363    };
1364
1365    let having = if let Some(span) = parser.skip_keyword(Keyword::HAVING) {
1366        Some((parse_expression_unreserved(parser, PRIORITY_MAX)?, span))
1367    } else {
1368        None
1369    };
1370
1371    let window_span = parser.skip_keyword(Keyword::WINDOW);
1372    if window_span.is_some() {
1373        //TODO window_name AS (window_spec) [, window_name AS (window_spec)] ...]
1374    }
1375
1376    let order_by = if let Some(span) = parser.skip_keyword(Keyword::ORDER) {
1377        let span = parser.consume_keyword(Keyword::BY)?.join_span(&span);
1378        let mut order = Vec::new();
1379        loop {
1380            let e = parse_expression_unreserved(parser, PRIORITY_MAX)?;
1381            let dir_span_opt = match &parser.token {
1382                Token::Ident(_, Keyword::ASC) => Some((true, parser.consume())),
1383                Token::Ident(_, Keyword::DESC) => Some((false, parser.consume())),
1384                _ => None,
1385            };
1386            let f = if let Some(nulls_span) = parser.skip_keyword(Keyword::NULLS) {
1387                match &parser.token {
1388                    Token::Ident(_, Keyword::FIRST) => {
1389                        let s = parser.consume().join_span(&nulls_span);
1390                        parser.postgres_only(&s);
1391                        match dir_span_opt {
1392                            Some((true, _)) => OrderFlag::AscNullsFirst(s),
1393                            Some((false, _)) => OrderFlag::DescNullsFirst(s),
1394                            None => OrderFlag::NullsFirst(s),
1395                        }
1396                    }
1397                    Token::Ident(_, Keyword::LAST) => {
1398                        let s = parser.consume().join_span(&nulls_span);
1399                        parser.postgres_only(&s);
1400                        match dir_span_opt {
1401                            Some((true, _)) => OrderFlag::AscNullsLast(s),
1402                            Some((false, _)) => OrderFlag::DescNullsLast(s),
1403                            None => OrderFlag::NullsLast(s),
1404                        }
1405                    }
1406                    _ => parser.expected_failure("FIRST or LAST")?,
1407                }
1408            } else {
1409                match dir_span_opt {
1410                    Some((true, s)) => OrderFlag::Asc(s),
1411                    Some((false, s)) => OrderFlag::Desc(s),
1412                    None => OrderFlag::None,
1413                }
1414            };
1415            order.push((e, f));
1416            if parser.skip_token(Token::Comma).is_none() {
1417                break;
1418            }
1419        }
1420        Some((span, order))
1421    } else {
1422        None
1423    };
1424
1425    let limit = if let Some(span) = parser.skip_keyword(Keyword::LIMIT) {
1426        let n = parse_expression_unreserved(parser, PRIORITY_MAX)?;
1427        match parser.token {
1428            Token::Comma => {
1429                parser.consume();
1430                Some((
1431                    span,
1432                    Some(n),
1433                    parse_expression_unreserved(parser, PRIORITY_MAX)?,
1434                ))
1435            }
1436            Token::Ident(_, Keyword::OFFSET) => {
1437                parser.consume();
1438                Some((
1439                    span,
1440                    Some(parse_expression_unreserved(parser, PRIORITY_MAX)?),
1441                    n,
1442                ))
1443            }
1444            _ => Some((span, None, n)),
1445        }
1446    } else {
1447        None
1448    };
1449
1450    // PostgreSQL: standalone OFFSET n [ROWS] (only when no LIMIT already consumed offset)
1451    let offset = if limit.is_none() {
1452        if let Some(offset_span) = parser.skip_keyword(Keyword::OFFSET) {
1453            parser.postgres_only(&offset_span);
1454            let n = parse_expression_unreserved(parser, PRIORITY_MAX)?;
1455            // skip optional ROWS or ROW
1456            if matches!(parser.token, Token::Ident(_, Keyword::ROWS | Keyword::ROW)) {
1457                parser.consume();
1458            }
1459            Some((offset_span, n))
1460        } else {
1461            None
1462        }
1463    } else {
1464        None
1465    };
1466
1467    // PostgreSQL: FETCH {FIRST|NEXT} n {ROW|ROWS} ONLY
1468    let fetch = if let Some(fetch_span) = parser.skip_keyword(Keyword::FETCH) {
1469        parser.postgres_only(&fetch_span);
1470        match &parser.token {
1471            Token::Ident(_, Keyword::FIRST | Keyword::NEXT) => {
1472                parser.consume();
1473            }
1474            _ => parser.expected_failure("FIRST or NEXT")?,
1475        }
1476        let n = parse_expression_unreserved(parser, PRIORITY_MAX)?;
1477        if matches!(parser.token, Token::Ident(_, Keyword::ROWS | Keyword::ROW)) {
1478            parser.consume();
1479        }
1480        parser.consume_keyword(Keyword::ONLY)?;
1481        Some((fetch_span, n))
1482    } else {
1483        None
1484    };
1485
1486    let locking = if let Some(for_span) = parser.skip_keyword(Keyword::FOR) {
1487        let strength = match &parser.token {
1488            Token::Ident(_, Keyword::UPDATE) => {
1489                LockStrength::Update(parser.consume_keyword(Keyword::UPDATE)?)
1490            }
1491            Token::Ident(_, Keyword::SHARE) => {
1492                LockStrength::Share(parser.consume_keyword(Keyword::SHARE)?)
1493            }
1494            Token::Ident(_, Keyword::NO) => {
1495                LockStrength::NoKeyUpdate(parser.consume_keywords(&[
1496                    Keyword::NO,
1497                    Keyword::KEY,
1498                    Keyword::UPDATE,
1499                ])?)
1500            }
1501            Token::Ident(_, Keyword::KEY) => {
1502                LockStrength::KeyShare(parser.consume_keywords(&[Keyword::KEY, Keyword::SHARE])?)
1503            }
1504            _ => parser.expected_failure("UPDATE, SHARE, NO KEY UPDATE or KEY SHARE here")?,
1505        };
1506
1507        if let LockStrength::NoKeyUpdate(s) | LockStrength::KeyShare(s) = &strength
1508            && !parser.options.dialect.is_postgresql()
1509        {
1510            parser.err("Only support by PostgreSQL", s);
1511        }
1512
1513        let of = if let Some(of_span) = parser.skip_keyword(Keyword::OF) {
1514            let mut table_references = Vec::new();
1515            loop {
1516                table_references.push(parser.consume_plain_identifier_unreserved()?);
1517                if parser.skip_token(Token::Comma).is_none() {
1518                    break;
1519                }
1520            }
1521            Some((of_span, table_references))
1522        } else {
1523            None
1524        };
1525
1526        let wait = match &parser.token {
1527            Token::Ident(_, Keyword::NOWAIT) => {
1528                LockWait::NoWait(parser.consume_keyword(Keyword::NOWAIT)?)
1529            }
1530            Token::Ident(_, Keyword::SKIP) => {
1531                LockWait::SkipLocket(parser.consume_keywords(&[Keyword::SKIP, Keyword::LOCKED])?)
1532            }
1533            _ => LockWait::Default,
1534        };
1535        Some(Locking {
1536            for_span,
1537            strength,
1538            of,
1539            wait,
1540        })
1541    } else {
1542        None
1543    };
1544
1545    // TODO [into_option]
1546    // [into_option]
1547
1548    // into_option: {
1549    // INTO OUTFILE 'file_name'
1550    //     [CHARACTER SET charset_name]
1551    //     export_options
1552    // | INTO DUMPFILE 'file_name'
1553    // | INTO var_name [, var_name] ...
1554    // }
1555
1556    Ok(Select {
1557        select_span,
1558        flags,
1559        select_exprs,
1560        from_span,
1561        table_references,
1562        where_,
1563        group_by,
1564        having,
1565        window_span,
1566        order_by,
1567        limit,
1568        distinct_on,
1569        offset,
1570        fetch,
1571        locking,
1572    })
1573}