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