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            // Consume the outer '(' if present. By doing this first we only need
468            // one level of peek to distinguish a parenthesised join group from a
469            // parenthesised subquery when the contents themselves start with '(':
470            //   ((t1 JOIN t2) JOIN t3)  – join group  (peek after inner ( is an ident)
471            //   ((SELECT …) UNION …)    – subquery    (peek after inner ( is SELECT)
472            let outer_paren = if matches!(parser.token, Token::LParen) {
473                Some(parser.consume_token(Token::LParen)?)
474            } else {
475                None
476            };
477
478            // A join group is only possible when we consumed an outer '(' and
479            // what follows is NOT a subquery start (SELECT/VALUES/WITH directly,
480            // or '(' whose own first token is SELECT/VALUES/WITH).
481            let is_join_group = outer_paren.is_some()
482                && !matches!(
483                    parser.token,
484                    Token::Ident(_, Keyword::SELECT | Keyword::VALUES | Keyword::WITH)
485                )
486                && !(matches!(parser.token, Token::LParen)
487                    && matches!(
488                        parser.peek(),
489                        Token::Ident(_, Keyword::SELECT | Keyword::VALUES | Keyword::WITH)
490                    ));
491
492            if is_join_group {
493                let inner = parse_table_reference(parser, additional_restrict)?;
494                parser.consume_token(Token::RParen)?;
495                return Ok(inner);
496            }
497
498            // Subquery path. parse_compound_query sees either SELECT (when
499            // outer_paren is None) or '(' / SELECT (when outer_paren is Some).
500            // Either way it returns with the matching closing ')' already consumed.
501            // We then consume the outer ')' we pre-consumed above (if any), and
502            // only after that do we look for the alias.
503            let query = parse_compound_query(parser)?;
504
505            if outer_paren.is_some() {
506                parser.consume_token(Token::RParen)?;
507            }
508
509            let as_span = parser.skip_keyword(Keyword::AS);
510            let as_ = if as_span.is_some()
511                || (matches!(&parser.token, Token::Ident(_, k) if !k.restricted(parser.reserved() | additional_restrict)))
512            {
513                Some(
514                    parser.consume_plain_identifier_restrict(
515                        parser.reserved() | additional_restrict,
516                    )?,
517                )
518            } else {
519                None
520            };
521            // Optional column list: AS alias (col1, col2, ...)
522            let mut col_list = Vec::new();
523            if as_.is_some() && matches!(parser.token, Token::LParen) {
524                parser.consume_token(Token::LParen)?;
525                loop {
526                    parser.recovered(
527                        "')' or ','",
528                        &|t| matches!(t, Token::RParen | Token::Comma),
529                        |parser| {
530                            col_list
531                                .push(parser.consume_plain_identifier_restrict(Restrict::EMPTY)?);
532                            Ok(())
533                        },
534                    )?;
535                    if parser.skip_token(Token::Comma).is_none() {
536                        break;
537                    }
538                }
539                parser.consume_token(Token::RParen)?;
540            };
541            Ok(TableReference::Query {
542                query: Box::new(query),
543                as_span,
544                as_,
545                col_list,
546            })
547        }
548        Token::Ident(_, _) => parse_table_reference_named(parser, additional_restrict),
549        Token::String(_, StringType::DoubleQuoted) if parser.options.dialect.is_postgresql() => {
550            parse_table_reference_named(parser, additional_restrict)
551        }
552        _ => parser.expected_failure("subquery or identifier"),
553    }
554}
555
556fn parse_table_reference_named<'a>(
557    parser: &mut Parser<'a, '_>,
558    additional_restrict: Restrict,
559) -> Result<TableReference<'a>, ParseError> {
560    if matches!(parser.token, Token::Ident(_, Keyword::JSON_TABLE))
561        && matches!(parser.peek(), Token::LParen)
562    {
563        let json_table_span = parser.consume_keyword(Keyword::JSON_TABLE)?;
564
565        parser.consume_token(Token::LParen)?;
566
567        // Parse JSON data expression (first argument)
568        let json_expr = parse_expression_unreserved(parser, PRIORITY_MAX)?;
569
570        // Expect comma
571        parser.consume_token(Token::Comma)?;
572
573        // Parse JSON path - just a simple string for now
574        let path = match &parser.token {
575            Token::String(s, _) => {
576                let val = *s;
577                let span = parser.consume();
578                Expression::String(Box::new(SString::new(Cow::Borrowed(val), span)))
579            }
580            _ => {
581                // Fall back to expression parsing
582                parse_expression_unreserved(parser, PRIORITY_MAX)?
583            }
584        };
585
586        // Parse COLUMNS clause (no comma before COLUMNS)
587        let columns_keyword_span = parser.consume_keyword(Keyword::COLUMNS)?;
588        parser.consume_token(Token::LParen)?;
589
590        let columns = parser.recovered(")", &|t| t == &Token::RParen, |parser| {
591            // Parse column definitions
592            parse_json_table_columns(parser)
593        })?;
594
595        parser.consume_token(Token::RParen)?;
596
597        // Closing parenthesis of JSON_TABLE
598        parser.consume_token(Token::RParen)?;
599
600        // Parse AS and alias
601        let as_span = parser.skip_keyword(Keyword::AS);
602        let as_ = if as_span.is_some()
603            || (matches!(&parser.token, Token::Ident(_, k) if !k.restricted(parser.reserved() | additional_restrict)))
604        {
605            Some(parser.consume_plain_identifier_unreserved()?)
606        } else {
607            None
608        };
609
610        return Ok(TableReference::JsonTable {
611            json_table_span,
612            json_expr,
613            path,
614            columns_keyword_span,
615            columns,
616            as_span,
617            as_,
618        });
619    }
620
621    // Snapshot the first token's keyword (if any) before consuming the qualified name,
622    // so we can build the correct TableFunctionName variant if this turns out to be a
623    // table-valued function call.
624    let first_kw = match &parser.token {
625        Token::Ident(_, kw) => Some(*kw),
626        _ => None,
627    };
628    let identifier = parse_qualified_name_unreserved(parser)?;
629
630    if matches!(parser.token, Token::LParen) {
631        // Table-valued function call (any set-returning function)
632        let func_name = if identifier.prefix.is_empty() {
633            match first_kw {
634                Some(Keyword::UNNEST) => TableFunctionName::Unnest(identifier.identifier.span),
635                Some(Keyword::GENERATE_SERIES) => {
636                    TableFunctionName::GenerateSeries(identifier.identifier.span)
637                }
638                Some(Keyword::STRING_TO_TABLE) => {
639                    TableFunctionName::StringToTable(identifier.identifier.span)
640                }
641                _ => TableFunctionName::Other(identifier),
642            }
643        } else {
644            TableFunctionName::Other(identifier)
645        };
646        parser.consume_token(Token::LParen)?;
647        let mut args = Vec::new();
648        if !matches!(parser.token, Token::RParen) {
649            loop {
650                parser.recovered(
651                    "')' or ','",
652                    &|t| matches!(t, Token::RParen | Token::Comma),
653                    |parser| {
654                        args.push(parse_expression_unreserved(parser, PRIORITY_MAX)?);
655                        Ok(())
656                    },
657                )?;
658                if parser.skip_token(Token::Comma).is_none() {
659                    break;
660                }
661            }
662        }
663        parser.consume_token(Token::RParen)?;
664        // WITH ORDINALITY is a general FROM-clause modifier supported by all SRFs
665        let with_ordinality = if let Some(with_span) = parser.skip_keyword(Keyword::WITH) {
666            let ord_span = parser.consume_keyword(Keyword::ORDINALITY)?;
667            Some(with_span.join_span(&ord_span))
668        } else {
669            None
670        };
671        let as_span = parser.skip_keyword(Keyword::AS);
672        let as_ = if as_span.is_some()
673            || (matches!(&parser.token, Token::Ident(_, k) if !k.restricted(parser.reserved() | additional_restrict)))
674        {
675            Some(parser.consume_plain_identifier_unreserved()?)
676        } else {
677            None
678        };
679        // Parse optional column alias list `alias(col1, col2, ...)` (PostgreSQL table-function syntax)
680        let col_list = if as_.is_some() && matches!(parser.token, Token::LParen) {
681            parser.consume_token(Token::LParen)?;
682            let mut cols = Vec::new();
683            loop {
684                parser.recovered(
685                    "')' or ','",
686                    &|t| matches!(t, Token::RParen | Token::Comma),
687                    |parser| {
688                        cols.push(parser.consume_plain_identifier_unreserved()?);
689                        Ok(())
690                    },
691                )?;
692                if parser.skip_token(Token::Comma).is_none() {
693                    break;
694                }
695            }
696            parser.consume_token(Token::RParen)?;
697            cols
698        } else {
699            Vec::new()
700        };
701        return Ok(TableReference::Function {
702            name: func_name,
703            args,
704            with_ordinality,
705            as_span,
706            as_,
707            col_list,
708        });
709    }
710
711    // TODO [PARTITION (partition_names)] [[AS] alias]
712    let as_span = parser.skip_keyword(Keyword::AS);
713    let as_ = if as_span.is_some()
714        || (matches!(&parser.token, Token::Ident(_, k) if !k.restricted(parser.reserved() | additional_restrict)))
715    {
716        Some(parser.consume_plain_identifier_restrict(parser.reserved() | additional_restrict)?)
717    } else {
718        None
719    };
720
721    let mut index_hints = Vec::new();
722    loop {
723        let use_ = match parser.token {
724            Token::Ident(_, Keyword::USE) => IndexHintUse::Use(parser.consume()),
725            Token::Ident(_, Keyword::IGNORE) => IndexHintUse::Ignore(parser.consume()),
726            Token::Ident(_, Keyword::FORCE) => IndexHintUse::Force(parser.consume()),
727            _ => break,
728        };
729        let type_ = match parser.token {
730            Token::Ident(_, Keyword::INDEX) => IndexHintType::Index(parser.consume()),
731            Token::Ident(_, Keyword::KEY) => IndexHintType::Key(parser.consume()),
732            _ => parser.expected_failure("'INDEX' or 'KEY'")?,
733        };
734        let for_ = if let Some(for_span) = parser.skip_keyword(Keyword::FOR) {
735            let v = match parser.token {
736                Token::Ident(_, Keyword::JOIN) => IndexHintFor::Join(parser.consume()),
737                Token::Ident(_, Keyword::GROUP) => {
738                    IndexHintFor::GroupBy(parser.consume_keywords(&[Keyword::GROUP, Keyword::BY])?)
739                }
740                Token::Ident(_, Keyword::ORDER) => {
741                    IndexHintFor::OrderBy(parser.consume_keywords(&[Keyword::ORDER, Keyword::BY])?)
742                }
743                _ => parser.expected_failure("'JOIN', 'GROUP BY' or 'ORDER BY'")?,
744            };
745            Some((for_span, v))
746        } else {
747            None
748        };
749        let lparen = parser.consume_token(Token::LParen)?;
750        let mut index_list = Vec::new();
751        loop {
752            parser.recovered(
753                "')' or ','",
754                &|t| matches!(t, Token::RParen | Token::Comma),
755                |parser| {
756                    index_list.push(parser.consume_plain_identifier_unreserved()?);
757                    Ok(())
758                },
759            )?;
760            if matches!(parser.token, Token::RParen) {
761                break;
762            }
763            parser.consume_token(Token::Comma)?;
764        }
765        let rparen = parser.consume_token(Token::RParen)?;
766        index_hints.push(IndexHint {
767            use_,
768            type_,
769            for_,
770            lparen,
771            index_list,
772            rparen,
773        })
774    }
775
776    if !index_hints.is_empty() && !parser.options.dialect.is_maria() {
777        parser.err(
778            "Index hints only supported by MariaDb",
779            &index_hints.opt_span().unwrap(),
780        );
781    }
782
783    Ok(TableReference::Table {
784        identifier,
785        as_span,
786        as_,
787        index_hints,
788    })
789}
790
791fn parse_json_table_columns<'a>(
792    parser: &mut Parser<'a, '_>,
793) -> Result<Vec<JsonTableColumn<'a>>, ParseError> {
794    let mut columns = Vec::new();
795
796    loop {
797        // Check for NESTED PATH
798        if let Some(nested_span) = parser.skip_keyword(Keyword::NESTED) {
799            let path_span = parser.consume_keyword(Keyword::PATH)?;
800            let path = match &parser.token {
801                Token::String(s, _) => {
802                    let val = *s;
803                    let span = parser.consume();
804                    Expression::String(Box::new(SString::new(Cow::Borrowed(val), span)))
805                }
806                _ => parse_expression_unreserved(parser, PRIORITY_MAX)?,
807            };
808            let columns_span = parser.consume_keyword(Keyword::COLUMNS)?;
809            parser.consume_token(Token::LParen)?;
810            let nested_columns = parser.recovered(")", &|t| t == &Token::RParen, |parser| {
811                parse_json_table_columns(parser)
812            })?;
813            parser.consume_token(Token::RParen)?;
814
815            columns.push(JsonTableColumn::Nested {
816                nested_span,
817                path_span,
818                path,
819                columns_span,
820                columns: nested_columns,
821            });
822        } else {
823            // Parse column name
824            let name = parser.consume_plain_identifier_unreserved()?;
825
826            // Check if this is FOR ORDINALITY
827            if let Some(for_span) = parser.skip_keyword(Keyword::FOR) {
828                let ordinality_span = parser.consume_keyword(Keyword::ORDINALITY)?;
829                let for_ordinality_span = for_span.join_span(&ordinality_span);
830
831                columns.push(JsonTableColumn::Ordinality {
832                    name,
833                    for_ordinality_span,
834                });
835            } else {
836                // Parse data type
837                let data_type = parse_data_type(parser, DataTypeContext::FunctionReturn)?;
838
839                // Check for EXISTS before PATH
840                let _ = parser.skip_keyword(Keyword::EXISTS);
841
842                // Parse PATH keyword and path expression
843                let path_span = parser.consume_keyword(Keyword::PATH)?;
844                let path = match &parser.token {
845                    Token::String(s, _) => {
846                        let val = *s;
847                        let span = parser.consume();
848                        Expression::String(Box::new(SString::new(Cow::Borrowed(val), span)))
849                    }
850                    _ => parse_expression_unreserved(parser, PRIORITY_MAX)?,
851                };
852
853                // Parse ON EMPTY and ON ERROR clauses
854                // These can appear in various orders: DEFAULT '...' ON EMPTY, ERROR ON ERROR, etc.
855                let mut on_empty = None;
856                let mut on_error = None;
857
858                loop {
859                    let behavior_start = parser.span.span().start;
860                    let behavior = match &parser.token {
861                        Token::Ident(_, Keyword::DEFAULT) => {
862                            parser.consume();
863                            // Parse the default value
864                            let default_val = parse_expression_unreserved(parser, PRIORITY_MAX)?;
865                            Some(JsonTableOnErrorEmpty::Default(default_val))
866                        }
867                        Token::Ident(_, Keyword::ERROR) => {
868                            let error_span = parser.consume();
869                            Some(JsonTableOnErrorEmpty::Error(error_span))
870                        }
871                        Token::Ident(_, Keyword::NULL) => {
872                            let null_span = parser.consume();
873                            Some(JsonTableOnErrorEmpty::Null(null_span))
874                        }
875                        _ => None,
876                    };
877
878                    if let Some(behavior) = behavior {
879                        parser.consume_keyword(Keyword::ON)?;
880                        let clause_end = parser.span.span().end;
881                        match &parser.token {
882                            Token::Ident(_, Keyword::EMPTY) => {
883                                parser.consume();
884                                let span = behavior_start..clause_end;
885                                on_empty = Some((behavior, span));
886                            }
887                            Token::Ident(_, Keyword::ERROR) => {
888                                parser.consume();
889                                let span = behavior_start..clause_end;
890                                on_error = Some((behavior, span));
891                            }
892                            _ => {
893                                // Not EMPTY or ERROR, emit an error
894                                parser.expected_failure("EMPTY or ERROR")?;
895                            }
896                        }
897                    } else {
898                        // No behavior keyword, we're done
899                        break;
900                    }
901                }
902
903                columns.push(JsonTableColumn::Column {
904                    name,
905                    data_type,
906                    path_span,
907                    path,
908                    on_empty,
909                    on_error,
910                });
911            }
912        }
913
914        // Check if there are more columns
915        if parser.skip_token(Token::Comma).is_none() {
916            break;
917        }
918
919        // Check if we've reached the end of the column list
920        if matches!(parser.token, Token::RParen) {
921            break;
922        }
923    }
924
925    Ok(columns)
926}
927
928pub(crate) fn parse_table_reference<'a>(
929    parser: &mut Parser<'a, '_>,
930    additional_restrict: crate::keywords::Restrict,
931) -> Result<TableReference<'a>, ParseError> {
932    let mut ans = parse_table_reference_inner(parser, additional_restrict)?;
933    loop {
934        let join = match parser.token {
935            Token::Ident(_, Keyword::FULL) => {
936                let full = parser.consume_keyword(Keyword::FULL)?;
937                parser.postgres_only(&full);
938                if let Some(outer) = parser.skip_keyword(Keyword::OUTER) {
939                    JoinType::FullOuter(
940                        full.join_span(&outer)
941                            .join_span(&parser.consume_keyword(Keyword::JOIN)?),
942                    )
943                } else {
944                    JoinType::FullOuter(full.join_span(&parser.consume_keyword(Keyword::JOIN)?))
945                }
946            }
947            Token::Ident(_, Keyword::INNER) => JoinType::Inner(
948                parser
949                    .consume_keyword(Keyword::INNER)?
950                    .join_span(&parser.consume_keyword(Keyword::JOIN)?),
951            ),
952            Token::Ident(_, Keyword::CROSS) => JoinType::Cross(
953                parser
954                    .consume_keyword(Keyword::CROSS)?
955                    .join_span(&parser.consume_keyword(Keyword::JOIN)?),
956            ),
957            Token::Ident(_, Keyword::JOIN) => {
958                JoinType::Normal(parser.consume_keyword(Keyword::JOIN)?)
959            }
960            Token::Ident(_, Keyword::STRAIGHT_JOIN) => {
961                JoinType::Straight(parser.consume_keyword(Keyword::STRAIGHT_JOIN)?)
962            }
963            Token::Ident(_, Keyword::LEFT) => {
964                let left = parser.consume_keyword(Keyword::LEFT)?;
965                if let Some(outer) = parser.skip_keyword(Keyword::OUTER) {
966                    JoinType::Left(
967                        left.join_span(&outer)
968                            .join_span(&parser.consume_keyword(Keyword::JOIN)?),
969                    )
970                } else {
971                    JoinType::Left(left.join_span(&parser.consume_keyword(Keyword::JOIN)?))
972                }
973            }
974            Token::Ident(_, Keyword::RIGHT) => {
975                let right = parser.consume_keyword(Keyword::RIGHT)?;
976                if let Some(outer) = parser.skip_keyword(Keyword::OUTER) {
977                    JoinType::Right(
978                        right
979                            .join_span(&outer)
980                            .join_span(&parser.consume_keyword(Keyword::JOIN)?),
981                    )
982                } else {
983                    JoinType::Right(right.join_span(&parser.consume_keyword(Keyword::JOIN)?))
984                }
985            }
986            Token::Ident(_, Keyword::NATURAL) => {
987                let natural = parser.consume_keyword(Keyword::NATURAL)?;
988                match &parser.token {
989                    Token::Ident(_, Keyword::INNER) => JoinType::NaturalInner(
990                        natural
991                            .join_span(&parser.consume_keywords(&[Keyword::INNER, Keyword::JOIN])?),
992                    ),
993                    Token::Ident(_, Keyword::LEFT) => {
994                        let left = parser.consume_keyword(Keyword::LEFT)?;
995                        if let Some(outer) = parser.skip_keyword(Keyword::OUTER) {
996                            JoinType::NaturalLeft(
997                                left.join_span(&outer)
998                                    .join_span(&parser.consume_keyword(Keyword::JOIN)?),
999                            )
1000                        } else {
1001                            JoinType::NaturalLeft(
1002                                left.join_span(&parser.consume_keyword(Keyword::JOIN)?),
1003                            )
1004                        }
1005                    }
1006                    Token::Ident(_, Keyword::RIGHT) => {
1007                        let right = parser.consume_keyword(Keyword::RIGHT)?;
1008                        if let Some(outer) = parser.skip_keyword(Keyword::OUTER) {
1009                            JoinType::NaturalRight(
1010                                right
1011                                    .join_span(&outer)
1012                                    .join_span(&parser.consume_keyword(Keyword::JOIN)?),
1013                            )
1014                        } else {
1015                            JoinType::NaturalRight(
1016                                right.join_span(&parser.consume_keyword(Keyword::JOIN)?),
1017                            )
1018                        }
1019                    }
1020                    Token::Ident(_, Keyword::JOIN) => JoinType::Natural(
1021                        natural.join_span(&parser.consume_keyword(Keyword::JOIN)?),
1022                    ),
1023                    _ => parser.expected_failure("'INNER', 'LEFT', 'RIGHT' or 'JOIN'")?,
1024                }
1025            }
1026            _ => break,
1027        };
1028
1029        let right = parse_table_reference_inner(parser, additional_restrict)?;
1030
1031        let specification = match &parser.token {
1032            Token::Ident(_, Keyword::ON) => {
1033                let on = parser.consume_keyword(Keyword::ON)?;
1034                let expr = parse_expression_unreserved(parser, PRIORITY_MAX)?;
1035                Some(JoinSpecification::On(expr, on))
1036            }
1037            Token::Ident(_, Keyword::USING) => {
1038                let using = parser.consume_keyword(Keyword::USING)?;
1039                let mut join_column_list = Vec::new();
1040                loop {
1041                    join_column_list.push(parser.consume_plain_identifier_unreserved()?);
1042                    if parser.skip_token(Token::Comma).is_none() {
1043                        break;
1044                    }
1045                }
1046                Some(JoinSpecification::Using(join_column_list, using))
1047            }
1048            _ => None,
1049        };
1050
1051        ans = TableReference::Join {
1052            join,
1053            left: Box::new(ans),
1054            right: Box::new(right),
1055            specification,
1056        };
1057    }
1058    Ok(ans)
1059}
1060
1061/// Flags specified after SELECT
1062#[derive(Debug, Clone)]
1063pub enum SelectFlag {
1064    All(Span),
1065    Distinct(Span),
1066    DistinctOn(Span),
1067    DistinctRow(Span),
1068    HighPriority(Span),
1069    StraightJoin(Span),
1070    SqlSmallResult(Span),
1071    SqlBigResult(Span),
1072    SqlBufferResult(Span),
1073    SqlNoCache(Span),
1074    SqlCalcFoundRows(Span),
1075}
1076
1077impl Spanned for SelectFlag {
1078    fn span(&self) -> Span {
1079        match &self {
1080            SelectFlag::All(v) => v.span(),
1081            SelectFlag::Distinct(v) => v.span(),
1082            SelectFlag::DistinctOn(v) => v.span(),
1083            SelectFlag::DistinctRow(v) => v.span(),
1084            SelectFlag::HighPriority(v) => v.span(),
1085            SelectFlag::StraightJoin(v) => v.span(),
1086            SelectFlag::SqlSmallResult(v) => v.span(),
1087            SelectFlag::SqlBigResult(v) => v.span(),
1088            SelectFlag::SqlBufferResult(v) => v.span(),
1089            SelectFlag::SqlNoCache(v) => v.span(),
1090            SelectFlag::SqlCalcFoundRows(v) => v.span(),
1091        }
1092    }
1093}
1094
1095/// Ordering direction
1096#[derive(Debug, Clone)]
1097pub enum OrderFlag {
1098    Asc(Span),
1099    Desc(Span),
1100    AscNullsFirst(Span),
1101    AscNullsLast(Span),
1102    DescNullsFirst(Span),
1103    DescNullsLast(Span),
1104    NullsFirst(Span),
1105    NullsLast(Span),
1106    None,
1107}
1108impl OptSpanned for OrderFlag {
1109    fn opt_span(&self) -> Option<Span> {
1110        match &self {
1111            OrderFlag::Asc(v) => v.opt_span(),
1112            OrderFlag::Desc(v) => v.opt_span(),
1113            OrderFlag::AscNullsFirst(v) => v.opt_span(),
1114            OrderFlag::AscNullsLast(v) => v.opt_span(),
1115            OrderFlag::DescNullsFirst(v) => v.opt_span(),
1116            OrderFlag::DescNullsLast(v) => v.opt_span(),
1117            OrderFlag::NullsFirst(v) => v.opt_span(),
1118            OrderFlag::NullsLast(v) => v.opt_span(),
1119            OrderFlag::None => None,
1120        }
1121    }
1122}
1123
1124/// Lock strength for locking
1125#[derive(Debug, Clone)]
1126pub enum LockStrength {
1127    Update(Span),
1128    Share(Span),
1129    NoKeyUpdate(Span),
1130    KeyShare(Span),
1131}
1132impl Spanned for LockStrength {
1133    fn span(&self) -> Span {
1134        match &self {
1135            LockStrength::Update(v) => v.span(),
1136            LockStrength::Share(v) => v.span(),
1137            LockStrength::NoKeyUpdate(v) => v.span(),
1138            LockStrength::KeyShare(v) => v.span(),
1139        }
1140    }
1141}
1142
1143#[derive(Debug, Clone)]
1144pub enum LockWait {
1145    NoWait(Span),
1146    SkipLocket(Span),
1147    Default,
1148}
1149impl OptSpanned for LockWait {
1150    fn opt_span(&self) -> Option<Span> {
1151        match &self {
1152            LockWait::NoWait(v) => v.opt_span(),
1153            LockWait::SkipLocket(v) => v.opt_span(),
1154            LockWait::Default => None,
1155        }
1156    }
1157}
1158
1159#[derive(Debug, Clone)]
1160pub struct Locking<'a> {
1161    /// Span of "FOR"
1162    pub for_span: Span,
1163    pub strength: LockStrength,
1164    pub of: Option<(Span, Vec<Identifier<'a>>)>,
1165    pub wait: LockWait,
1166}
1167impl<'a> Spanned for Locking<'a> {
1168    fn span(&self) -> Span {
1169        self.for_span
1170            .join_span(&self.strength)
1171            .join_span(&self.of)
1172            .join_span(&self.wait)
1173    }
1174}
1175
1176/// Representation of select Statement
1177///
1178/// ```
1179/// # use qusql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statement, Select, Statement, Issues};
1180/// # let options = ParseOptions::new().dialect(SQLDialect::MariaDB);
1181/// #
1182/// let sql = "SELECT f1,f2 FROM t1 WHERE f3<=10 AND f4='y'";
1183/// let mut issues = Issues::new(sql);
1184/// let stmt = parse_statement(sql, &mut issues, &options);
1185///
1186/// # assert!(issues.is_ok());
1187/// let s: Select = match stmt {
1188///     Some(Statement::Select(s)) => *s,
1189///     _ => panic!("We should get an select statement")
1190/// };
1191///
1192/// println!("{:#?}", s.where_);
1193///
1194/// let sql = "SELECT CAST(NULL AS CHAR)";
1195/// let stmt = parse_statement(sql, &mut issues, &options);
1196///
1197/// # assert!(issues.is_ok());
1198/// let s: Select = match stmt {
1199///     Some(Statement::Select(s)) => *s,
1200///     _ => panic!("We should get an select statement")
1201/// };
1202///
1203/// println!("{:#?}", s.where_);
1204///
1205/// let sql = "SELECT * FROM t1, d2.t2 FOR SHARE OF t1, t2 NOWAIT";
1206/// let stmt = parse_statement(sql, &mut issues, &options);
1207///
1208/// # assert!(issues.is_ok());
1209/// let s: Select = match stmt {
1210///     Some(Statement::Select(s)) => *s,
1211///     _ => panic!("We should get an select statement")
1212/// };
1213///
1214/// assert!(s.locking.is_some());
1215/// println!("{:#?}", s.locking);
1216/// ```
1217#[derive(Debug, Clone)]
1218pub struct Select<'a> {
1219    /// Span of "SELECT"
1220    pub select_span: Span,
1221    /// Flags specified after "SELECT"
1222    pub flags: Vec<SelectFlag>,
1223    /// List of values to select
1224    pub select_exprs: Vec<SelectExpr<'a>>,
1225    /// Span of "FROM"
1226    pub from_span: Option<Span>,
1227    /// List of tables to select from
1228    pub table_references: Option<Vec<TableReference<'a>>>,
1229    /// Where expression and span of "WHERE" if specified
1230    pub where_: Option<(Expression<'a>, Span)>,
1231    /// Span of "GROUP_BY" and group expression if specified
1232    pub group_by: Option<(Span, Vec<Expression<'a>>)>,
1233    /// Having expression and span of "HAVING" if specified
1234    pub having: Option<(Expression<'a>, Span)>,
1235    /// Span of window if specified
1236    pub window_span: Option<Span>,
1237    /// Span of "ORDER BY" and list of order expression and directions, if specified
1238    pub order_by: Option<(Span, Vec<(Expression<'a>, OrderFlag)>)>,
1239    /// Span of "LIMIT", offset and count expressions if specified
1240    pub limit: Option<(Span, Option<Expression<'a>>, Expression<'a>)>,
1241    /// PostgreSQL: DISTINCT ON (expr, ...) list
1242    pub distinct_on: Option<(Span, Vec<Expression<'a>>)>,
1243    /// PostgreSQL: OFFSET n [ROWS] (when no LIMIT is present)
1244    pub offset: Option<(Span, Expression<'a>)>,
1245    /// PostgreSQL: FETCH {FIRST|NEXT} n {ROW|ROWS} ONLY
1246    pub fetch: Option<(Span, Expression<'a>)>,
1247    /// Row locking clause
1248    pub locking: Option<Locking<'a>>,
1249}
1250
1251impl<'a> Spanned for Select<'a> {
1252    fn span(&self) -> Span {
1253        self.select_span
1254            .join_span(&self.flags)
1255            .join_span(&self.select_exprs)
1256            .join_span(&self.from_span)
1257            .join_span(&self.table_references)
1258            .join_span(&self.where_)
1259            .join_span(&self.group_by)
1260            .join_span(&self.having)
1261            .join_span(&self.window_span)
1262            .join_span(&self.order_by)
1263            .join_span(&self.limit)
1264            .join_span(&self.distinct_on)
1265            .join_span(&self.offset)
1266            .join_span(&self.fetch)
1267    }
1268}
1269
1270/// Parse a SELECT body starting after the `SELECT` keyword has already been consumed.
1271/// `select_span` is the span of the keyword (or a synthetic span standing in for it).
1272pub(crate) fn parse_select_body<'a>(
1273    parser: &mut Parser<'a, '_>,
1274    select_span: Span,
1275) -> Result<Select<'a>, ParseError> {
1276    let mut flags = Vec::new();
1277    let mut select_exprs = Vec::new();
1278
1279    loop {
1280        match &parser.token {
1281            Token::Ident(_, Keyword::ALL) => {
1282                flags.push(SelectFlag::All(parser.consume_keyword(Keyword::ALL)?))
1283            }
1284            Token::Ident(_, Keyword::DISTINCT) => {
1285                let distinct_span = parser.consume_keyword(Keyword::DISTINCT)?;
1286                // PostgreSQL: DISTINCT ON (expr, ...)
1287                if matches!(parser.token, Token::Ident(_, Keyword::ON)) {
1288                    flags.push(SelectFlag::DistinctOn(distinct_span));
1289                } else {
1290                    flags.push(SelectFlag::Distinct(distinct_span));
1291                }
1292            }
1293            Token::Ident(_, Keyword::DISTINCTROW) => flags.push(SelectFlag::DistinctRow(
1294                parser.consume_keyword(Keyword::DISTINCTROW)?,
1295            )),
1296            Token::Ident(_, Keyword::HIGH_PRIORITY) => flags.push(SelectFlag::HighPriority(
1297                parser.consume_keyword(Keyword::HIGH_PRIORITY)?,
1298            )),
1299            Token::Ident(_, Keyword::STRAIGHT_JOIN) => flags.push(SelectFlag::StraightJoin(
1300                parser.consume_keyword(Keyword::STRAIGHT_JOIN)?,
1301            )),
1302            Token::Ident(_, Keyword::SQL_SMALL_RESULT) => flags.push(SelectFlag::SqlSmallResult(
1303                parser.consume_keyword(Keyword::SQL_SMALL_RESULT)?,
1304            )),
1305            Token::Ident(_, Keyword::SQL_BIG_RESULT) => flags.push(SelectFlag::SqlBigResult(
1306                parser.consume_keyword(Keyword::SQL_BIG_RESULT)?,
1307            )),
1308            Token::Ident(_, Keyword::SQL_BUFFER_RESULT) => flags.push(SelectFlag::SqlBufferResult(
1309                parser.consume_keyword(Keyword::SQL_BUFFER_RESULT)?,
1310            )),
1311            Token::Ident(_, Keyword::SQL_NO_CACHE) => flags.push(SelectFlag::SqlNoCache(
1312                parser.consume_keyword(Keyword::SQL_NO_CACHE)?,
1313            )),
1314            Token::Ident(_, Keyword::SQL_CALC_FOUND_ROWS) => flags.push(
1315                SelectFlag::SqlCalcFoundRows(parser.consume_keyword(Keyword::SQL_CALC_FOUND_ROWS)?),
1316            ),
1317            _ => break,
1318        }
1319    }
1320
1321    // PostgreSQL: parse DISTINCT ON (expr, ...) if signaled by DistinctOn flag
1322    let distinct_on = if flags
1323        .last()
1324        .is_some_and(|f| matches!(f, SelectFlag::DistinctOn(_)))
1325    {
1326        let on_span = parser.consume_keyword(Keyword::ON)?;
1327        parser.postgres_only(&on_span);
1328        parser.consume_token(Token::LParen)?;
1329        let mut exprs = Vec::new();
1330        loop {
1331            parser.recovered(
1332                "')' or ','",
1333                &|t| matches!(t, Token::RParen | Token::Comma),
1334                |parser| {
1335                    exprs.push(parse_expression_unreserved(parser, PRIORITY_MAX)?);
1336                    Ok(())
1337                },
1338            )?;
1339            if parser.skip_token(Token::Comma).is_none() {
1340                break;
1341            }
1342        }
1343        parser.consume_token(Token::RParen)?;
1344        Some((on_span, exprs))
1345    } else {
1346        None
1347    };
1348
1349    loop {
1350        select_exprs.push(parse_select_expr(parser)?);
1351        if parser.skip_token(Token::Comma).is_none() {
1352            break;
1353        }
1354    }
1355
1356    // TODO [into_option]
1357
1358    let from_span = parser.skip_keyword(Keyword::FROM);
1359
1360    let table_references = if from_span.is_some() {
1361        let mut table_references = Vec::new();
1362        loop {
1363            table_references.push(parse_table_reference(parser, Restrict::EMPTY)?);
1364            if parser.skip_token(Token::Comma).is_none() {
1365                break;
1366            }
1367        }
1368        Some(table_references)
1369    } else {
1370        None
1371    };
1372
1373    // TODO PARTITION partition_list;
1374    let where_ = if let Some(span) = parser.skip_keyword(Keyword::WHERE) {
1375        Some((parse_expression_unreserved(parser, PRIORITY_MAX)?, span))
1376    } else {
1377        None
1378    };
1379
1380    let group_by = if let Some(group_span) = parser.skip_keyword(Keyword::GROUP) {
1381        let span = parser.consume_keyword(Keyword::BY)?.join_span(&group_span);
1382        let mut groups = Vec::new();
1383        loop {
1384            groups.push(parse_expression_unreserved(parser, PRIORITY_MAX)?);
1385            if parser.skip_token(Token::Comma).is_none() {
1386                break;
1387            }
1388        }
1389        // TODO [WITH ROLLUP]]
1390        Some((span, groups))
1391    } else {
1392        None
1393    };
1394
1395    let having = if let Some(span) = parser.skip_keyword(Keyword::HAVING) {
1396        Some((parse_expression_unreserved(parser, PRIORITY_MAX)?, span))
1397    } else {
1398        None
1399    };
1400
1401    let window_span = parser.skip_keyword(Keyword::WINDOW);
1402    if window_span.is_some() {
1403        //TODO window_name AS (window_spec) [, window_name AS (window_spec)] ...]
1404    }
1405
1406    let order_by = if let Some(span) = parser.skip_keyword(Keyword::ORDER) {
1407        let span = parser.consume_keyword(Keyword::BY)?.join_span(&span);
1408        let mut order = Vec::new();
1409        loop {
1410            let e = parse_expression_unreserved(parser, PRIORITY_MAX)?;
1411            let dir_span_opt = match &parser.token {
1412                Token::Ident(_, Keyword::ASC) => Some((true, parser.consume())),
1413                Token::Ident(_, Keyword::DESC) => Some((false, parser.consume())),
1414                _ => None,
1415            };
1416            let f = if let Some(nulls_span) = parser.skip_keyword(Keyword::NULLS) {
1417                match &parser.token {
1418                    Token::Ident(_, Keyword::FIRST) => {
1419                        let s = parser.consume().join_span(&nulls_span);
1420                        parser.postgres_only(&s);
1421                        match dir_span_opt {
1422                            Some((true, _)) => OrderFlag::AscNullsFirst(s),
1423                            Some((false, _)) => OrderFlag::DescNullsFirst(s),
1424                            None => OrderFlag::NullsFirst(s),
1425                        }
1426                    }
1427                    Token::Ident(_, Keyword::LAST) => {
1428                        let s = parser.consume().join_span(&nulls_span);
1429                        parser.postgres_only(&s);
1430                        match dir_span_opt {
1431                            Some((true, _)) => OrderFlag::AscNullsLast(s),
1432                            Some((false, _)) => OrderFlag::DescNullsLast(s),
1433                            None => OrderFlag::NullsLast(s),
1434                        }
1435                    }
1436                    _ => parser.expected_failure("FIRST or LAST")?,
1437                }
1438            } else {
1439                match dir_span_opt {
1440                    Some((true, s)) => OrderFlag::Asc(s),
1441                    Some((false, s)) => OrderFlag::Desc(s),
1442                    None => OrderFlag::None,
1443                }
1444            };
1445            order.push((e, f));
1446            if parser.skip_token(Token::Comma).is_none() {
1447                break;
1448            }
1449        }
1450        Some((span, order))
1451    } else {
1452        None
1453    };
1454
1455    let limit = if let Some(span) = parser.skip_keyword(Keyword::LIMIT) {
1456        let n = parse_expression_unreserved(parser, PRIORITY_MAX)?;
1457        match parser.token {
1458            Token::Comma => {
1459                parser.consume();
1460                Some((
1461                    span,
1462                    Some(n),
1463                    parse_expression_unreserved(parser, PRIORITY_MAX)?,
1464                ))
1465            }
1466            Token::Ident(_, Keyword::OFFSET) => {
1467                parser.consume();
1468                Some((
1469                    span,
1470                    Some(parse_expression_unreserved(parser, PRIORITY_MAX)?),
1471                    n,
1472                ))
1473            }
1474            _ => Some((span, None, n)),
1475        }
1476    } else {
1477        None
1478    };
1479
1480    // PostgreSQL: standalone OFFSET n [ROWS] (only when no LIMIT already consumed offset)
1481    let offset = if limit.is_none() {
1482        if let Some(offset_span) = parser.skip_keyword(Keyword::OFFSET) {
1483            parser.postgres_only(&offset_span);
1484            let n = parse_expression_unreserved(parser, PRIORITY_MAX)?;
1485            // skip optional ROWS or ROW
1486            if matches!(parser.token, Token::Ident(_, Keyword::ROWS | Keyword::ROW)) {
1487                parser.consume();
1488            }
1489            Some((offset_span, n))
1490        } else {
1491            None
1492        }
1493    } else {
1494        None
1495    };
1496
1497    // PostgreSQL: FETCH {FIRST|NEXT} n {ROW|ROWS} ONLY
1498    let fetch = if let Some(fetch_span) = parser.skip_keyword(Keyword::FETCH) {
1499        parser.postgres_only(&fetch_span);
1500        match &parser.token {
1501            Token::Ident(_, Keyword::FIRST | Keyword::NEXT) => {
1502                parser.consume();
1503            }
1504            _ => parser.expected_failure("FIRST or NEXT")?,
1505        }
1506        let n = parse_expression_unreserved(parser, PRIORITY_MAX)?;
1507        if matches!(parser.token, Token::Ident(_, Keyword::ROWS | Keyword::ROW)) {
1508            parser.consume();
1509        }
1510        parser.consume_keyword(Keyword::ONLY)?;
1511        Some((fetch_span, n))
1512    } else {
1513        None
1514    };
1515
1516    let locking = if let Some(for_span) = parser.skip_keyword(Keyword::FOR) {
1517        let strength = match &parser.token {
1518            Token::Ident(_, Keyword::UPDATE) => {
1519                LockStrength::Update(parser.consume_keyword(Keyword::UPDATE)?)
1520            }
1521            Token::Ident(_, Keyword::SHARE) => {
1522                LockStrength::Share(parser.consume_keyword(Keyword::SHARE)?)
1523            }
1524            Token::Ident(_, Keyword::NO) => {
1525                LockStrength::NoKeyUpdate(parser.consume_keywords(&[
1526                    Keyword::NO,
1527                    Keyword::KEY,
1528                    Keyword::UPDATE,
1529                ])?)
1530            }
1531            Token::Ident(_, Keyword::KEY) => {
1532                LockStrength::KeyShare(parser.consume_keywords(&[Keyword::KEY, Keyword::SHARE])?)
1533            }
1534            _ => parser.expected_failure("UPDATE, SHARE, NO KEY UPDATE or KEY SHARE here")?,
1535        };
1536
1537        if let LockStrength::NoKeyUpdate(s) | LockStrength::KeyShare(s) = &strength
1538            && !parser.options.dialect.is_postgresql()
1539        {
1540            parser.err("Only support by PostgreSQL", s);
1541        }
1542
1543        let of = if let Some(of_span) = parser.skip_keyword(Keyword::OF) {
1544            let mut table_references = Vec::new();
1545            loop {
1546                table_references.push(parser.consume_plain_identifier_unreserved()?);
1547                if parser.skip_token(Token::Comma).is_none() {
1548                    break;
1549                }
1550            }
1551            Some((of_span, table_references))
1552        } else {
1553            None
1554        };
1555
1556        let wait = match &parser.token {
1557            Token::Ident(_, Keyword::NOWAIT) => {
1558                LockWait::NoWait(parser.consume_keyword(Keyword::NOWAIT)?)
1559            }
1560            Token::Ident(_, Keyword::SKIP) => {
1561                LockWait::SkipLocket(parser.consume_keywords(&[Keyword::SKIP, Keyword::LOCKED])?)
1562            }
1563            _ => LockWait::Default,
1564        };
1565        Some(Locking {
1566            for_span,
1567            strength,
1568            of,
1569            wait,
1570        })
1571    } else {
1572        None
1573    };
1574
1575    // TODO [into_option]
1576    // [into_option]
1577
1578    // into_option: {
1579    // INTO OUTFILE 'file_name'
1580    //     [CHARACTER SET charset_name]
1581    //     export_options
1582    // | INTO DUMPFILE 'file_name'
1583    // | INTO var_name [, var_name] ...
1584    // }
1585
1586    Ok(Select {
1587        select_span,
1588        flags,
1589        select_exprs,
1590        from_span,
1591        table_references,
1592        where_,
1593        group_by,
1594        having,
1595        window_span,
1596        order_by,
1597        limit,
1598        distinct_on,
1599        offset,
1600        fetch,
1601        locking,
1602    })
1603}
1604
1605pub(crate) fn parse_select<'a>(parser: &mut Parser<'a, '_>) -> Result<Select<'a>, ParseError> {
1606    let select_span = parser.consume_keyword(Keyword::SELECT)?;
1607    parse_select_body(parser, select_span)
1608}