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 base_restrict = parser.reserved() | additional_restrict;
714    let as_ = if as_span.is_some()
715        || (matches!(&parser.token, Token::Ident(_, k) if !k.restricted(base_restrict | Restrict::FROM_ALIAS)))
716    {
717        Some(parser.consume_plain_identifier_restrict(base_restrict)?)
718    } else {
719        None
720    };
721
722    let mut index_hints = Vec::new();
723    loop {
724        let use_ = match parser.token {
725            Token::Ident(_, Keyword::USE) => IndexHintUse::Use(parser.consume()),
726            Token::Ident(_, Keyword::IGNORE) => IndexHintUse::Ignore(parser.consume()),
727            Token::Ident(_, Keyword::FORCE) => IndexHintUse::Force(parser.consume()),
728            _ => break,
729        };
730        let type_ = match parser.token {
731            Token::Ident(_, Keyword::INDEX) => IndexHintType::Index(parser.consume()),
732            Token::Ident(_, Keyword::KEY) => IndexHintType::Key(parser.consume()),
733            _ => parser.expected_failure("'INDEX' or 'KEY'")?,
734        };
735        let for_ = if let Some(for_span) = parser.skip_keyword(Keyword::FOR) {
736            let v = match parser.token {
737                Token::Ident(_, Keyword::JOIN) => IndexHintFor::Join(parser.consume()),
738                Token::Ident(_, Keyword::GROUP) => {
739                    IndexHintFor::GroupBy(parser.consume_keywords(&[Keyword::GROUP, Keyword::BY])?)
740                }
741                Token::Ident(_, Keyword::ORDER) => {
742                    IndexHintFor::OrderBy(parser.consume_keywords(&[Keyword::ORDER, Keyword::BY])?)
743                }
744                _ => parser.expected_failure("'JOIN', 'GROUP BY' or 'ORDER BY'")?,
745            };
746            Some((for_span, v))
747        } else {
748            None
749        };
750        let lparen = parser.consume_token(Token::LParen)?;
751        let mut index_list = Vec::new();
752        loop {
753            parser.recovered(
754                "')' or ','",
755                &|t| matches!(t, Token::RParen | Token::Comma),
756                |parser| {
757                    index_list.push(parser.consume_plain_identifier_unreserved()?);
758                    Ok(())
759                },
760            )?;
761            if matches!(parser.token, Token::RParen) {
762                break;
763            }
764            parser.consume_token(Token::Comma)?;
765        }
766        let rparen = parser.consume_token(Token::RParen)?;
767        index_hints.push(IndexHint {
768            use_,
769            type_,
770            for_,
771            lparen,
772            index_list,
773            rparen,
774        })
775    }
776
777    if !index_hints.is_empty() && !parser.options.dialect.is_maria() {
778        parser.err(
779            "Index hints only supported by MariaDb",
780            &index_hints.opt_span().unwrap(),
781        );
782    }
783
784    Ok(TableReference::Table {
785        identifier,
786        as_span,
787        as_,
788        index_hints,
789    })
790}
791
792fn parse_json_table_columns<'a>(
793    parser: &mut Parser<'a, '_>,
794) -> Result<Vec<JsonTableColumn<'a>>, ParseError> {
795    let mut columns = Vec::new();
796
797    loop {
798        // Check for NESTED PATH
799        if let Some(nested_span) = parser.skip_keyword(Keyword::NESTED) {
800            let path_span = parser.consume_keyword(Keyword::PATH)?;
801            let path = match &parser.token {
802                Token::String(s, _) => {
803                    let val = *s;
804                    let span = parser.consume();
805                    Expression::String(Box::new(SString::new(Cow::Borrowed(val), span)))
806                }
807                _ => parse_expression_unreserved(parser, PRIORITY_MAX)?,
808            };
809            let columns_span = parser.consume_keyword(Keyword::COLUMNS)?;
810            parser.consume_token(Token::LParen)?;
811            let nested_columns = parser.recovered(")", &|t| t == &Token::RParen, |parser| {
812                parse_json_table_columns(parser)
813            })?;
814            parser.consume_token(Token::RParen)?;
815
816            columns.push(JsonTableColumn::Nested {
817                nested_span,
818                path_span,
819                path,
820                columns_span,
821                columns: nested_columns,
822            });
823        } else {
824            // Parse column name
825            let name = parser.consume_plain_identifier_unreserved()?;
826
827            // Check if this is FOR ORDINALITY
828            if let Some(for_span) = parser.skip_keyword(Keyword::FOR) {
829                let ordinality_span = parser.consume_keyword(Keyword::ORDINALITY)?;
830                let for_ordinality_span = for_span.join_span(&ordinality_span);
831
832                columns.push(JsonTableColumn::Ordinality {
833                    name,
834                    for_ordinality_span,
835                });
836            } else {
837                // Parse data type
838                let data_type = parse_data_type(parser, DataTypeContext::FunctionReturn)?;
839
840                // Check for EXISTS before PATH
841                let _ = parser.skip_keyword(Keyword::EXISTS);
842
843                // Parse PATH keyword and path expression
844                let path_span = parser.consume_keyword(Keyword::PATH)?;
845                let path = match &parser.token {
846                    Token::String(s, _) => {
847                        let val = *s;
848                        let span = parser.consume();
849                        Expression::String(Box::new(SString::new(Cow::Borrowed(val), span)))
850                    }
851                    _ => parse_expression_unreserved(parser, PRIORITY_MAX)?,
852                };
853
854                // Parse ON EMPTY and ON ERROR clauses
855                // These can appear in various orders: DEFAULT '...' ON EMPTY, ERROR ON ERROR, etc.
856                let mut on_empty = None;
857                let mut on_error = None;
858
859                loop {
860                    let behavior_start = parser.span.span().start;
861                    let behavior = match &parser.token {
862                        Token::Ident(_, Keyword::DEFAULT) => {
863                            parser.consume();
864                            // Parse the default value
865                            let default_val = parse_expression_unreserved(parser, PRIORITY_MAX)?;
866                            Some(JsonTableOnErrorEmpty::Default(default_val))
867                        }
868                        Token::Ident(_, Keyword::ERROR) => {
869                            let error_span = parser.consume();
870                            Some(JsonTableOnErrorEmpty::Error(error_span))
871                        }
872                        Token::Ident(_, Keyword::NULL) => {
873                            let null_span = parser.consume();
874                            Some(JsonTableOnErrorEmpty::Null(null_span))
875                        }
876                        _ => None,
877                    };
878
879                    if let Some(behavior) = behavior {
880                        parser.consume_keyword(Keyword::ON)?;
881                        let clause_end = parser.span.span().end;
882                        match &parser.token {
883                            Token::Ident(_, Keyword::EMPTY) => {
884                                parser.consume();
885                                let span = behavior_start..clause_end;
886                                on_empty = Some((behavior, span));
887                            }
888                            Token::Ident(_, Keyword::ERROR) => {
889                                parser.consume();
890                                let span = behavior_start..clause_end;
891                                on_error = Some((behavior, span));
892                            }
893                            _ => {
894                                // Not EMPTY or ERROR, emit an error
895                                parser.expected_failure("EMPTY or ERROR")?;
896                            }
897                        }
898                    } else {
899                        // No behavior keyword, we're done
900                        break;
901                    }
902                }
903
904                columns.push(JsonTableColumn::Column {
905                    name,
906                    data_type,
907                    path_span,
908                    path,
909                    on_empty,
910                    on_error,
911                });
912            }
913        }
914
915        // Check if there are more columns
916        if parser.skip_token(Token::Comma).is_none() {
917            break;
918        }
919
920        // Check if we've reached the end of the column list
921        if matches!(parser.token, Token::RParen) {
922            break;
923        }
924    }
925
926    Ok(columns)
927}
928
929pub(crate) fn parse_table_reference<'a>(
930    parser: &mut Parser<'a, '_>,
931    additional_restrict: crate::keywords::Restrict,
932) -> Result<TableReference<'a>, ParseError> {
933    let mut ans = parse_table_reference_inner(parser, additional_restrict)?;
934    loop {
935        let join = match parser.token {
936            Token::Ident(_, Keyword::FULL) => {
937                let full = parser.consume_keyword(Keyword::FULL)?;
938                parser.postgres_only(&full);
939                if let Some(outer) = parser.skip_keyword(Keyword::OUTER) {
940                    JoinType::FullOuter(
941                        full.join_span(&outer)
942                            .join_span(&parser.consume_keyword(Keyword::JOIN)?),
943                    )
944                } else {
945                    JoinType::FullOuter(full.join_span(&parser.consume_keyword(Keyword::JOIN)?))
946                }
947            }
948            Token::Ident(_, Keyword::INNER) => JoinType::Inner(
949                parser
950                    .consume_keyword(Keyword::INNER)?
951                    .join_span(&parser.consume_keyword(Keyword::JOIN)?),
952            ),
953            Token::Ident(_, Keyword::CROSS) => JoinType::Cross(
954                parser
955                    .consume_keyword(Keyword::CROSS)?
956                    .join_span(&parser.consume_keyword(Keyword::JOIN)?),
957            ),
958            Token::Ident(_, Keyword::JOIN) => {
959                JoinType::Normal(parser.consume_keyword(Keyword::JOIN)?)
960            }
961            Token::Ident(_, Keyword::STRAIGHT_JOIN) => {
962                JoinType::Straight(parser.consume_keyword(Keyword::STRAIGHT_JOIN)?)
963            }
964            Token::Ident(_, Keyword::LEFT) => {
965                let left = parser.consume_keyword(Keyword::LEFT)?;
966                if let Some(outer) = parser.skip_keyword(Keyword::OUTER) {
967                    JoinType::Left(
968                        left.join_span(&outer)
969                            .join_span(&parser.consume_keyword(Keyword::JOIN)?),
970                    )
971                } else {
972                    JoinType::Left(left.join_span(&parser.consume_keyword(Keyword::JOIN)?))
973                }
974            }
975            Token::Ident(_, Keyword::RIGHT) => {
976                let right = parser.consume_keyword(Keyword::RIGHT)?;
977                if let Some(outer) = parser.skip_keyword(Keyword::OUTER) {
978                    JoinType::Right(
979                        right
980                            .join_span(&outer)
981                            .join_span(&parser.consume_keyword(Keyword::JOIN)?),
982                    )
983                } else {
984                    JoinType::Right(right.join_span(&parser.consume_keyword(Keyword::JOIN)?))
985                }
986            }
987            Token::Ident(_, Keyword::NATURAL) => {
988                let natural = parser.consume_keyword(Keyword::NATURAL)?;
989                match &parser.token {
990                    Token::Ident(_, Keyword::INNER) => JoinType::NaturalInner(
991                        natural
992                            .join_span(&parser.consume_keywords(&[Keyword::INNER, Keyword::JOIN])?),
993                    ),
994                    Token::Ident(_, Keyword::LEFT) => {
995                        let left = parser.consume_keyword(Keyword::LEFT)?;
996                        if let Some(outer) = parser.skip_keyword(Keyword::OUTER) {
997                            JoinType::NaturalLeft(
998                                left.join_span(&outer)
999                                    .join_span(&parser.consume_keyword(Keyword::JOIN)?),
1000                            )
1001                        } else {
1002                            JoinType::NaturalLeft(
1003                                left.join_span(&parser.consume_keyword(Keyword::JOIN)?),
1004                            )
1005                        }
1006                    }
1007                    Token::Ident(_, Keyword::RIGHT) => {
1008                        let right = parser.consume_keyword(Keyword::RIGHT)?;
1009                        if let Some(outer) = parser.skip_keyword(Keyword::OUTER) {
1010                            JoinType::NaturalRight(
1011                                right
1012                                    .join_span(&outer)
1013                                    .join_span(&parser.consume_keyword(Keyword::JOIN)?),
1014                            )
1015                        } else {
1016                            JoinType::NaturalRight(
1017                                right.join_span(&parser.consume_keyword(Keyword::JOIN)?),
1018                            )
1019                        }
1020                    }
1021                    Token::Ident(_, Keyword::JOIN) => JoinType::Natural(
1022                        natural.join_span(&parser.consume_keyword(Keyword::JOIN)?),
1023                    ),
1024                    _ => parser.expected_failure("'INNER', 'LEFT', 'RIGHT' or 'JOIN'")?,
1025                }
1026            }
1027            _ => break,
1028        };
1029
1030        let right = parse_table_reference_inner(parser, additional_restrict)?;
1031
1032        let specification = match &parser.token {
1033            Token::Ident(_, Keyword::ON) => {
1034                let on = parser.consume_keyword(Keyword::ON)?;
1035                let expr = parse_expression_unreserved(parser, PRIORITY_MAX)?;
1036                Some(JoinSpecification::On(expr, on))
1037            }
1038            Token::Ident(_, Keyword::USING) => {
1039                let using = parser.consume_keyword(Keyword::USING)?;
1040                let mut join_column_list = Vec::new();
1041                loop {
1042                    join_column_list.push(parser.consume_plain_identifier_unreserved()?);
1043                    if parser.skip_token(Token::Comma).is_none() {
1044                        break;
1045                    }
1046                }
1047                Some(JoinSpecification::Using(join_column_list, using))
1048            }
1049            _ => None,
1050        };
1051
1052        ans = TableReference::Join {
1053            join,
1054            left: Box::new(ans),
1055            right: Box::new(right),
1056            specification,
1057        };
1058    }
1059    Ok(ans)
1060}
1061
1062/// Flags specified after SELECT
1063#[derive(Debug, Clone)]
1064pub enum SelectFlag {
1065    All(Span),
1066    Distinct(Span),
1067    DistinctOn(Span),
1068    DistinctRow(Span),
1069    HighPriority(Span),
1070    StraightJoin(Span),
1071    SqlSmallResult(Span),
1072    SqlBigResult(Span),
1073    SqlBufferResult(Span),
1074    SqlNoCache(Span),
1075    SqlCalcFoundRows(Span),
1076}
1077
1078impl Spanned for SelectFlag {
1079    fn span(&self) -> Span {
1080        match &self {
1081            SelectFlag::All(v) => v.span(),
1082            SelectFlag::Distinct(v) => v.span(),
1083            SelectFlag::DistinctOn(v) => v.span(),
1084            SelectFlag::DistinctRow(v) => v.span(),
1085            SelectFlag::HighPriority(v) => v.span(),
1086            SelectFlag::StraightJoin(v) => v.span(),
1087            SelectFlag::SqlSmallResult(v) => v.span(),
1088            SelectFlag::SqlBigResult(v) => v.span(),
1089            SelectFlag::SqlBufferResult(v) => v.span(),
1090            SelectFlag::SqlNoCache(v) => v.span(),
1091            SelectFlag::SqlCalcFoundRows(v) => v.span(),
1092        }
1093    }
1094}
1095
1096/// Ordering direction
1097#[derive(Debug, Clone)]
1098pub enum OrderFlag {
1099    Asc(Span),
1100    Desc(Span),
1101    AscNullsFirst(Span),
1102    AscNullsLast(Span),
1103    DescNullsFirst(Span),
1104    DescNullsLast(Span),
1105    NullsFirst(Span),
1106    NullsLast(Span),
1107    None,
1108}
1109impl OptSpanned for OrderFlag {
1110    fn opt_span(&self) -> Option<Span> {
1111        match &self {
1112            OrderFlag::Asc(v) => v.opt_span(),
1113            OrderFlag::Desc(v) => v.opt_span(),
1114            OrderFlag::AscNullsFirst(v) => v.opt_span(),
1115            OrderFlag::AscNullsLast(v) => v.opt_span(),
1116            OrderFlag::DescNullsFirst(v) => v.opt_span(),
1117            OrderFlag::DescNullsLast(v) => v.opt_span(),
1118            OrderFlag::NullsFirst(v) => v.opt_span(),
1119            OrderFlag::NullsLast(v) => v.opt_span(),
1120            OrderFlag::None => None,
1121        }
1122    }
1123}
1124
1125/// Lock strength for locking
1126#[derive(Debug, Clone)]
1127pub enum LockStrength {
1128    Update(Span),
1129    Share(Span),
1130    NoKeyUpdate(Span),
1131    KeyShare(Span),
1132}
1133impl Spanned for LockStrength {
1134    fn span(&self) -> Span {
1135        match &self {
1136            LockStrength::Update(v) => v.span(),
1137            LockStrength::Share(v) => v.span(),
1138            LockStrength::NoKeyUpdate(v) => v.span(),
1139            LockStrength::KeyShare(v) => v.span(),
1140        }
1141    }
1142}
1143
1144#[derive(Debug, Clone)]
1145pub enum LockWait {
1146    NoWait(Span),
1147    SkipLocket(Span),
1148    Default,
1149}
1150impl OptSpanned for LockWait {
1151    fn opt_span(&self) -> Option<Span> {
1152        match &self {
1153            LockWait::NoWait(v) => v.opt_span(),
1154            LockWait::SkipLocket(v) => v.opt_span(),
1155            LockWait::Default => None,
1156        }
1157    }
1158}
1159
1160#[derive(Debug, Clone)]
1161pub struct Locking<'a> {
1162    /// Span of "FOR"
1163    pub for_span: Span,
1164    pub strength: LockStrength,
1165    pub of: Option<(Span, Vec<Identifier<'a>>)>,
1166    pub wait: LockWait,
1167}
1168impl<'a> Spanned for Locking<'a> {
1169    fn span(&self) -> Span {
1170        self.for_span
1171            .join_span(&self.strength)
1172            .join_span(&self.of)
1173            .join_span(&self.wait)
1174    }
1175}
1176
1177/// Representation of select Statement
1178///
1179/// ```
1180/// # use qusql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statement, Select, Statement, Issues};
1181/// # let options = ParseOptions::new().dialect(SQLDialect::MariaDB);
1182/// #
1183/// let sql = "SELECT f1,f2 FROM t1 WHERE f3<=10 AND f4='y'";
1184/// let mut issues = Issues::new(sql);
1185/// let stmt = parse_statement(sql, &mut issues, &options);
1186///
1187/// # assert!(issues.is_ok());
1188/// let s: Select = match stmt {
1189///     Some(Statement::Select(s)) => *s,
1190///     _ => panic!("We should get an select statement")
1191/// };
1192///
1193/// println!("{:#?}", s.where_);
1194///
1195/// let sql = "SELECT CAST(NULL AS CHAR)";
1196/// let stmt = parse_statement(sql, &mut issues, &options);
1197///
1198/// # assert!(issues.is_ok());
1199/// let s: Select = match stmt {
1200///     Some(Statement::Select(s)) => *s,
1201///     _ => panic!("We should get an select statement")
1202/// };
1203///
1204/// println!("{:#?}", s.where_);
1205///
1206/// let sql = "SELECT * FROM t1, d2.t2 FOR SHARE OF t1, t2 NOWAIT";
1207/// let stmt = parse_statement(sql, &mut issues, &options);
1208///
1209/// # assert!(issues.is_ok());
1210/// let s: Select = match stmt {
1211///     Some(Statement::Select(s)) => *s,
1212///     _ => panic!("We should get an select statement")
1213/// };
1214///
1215/// assert!(s.locking.is_some());
1216/// println!("{:#?}", s.locking);
1217/// ```
1218#[derive(Debug, Clone)]
1219pub struct Select<'a> {
1220    /// Span of "SELECT"
1221    pub select_span: Span,
1222    /// Flags specified after "SELECT"
1223    pub flags: Vec<SelectFlag>,
1224    /// List of values to select
1225    pub select_exprs: Vec<SelectExpr<'a>>,
1226    /// Span of "FROM"
1227    pub from_span: Option<Span>,
1228    /// List of tables to select from
1229    pub table_references: Option<Vec<TableReference<'a>>>,
1230    /// Where expression and span of "WHERE" if specified
1231    pub where_: Option<(Expression<'a>, Span)>,
1232    /// Span of "GROUP_BY" and group expression if specified
1233    pub group_by: Option<(Span, Vec<Expression<'a>>)>,
1234    /// Having expression and span of "HAVING" if specified
1235    pub having: Option<(Expression<'a>, Span)>,
1236    /// Span of window if specified
1237    pub window_span: Option<Span>,
1238    /// Span of "ORDER BY" and list of order expression and directions, if specified
1239    pub order_by: Option<(Span, Vec<(Expression<'a>, OrderFlag)>)>,
1240    /// Span of "LIMIT", offset and count expressions if specified
1241    pub limit: Option<(Span, Option<Expression<'a>>, Expression<'a>)>,
1242    /// PostgreSQL: DISTINCT ON (expr, ...) list
1243    pub distinct_on: Option<(Span, Vec<Expression<'a>>)>,
1244    /// PostgreSQL: OFFSET n [ROWS] (when no LIMIT is present)
1245    pub offset: Option<(Span, Expression<'a>)>,
1246    /// PostgreSQL: FETCH {FIRST|NEXT} n {ROW|ROWS} ONLY
1247    pub fetch: Option<(Span, Expression<'a>)>,
1248    /// Row locking clause
1249    pub locking: Option<Locking<'a>>,
1250}
1251
1252impl<'a> Spanned for Select<'a> {
1253    fn span(&self) -> Span {
1254        self.select_span
1255            .join_span(&self.flags)
1256            .join_span(&self.select_exprs)
1257            .join_span(&self.from_span)
1258            .join_span(&self.table_references)
1259            .join_span(&self.where_)
1260            .join_span(&self.group_by)
1261            .join_span(&self.having)
1262            .join_span(&self.window_span)
1263            .join_span(&self.order_by)
1264            .join_span(&self.limit)
1265            .join_span(&self.distinct_on)
1266            .join_span(&self.offset)
1267            .join_span(&self.fetch)
1268            .join_span(&self.locking)
1269    }
1270}
1271
1272/// Parse a SELECT body starting after the `SELECT` keyword has already been consumed.
1273/// `select_span` is the span of the keyword (or a synthetic span standing in for it).
1274pub(crate) fn parse_select_body<'a>(
1275    parser: &mut Parser<'a, '_>,
1276    select_span: Span,
1277) -> Result<Select<'a>, ParseError> {
1278    let mut flags = Vec::new();
1279    let mut select_exprs = Vec::new();
1280
1281    loop {
1282        match &parser.token {
1283            Token::Ident(_, Keyword::ALL) => {
1284                flags.push(SelectFlag::All(parser.consume_keyword(Keyword::ALL)?))
1285            }
1286            Token::Ident(_, Keyword::DISTINCT) => {
1287                let distinct_span = parser.consume_keyword(Keyword::DISTINCT)?;
1288                // PostgreSQL: DISTINCT ON (expr, ...)
1289                if matches!(parser.token, Token::Ident(_, Keyword::ON)) {
1290                    flags.push(SelectFlag::DistinctOn(distinct_span));
1291                } else {
1292                    flags.push(SelectFlag::Distinct(distinct_span));
1293                }
1294            }
1295            Token::Ident(_, Keyword::DISTINCTROW) => flags.push(SelectFlag::DistinctRow(
1296                parser.consume_keyword(Keyword::DISTINCTROW)?,
1297            )),
1298            Token::Ident(_, Keyword::HIGH_PRIORITY) => flags.push(SelectFlag::HighPriority(
1299                parser.consume_keyword(Keyword::HIGH_PRIORITY)?,
1300            )),
1301            Token::Ident(_, Keyword::STRAIGHT_JOIN) => flags.push(SelectFlag::StraightJoin(
1302                parser.consume_keyword(Keyword::STRAIGHT_JOIN)?,
1303            )),
1304            Token::Ident(_, Keyword::SQL_SMALL_RESULT) => flags.push(SelectFlag::SqlSmallResult(
1305                parser.consume_keyword(Keyword::SQL_SMALL_RESULT)?,
1306            )),
1307            Token::Ident(_, Keyword::SQL_BIG_RESULT) => flags.push(SelectFlag::SqlBigResult(
1308                parser.consume_keyword(Keyword::SQL_BIG_RESULT)?,
1309            )),
1310            Token::Ident(_, Keyword::SQL_BUFFER_RESULT) => flags.push(SelectFlag::SqlBufferResult(
1311                parser.consume_keyword(Keyword::SQL_BUFFER_RESULT)?,
1312            )),
1313            Token::Ident(_, Keyword::SQL_NO_CACHE) => flags.push(SelectFlag::SqlNoCache(
1314                parser.consume_keyword(Keyword::SQL_NO_CACHE)?,
1315            )),
1316            Token::Ident(_, Keyword::SQL_CALC_FOUND_ROWS) => flags.push(
1317                SelectFlag::SqlCalcFoundRows(parser.consume_keyword(Keyword::SQL_CALC_FOUND_ROWS)?),
1318            ),
1319            _ => break,
1320        }
1321    }
1322
1323    // PostgreSQL: parse DISTINCT ON (expr, ...) if signaled by DistinctOn flag
1324    let distinct_on = if flags
1325        .last()
1326        .is_some_and(|f| matches!(f, SelectFlag::DistinctOn(_)))
1327    {
1328        let on_span = parser.consume_keyword(Keyword::ON)?;
1329        parser.postgres_only(&on_span);
1330        parser.consume_token(Token::LParen)?;
1331        let mut exprs = Vec::new();
1332        loop {
1333            parser.recovered(
1334                "')' or ','",
1335                &|t| matches!(t, Token::RParen | Token::Comma),
1336                |parser| {
1337                    exprs.push(parse_expression_unreserved(parser, PRIORITY_MAX)?);
1338                    Ok(())
1339                },
1340            )?;
1341            if parser.skip_token(Token::Comma).is_none() {
1342                break;
1343            }
1344        }
1345        parser.consume_token(Token::RParen)?;
1346        Some((on_span, exprs))
1347    } else {
1348        None
1349    };
1350
1351    loop {
1352        select_exprs.push(parse_select_expr(parser)?);
1353        if parser.skip_token(Token::Comma).is_none() {
1354            break;
1355        }
1356    }
1357
1358    // TODO [into_option]
1359
1360    let from_span = parser.skip_keyword(Keyword::FROM);
1361
1362    let table_references = if from_span.is_some() {
1363        let mut table_references = Vec::new();
1364        loop {
1365            table_references.push(parse_table_reference(parser, Restrict::EMPTY)?);
1366            if parser.skip_token(Token::Comma).is_none() {
1367                break;
1368            }
1369        }
1370        Some(table_references)
1371    } else {
1372        None
1373    };
1374
1375    // TODO PARTITION partition_list;
1376    let where_ = if let Some(span) = parser.skip_keyword(Keyword::WHERE) {
1377        Some((parse_expression_unreserved(parser, PRIORITY_MAX)?, span))
1378    } else {
1379        None
1380    };
1381
1382    let group_by = if let Some(group_span) = parser.skip_keyword(Keyword::GROUP) {
1383        let span = parser.consume_keyword(Keyword::BY)?.join_span(&group_span);
1384        let mut groups = Vec::new();
1385        loop {
1386            groups.push(parse_expression_unreserved(parser, PRIORITY_MAX)?);
1387            if parser.skip_token(Token::Comma).is_none() {
1388                break;
1389            }
1390        }
1391        // TODO [WITH ROLLUP]]
1392        Some((span, groups))
1393    } else {
1394        None
1395    };
1396
1397    let having = if let Some(span) = parser.skip_keyword(Keyword::HAVING) {
1398        Some((parse_expression_unreserved(parser, PRIORITY_MAX)?, span))
1399    } else {
1400        None
1401    };
1402
1403    let window_span = parser.skip_keyword(Keyword::WINDOW);
1404    if window_span.is_some() {
1405        //TODO window_name AS (window_spec) [, window_name AS (window_spec)] ...]
1406    }
1407
1408    let order_by = if let Some(span) = parser.skip_keyword(Keyword::ORDER) {
1409        let span = parser.consume_keyword(Keyword::BY)?.join_span(&span);
1410        let mut order = Vec::new();
1411        loop {
1412            let e = parse_expression_unreserved(parser, PRIORITY_MAX)?;
1413            let dir_span_opt = match &parser.token {
1414                Token::Ident(_, Keyword::ASC) => Some((true, parser.consume())),
1415                Token::Ident(_, Keyword::DESC) => Some((false, parser.consume())),
1416                _ => None,
1417            };
1418            let f = if let Some(nulls_span) = parser.skip_keyword(Keyword::NULLS) {
1419                match &parser.token {
1420                    Token::Ident(_, Keyword::FIRST) => {
1421                        let s = parser.consume().join_span(&nulls_span);
1422                        parser.postgres_only(&s);
1423                        match dir_span_opt {
1424                            Some((true, _)) => OrderFlag::AscNullsFirst(s),
1425                            Some((false, _)) => OrderFlag::DescNullsFirst(s),
1426                            None => OrderFlag::NullsFirst(s),
1427                        }
1428                    }
1429                    Token::Ident(_, Keyword::LAST) => {
1430                        let s = parser.consume().join_span(&nulls_span);
1431                        parser.postgres_only(&s);
1432                        match dir_span_opt {
1433                            Some((true, _)) => OrderFlag::AscNullsLast(s),
1434                            Some((false, _)) => OrderFlag::DescNullsLast(s),
1435                            None => OrderFlag::NullsLast(s),
1436                        }
1437                    }
1438                    _ => parser.expected_failure("FIRST or LAST")?,
1439                }
1440            } else {
1441                match dir_span_opt {
1442                    Some((true, s)) => OrderFlag::Asc(s),
1443                    Some((false, s)) => OrderFlag::Desc(s),
1444                    None => OrderFlag::None,
1445                }
1446            };
1447            order.push((e, f));
1448            if parser.skip_token(Token::Comma).is_none() {
1449                break;
1450            }
1451        }
1452        Some((span, order))
1453    } else {
1454        None
1455    };
1456
1457    let limit = if let Some(span) = parser.skip_keyword(Keyword::LIMIT) {
1458        let n = parse_expression_unreserved(parser, PRIORITY_MAX)?;
1459        match parser.token {
1460            Token::Comma => {
1461                parser.consume();
1462                Some((
1463                    span,
1464                    Some(n),
1465                    parse_expression_unreserved(parser, PRIORITY_MAX)?,
1466                ))
1467            }
1468            Token::Ident(_, Keyword::OFFSET) => {
1469                parser.consume();
1470                Some((
1471                    span,
1472                    Some(parse_expression_unreserved(parser, PRIORITY_MAX)?),
1473                    n,
1474                ))
1475            }
1476            _ => Some((span, None, n)),
1477        }
1478    } else {
1479        None
1480    };
1481
1482    // PostgreSQL: standalone OFFSET n [ROWS] (only when no LIMIT already consumed offset)
1483    let offset = if limit.is_none() {
1484        if let Some(offset_span) = parser.skip_keyword(Keyword::OFFSET) {
1485            parser.postgres_only(&offset_span);
1486            let n = parse_expression_unreserved(parser, PRIORITY_MAX)?;
1487            // skip optional ROWS or ROW
1488            if matches!(parser.token, Token::Ident(_, Keyword::ROWS | Keyword::ROW)) {
1489                parser.consume();
1490            }
1491            Some((offset_span, n))
1492        } else {
1493            None
1494        }
1495    } else {
1496        None
1497    };
1498
1499    // PostgreSQL: FETCH {FIRST|NEXT} n {ROW|ROWS} ONLY
1500    let fetch = if let Some(fetch_span) = parser.skip_keyword(Keyword::FETCH) {
1501        parser.postgres_only(&fetch_span);
1502        match &parser.token {
1503            Token::Ident(_, Keyword::FIRST | Keyword::NEXT) => {
1504                parser.consume();
1505            }
1506            _ => parser.expected_failure("FIRST or NEXT")?,
1507        }
1508        let n = parse_expression_unreserved(parser, PRIORITY_MAX)?;
1509        if matches!(parser.token, Token::Ident(_, Keyword::ROWS | Keyword::ROW)) {
1510            parser.consume();
1511        }
1512        parser.consume_keyword(Keyword::ONLY)?;
1513        Some((fetch_span, n))
1514    } else {
1515        None
1516    };
1517
1518    let locking = if let Some(for_span) = parser.skip_keyword(Keyword::FOR) {
1519        let strength = match &parser.token {
1520            Token::Ident(_, Keyword::UPDATE) => {
1521                LockStrength::Update(parser.consume_keyword(Keyword::UPDATE)?)
1522            }
1523            Token::Ident(_, Keyword::SHARE) => {
1524                LockStrength::Share(parser.consume_keyword(Keyword::SHARE)?)
1525            }
1526            Token::Ident(_, Keyword::NO) => {
1527                LockStrength::NoKeyUpdate(parser.consume_keywords(&[
1528                    Keyword::NO,
1529                    Keyword::KEY,
1530                    Keyword::UPDATE,
1531                ])?)
1532            }
1533            Token::Ident(_, Keyword::KEY) => {
1534                LockStrength::KeyShare(parser.consume_keywords(&[Keyword::KEY, Keyword::SHARE])?)
1535            }
1536            _ => parser.expected_failure("UPDATE, SHARE, NO KEY UPDATE or KEY SHARE here")?,
1537        };
1538
1539        if let LockStrength::NoKeyUpdate(s) | LockStrength::KeyShare(s) = &strength
1540            && !parser.options.dialect.is_postgresql()
1541        {
1542            parser.err("Only support by PostgreSQL", s);
1543        }
1544
1545        let of = if let Some(of_span) = parser.skip_keyword(Keyword::OF) {
1546            let mut table_references = Vec::new();
1547            loop {
1548                table_references.push(parser.consume_plain_identifier_unreserved()?);
1549                if parser.skip_token(Token::Comma).is_none() {
1550                    break;
1551                }
1552            }
1553            Some((of_span, table_references))
1554        } else {
1555            None
1556        };
1557
1558        let wait = match &parser.token {
1559            Token::Ident(_, Keyword::NOWAIT) => {
1560                LockWait::NoWait(parser.consume_keyword(Keyword::NOWAIT)?)
1561            }
1562            Token::Ident(_, Keyword::SKIP) => {
1563                LockWait::SkipLocket(parser.consume_keywords(&[Keyword::SKIP, Keyword::LOCKED])?)
1564            }
1565            _ => LockWait::Default,
1566        };
1567        Some(Locking {
1568            for_span,
1569            strength,
1570            of,
1571            wait,
1572        })
1573    } else {
1574        None
1575    };
1576
1577    // TODO [into_option]
1578    // [into_option]
1579
1580    // into_option: {
1581    // INTO OUTFILE 'file_name'
1582    //     [CHARACTER SET charset_name]
1583    //     export_options
1584    // | INTO DUMPFILE 'file_name'
1585    // | INTO var_name [, var_name] ...
1586    // }
1587
1588    Ok(Select {
1589        select_span,
1590        flags,
1591        select_exprs,
1592        from_span,
1593        table_references,
1594        where_,
1595        group_by,
1596        having,
1597        window_span,
1598        order_by,
1599        limit,
1600        distinct_on,
1601        offset,
1602        fetch,
1603        locking,
1604    })
1605}
1606
1607pub(crate) fn parse_select<'a>(parser: &mut Parser<'a, '_>) -> Result<Select<'a>, ParseError> {
1608    let select_span = parser.consume_keyword(Keyword::SELECT)?;
1609    parse_select_body(parser, select_span)
1610}