Skip to main content

qusql_parse/
statement.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.
12
13use alloc::{boxed::Box, vec::Vec};
14
15use crate::{
16    AlterOperator, AlterOperatorClass, AlterOperatorFamily, AlterRole, AlterSequence, AlterTable,
17    AlterType, CreateConstraintTrigger, CreateDomain, CreateExtension, CreateIndex, CreateOperator,
18    CreateOperatorClass, CreateOperatorFamily, CreateRole, CreateTrigger, DropOperatorClass,
19    DropOperatorFamily, ExecuteFunction, QualifiedName, RenameTable, Span, Spanned, WithQuery,
20    alter_role::parse_alter_role,
21    alter_sequence::parse_alter_sequence,
22    alter_table::parse_alter_table,
23    copy::{CopyFrom, CopyTo, parse_copy_statement},
24    create::{
25        CreateDatabase, CreateSchema, CreateSequence, CreateServer, CreateTypeEnum, parse_create,
26    },
27    create_function::{CreateFunction, CreateProcedure},
28    create_table::{CreateTable, CreateTablePartitionOf},
29    create_view::CreateView,
30    delete::{Delete, parse_delete},
31    drop::{
32        DropDatabase, DropDomain, DropEvent, DropExtension, DropFunction, DropIndex, DropOperator,
33        DropProcedure, DropSchema, DropSequence, DropServer, DropTable, DropTrigger, DropType,
34        DropView, parse_drop,
35    },
36    expression::{
37        Expression, NullExpression, PRIORITY_CMP, PRIORITY_MAX, parse_expression_unreserved,
38    },
39    flush::{Flush, parse_flush},
40    grant::{Grant, parse_grant},
41    insert_replace::{InsertReplace, parse_insert_replace},
42    keywords::Keyword,
43    kill::{Kill, parse_kill},
44    lexer::{StringType, Token},
45    lock::{Lock, Unlock, parse_lock, parse_unlock},
46    parser::{ParseError, Parser},
47    qualified_name::parse_qualified_name_unreserved,
48    rename::parse_rename_table,
49    select::{OrderFlag, Select, parse_select, parse_select_body},
50    show::{
51        ShowCharacterSet, ShowCollation, ShowColumns, ShowCreateDatabase, ShowCreateTable,
52        ShowCreateView, ShowDatabases, ShowEngines, ShowProcessList, ShowStatus, ShowTables,
53        ShowVariables, parse_show,
54    },
55    span::OptSpanned,
56    truncate::{TruncateTable, parse_truncate_table},
57    update::{Update, parse_update},
58    values::parse_values,
59    with_query::parse_with_query,
60};
61
62#[derive(Clone, Debug)]
63pub struct Analyze<'a> {
64    pub analyze_span: Span,
65    pub tables: Vec<QualifiedName<'a>>,
66}
67
68impl<'a> Spanned for Analyze<'a> {
69    fn span(&self) -> Span {
70        self.analyze_span.join_span(&self.tables)
71    }
72}
73
74#[derive(Clone, Debug)]
75pub struct Set<'a> {
76    pub set_span: Span,
77    /// `LOCAL` modifier in `SET LOCAL name TO value` (PostgreSQL)
78    pub local_span: Option<Span>,
79    /// `SESSION` modifier in `SET SESSION name TO value` (PostgreSQL)
80    pub session_span: Option<Span>,
81    pub values: Vec<(SetVariable<'a>, Vec<Expression<'a>>)>,
82}
83
84impl<'a> Spanned for Set<'a> {
85    fn span(&self) -> Span {
86        self.set_span
87            .join_span(&self.local_span)
88            .join_span(&self.session_span)
89            .join_span(&self.values)
90    }
91}
92
93/// The target name of a `SET` assignment
94#[derive(Clone, Debug)]
95pub enum SetVariable<'a> {
96    /// Plain (possibly qualified) identifier, e.g. `SET \`x\` = 1` inside stored routines
97    Named(QualifiedName<'a>),
98    /// User-defined variable: `SET @name = expr`
99    User {
100        at_span: Span,
101        name: crate::Identifier<'a>,
102    },
103    /// System variable with explicit scope qualifier: `SET @@GLOBAL.name = expr` or `SET @@SESSION.name = expr`
104    System {
105        global: Option<Span>,
106        session: Option<Span>,
107        dot_span: Span,
108        name: crate::Identifier<'a>,
109    },
110    /// System variable without explicit scope: `SET @@name = expr`
111    SystemBare {
112        at_at_span: Span,
113        name: crate::Identifier<'a>,
114    },
115}
116
117impl Spanned for SetVariable<'_> {
118    fn span(&self) -> Span {
119        match self {
120            SetVariable::Named(q) => q.span(),
121            SetVariable::User { at_span, name } => at_span.join_span(name),
122            SetVariable::System {
123                global,
124                session,
125                dot_span,
126                name,
127            } => name
128                .span()
129                .join_span(global)
130                .join_span(session)
131                .join_span(dot_span),
132            SetVariable::SystemBare { at_at_span, name } => at_at_span.join_span(name),
133        }
134    }
135}
136
137fn parse_set_variable<'a>(parser: &mut Parser<'a, '_>) -> Result<SetVariable<'a>, ParseError> {
138    match parser.token {
139        Token::At => {
140            let at_span = parser.consume_token(Token::At)?;
141            parser.maria_only(&at_span);
142            let name = parser.consume_plain_identifier_unreserved()?;
143            Ok(SetVariable::User { at_span, name })
144        }
145        Token::AtAtGlobal | Token::AtAtSession => {
146            let global = parser.skip_token(Token::AtAtGlobal);
147            let session = if global.is_none() {
148                Some(parser.consume_token(Token::AtAtSession)?)
149            } else {
150                None
151            };
152            parser.maria_only(&global.clone().or_else(|| session.clone()));
153            let dot_span = parser.consume_token(Token::Period)?;
154            let name = parser.consume_plain_identifier_unreserved()?;
155            Ok(SetVariable::System {
156                global,
157                session,
158                dot_span,
159                name,
160            })
161        }
162        Token::AtAt => {
163            let at_at_span = parser.consume_token(Token::AtAt)?;
164            parser.maria_only(&at_at_span);
165            let name = parser.consume_plain_identifier_unreserved()?;
166            Ok(SetVariable::SystemBare { at_at_span, name })
167        }
168        _ => {
169            let name = parse_qualified_name_unreserved(parser)?;
170            Ok(SetVariable::Named(name))
171        }
172    }
173}
174
175fn parse_set<'a>(parser: &mut Parser<'a, '_>) -> Result<Set<'a>, ParseError> {
176    let set_span = parser.consume_keyword(Keyword::SET)?;
177    // Optional LOCAL / SESSION scope modifier (PostgreSQL only)
178    let local_span = parser.skip_keyword(Keyword::LOCAL);
179    parser.postgres_only(&local_span);
180    let session_span = if local_span.is_none() {
181        parser.skip_keyword(Keyword::SESSION)
182    } else {
183        None
184    };
185    parser.postgres_only(&session_span);
186    let mut values = Vec::new();
187    let is_pg = parser.options.dialect.is_postgresql();
188    loop {
189        let name = parse_set_variable(parser)?;
190        // TO is PostgreSQL syntax; = is accepted by all dialects
191        let to_span = parser.skip_keyword(Keyword::TO);
192        parser.postgres_only(&to_span);
193        let use_to = to_span.is_some();
194        if !use_to {
195            parser.consume_token(Token::Eq)?;
196        }
197        let mut exprs = Vec::new();
198        loop {
199            let val = parse_expression_unreserved(parser, PRIORITY_MAX)?;
200            exprs.push(val);
201            // In PostgreSQL, both TO and = allow comma-separated value lists for the
202            // same variable (e.g. SET search_path = public, myschema).
203            // In MySQL/MariaDB/SQLite, commas separate distinct variable assignments.
204            if is_pg {
205                if parser.skip_token(Token::Comma).is_none() {
206                    break;
207                }
208            } else {
209                break;
210            }
211        }
212        values.push((name, exprs));
213        if is_pg {
214            break; // PostgreSQL SET assigns exactly one variable per statement
215        }
216        if parser.skip_token(Token::Comma).is_none() {
217            break;
218        }
219    }
220    Ok(Set {
221        set_span,
222        local_span,
223        session_span,
224        values,
225    })
226}
227
228fn parse_plpgsql_declare_section<'a>(
229    parser: &mut Parser<'a, '_>,
230    out: &mut Vec<Statement<'a>>,
231) -> Result<(), ParseError> {
232    use crate::data_type::{DataTypeContext, parse_data_type};
233    let declare_span = parser.consume_keyword(Keyword::DECLARE)?;
234    loop {
235        // Skip semicolons between declarations
236        while parser.skip_token(Token::Delimiter).is_some() {}
237        // Stop at block boundaries or EOF
238        match &parser.token {
239            Token::Ident(_, Keyword::BEGIN | Keyword::END | Keyword::EXCEPTION) | Token::Eof => {
240                break;
241            }
242            Token::Ident(_, _) => {} // continue to parse declaration
243            _ => break,
244        }
245        // Each declaration: `name type [ [NOT NULL] [ DEFAULT | := | = ] expr|select ]`
246        let name = parser.consume_plain_identifier_unreserved()?;
247        let data_type = parse_data_type(parser, DataTypeContext::Column)?;
248        let default = if let Some(default_span) = parser.skip_keyword(Keyword::DEFAULT) {
249            let select = parse_select_body(parser, default_span.clone())?;
250            Some((default_span, select))
251        } else if matches!(parser.token, Token::ColonEq | Token::Eq) {
252            let assign_span = parser.consume();
253            let select = parse_select_body(parser, assign_span.clone())?;
254            Some((assign_span, select))
255        } else {
256            None
257        };
258        out.push(Statement::DeclareVariable(Box::new(DeclareVariable {
259            declare_span: declare_span.clone(),
260            name,
261            data_type,
262            default,
263        })));
264    }
265    Ok(())
266}
267
268fn parse_statement_list_inner<'a>(
269    parser: &mut Parser<'a, '_>,
270    out: &mut Vec<Statement<'a>>,
271) -> Result<(), ParseError> {
272    loop {
273        while parser.skip_token(Token::Delimiter).is_some() {}
274        // PL/pgSQL DECLARE section: single DECLARE keyword introduces multiple variable
275        // declarations (each terminated by `;`) before the BEGIN block.
276        if parser.permit_compound_statements
277            && parser.options.dialect.is_postgresql()
278            && matches!(&parser.token, Token::Ident(_, Keyword::DECLARE))
279        {
280            parse_plpgsql_declare_section(parser, out)?;
281            continue;
282        }
283        // Detect MariaDB statement labels: `label_name:`
284        let label = if parser.permit_compound_statements
285            && matches!(&parser.token, Token::Ident(_, Keyword::NOT_A_KEYWORD))
286            && matches!(parser.peek(), Token::Colon)
287        {
288            let l = parser.consume_plain_identifier_unreserved()?;
289            parser.consume(); // colon
290            Some(l)
291        } else {
292            None
293        };
294        let stmt = if let Some(label) = label {
295            // After a label, only loop constructs are valid; label is stored in AST
296            match &parser.token {
297                Token::Ident(_, Keyword::LOOP) if parser.options.dialect.is_maria() => {
298                    Some(Statement::Loop(Box::new(parse_loop(parser, Some(label))?)))
299                }
300                Token::Ident(_, Keyword::WHILE) if parser.options.dialect.is_maria() => Some(
301                    Statement::While(Box::new(parse_while(parser, Some(label))?)),
302                ),
303                Token::Ident(_, Keyword::REPEAT) if parser.options.dialect.is_maria() => Some(
304                    Statement::Repeat(Box::new(parse_repeat(parser, Some(label))?)),
305                ),
306                _ => parse_statement(parser)?,
307            }
308        } else {
309            parse_statement(parser)?
310        };
311        let stdin = match stmt {
312            Some(v) => {
313                let stdin = v.reads_from_stdin();
314                out.push(v);
315                stdin
316            }
317            None => break,
318        };
319        if !matches!(parser.token, Token::Delimiter) {
320            break;
321        }
322        if stdin {
323            let (s, span) = parser.read_from_stdin_and_next();
324            out.push(Statement::Stdin(Box::new(Stdin { input: s, span })));
325        } else {
326            parser.consume_token(Token::Delimiter)?;
327        }
328    }
329    Ok(())
330}
331
332fn parse_statement_list<'a>(
333    parser: &mut Parser<'a, '_>,
334    out: &mut Vec<Statement<'a>>,
335) -> Result<(), ParseError> {
336    let old = core::mem::replace(&mut parser.lexer.semicolon_as_delimiter, true);
337    let r = parse_statement_list_inner(parser, out);
338    parser.lexer.semicolon_as_delimiter = old;
339    r
340}
341
342fn parse_begin(parser: &mut Parser<'_, '_>) -> Result<Begin, ParseError> {
343    Ok(Begin {
344        span: parser.consume_keyword(Keyword::BEGIN)?,
345    })
346}
347
348fn parse_end(parser: &mut Parser<'_, '_>) -> Result<End, ParseError> {
349    Ok(End {
350        span: parser.consume_keyword(Keyword::END)?,
351    })
352}
353
354fn parse_start_transaction<'a>(
355    parser: &mut Parser<'a, '_>,
356) -> Result<StartTransaction, ParseError> {
357    Ok(StartTransaction {
358        span: parser.consume_keywords(&[Keyword::START, Keyword::TRANSACTION])?,
359    })
360}
361
362fn parse_commit(parser: &mut Parser<'_, '_>) -> Result<Commit, ParseError> {
363    Ok(Commit {
364        span: parser.consume_keyword(Keyword::COMMIT)?,
365    })
366}
367
368fn parse_block<'a>(parser: &mut Parser<'a, '_>) -> Result<Block<'a>, ParseError> {
369    let begin_span = parser.consume_keyword(Keyword::BEGIN)?;
370    let mut statements = Vec::new();
371    parser.recovered(
372        "'END' | 'EXCEPTION'",
373        &|e| matches!(e, Token::Ident(_, Keyword::END | Keyword::EXCEPTION)),
374        |parser| parse_statement_list(parser, &mut statements),
375    )?;
376    let mut exception_handlers = Vec::new();
377    let exception_span = if let Some(exception_span) = parser.skip_keyword(Keyword::EXCEPTION) {
378        while let Some(when_span) = parser.skip_keyword(Keyword::WHEN) {
379            let condition = parser.consume_plain_identifier_unreserved()?;
380            let then_span = parser.consume_keyword(Keyword::THEN)?;
381            let mut handler_stmts = Vec::new();
382            parse_statement_list(parser, &mut handler_stmts)?;
383            exception_handlers.push(ExceptionHandler {
384                when_span,
385                condition,
386                then_span,
387                statements: handler_stmts,
388            });
389        }
390        Some(exception_span)
391    } else {
392        None
393    };
394    let end_span = parser.consume_keyword(Keyword::END)?;
395    Ok(Block {
396        begin_span,
397        statements,
398        exception_span,
399        exception_handlers,
400        end_span,
401    })
402}
403
404/// Condition in if statement
405#[derive(Clone, Debug)]
406pub struct IfCondition<'a> {
407    /// Span of "ELSEIF" / "ELSIF" if specified
408    pub elseif_span: Option<Span>,
409    /// The condition, parsed as an implicit SELECT body.
410    /// `IF expr FROM table THEN` is treated as `SELECT expr FROM table`,
411    /// so `search_condition.select_span` carries the span of the IF/ELSIF keyword.
412    pub search_condition: Select<'a>,
413    /// Span of "THEN"
414    pub then_span: Span,
415    /// List of statement to be executed if `search_condition` is true
416    pub then: Vec<Statement<'a>>,
417}
418
419impl<'a> Spanned for IfCondition<'a> {
420    fn span(&self) -> Span {
421        self.then_span
422            .join_span(&self.elseif_span)
423            .join_span(&self.search_condition)
424            .join_span(&self.then_span)
425            .join_span(&self.then)
426    }
427}
428
429/// If statement
430#[derive(Clone, Debug)]
431pub struct If<'a> {
432    /// Span of "IF"
433    pub if_span: Span,
434    // List of if a then v parts
435    pub conditions: Vec<IfCondition<'a>>,
436    /// Span of "ELSE" and else Statement if specified
437    pub else_: Option<(Span, Vec<Statement<'a>>)>,
438    /// Span of "ENDIF"
439    pub endif_span: Span,
440}
441
442impl<'a> Spanned for If<'a> {
443    fn span(&self) -> Span {
444        self.if_span
445            .join_span(&self.conditions)
446            .join_span(&self.else_)
447            .join_span(&self.endif_span)
448    }
449}
450
451fn parse_if<'a>(parser: &mut Parser<'a, '_>) -> Result<If<'a>, ParseError> {
452    let if_span = parser.consume_keyword(Keyword::IF)?;
453    let mut conditions = Vec::new();
454    let mut else_ = None;
455    parser.recovered(
456        "'END'",
457        &|e| matches!(e, Token::Ident(_, Keyword::END)),
458        |parser| {
459            // The IF condition is an implicit SELECT body: `IF expr [FROM tbl] THEN`
460            // is equivalent to `SELECT expr [FROM tbl]` evaluated at runtime.
461            // We reuse parse_select_body so we get full FROM/WHERE/GROUP BY support
462            // without reimplementing the select parser.
463            let search_condition = parse_select_body(parser, if_span.clone())?;
464            let then_span = parser.consume_keyword(Keyword::THEN)?;
465            let mut then = Vec::new();
466            parse_statement_list(parser, &mut then)?;
467            conditions.push(IfCondition {
468                elseif_span: None,
469                search_condition,
470                then_span,
471                then,
472            });
473            while let Some(elseif_span) = parser
474                .skip_keyword(Keyword::ELSEIF)
475                .or_else(|| parser.skip_keyword(Keyword::ELSIF))
476            {
477                let search_condition = parse_select_body(parser, elseif_span.clone())?;
478                let then_span = parser.consume_keyword(Keyword::THEN)?;
479                let mut then = Vec::new();
480                parse_statement_list(parser, &mut then)?;
481                conditions.push(IfCondition {
482                    elseif_span: Some(elseif_span),
483                    search_condition,
484                    then_span,
485                    then,
486                })
487            }
488            if let Some(else_span) = parser.skip_keyword(Keyword::ELSE) {
489                let mut o = Vec::new();
490                parse_statement_list(parser, &mut o)?;
491                else_ = Some((else_span, o));
492            }
493            Ok(())
494        },
495    )?;
496    let endif_span = parser.consume_keywords(&[Keyword::END, Keyword::IF])?;
497    Ok(If {
498        if_span,
499        conditions,
500        else_,
501        endif_span,
502    })
503}
504
505/// Return statement
506#[derive(Clone, Debug)]
507pub struct Return<'a> {
508    /// Span of "Return"
509    pub return_span: Span,
510    pub expr: Expression<'a>,
511}
512
513impl<'a> Spanned for Return<'a> {
514    fn span(&self) -> Span {
515        self.return_span.join_span(&self.expr)
516    }
517}
518
519fn parse_return<'a>(parser: &mut Parser<'a, '_>) -> Result<Return<'a>, ParseError> {
520    let return_span = parser.consume_keyword(Keyword::RETURN)?;
521    let expr = parse_expression_unreserved(parser, PRIORITY_MAX)?;
522    Ok(Return { return_span, expr })
523}
524
525/// PL/pgSQL PERFORM statement - executes an expression and discards the result.
526#[derive(Clone, Debug)]
527pub struct Perform<'a> {
528    /// Span of "PERFORM"
529    pub perform_span: Span,
530    /// Expression to evaluate
531    pub expr: Expression<'a>,
532}
533
534impl<'a> Spanned for Perform<'a> {
535    fn span(&self) -> Span {
536        self.perform_span.join_span(&self.expr)
537    }
538}
539
540fn parse_perform<'a>(parser: &mut Parser<'a, '_>) -> Result<Perform<'a>, ParseError> {
541    let perform_span = parser.consume_keyword(Keyword::PERFORM)?;
542    let expr = parse_expression_unreserved(parser, PRIORITY_MAX)?;
543    Ok(Perform { perform_span, expr })
544}
545
546/// PL/pgSQL assignment statement: `target := expression [FROM ...]`
547#[derive(Clone, Debug)]
548pub struct Assign<'a> {
549    /// Left-hand side (assignment target)
550    pub target: Expression<'a>,
551    /// Span of `:=`
552    pub assign_span: Span,
553    /// Right-hand side value (may include FROM/WHERE/etc. clauses)
554    pub value: Select<'a>,
555}
556
557impl<'a> Spanned for Assign<'a> {
558    fn span(&self) -> Span {
559        self.target
560            .join_span(&self.assign_span)
561            .join_span(&self.value)
562    }
563}
564
565/// PL/pgSQL EXECUTE statement (dynamic SQL execution):
566/// `EXECUTE string [USING expression [, ...]]`
567#[derive(Clone, Debug)]
568pub struct PlpgsqlExecute<'a> {
569    /// Span of `EXECUTE`
570    pub execute_span: Span,
571    /// Dynamic SQL string expression
572    pub command: Expression<'a>,
573    /// Optional USING arguments
574    pub using: Vec<Expression<'a>>,
575}
576
577impl<'a> Spanned for PlpgsqlExecute<'a> {
578    fn span(&self) -> Span {
579        self.execute_span
580            .join_span(&self.command)
581            .join_span(&self.using)
582    }
583}
584
585fn parse_plpgsql_execute<'a>(
586    parser: &mut Parser<'a, '_>,
587) -> Result<PlpgsqlExecute<'a>, ParseError> {
588    let execute_span = parser.consume_keyword(Keyword::EXECUTE)?;
589    let command = parse_expression_unreserved(parser, PRIORITY_MAX)?;
590    let mut using = Vec::new();
591    if parser.skip_keyword(Keyword::USING).is_some() {
592        loop {
593            using.push(parse_expression_unreserved(parser, PRIORITY_MAX)?);
594            if parser.skip_token(Token::Comma).is_none() {
595                break;
596            }
597        }
598    }
599    Ok(PlpgsqlExecute {
600        execute_span,
601        command,
602        using,
603    })
604}
605
606/// PL/pgSQL RAISE severity level
607#[derive(Clone, Debug)]
608pub enum RaiseLevel {
609    Debug(Span),
610    Log(Span),
611    Info(Span),
612    Notice(Span),
613    Warning(Span),
614    Exception(Span),
615}
616
617impl Spanned for RaiseLevel {
618    fn span(&self) -> Span {
619        match self {
620            RaiseLevel::Debug(s)
621            | RaiseLevel::Log(s)
622            | RaiseLevel::Info(s)
623            | RaiseLevel::Notice(s)
624            | RaiseLevel::Warning(s)
625            | RaiseLevel::Exception(s) => s.clone(),
626        }
627    }
628}
629
630/// Option name in `RAISE ... USING option = expr`
631#[derive(Clone, Debug)]
632pub enum RaiseOptionName {
633    Message(Span),
634    Detail(Span),
635    Hint(Span),
636    Errcode(Span),
637    Column(Span),
638    Constraint(Span),
639    Datatype(Span),
640    Table(Span),
641    Schema(Span),
642}
643
644impl Spanned for RaiseOptionName {
645    fn span(&self) -> Span {
646        match self {
647            RaiseOptionName::Message(s)
648            | RaiseOptionName::Detail(s)
649            | RaiseOptionName::Hint(s)
650            | RaiseOptionName::Errcode(s)
651            | RaiseOptionName::Column(s)
652            | RaiseOptionName::Constraint(s)
653            | RaiseOptionName::Datatype(s)
654            | RaiseOptionName::Table(s)
655            | RaiseOptionName::Schema(s) => s.clone(),
656        }
657    }
658}
659
660/// PL/pgSQL RAISE statement
661///
662/// Syntax:
663/// ```sql
664/// RAISE [ level ] 'format' [, expr, ...] [ USING option = expr, ... ];
665/// RAISE [ level ] condition_name [ USING option = expr, ... ];
666/// RAISE [ level ] SQLSTATE 'sqlstate' [ USING option = expr, ... ];
667/// RAISE [ level ] USING option = expr, ...;
668/// RAISE;
669/// ```
670#[derive(Clone, Debug)]
671pub struct Raise<'a> {
672    /// Span of RAISE keyword
673    pub raise_span: Span,
674    /// Optional severity level
675    pub level: Option<RaiseLevel>,
676    /// Format string (for `RAISE level 'format' [, args...]`)
677    pub message: Option<crate::SString<'a>>,
678    /// Positional format arguments
679    pub args: Vec<Expression<'a>>,
680    /// USING clause options
681    pub using: Vec<(RaiseOptionName, Span, Expression<'a>)>,
682}
683
684impl<'a> Spanned for Raise<'a> {
685    fn span(&self) -> Span {
686        self.raise_span
687            .join_span(&self.level)
688            .join_span(&self.message)
689            .join_span(&self.args)
690            .join_span(&self.using)
691    }
692}
693
694fn parse_raise<'a>(parser: &mut Parser<'a, '_>) -> Result<Raise<'a>, ParseError> {
695    let raise_span = parser.consume_keyword(Keyword::RAISE)?;
696
697    // Optional level keyword
698    let level = match &parser.token {
699        Token::Ident(_, Keyword::DEBUG) => {
700            Some(RaiseLevel::Debug(parser.consume_keyword(Keyword::DEBUG)?))
701        }
702        Token::Ident(_, Keyword::LOG) => {
703            Some(RaiseLevel::Log(parser.consume_keyword(Keyword::LOG)?))
704        }
705        Token::Ident(_, Keyword::INFO) => {
706            Some(RaiseLevel::Info(parser.consume_keyword(Keyword::INFO)?))
707        }
708        Token::Ident(_, Keyword::NOTICE) => {
709            Some(RaiseLevel::Notice(parser.consume_keyword(Keyword::NOTICE)?))
710        }
711        Token::Ident(_, Keyword::WARNING) => Some(RaiseLevel::Warning(
712            parser.consume_keyword(Keyword::WARNING)?,
713        )),
714        Token::Ident(_, Keyword::EXCEPTION) => Some(RaiseLevel::Exception(
715            parser.consume_keyword(Keyword::EXCEPTION)?,
716        )),
717        _ => None,
718    };
719
720    // Optional message: either a string literal, SQLSTATE 'code', or a condition name identifier
721    let (mut message, mut args) = (None, Vec::new());
722
723    match &parser.token {
724        // RAISE [level] 'format' [, arg, ...]
725        Token::String(_, _) => {
726            message = Some(parser.consume_string()?);
727            while parser.skip_token(Token::Comma).is_some() {
728                args.push(parse_expression_unreserved(parser, PRIORITY_MAX)?);
729            }
730        }
731        // RAISE [level] SQLSTATE 'code'
732        Token::Ident(_, Keyword::SQLSTATE) => {
733            parser.consume_keyword(Keyword::SQLSTATE)?;
734            message = Some(parser.consume_string()?);
735        }
736        // RAISE [level] condition_name  (plain identifier that is not USING / semicolon / EOF)
737        Token::Ident(_, kw)
738            if !matches!(
739                kw,
740                Keyword::USING
741                    | Keyword::NOT_A_KEYWORD
742                    | Keyword::EXCEPTION
743                    | Keyword::NOTICE
744                    | Keyword::WARNING
745                    | Keyword::LOG
746                    | Keyword::INFO
747                    | Keyword::DEBUG
748            ) => {}
749        Token::Ident(_, Keyword::NOT_A_KEYWORD) => {
750            // unquoted plain identifier used as condition name
751            parser.consume_plain_identifier_unreserved()?;
752        }
753        _ => {} // bare RAISE; or RAISE level;
754    }
755
756    // Optional USING clause
757    let mut using = Vec::new();
758    if parser.skip_keyword(Keyword::USING).is_some() {
759        loop {
760            let opt_name = match &parser.token {
761                Token::Ident(_, Keyword::MESSAGE) => {
762                    RaiseOptionName::Message(parser.consume_keyword(Keyword::MESSAGE)?)
763                }
764                Token::Ident(_, Keyword::DETAIL) => {
765                    RaiseOptionName::Detail(parser.consume_keyword(Keyword::DETAIL)?)
766                }
767                Token::Ident(_, Keyword::HINT) => {
768                    RaiseOptionName::Hint(parser.consume_keyword(Keyword::HINT)?)
769                }
770                Token::Ident(_, Keyword::ERRCODE) => {
771                    RaiseOptionName::Errcode(parser.consume_keyword(Keyword::ERRCODE)?)
772                }
773                Token::Ident(_, Keyword::COLUMN) => {
774                    RaiseOptionName::Column(parser.consume_keyword(Keyword::COLUMN)?)
775                }
776                Token::Ident(_, Keyword::CONSTRAINT) => {
777                    RaiseOptionName::Constraint(parser.consume_keyword(Keyword::CONSTRAINT)?)
778                }
779                Token::Ident(_, Keyword::DATATYPE) => {
780                    RaiseOptionName::Datatype(parser.consume_keyword(Keyword::DATATYPE)?)
781                }
782                Token::Ident(_, Keyword::TABLE) => {
783                    RaiseOptionName::Table(parser.consume_keyword(Keyword::TABLE)?)
784                }
785                Token::Ident(_, Keyword::SCHEMA) => {
786                    RaiseOptionName::Schema(parser.consume_keyword(Keyword::SCHEMA)?)
787                }
788                _ => parser.expected_failure("RAISE USING option name")?,
789            };
790            let eq_span = parser.consume_token(Token::Eq)?;
791            let val = parse_expression_unreserved(parser, PRIORITY_MAX)?;
792            using.push((opt_name, eq_span, val));
793            if parser.skip_token(Token::Comma).is_none() {
794                break;
795            }
796        }
797    }
798
799    Ok(Raise {
800        raise_span,
801        level,
802        message,
803        args,
804        using,
805    })
806}
807
808#[derive(Clone, Debug)]
809pub enum SignalConditionInformationName {
810    ClassOrigin(Span),
811    SubclassOrigin(Span),
812    MessageText(Span),
813    MysqlErrno(Span),
814    ConstraintCatalog(Span),
815    ConstraintSchema(Span),
816    ConstraintName(Span),
817    CatalogName(Span),
818    SchemaName(Span),
819    TableName(Span),
820    ColumnName(Span),
821    CursorName(Span),
822}
823
824impl Spanned for SignalConditionInformationName {
825    fn span(&self) -> Span {
826        match self {
827            SignalConditionInformationName::ClassOrigin(span) => span.clone(),
828            SignalConditionInformationName::SubclassOrigin(span) => span.clone(),
829            SignalConditionInformationName::MessageText(span) => span.clone(),
830            SignalConditionInformationName::MysqlErrno(span) => span.clone(),
831            SignalConditionInformationName::ConstraintCatalog(span) => span.clone(),
832            SignalConditionInformationName::ConstraintSchema(span) => span.clone(),
833            SignalConditionInformationName::ConstraintName(span) => span.clone(),
834            SignalConditionInformationName::CatalogName(span) => span.clone(),
835            SignalConditionInformationName::SchemaName(span) => span.clone(),
836            SignalConditionInformationName::TableName(span) => span.clone(),
837            SignalConditionInformationName::ColumnName(span) => span.clone(),
838            SignalConditionInformationName::CursorName(span) => span.clone(),
839        }
840    }
841}
842
843/// Return statement
844#[derive(Clone, Debug)]
845pub struct Signal<'a> {
846    pub signal_span: Span,
847    pub sqlstate_span: Span,
848    pub value_span: Option<Span>,
849    pub sql_state: Expression<'a>,
850    pub set_span: Option<Span>,
851    pub sets: Vec<(SignalConditionInformationName, Span, Expression<'a>)>,
852}
853
854impl<'a> Spanned for Signal<'a> {
855    fn span(&self) -> Span {
856        self.signal_span
857            .join_span(&self.sqlstate_span)
858            .join_span(&self.value_span)
859            .join_span(&self.sql_state)
860            .join_span(&self.set_span)
861            .join_span(&self.sets)
862    }
863}
864
865fn parse_signal<'a>(parser: &mut Parser<'a, '_>) -> Result<Signal<'a>, ParseError> {
866    let signal_span = parser.consume_keyword(Keyword::SIGNAL)?;
867    let sqlstate_span = parser.consume_keyword(Keyword::SQLSTATE)?;
868    let value_span = parser.skip_keyword(Keyword::VALUE);
869    let sql_state = parse_expression_unreserved(parser, PRIORITY_MAX)?;
870    let mut sets = Vec::new();
871    let set_span = parser.skip_keyword(Keyword::SET);
872    if set_span.is_some() {
873        loop {
874            let v = match &parser.token {
875                Token::Ident(_, Keyword::CLASS_ORIGIN) => {
876                    SignalConditionInformationName::ClassOrigin(parser.consume())
877                }
878                Token::Ident(_, Keyword::SUBCLASS_ORIGIN) => {
879                    SignalConditionInformationName::SubclassOrigin(parser.consume())
880                }
881                Token::Ident(_, Keyword::MESSAGE_TEXT) => {
882                    SignalConditionInformationName::MessageText(parser.consume())
883                }
884                Token::Ident(_, Keyword::MYSQL_ERRNO) => {
885                    SignalConditionInformationName::MysqlErrno(parser.consume())
886                }
887                Token::Ident(_, Keyword::CONSTRAINT_CATALOG) => {
888                    SignalConditionInformationName::ConstraintCatalog(parser.consume())
889                }
890                Token::Ident(_, Keyword::CONSTRAINT_SCHEMA) => {
891                    SignalConditionInformationName::ConstraintSchema(parser.consume())
892                }
893                Token::Ident(_, Keyword::CONSTRAINT_NAME) => {
894                    SignalConditionInformationName::ConstraintName(parser.consume())
895                }
896                Token::Ident(_, Keyword::CATALOG_NAME) => {
897                    SignalConditionInformationName::CatalogName(parser.consume())
898                }
899                Token::Ident(_, Keyword::SCHEMA_NAME) => {
900                    SignalConditionInformationName::SchemaName(parser.consume())
901                }
902                Token::Ident(_, Keyword::TABLE_NAME) => {
903                    SignalConditionInformationName::TableName(parser.consume())
904                }
905                Token::Ident(_, Keyword::COLUMN_NAME) => {
906                    SignalConditionInformationName::ColumnName(parser.consume())
907                }
908                Token::Ident(_, Keyword::CURSOR_NAME) => {
909                    SignalConditionInformationName::CursorName(parser.consume())
910                }
911                _ => parser.expected_failure("Condition information item name")?,
912            };
913            let eq_span = parser.consume_token(Token::Eq)?;
914            let value = parse_expression_unreserved(parser, PRIORITY_MAX)?;
915            sets.push((v, eq_span, value));
916            if parser.skip_token(Token::Comma).is_none() {
917                break;
918            }
919        }
920    }
921    Ok(Signal {
922        signal_span,
923        sqlstate_span,
924        value_span,
925        sql_state,
926        set_span,
927        sets,
928    })
929}
930
931/// A single `WHEN condition THEN stmts` handler inside a PL/pgSQL EXCEPTION block
932#[derive(Clone, Debug)]
933pub struct ExceptionHandler<'a> {
934    /// Span of "WHEN"
935    pub when_span: Span,
936    /// Condition name (e.g. `division_by_zero`, `OTHERS`)
937    pub condition: crate::Identifier<'a>,
938    /// Span of "THEN"
939    pub then_span: Span,
940    /// Handler body statements
941    pub statements: Vec<Statement<'a>>,
942}
943
944impl<'a> Spanned for ExceptionHandler<'a> {
945    fn span(&self) -> Span {
946        self.when_span
947            .join_span(&self.condition)
948            .join_span(&self.then_span)
949            .join_span(&self.statements)
950    }
951}
952
953/// Block statement, for example in stored procedures
954#[derive(Clone, Debug)]
955pub struct Block<'a> {
956    /// Span of "BEGIN"
957    pub begin_span: Span,
958    /// Statements in block
959    pub statements: Vec<Statement<'a>>,
960    /// Span of "EXCEPTION" if present
961    pub exception_span: Option<Span>,
962    /// Exception handlers: `WHEN cond THEN stmts`
963    pub exception_handlers: Vec<ExceptionHandler<'a>>,
964    /// Span of "END"
965    pub end_span: Span,
966}
967
968impl Spanned for Block<'_> {
969    fn span(&self) -> Span {
970        self.begin_span
971            .join_span(&self.statements)
972            .join_span(&self.exception_span)
973            .join_span(&self.exception_handlers)
974            .join_span(&self.end_span)
975    }
976}
977
978/// Begin statement
979#[derive(Clone, Debug)]
980pub struct Begin {
981    /// Span of "BEGIN"
982    pub span: Span,
983}
984
985impl Spanned for Begin {
986    fn span(&self) -> Span {
987        self.span.clone()
988    }
989}
990
991/// End statement
992#[derive(Clone, Debug)]
993pub struct End {
994    /// Span of "END"
995    pub span: Span,
996}
997
998impl Spanned for End {
999    fn span(&self) -> Span {
1000        self.span.clone()
1001    }
1002}
1003
1004/// Commit statement
1005#[derive(Clone, Debug)]
1006pub struct Commit {
1007    /// Span of "COMMIT"
1008    pub span: Span,
1009}
1010
1011impl Spanned for Commit {
1012    fn span(&self) -> Span {
1013        self.span.clone()
1014    }
1015}
1016
1017/// Start transaction statement
1018#[derive(Clone, Debug)]
1019pub struct StartTransaction {
1020    /// Span of "START TRANSACTION"
1021    pub span: Span,
1022}
1023
1024impl Spanned for StartTransaction {
1025    fn span(&self) -> Span {
1026        self.span.clone()
1027    }
1028}
1029
1030/// Body of a DO statement
1031#[derive(Clone, Debug)]
1032pub enum DoBody<'a> {
1033    /// Parsed statements from `DO $$ BEGIN ... END $$`
1034    Statements(Vec<Statement<'a>>),
1035    /// Unparsed dollar-quoted string literal, e.g. `DO $$ ... $$`
1036    String(&'a str, Span),
1037}
1038
1039impl<'a> OptSpanned for DoBody<'a> {
1040    fn opt_span(&self) -> Option<Span> {
1041        match self {
1042            DoBody::Statements(s) => s.opt_span(),
1043            DoBody::String(_, span) => Some(span.clone()),
1044        }
1045    }
1046}
1047
1048/// Do statement
1049#[derive(Clone, Debug)]
1050pub struct Do<'a> {
1051    /// Span of "DO"
1052    pub do_span: Span,
1053    /// Body of the DO block
1054    pub body: DoBody<'a>,
1055}
1056
1057impl<'a> Spanned for Do<'a> {
1058    fn span(&self) -> Span {
1059        self.do_span.join_span(&self.body)
1060    }
1061}
1062
1063/// Invalid statement produced after recovering from parse error
1064#[derive(Clone, Debug)]
1065pub struct Invalid {
1066    /// Span of invalid statement
1067    pub span: Span,
1068}
1069
1070impl Spanned for Invalid {
1071    fn span(&self) -> Span {
1072        self.span.clone()
1073    }
1074}
1075
1076/// Stdin statement, used to represent input from stdin after a COPY statement
1077#[derive(Clone, Debug)]
1078pub struct Stdin<'a> {
1079    /// The input from stdin
1080    pub input: &'a str,
1081    /// Span of the input
1082    pub span: Span,
1083}
1084
1085impl Spanned for Stdin<'_> {
1086    fn span(&self) -> Span {
1087        self.span.clone()
1088    }
1089}
1090
1091/// ALTER SCHEMA statement (PostgreSQL)
1092#[derive(Clone, Debug)]
1093pub struct AlterSchema<'a> {
1094    /// Span of "ALTER SCHEMA"
1095    pub alter_schema_span: Span,
1096    /// The schema name
1097    pub name: QualifiedName<'a>,
1098    /// The action (RENAME TO, OWNER TO)
1099    pub action: AlterSchemaAction<'a>,
1100}
1101
1102#[derive(Clone, Debug)]
1103pub enum AlterSchemaAction<'a> {
1104    /// RENAME TO new_name
1105    RenameTo {
1106        rename_to_span: Span,
1107        new_name: QualifiedName<'a>,
1108    },
1109    /// OWNER TO new_owner
1110    OwnerTo {
1111        owner_to_span: Span,
1112        new_owner: crate::alter_table::AlterTableOwner<'a>,
1113    },
1114}
1115
1116impl<'a> Spanned for AlterSchemaAction<'a> {
1117    fn span(&self) -> Span {
1118        match self {
1119            AlterSchemaAction::RenameTo {
1120                rename_to_span,
1121                new_name,
1122            } => rename_to_span.join_span(new_name),
1123            AlterSchemaAction::OwnerTo {
1124                owner_to_span,
1125                new_owner,
1126            } => owner_to_span.join_span(new_owner),
1127        }
1128    }
1129}
1130
1131impl<'a> Spanned for AlterSchema<'a> {
1132    fn span(&self) -> Span {
1133        self.alter_schema_span
1134            .join_span(&self.name)
1135            .join_span(&self.action)
1136    }
1137}
1138
1139/// Parse ALTER SCHEMA statement (PostgreSQL)
1140pub(crate) fn parse_alter_schema<'a>(
1141    parser: &mut Parser<'a, '_>,
1142    alter_schema_span: Span,
1143) -> Result<AlterSchema<'a>, ParseError> {
1144    parser.postgres_only(&alter_schema_span);
1145    let name = parse_qualified_name_unreserved(parser)?;
1146    let action = match &parser.token {
1147        Token::Ident(_, Keyword::RENAME) => {
1148            let rename_to_span = parser.consume_keywords(&[Keyword::RENAME, Keyword::TO])?;
1149            let new_name = parse_qualified_name_unreserved(parser)?;
1150            AlterSchemaAction::RenameTo {
1151                rename_to_span,
1152                new_name,
1153            }
1154        }
1155        Token::Ident(_, Keyword::OWNER) => {
1156            let owner_to_span = parser.consume_keywords(&[Keyword::OWNER, Keyword::TO])?;
1157            let new_owner = crate::alter_table::parse_alter_owner(parser)?;
1158            AlterSchemaAction::OwnerTo {
1159                owner_to_span,
1160                new_owner,
1161            }
1162        }
1163        _ => parser.expected_failure("'RENAME TO' or 'OWNER TO' after ALTER SCHEMA ...")?,
1164    };
1165    Ok(AlterSchema {
1166        alter_schema_span,
1167        name,
1168        action,
1169    })
1170}
1171
1172pub fn parse_alter<'a>(parser: &mut Parser<'a, '_>) -> Result<Statement<'a>, ParseError> {
1173    let alter_span = parser.consume_keyword(Keyword::ALTER)?;
1174    let online = parser.skip_keyword(Keyword::ONLINE);
1175    let ignore = parser.skip_keyword(Keyword::IGNORE);
1176
1177    match &parser.token {
1178        Token::Ident(_, Keyword::SCHEMA) => {
1179            let schema_span = parser.consume_keyword(Keyword::SCHEMA)?;
1180            Ok(Statement::AlterSchema(Box::new(parse_alter_schema(
1181                parser,
1182                alter_span.join_span(&schema_span),
1183            )?)))
1184        }
1185        Token::Ident(_, Keyword::TABLE) => Ok(Statement::AlterTable(Box::new(parse_alter_table(
1186            parser, alter_span, online, ignore,
1187        )?))),
1188        Token::Ident(_, Keyword::SEQUENCE) => {
1189            let sequence_span = parser.consume_keyword(Keyword::SEQUENCE)?;
1190            Ok(Statement::AlterSequence(Box::new(parse_alter_sequence(
1191                parser,
1192                alter_span.join_span(&sequence_span),
1193            )?)))
1194        }
1195        Token::Ident(_, Keyword::ROLE) => Ok(Statement::AlterRole(Box::new(parse_alter_role(
1196            parser, alter_span,
1197        )?))),
1198        Token::Ident(_, Keyword::TYPE) => {
1199            let type_span = parser.consume_keyword(Keyword::TYPE)?;
1200            Ok(Statement::AlterType(Box::new(
1201                crate::alter_type::parse_alter_type(parser, alter_span.join_span(&type_span))?,
1202            )))
1203        }
1204        Token::Ident(_, Keyword::OPERATOR) => {
1205            let operator_span = parser.consume_keyword(Keyword::OPERATOR)?;
1206            match &parser.token {
1207                Token::Ident(_, Keyword::CLASS) => {
1208                    let class_span = parser.consume_keyword(Keyword::CLASS)?;
1209                    Ok(Statement::AlterOperatorClass(Box::new(
1210                        crate::operator::parse_alter_operator_class(
1211                            parser,
1212                            alter_span.join_span(&operator_span).join_span(&class_span),
1213                        )?,
1214                    )))
1215                }
1216                Token::Ident(_, Keyword::FAMILY) => {
1217                    let family_span = parser.consume_keyword(Keyword::FAMILY)?;
1218                    Ok(Statement::AlterOperatorFamily(Box::new(
1219                        crate::operator::parse_alter_operator_family(
1220                            parser,
1221                            alter_span.join_span(&operator_span).join_span(&family_span),
1222                        )?,
1223                    )))
1224                }
1225                _ => Ok(Statement::AlterOperator(Box::new(
1226                    crate::operator::parse_alter_operator(
1227                        parser,
1228                        alter_span.join_span(&operator_span),
1229                    )?,
1230                ))),
1231            }
1232        }
1233        _ => parser.expected_failure("alterable"),
1234    }
1235}
1236
1237/// CALL statement — invokes a stored procedure
1238#[derive(Clone, Debug)]
1239pub struct Call<'a> {
1240    /// Span of "CALL"
1241    pub call_span: Span,
1242    /// Name of the procedure (possibly qualified)
1243    pub name: crate::QualifiedName<'a>,
1244    /// Argument expressions
1245    pub args: Vec<Expression<'a>>,
1246}
1247
1248impl<'a> Spanned for Call<'a> {
1249    fn span(&self) -> Span {
1250        self.call_span.join_span(&self.name).join_span(&self.args)
1251    }
1252}
1253
1254fn parse_call<'a>(parser: &mut Parser<'a, '_>) -> Result<Call<'a>, ParseError> {
1255    let call_span = parser.consume_keyword(Keyword::CALL)?;
1256    let name = parse_qualified_name_unreserved(parser)?;
1257    let mut args = Vec::new();
1258    parser.consume_token(Token::LParen)?;
1259    parser.recovered("')'", &|t| t == &Token::RParen, |parser| {
1260        loop {
1261            if matches!(parser.token, Token::RParen) {
1262                break;
1263            }
1264            args.push(parse_expression_unreserved(parser, PRIORITY_MAX)?);
1265            if parser.skip_token(Token::Comma).is_none() {
1266                break;
1267            }
1268        }
1269        Ok(())
1270    })?;
1271    parser.consume_token(Token::RParen)?;
1272    Ok(Call {
1273        call_span,
1274        name,
1275        args,
1276    })
1277}
1278
1279/// Object type for COMMENT ON
1280#[derive(Clone, Debug)]
1281pub enum CommentOnObjectType {
1282    Column(Span),
1283    Table(Span),
1284}
1285
1286impl Spanned for CommentOnObjectType {
1287    fn span(&self) -> Span {
1288        match self {
1289            CommentOnObjectType::Column(s) => s.clone(),
1290            CommentOnObjectType::Table(s) => s.clone(),
1291        }
1292    }
1293}
1294
1295/// PostgreSQL COMMENT ON object IS 'text' statement
1296#[derive(Clone, Debug)]
1297pub struct CommentOn<'a> {
1298    /// Span of "COMMENT ON"
1299    pub comment_on_span: Span,
1300    /// Type of object being commented
1301    pub object_type: CommentOnObjectType,
1302    /// Name of the object
1303    pub name: QualifiedName<'a>,
1304    /// Span of "IS"
1305    pub is_span: Span,
1306    /// Comment text, or None if NULL (clears comment)
1307    pub comment: Option<crate::SString<'a>>,
1308}
1309
1310impl<'a> Spanned for CommentOn<'a> {
1311    fn span(&self) -> Span {
1312        self.comment_on_span
1313            .join_span(&self.object_type)
1314            .join_span(&self.name)
1315            .join_span(&self.is_span)
1316            .join_span(&self.comment)
1317    }
1318}
1319
1320fn parse_comment_on<'a>(
1321    parser: &mut Parser<'a, '_>,
1322    comment_span: Span,
1323) -> Result<Statement<'a>, ParseError> {
1324    parser.postgres_only(&comment_span);
1325    let on_span = parser.consume_keyword(Keyword::ON)?;
1326    let comment_on_span = comment_span.join_span(&on_span);
1327
1328    let object_type = match &parser.token {
1329        Token::Ident(_, Keyword::COLUMN) => {
1330            CommentOnObjectType::Column(parser.consume_keyword(Keyword::COLUMN)?)
1331        }
1332        Token::Ident(_, Keyword::TABLE) => {
1333            CommentOnObjectType::Table(parser.consume_keyword(Keyword::TABLE)?)
1334        }
1335        _ => parser.expected_failure("'COLUMN' or 'TABLE'")?,
1336    };
1337
1338    let name = parse_qualified_name_unreserved(parser)?;
1339    let is_span = parser.consume_keyword(Keyword::IS)?;
1340    let comment = if parser.skip_keyword(Keyword::NULL).is_some() {
1341        None
1342    } else {
1343        Some(parser.consume_string()?)
1344    };
1345    Ok(Statement::CommentOn(Box::new(CommentOn {
1346        comment_on_span,
1347        object_type,
1348        name,
1349        is_span,
1350        comment,
1351    })))
1352}
1353
1354/// SQL statement
1355#[derive(Clone, Debug)]
1356pub enum Statement<'a> {
1357    AlterSchema(Box<AlterSchema<'a>>),
1358    CreateIndex(Box<CreateIndex<'a>>),
1359    CreateTable(Box<CreateTable<'a>>),
1360    CreateView(Box<CreateView<'a>>),
1361    CreateTrigger(Box<CreateTrigger<'a>>),
1362    CreateFunction(Box<CreateFunction<'a>>),
1363    CreateProcedure(Box<CreateProcedure<'a>>),
1364    CreateDatabase(Box<CreateDatabase<'a>>),
1365    CreateSchema(Box<CreateSchema<'a>>),
1366    CreateSequence(Box<CreateSequence<'a>>),
1367    CreateServer(Box<CreateServer<'a>>),
1368    CreateRole(Box<CreateRole<'a>>),
1369    CreateOperator(Box<CreateOperator<'a>>),
1370    CreateTypeEnum(Box<CreateTypeEnum<'a>>),
1371    CreateOperatorClass(Box<CreateOperatorClass<'a>>),
1372    CreateOperatorFamily(Box<CreateOperatorFamily<'a>>),
1373    CreateExtension(Box<CreateExtension<'a>>),
1374    CreateDomain(Box<CreateDomain<'a>>),
1375    CreateConstraintTrigger(Box<CreateConstraintTrigger<'a>>),
1376    CreateTablePartitionOf(Box<CreateTablePartitionOf<'a>>),
1377    AlterOperator(Box<AlterOperator<'a>>),
1378    AlterOperatorClass(Box<AlterOperatorClass<'a>>),
1379    Select(Box<Select<'a>>),
1380    Delete(Box<Delete<'a>>),
1381    InsertReplace(Box<InsertReplace<'a>>),
1382    Update(Box<Update<'a>>),
1383    Unlock(Box<Unlock>),
1384    DropIndex(Box<DropIndex<'a>>),
1385    DropTable(Box<DropTable<'a>>),
1386    DropFunction(Box<DropFunction<'a>>),
1387    DropProcedure(Box<DropProcedure<'a>>),
1388    DropSequence(Box<DropSequence<'a>>),
1389    DropEvent(Box<DropEvent<'a>>),
1390    DropDatabase(Box<DropDatabase<'a>>),
1391    DropSchema(Box<DropSchema<'a>>),
1392    DropServer(Box<DropServer<'a>>),
1393    DropTrigger(Box<DropTrigger<'a>>),
1394    DropView(Box<DropView<'a>>),
1395    DropExtension(Box<DropExtension<'a>>),
1396    DropOperator(Box<DropOperator<'a>>),
1397    DropOperatorFamily(Box<DropOperatorFamily<'a>>),
1398    DropOperatorClass(Box<DropOperatorClass<'a>>),
1399    DropDomain(Box<DropDomain<'a>>),
1400    DropType(Box<DropType<'a>>),
1401    Set(Box<Set<'a>>),
1402    Signal(Box<Signal<'a>>),
1403    Kill(Box<Kill<'a>>),
1404    ShowTables(Box<ShowTables<'a>>),
1405    ShowDatabases(Box<ShowDatabases>),
1406    ShowProcessList(Box<ShowProcessList>),
1407    ShowVariables(Box<ShowVariables<'a>>),
1408    ShowStatus(Box<ShowStatus<'a>>),
1409    ShowColumns(Box<ShowColumns<'a>>),
1410    ShowCreateTable(Box<ShowCreateTable<'a>>),
1411    ShowCreateDatabase(Box<ShowCreateDatabase<'a>>),
1412    ShowCreateView(Box<ShowCreateView<'a>>),
1413    ShowCharacterSet(Box<ShowCharacterSet<'a>>),
1414    ShowCollation(Box<ShowCollation<'a>>),
1415    ShowEngines(Box<ShowEngines>),
1416    AlterTable(Box<AlterTable<'a>>),
1417    AlterRole(Box<AlterRole<'a>>),
1418    AlterSequence(Box<AlterSequence<'a>>),
1419    AlterType(Box<AlterType<'a>>),
1420    AlterOperatorFamily(Box<AlterOperatorFamily<'a>>),
1421    Block(Box<Block<'a>>),
1422    Begin(Box<Begin>),
1423    End(Box<End>),
1424    Commit(Box<Commit>),
1425    StartTransaction(Box<StartTransaction>),
1426    If(Box<If<'a>>),
1427    /// Invalid statement produced after recovering from parse error
1428    Invalid(Box<Invalid>),
1429    Lock(Box<Lock<'a>>),
1430    CompoundQuery(Box<CompoundQuery<'a>>),
1431    Case(Box<CaseStatement<'a>>),
1432    CopyFrom(Box<CopyFrom<'a>>),
1433    CopyTo(Box<CopyTo<'a>>),
1434    Stdin(Box<Stdin<'a>>),
1435    Do(Box<Do<'a>>),
1436    TruncateTable(Box<TruncateTable<'a>>),
1437    RenameTable(Box<RenameTable<'a>>),
1438    WithQuery(Box<WithQuery<'a>>),
1439    Return(Box<Return<'a>>),
1440    /// PL/pgSQL PERFORM statement
1441    Perform(Box<Perform<'a>>),
1442    /// PL/pgSQL RAISE statement
1443    Raise(Box<Raise<'a>>),
1444    /// PL/pgSQL assignment: `target := value`
1445    Assign(Box<Assign<'a>>),
1446    /// PL/pgSQL EXECUTE for dynamic SQL
1447    PlpgsqlExecute(Box<PlpgsqlExecute<'a>>),
1448    Flush(Box<Flush<'a>>),
1449    /// PostgreSQL VALUES statement
1450    Values(Box<crate::values::Values<'a>>),
1451    /// PostgreSQL EXPLAIN statement
1452    Explain(Box<Explain<'a>>),
1453    /// PostgreSQL DECLARE cursor statement
1454    DeclareCursor(Box<DeclareCursor<'a>>),
1455    /// MariaDB/MySQL DECLARE variable inside a stored procedure/function
1456    DeclareVariable(Box<DeclareVariable<'a>>),
1457    /// MariaDB/MySQL DECLARE cursor inside a stored procedure/function
1458    DeclareCursorMariaDb(Box<DeclareCursorMariaDb<'a>>),
1459    /// MariaDB/MySQL DECLARE handler inside a stored procedure/function
1460    DeclareHandler(Box<DeclareHandler<'a>>),
1461    /// MariaDB/MySQL OPEN cursor statement
1462    OpenCursor(Box<OpenCursor<'a>>),
1463    /// MariaDB/MySQL CLOSE cursor statement
1464    CloseCursor(Box<CloseCursor<'a>>),
1465    /// MariaDB/MySQL FETCH cursor statement
1466    FetchCursor(Box<FetchCursor<'a>>),
1467    /// MariaDB/MySQL LEAVE label statement
1468    Leave(Box<Leave<'a>>),
1469    /// MariaDB/MySQL ITERATE label statement
1470    Iterate(Box<Iterate<'a>>),
1471    /// MariaDB/MySQL LOOP body END LOOP construct
1472    Loop(Box<Loop<'a>>),
1473    /// MariaDB/MySQL WHILE condition DO body END WHILE construct
1474    While(Box<While<'a>>),
1475    /// MariaDB/MySQL REPEAT body UNTIL condition END REPEAT construct
1476    Repeat(Box<Repeat<'a>>),
1477    /// PostgreSQL REFRESH MATERIALIZED VIEW statement
1478    RefreshMaterializedView(Box<RefreshMaterializedView<'a>>),
1479    /// PostgreSQL PREPARE statement
1480    Prepare(Box<Prepare<'a>>),
1481    /// CALL statement for invoking stored procedures
1482    Call(Box<Call<'a>>),
1483    /// GRANT privileges statement
1484    Grant(Box<Grant<'a>>),
1485    /// PostgreSQL COMMENT ON statement
1486    CommentOn(Box<CommentOn<'a>>),
1487    /// PostgreSQL EXECUTE FUNCTION in trigger body
1488    ExecuteFunction(Box<ExecuteFunction<'a>>),
1489    /// ANALYZE statement
1490    Analyze(Box<Analyze<'a>>),
1491}
1492
1493impl<'a> Spanned for Statement<'a> {
1494    fn span(&self) -> Span {
1495        match &self {
1496            Statement::AlterOperator(v) => v.span(),
1497            Statement::AlterSchema(v) => v.span(),
1498            Statement::CreateIndex(v) => v.span(),
1499            Statement::CreateTable(v) => v.span(),
1500            Statement::CreateView(v) => v.span(),
1501            Statement::CreateTrigger(v) => v.span(),
1502            Statement::CreateFunction(v) => v.span(),
1503            Statement::CreateProcedure(v) => v.span(),
1504            Statement::CreateDatabase(v) => v.span(),
1505            Statement::CreateSchema(v) => v.span(),
1506            Statement::CreateSequence(v) => v.span(),
1507            Statement::CreateServer(v) => v.span(),
1508            Statement::CreateRole(v) => v.span(),
1509            Statement::CreateOperator(v) => v.span(),
1510            Statement::Select(v) => v.span(),
1511            Statement::Delete(v) => v.span(),
1512            Statement::InsertReplace(v) => v.span(),
1513            Statement::Update(v) => v.span(),
1514            Statement::Unlock(v) => v.span(),
1515            Statement::DropDatabase(v) => v.span(),
1516            Statement::DropSchema(v) => v.span(),
1517            Statement::DropDomain(v) => v.span(),
1518            Statement::DropType(v) => v.span(),
1519            Statement::DropEvent(v) => v.span(),
1520            Statement::DropExtension(v) => v.span(),
1521            Statement::DropFunction(v) => v.span(),
1522            Statement::DropIndex(v) => v.span(),
1523            Statement::DropOperator(v) => v.span(),
1524            Statement::DropOperatorClass(v) => v.span(),
1525            Statement::AlterOperatorClass(v) => v.span(),
1526            Statement::DropProcedure(v) => v.span(),
1527            Statement::DropSequence(v) => v.span(),
1528            Statement::DropServer(v) => v.span(),
1529            Statement::DropTable(v) => v.span(),
1530            Statement::DropTrigger(v) => v.span(),
1531            Statement::DropView(v) => v.span(),
1532            Statement::Set(v) => v.span(),
1533            Statement::AlterOperatorFamily(v) => v.span(),
1534            Statement::DropOperatorFamily(v) => v.span(),
1535            Statement::AlterRole(v) => v.span(),
1536            Statement::AlterSequence(v) => v.span(),
1537            Statement::AlterType(v) => v.span(),
1538            Statement::AlterTable(v) => v.span(),
1539            Statement::Block(v) => v.opt_span().expect("Span of block"),
1540            Statement::If(v) => v.span(),
1541            Statement::Invalid(v) => v.span(),
1542            Statement::Lock(v) => v.span(),
1543            Statement::CompoundQuery(v) => v.span(),
1544            Statement::Case(v) => v.span(),
1545            Statement::CopyFrom(v) => v.span(),
1546            Statement::CopyTo(v) => v.span(),
1547            Statement::Stdin(v) => v.span(),
1548            Statement::Begin(v) => v.span(),
1549            Statement::End(v) => v.span(),
1550            Statement::Commit(v) => v.span(),
1551            Statement::StartTransaction(v) => v.span(),
1552            Statement::CreateTypeEnum(v) => v.span(),
1553            Statement::CreateOperatorClass(v) => v.span(),
1554            Statement::Do(v) => v.opt_span().expect("Span of block"),
1555            Statement::TruncateTable(v) => v.span(),
1556            Statement::RenameTable(v) => v.span(),
1557            Statement::WithQuery(v) => v.span(),
1558            Statement::Return(v) => v.span(),
1559            Statement::Perform(v) => v.span(),
1560            Statement::Raise(v) => v.span(),
1561            Statement::Assign(v) => v.span(),
1562            Statement::PlpgsqlExecute(v) => v.span(),
1563            Statement::Signal(v) => v.span(),
1564            Statement::Kill(v) => v.span(),
1565            Statement::ShowTables(v) => v.span(),
1566            Statement::ShowDatabases(v) => v.span(),
1567            Statement::ShowProcessList(v) => v.span(),
1568            Statement::ShowVariables(v) => v.span(),
1569            Statement::ShowStatus(v) => v.span(),
1570            Statement::ShowColumns(v) => v.span(),
1571            Statement::ShowCreateTable(v) => v.span(),
1572            Statement::ShowCreateDatabase(v) => v.span(),
1573            Statement::ShowCreateView(v) => v.span(),
1574            Statement::ShowCharacterSet(v) => v.span(),
1575            Statement::ShowCollation(v) => v.span(),
1576            Statement::ShowEngines(v) => v.span(),
1577            Statement::Flush(v) => v.span(),
1578            Statement::CreateOperatorFamily(v) => v.span(),
1579            Statement::Values(v) => v.span(),
1580            Statement::CreateExtension(v) => v.span(),
1581            Statement::CreateDomain(v) => v.span(),
1582            Statement::CreateConstraintTrigger(v) => v.span(),
1583            Statement::CreateTablePartitionOf(v) => v.span(),
1584            Statement::Explain(v) => v.span(),
1585            Statement::DeclareCursor(v) => v.span(),
1586            Statement::DeclareVariable(v) => v.span(),
1587            Statement::DeclareCursorMariaDb(v) => v.span(),
1588            Statement::DeclareHandler(v) => v.span(),
1589            Statement::OpenCursor(v) => v.span(),
1590            Statement::CloseCursor(v) => v.span(),
1591            Statement::FetchCursor(v) => v.span(),
1592            Statement::Leave(v) => v.span(),
1593            Statement::Iterate(v) => v.span(),
1594            Statement::Loop(v) => v.span(),
1595            Statement::While(v) => v.span(),
1596            Statement::Repeat(v) => v.span(),
1597            Statement::RefreshMaterializedView(v) => v.span(),
1598            Statement::Prepare(v) => v.span(),
1599            Statement::Call(v) => v.span(),
1600            Statement::Grant(v) => v.span(),
1601            Statement::CommentOn(v) => v.span(),
1602            Statement::ExecuteFunction(v) => v.span(),
1603            Statement::Analyze(v) => v.span(),
1604        }
1605    }
1606}
1607
1608impl Statement<'_> {
1609    fn reads_from_stdin(&self) -> bool {
1610        match self {
1611            Statement::CopyFrom(v) => v.reads_from_stdin(),
1612            _ => false,
1613        }
1614    }
1615}
1616
1617pub(crate) fn parse_statement<'a>(
1618    parser: &mut Parser<'a, '_>,
1619) -> Result<Option<Statement<'a>>, ParseError> {
1620    Ok(match &parser.token {
1621        Token::Ident(_, Keyword::CREATE) => Some(parse_create(parser)?),
1622        Token::Ident(_, Keyword::DROP) => Some(parse_drop(parser)?),
1623        Token::Ident(_, Keyword::SELECT) | Token::LParen => Some(parse_compound_query(parser)?),
1624        Token::Ident(_, Keyword::VALUES) => {
1625            Some(Statement::Values(Box::new(parse_values(parser)?)))
1626        }
1627        Token::Ident(_, Keyword::DELETE) => {
1628            Some(Statement::Delete(Box::new(parse_delete(parser)?)))
1629        }
1630        Token::Ident(_, Keyword::INSERT | Keyword::REPLACE) => Some(Statement::InsertReplace(
1631            Box::new(parse_insert_replace(parser)?),
1632        )),
1633        Token::Ident(_, Keyword::UPDATE) => {
1634            Some(Statement::Update(Box::new(parse_update(parser)?)))
1635        }
1636        Token::Ident(_, Keyword::SET) => Some(Statement::Set(Box::new(parse_set(parser)?))),
1637        Token::Ident(_, Keyword::SIGNAL) => {
1638            Some(Statement::Signal(Box::new(parse_signal(parser)?)))
1639        }
1640        Token::Ident(_, Keyword::KILL) => Some(Statement::Kill(Box::new(parse_kill(parser)?))),
1641        Token::Ident(_, Keyword::SHOW) => Some(parse_show(parser)?),
1642        Token::Ident(_, Keyword::BEGIN) => Some(if parser.permit_compound_statements {
1643            Statement::Block(Box::new(parse_block(parser)?))
1644        } else {
1645            Statement::Begin(Box::new(parse_begin(parser)?))
1646        }),
1647        Token::Ident(_, Keyword::END) if !parser.permit_compound_statements => {
1648            Some(Statement::End(Box::new(parse_end(parser)?)))
1649        }
1650        Token::Ident(_, Keyword::START) => Some(Statement::StartTransaction(Box::new(
1651            parse_start_transaction(parser)?,
1652        ))),
1653        Token::Ident(_, Keyword::COMMIT) => {
1654            Some(Statement::Commit(Box::new(parse_commit(parser)?)))
1655        }
1656        Token::Ident(_, Keyword::IF) => Some(Statement::If(Box::new(parse_if(parser)?))),
1657        Token::Ident(_, Keyword::RETURN) => {
1658            Some(Statement::Return(Box::new(parse_return(parser)?)))
1659        }
1660        Token::Ident(_, Keyword::PERFORM) => {
1661            Some(Statement::Perform(Box::new(parse_perform(parser)?)))
1662        }
1663        Token::Ident(_, Keyword::RAISE) => Some(Statement::Raise(Box::new(parse_raise(parser)?))),
1664        // PL/pgSQL EXECUTE (dynamic SQL) - only inside function/procedure bodies
1665        Token::Ident(_, Keyword::EXECUTE) if parser.permit_compound_statements => Some(
1666            Statement::PlpgsqlExecute(Box::new(parse_plpgsql_execute(parser)?)),
1667        ),
1668        Token::Ident(_, Keyword::ALTER) => Some(parse_alter(parser)?),
1669        Token::Ident(_, Keyword::CASE) => {
1670            Some(Statement::Case(Box::new(parse_case_statement(parser)?)))
1671        }
1672        Token::Ident(_, Keyword::COPY) => Some(parse_copy_statement(parser)?),
1673        Token::Ident(_, Keyword::DO) => Some(parse_do(parser)?),
1674        Token::Ident(_, Keyword::LOCK) => Some(Statement::Lock(Box::new(parse_lock(parser)?))),
1675        Token::Ident(_, Keyword::UNLOCK) => {
1676            Some(Statement::Unlock(Box::new(parse_unlock(parser)?)))
1677        }
1678        Token::Ident(_, Keyword::TRUNCATE) => Some(Statement::TruncateTable(Box::new(
1679            parse_truncate_table(parser)?,
1680        ))),
1681        Token::Ident(_, Keyword::RENAME) => Some(Statement::RenameTable(Box::new(
1682            parse_rename_table(parser)?,
1683        ))),
1684        Token::Ident(_, Keyword::WITH) => {
1685            Some(Statement::WithQuery(Box::new(parse_with_query(parser)?)))
1686        }
1687        Token::Ident(_, Keyword::FLUSH) => Some(Statement::Flush(Box::new(parse_flush(parser)?))),
1688        Token::Ident(_, Keyword::EXPLAIN) => {
1689            Some(Statement::Explain(Box::new(parse_explain(parser)?)))
1690        }
1691        Token::Ident(_, Keyword::DECLARE) => Some(
1692            if parser.permit_compound_statements && parser.options.dialect.is_maria() {
1693                parse_declare_maria(parser)?
1694            } else {
1695                Statement::DeclareCursor(Box::new(parse_declare_cursor(parser)?))
1696            },
1697        ),
1698        Token::Ident(_, Keyword::PREPARE) => {
1699            Some(Statement::Prepare(Box::new(parse_prepare(parser)?)))
1700        }
1701        Token::Ident(_, Keyword::REFRESH) => Some(Statement::RefreshMaterializedView(Box::new(
1702            parse_refresh_materialized_view(parser)?,
1703        ))),
1704        Token::Ident(_, Keyword::CALL) => Some(Statement::Call(Box::new(parse_call(parser)?))),
1705        Token::Ident(_, Keyword::GRANT) => Some(Statement::Grant(Box::new(parse_grant(parser)?))),
1706        Token::Ident(_, Keyword::COMMENT) => {
1707            let comment_span = parser.consume_keyword(Keyword::COMMENT)?;
1708            Some(parse_comment_on(parser, comment_span)?)
1709        }
1710        Token::Ident(_, Keyword::ANALYZE) => {
1711            let analyze_span = parser.consume_keyword(Keyword::ANALYZE)?;
1712            let mut tables = Vec::new();
1713            if !matches!(parser.token, Token::Delimiter | Token::Eof) {
1714                tables.push(parse_qualified_name_unreserved(parser)?);
1715                while parser.skip_token(Token::Comma).is_some() {
1716                    tables.push(parse_qualified_name_unreserved(parser)?);
1717                }
1718            }
1719            Some(Statement::Analyze(Box::new(Analyze {
1720                analyze_span,
1721                tables,
1722            })))
1723        }
1724        // MariaDB compound-block control statements
1725        Token::Ident(_, Keyword::OPEN)
1726            if parser.permit_compound_statements && parser.options.dialect.is_maria() =>
1727        {
1728            Some(Statement::OpenCursor(Box::new(parse_open_cursor(parser)?)))
1729        }
1730        Token::Ident(_, Keyword::CLOSE)
1731            if parser.permit_compound_statements && parser.options.dialect.is_maria() =>
1732        {
1733            Some(Statement::CloseCursor(Box::new(parse_close_cursor(
1734                parser,
1735            )?)))
1736        }
1737        Token::Ident(_, Keyword::FETCH)
1738            if parser.permit_compound_statements && parser.options.dialect.is_maria() =>
1739        {
1740            Some(Statement::FetchCursor(Box::new(parse_fetch_cursor(
1741                parser,
1742            )?)))
1743        }
1744        Token::Ident(_, Keyword::LEAVE)
1745            if parser.permit_compound_statements && parser.options.dialect.is_maria() =>
1746        {
1747            Some(Statement::Leave(Box::new(parse_leave(parser)?)))
1748        }
1749        Token::Ident(_, Keyword::ITERATE)
1750            if parser.permit_compound_statements && parser.options.dialect.is_maria() =>
1751        {
1752            Some(Statement::Iterate(Box::new(parse_iterate(parser)?)))
1753        }
1754        Token::Ident(_, Keyword::LOOP)
1755            if parser.permit_compound_statements && parser.options.dialect.is_maria() =>
1756        {
1757            Some(Statement::Loop(Box::new(parse_loop(parser, None)?)))
1758        }
1759        Token::Ident(_, Keyword::WHILE)
1760            if parser.permit_compound_statements && parser.options.dialect.is_maria() =>
1761        {
1762            Some(Statement::While(Box::new(parse_while(parser, None)?)))
1763        }
1764        Token::Ident(_, Keyword::REPEAT)
1765            if parser.permit_compound_statements && parser.options.dialect.is_maria() =>
1766        {
1767            Some(Statement::Repeat(Box::new(parse_repeat(parser, None)?)))
1768        }
1769        // PL/pgSQL NULL statement: `NULL;` — syntactic no-op, valid everywhere a statement is.
1770        // Emit as Perform(NULL) so the evaluator can silently ignore it.
1771        Token::Ident(_, Keyword::NULL) if parser.permit_compound_statements => {
1772            let null_span = parser.consume_keyword(Keyword::NULL)?;
1773            Some(Statement::Perform(Box::new(Perform {
1774                perform_span: null_span.clone(),
1775                expr: Expression::Null(Box::new(NullExpression { span: null_span })),
1776            })))
1777        }
1778        // PL/pgSQL assignment: `target := expression` or `target = expression` (PostgreSQL)
1779        // Must come last - only active inside compound blocks and only when the
1780        // next token is not a block-terminating keyword (END, ELSE, EXCEPTION, …).
1781        _ if parser.permit_compound_statements
1782            && !matches!(
1783                parser.token,
1784                Token::Ident(
1785                    _,
1786                    Keyword::END
1787                        | Keyword::EXCEPTION
1788                        | Keyword::ELSE
1789                        | Keyword::ELSEIF
1790                        | Keyword::ELSIF
1791                        | Keyword::WHEN
1792                        | Keyword::UNTIL
1793                ) | Token::Delimiter
1794                    | Token::Eof
1795            ) =>
1796        {
1797            // Parse the LHS stopping before `=` / `:=` so the expression parser
1798            // doesn't greedily consume either as a binary operator.
1799            let target = parse_expression_unreserved(parser, PRIORITY_CMP)?;
1800            let assign_span = if matches!(parser.token, Token::ColonEq) {
1801                parser.consume_token(Token::ColonEq)?
1802            } else if parser.options.dialect.is_postgresql() && matches!(parser.token, Token::Eq) {
1803                parser.consume_token(Token::Eq)?
1804            } else {
1805                parser.consume_token(Token::ColonEq)? // will emit "Expected ':='" error
1806            };
1807            let value = parse_select_body(parser, assign_span.clone())?;
1808            Some(Statement::Assign(Box::new(Assign {
1809                target,
1810                assign_span,
1811                value,
1812            })))
1813        }
1814        _ => None,
1815    })
1816}
1817
1818pub(crate) fn parse_do<'a>(parser: &mut Parser<'a, '_>) -> Result<Statement<'a>, ParseError> {
1819    let do_span = parser.consume_keyword(Keyword::DO)?;
1820    if let Token::String(s, StringType::DollarQuoted) = parser.token {
1821        // PostgreSQL: DO $$...$$ — the body is a dollar-quoted string literal
1822        let body_str = s;
1823        let body_span = parser.consume();
1824        return Ok(Statement::Do(Box::new(Do {
1825            do_span,
1826            body: DoBody::String(body_str, body_span),
1827        })));
1828    }
1829    parser.consume_token(Token::DoubleDollar)?;
1830    let block = parse_block(parser)?;
1831    parser.consume_token(Token::DoubleDollar)?;
1832    Ok(Statement::Do(Box::new(Do {
1833        do_span,
1834        body: DoBody::Statements(block.statements),
1835    })))
1836}
1837
1838/// PostgreSQL EXPLAIN output format
1839#[derive(Clone, Debug)]
1840pub enum ExplainFormat {
1841    Text(Span),
1842    Xml(Span),
1843    Json(Span),
1844    Yaml(Span),
1845}
1846
1847impl Spanned for ExplainFormat {
1848    fn span(&self) -> Span {
1849        match self {
1850            ExplainFormat::Text(s)
1851            | ExplainFormat::Xml(s)
1852            | ExplainFormat::Json(s)
1853            | ExplainFormat::Yaml(s) => s.clone(),
1854        }
1855    }
1856}
1857
1858/// A single option in a parenthesized EXPLAIN (...) list
1859#[derive(Clone, Debug)]
1860pub enum ExplainOption {
1861    Analyze(Span, Option<(bool, Span)>),
1862    Verbose(Span, Option<(bool, Span)>),
1863    Costs(Span, Option<(bool, Span)>),
1864    Settings(Span, Option<(bool, Span)>),
1865    GenericPlan(Span, Option<(bool, Span)>),
1866    Buffers(Span, Option<(bool, Span)>),
1867    Wal(Span, Option<(bool, Span)>),
1868    Timing(Span, Option<(bool, Span)>),
1869    Summary(Span, Option<(bool, Span)>),
1870    Memory(Span, Option<(bool, Span)>),
1871    Format(Span, ExplainFormat),
1872}
1873
1874impl Spanned for ExplainOption {
1875    fn span(&self) -> Span {
1876        match self {
1877            ExplainOption::Analyze(s, b)
1878            | ExplainOption::Verbose(s, b)
1879            | ExplainOption::Costs(s, b)
1880            | ExplainOption::Settings(s, b)
1881            | ExplainOption::GenericPlan(s, b)
1882            | ExplainOption::Buffers(s, b)
1883            | ExplainOption::Wal(s, b)
1884            | ExplainOption::Timing(s, b)
1885            | ExplainOption::Summary(s, b)
1886            | ExplainOption::Memory(s, b) => s.join_span(&b.as_ref().map(|(_, vs)| vs.clone())),
1887            ExplainOption::Format(s, fmt) => s.join_span(fmt),
1888        }
1889    }
1890}
1891
1892/// PostgreSQL EXPLAIN statement
1893#[derive(Clone, Debug)]
1894pub struct Explain<'a> {
1895    pub explain_span: Span,
1896    pub options: Vec<ExplainOption>,
1897    pub statement: Box<Statement<'a>>,
1898}
1899
1900impl<'a> Spanned for Explain<'a> {
1901    fn span(&self) -> Span {
1902        self.explain_span.join_span(&self.statement)
1903    }
1904}
1905
1906fn parse_explain<'a>(parser: &mut Parser<'a, '_>) -> Result<Explain<'a>, ParseError> {
1907    let explain_span = parser.consume_keyword(Keyword::EXPLAIN)?;
1908    parser.postgres_only(&explain_span);
1909    let mut options = Vec::new();
1910    if matches!(parser.token, Token::LParen) {
1911        // Parenthesized option list: EXPLAIN (ANALYZE, BUFFERS, ...)
1912        parser.consume_token(Token::LParen)?;
1913        loop {
1914            let opt = match &parser.token {
1915                Token::Ident(_, Keyword::ANALYZE) => {
1916                    let s = parser.consume_keyword(Keyword::ANALYZE)?;
1917                    ExplainOption::Analyze(s, parser.try_parse_bool())
1918                }
1919                Token::Ident(_, Keyword::VERBOSE) => {
1920                    let s = parser.consume_keyword(Keyword::VERBOSE)?;
1921                    ExplainOption::Verbose(s, parser.try_parse_bool())
1922                }
1923                Token::Ident(_, Keyword::COSTS) => {
1924                    let s = parser.consume_keyword(Keyword::COSTS)?;
1925                    ExplainOption::Costs(s, parser.try_parse_bool())
1926                }
1927                Token::Ident(_, Keyword::SETTINGS) => {
1928                    let s = parser.consume_keyword(Keyword::SETTINGS)?;
1929                    ExplainOption::Settings(s, parser.try_parse_bool())
1930                }
1931                Token::Ident(_, Keyword::GENERIC_PLAN) => {
1932                    let s = parser.consume_keyword(Keyword::GENERIC_PLAN)?;
1933                    ExplainOption::GenericPlan(s, parser.try_parse_bool())
1934                }
1935                Token::Ident(_, Keyword::BUFFERS) => {
1936                    let s = parser.consume_keyword(Keyword::BUFFERS)?;
1937                    ExplainOption::Buffers(s, parser.try_parse_bool())
1938                }
1939                Token::Ident(_, Keyword::WAL) => {
1940                    let s = parser.consume_keyword(Keyword::WAL)?;
1941                    ExplainOption::Wal(s, parser.try_parse_bool())
1942                }
1943                Token::Ident(_, Keyword::TIMING) => {
1944                    let s = parser.consume_keyword(Keyword::TIMING)?;
1945                    ExplainOption::Timing(s, parser.try_parse_bool())
1946                }
1947                Token::Ident(_, Keyword::SUMMARY) => {
1948                    let s = parser.consume_keyword(Keyword::SUMMARY)?;
1949                    ExplainOption::Summary(s, parser.try_parse_bool())
1950                }
1951                Token::Ident(_, Keyword::MEMORY) => {
1952                    let s = parser.consume_keyword(Keyword::MEMORY)?;
1953                    ExplainOption::Memory(s, parser.try_parse_bool())
1954                }
1955                Token::Ident(_, Keyword::FORMAT) => {
1956                    let fmt_kw = parser.consume_keyword(Keyword::FORMAT)?;
1957                    let fmt = match &parser.token {
1958                        Token::Ident(_, Keyword::TEXT) => ExplainFormat::Text(parser.consume()),
1959                        Token::Ident(_, Keyword::XML) => ExplainFormat::Xml(parser.consume()),
1960                        Token::Ident(_, Keyword::JSON) => ExplainFormat::Json(parser.consume()),
1961                        Token::Ident(_, Keyword::YAML) => ExplainFormat::Yaml(parser.consume()),
1962                        _ => parser.expected_failure("TEXT, XML, JSON, or YAML")?,
1963                    };
1964                    ExplainOption::Format(fmt_kw, fmt)
1965                }
1966                _ => parser.expected_failure("EXPLAIN option")?,
1967            };
1968            options.push(opt);
1969            if parser.skip_token(Token::Comma).is_none() {
1970                break;
1971            }
1972        }
1973        parser.consume_token(Token::RParen)?;
1974    } else {
1975        // Legacy: EXPLAIN [ANALYZE] [VERBOSE]
1976        if let Some(s) = parser.skip_keyword(Keyword::ANALYZE) {
1977            options.push(ExplainOption::Analyze(s.clone(), Some((true, s))));
1978        }
1979        if let Some(s) = parser.skip_keyword(Keyword::VERBOSE) {
1980            options.push(ExplainOption::Verbose(s.clone(), Some((true, s))));
1981        }
1982    }
1983    let inner = match parse_statement(parser)? {
1984        Some(s) => s,
1985        None => parser.expected_failure("Statement after EXPLAIN")?,
1986    };
1987    Ok(Explain {
1988        explain_span,
1989        options,
1990        statement: Box::new(inner),
1991    })
1992}
1993
1994/// Sensitivity of a declared cursor
1995#[derive(Clone, Debug)]
1996pub enum CursorSensitivity {
1997    Asensitive(Span),
1998    Insensitive(Span),
1999}
2000
2001impl Spanned for CursorSensitivity {
2002    fn span(&self) -> Span {
2003        match self {
2004            CursorSensitivity::Asensitive(s) | CursorSensitivity::Insensitive(s) => s.clone(),
2005        }
2006    }
2007}
2008
2009/// Scroll behaviour of a declared cursor
2010#[derive(Clone, Debug)]
2011pub enum CursorScroll {
2012    Scroll(Span),
2013    NoScroll(Span),
2014}
2015
2016impl Spanned for CursorScroll {
2017    fn span(&self) -> Span {
2018        match self {
2019            CursorScroll::Scroll(s) | CursorScroll::NoScroll(s) => s.clone(),
2020        }
2021    }
2022}
2023
2024/// Hold behaviour of a declared cursor
2025#[derive(Clone, Debug)]
2026pub enum CursorHold {
2027    WithHold(Span),
2028    WithoutHold(Span),
2029}
2030
2031impl Spanned for CursorHold {
2032    fn span(&self) -> Span {
2033        match self {
2034            CursorHold::WithHold(s) | CursorHold::WithoutHold(s) => s.clone(),
2035        }
2036    }
2037}
2038
2039/// MariaDB/MySQL DECLARE variable statement inside a stored procedure/function.
2040/// `DECLARE name data_type [DEFAULT expr]`
2041#[derive(Clone, Debug)]
2042pub struct DeclareVariable<'a> {
2043    pub declare_span: Span,
2044    pub name: crate::Identifier<'a>,
2045    pub data_type: crate::DataType<'a>,
2046    pub default: Option<(Span, Select<'a>)>,
2047}
2048
2049impl<'a> Spanned for DeclareVariable<'a> {
2050    fn span(&self) -> Span {
2051        self.declare_span
2052            .join_span(&self.name)
2053            .join_span(&self.data_type)
2054            .join_span(&self.default)
2055    }
2056}
2057
2058/// MariaDB/MySQL DECLARE cursor statement inside a stored procedure/function.
2059/// `DECLARE name CURSOR FOR select`
2060#[derive(Clone, Debug)]
2061pub struct DeclareCursorMariaDb<'a> {
2062    pub declare_span: Span,
2063    pub name: crate::Identifier<'a>,
2064    pub cursor_span: Span,
2065    pub for_span: Span,
2066    pub query: Box<Select<'a>>,
2067}
2068
2069impl<'a> Spanned for DeclareCursorMariaDb<'a> {
2070    fn span(&self) -> Span {
2071        self.declare_span.join_span(&self.query)
2072    }
2073}
2074
2075/// Action part of a MariaDB/MySQL handler declaration.
2076#[derive(Clone, Debug)]
2077pub enum HandlerAction {
2078    Continue(Span),
2079    Exit(Span),
2080}
2081
2082impl Spanned for HandlerAction {
2083    fn span(&self) -> Span {
2084        match self {
2085            HandlerAction::Continue(s) | HandlerAction::Exit(s) => s.clone(),
2086        }
2087    }
2088}
2089
2090/// Condition part of a MariaDB/MySQL handler declaration.
2091#[derive(Clone, Debug)]
2092pub enum HandlerCondition<'a> {
2093    /// `NOT FOUND`
2094    NotFound(Span, Span),
2095    /// `SQLEXCEPTION`
2096    SqlException(Span),
2097    /// `SQLWARNING`
2098    SqlWarning(Span),
2099    /// `SQLSTATE [VALUE] 'code'`
2100    SqlState(Span, crate::SString<'a>),
2101}
2102
2103impl<'a> Spanned for HandlerCondition<'a> {
2104    fn span(&self) -> Span {
2105        match self {
2106            HandlerCondition::NotFound(a, b) => a.join_span(b),
2107            HandlerCondition::SqlException(s) => s.clone(),
2108            HandlerCondition::SqlWarning(s) => s.clone(),
2109            HandlerCondition::SqlState(s, v) => s.join_span(v),
2110        }
2111    }
2112}
2113
2114/// MariaDB/MySQL DECLARE handler statement inside a stored procedure/function.
2115/// `DECLARE CONTINUE|EXIT HANDLER FOR condition statement`
2116#[derive(Clone, Debug)]
2117pub struct DeclareHandler<'a> {
2118    pub declare_span: Span,
2119    pub action: HandlerAction,
2120    pub handler_span: Span,
2121    pub for_span: Span,
2122    pub condition: HandlerCondition<'a>,
2123    pub statement: Box<Statement<'a>>,
2124}
2125
2126impl<'a> Spanned for DeclareHandler<'a> {
2127    fn span(&self) -> Span {
2128        self.declare_span.join_span(&self.statement)
2129    }
2130}
2131
2132/// MariaDB/MySQL OPEN cursor statement.
2133/// `OPEN cursor_name`
2134#[derive(Clone, Debug)]
2135pub struct OpenCursor<'a> {
2136    pub open_span: Span,
2137    pub name: crate::Identifier<'a>,
2138}
2139
2140impl<'a> Spanned for OpenCursor<'a> {
2141    fn span(&self) -> Span {
2142        self.open_span.join_span(&self.name)
2143    }
2144}
2145
2146/// MariaDB/MySQL CLOSE cursor statement.
2147/// `CLOSE cursor_name`
2148#[derive(Clone, Debug)]
2149pub struct CloseCursor<'a> {
2150    pub close_span: Span,
2151    pub name: crate::Identifier<'a>,
2152}
2153
2154impl<'a> Spanned for CloseCursor<'a> {
2155    fn span(&self) -> Span {
2156        self.close_span.join_span(&self.name)
2157    }
2158}
2159
2160/// MariaDB/MySQL FETCH cursor statement.
2161/// `FETCH [NEXT] [FROM] cursor INTO var, ...`
2162#[derive(Clone, Debug)]
2163pub struct FetchCursor<'a> {
2164    pub fetch_span: Span,
2165    pub next_span: Option<Span>,
2166    pub from_span: Option<Span>,
2167    pub cursor: crate::Identifier<'a>,
2168    pub into_span: Span,
2169    pub variables: Vec<crate::Identifier<'a>>,
2170}
2171
2172impl<'a> Spanned for FetchCursor<'a> {
2173    fn span(&self) -> Span {
2174        self.fetch_span.join_span(&self.variables)
2175    }
2176}
2177
2178/// MariaDB/MySQL LEAVE label statement.
2179/// `LEAVE label`
2180#[derive(Clone, Debug)]
2181pub struct Leave<'a> {
2182    pub leave_span: Span,
2183    pub label: crate::Identifier<'a>,
2184}
2185
2186impl<'a> Spanned for Leave<'a> {
2187    fn span(&self) -> Span {
2188        self.leave_span.join_span(&self.label)
2189    }
2190}
2191
2192/// MariaDB/MySQL ITERATE label statement.
2193/// `ITERATE label`
2194#[derive(Clone, Debug)]
2195pub struct Iterate<'a> {
2196    pub iterate_span: Span,
2197    pub label: crate::Identifier<'a>,
2198}
2199
2200impl<'a> Spanned for Iterate<'a> {
2201    fn span(&self) -> Span {
2202        self.iterate_span.join_span(&self.label)
2203    }
2204}
2205
2206/// MariaDB/MySQL LOOP body END LOOP construct.
2207/// `[label:] LOOP body END LOOP [label]`
2208#[derive(Clone, Debug)]
2209pub struct Loop<'a> {
2210    pub label: Option<crate::Identifier<'a>>,
2211    pub loop_span: Span,
2212    pub body: Vec<Statement<'a>>,
2213    pub end_loop_span: Span,
2214    pub end_label: Option<crate::Identifier<'a>>,
2215}
2216
2217impl<'a> Spanned for Loop<'a> {
2218    fn span(&self) -> Span {
2219        self.loop_span
2220            .join_span(&self.label)
2221            .join_span(&self.body)
2222            .join_span(&self.end_loop_span)
2223            .join_span(&self.end_label)
2224    }
2225}
2226
2227/// MariaDB/MySQL WHILE condition DO body END WHILE construct.
2228/// `[label:] WHILE condition DO body END WHILE [label]`
2229#[derive(Clone, Debug)]
2230pub struct While<'a> {
2231    pub label: Option<crate::Identifier<'a>>,
2232    pub while_span: Span,
2233    pub condition: Expression<'a>,
2234    pub do_span: Span,
2235    pub body: Vec<Statement<'a>>,
2236    pub end_while_span: Span,
2237    pub end_label: Option<crate::Identifier<'a>>,
2238}
2239
2240impl<'a> Spanned for While<'a> {
2241    fn span(&self) -> Span {
2242        self.while_span
2243            .join_span(&self.label)
2244            .join_span(&self.condition)
2245            .join_span(&self.do_span)
2246            .join_span(&self.body)
2247            .join_span(&self.end_while_span)
2248            .join_span(&self.end_label)
2249    }
2250}
2251
2252/// MariaDB/MySQL REPEAT body UNTIL condition END REPEAT construct.
2253/// `[label:] REPEAT body UNTIL condition END REPEAT [label]`
2254#[derive(Clone, Debug)]
2255pub struct Repeat<'a> {
2256    pub label: Option<crate::Identifier<'a>>,
2257    pub repeat_span: Span,
2258    pub body: Vec<Statement<'a>>,
2259    pub until_span: Span,
2260    pub condition: Expression<'a>,
2261    pub end_repeat_span: Span,
2262    pub end_label: Option<crate::Identifier<'a>>,
2263}
2264
2265impl<'a> Spanned for Repeat<'a> {
2266    fn span(&self) -> Span {
2267        self.repeat_span
2268            .join_span(&self.label)
2269            .join_span(&self.body)
2270            .join_span(&self.until_span)
2271            .join_span(&self.condition)
2272            .join_span(&self.end_repeat_span)
2273            .join_span(&self.end_label)
2274    }
2275}
2276
2277/// Dispatcher: parse a MariaDB DECLARE and return the appropriate Statement variant.
2278fn parse_declare_maria<'a>(parser: &mut Parser<'a, '_>) -> Result<Statement<'a>, ParseError> {
2279    let declare_span = parser.consume_keyword(Keyword::DECLARE)?;
2280    match &parser.token {
2281        Token::Ident(_, Keyword::CONTINUE | Keyword::EXIT) => Ok(Statement::DeclareHandler(
2282            Box::new(parse_handler_body(parser, declare_span)?),
2283        )),
2284        _ => {
2285            let name = parser.consume_plain_identifier_unreserved()?;
2286            if matches!(&parser.token, Token::Ident(_, Keyword::CURSOR)) {
2287                Ok(Statement::DeclareCursorMariaDb(Box::new(
2288                    parse_cursor_mariadb_body(parser, declare_span, name)?,
2289                )))
2290            } else {
2291                Ok(Statement::DeclareVariable(Box::new(parse_variable_body(
2292                    parser,
2293                    declare_span,
2294                    name,
2295                )?)))
2296            }
2297        }
2298    }
2299}
2300
2301fn parse_variable_body<'a>(
2302    parser: &mut Parser<'a, '_>,
2303    declare_span: Span,
2304    name: crate::Identifier<'a>,
2305) -> Result<DeclareVariable<'a>, ParseError> {
2306    use crate::data_type::{DataTypeContext, parse_data_type};
2307    let data_type = parse_data_type(parser, DataTypeContext::TypeRef)?;
2308    let default = if let Some(default_span) = parser.skip_keyword(Keyword::DEFAULT) {
2309        let select = parse_select_body(parser, default_span.clone())?;
2310        Some((default_span, select))
2311    } else {
2312        None
2313    };
2314    Ok(DeclareVariable {
2315        declare_span,
2316        name,
2317        data_type,
2318        default,
2319    })
2320}
2321
2322fn parse_cursor_mariadb_body<'a>(
2323    parser: &mut Parser<'a, '_>,
2324    declare_span: Span,
2325    name: crate::Identifier<'a>,
2326) -> Result<DeclareCursorMariaDb<'a>, ParseError> {
2327    let cursor_span = parser.consume_keyword(Keyword::CURSOR)?;
2328    let for_span = parser.consume_keyword(Keyword::FOR)?;
2329    let query = Box::new(parse_select(parser)?);
2330    Ok(DeclareCursorMariaDb {
2331        declare_span,
2332        name,
2333        cursor_span,
2334        for_span,
2335        query,
2336    })
2337}
2338
2339fn parse_handler_body<'a>(
2340    parser: &mut Parser<'a, '_>,
2341    declare_span: Span,
2342) -> Result<DeclareHandler<'a>, ParseError> {
2343    let action = match &parser.token {
2344        Token::Ident(_, Keyword::CONTINUE) => {
2345            HandlerAction::Continue(parser.consume_keyword(Keyword::CONTINUE)?)
2346        }
2347        _ => HandlerAction::Exit(parser.consume_keyword(Keyword::EXIT)?),
2348    };
2349    let handler_span = parser.consume_keyword(Keyword::HANDLER)?;
2350    let for_span = parser.consume_keyword(Keyword::FOR)?;
2351    let condition = match &parser.token {
2352        Token::Ident(_, Keyword::NOT) => {
2353            let not_span = parser.consume_keyword(Keyword::NOT)?;
2354            let found_span = parser.consume_keyword(Keyword::FOUND)?;
2355            HandlerCondition::NotFound(not_span, found_span)
2356        }
2357        Token::Ident(_, Keyword::SQLEXCEPTION) => {
2358            HandlerCondition::SqlException(parser.consume_keyword(Keyword::SQLEXCEPTION)?)
2359        }
2360        Token::Ident(_, Keyword::SQLWARNING) => {
2361            HandlerCondition::SqlWarning(parser.consume_keyword(Keyword::SQLWARNING)?)
2362        }
2363        Token::Ident(_, Keyword::SQLSTATE) => {
2364            let sqlstate_span = parser.consume_keyword(Keyword::SQLSTATE)?;
2365            parser.skip_keyword(Keyword::VALUE);
2366            let code = parser.consume_string()?;
2367            HandlerCondition::SqlState(sqlstate_span, code)
2368        }
2369        _ => parser.expected_failure("NOT FOUND, SQLEXCEPTION, SQLWARNING, or SQLSTATE")?,
2370    };
2371    let statement = match parse_statement(parser)? {
2372        Some(s) => Box::new(s),
2373        None => parser.expected_failure("statement after handler condition")?,
2374    };
2375    Ok(DeclareHandler {
2376        declare_span,
2377        action,
2378        handler_span,
2379        for_span,
2380        condition,
2381        statement,
2382    })
2383}
2384
2385fn parse_open_cursor<'a>(parser: &mut Parser<'a, '_>) -> Result<OpenCursor<'a>, ParseError> {
2386    let open_span = parser.consume_keyword(Keyword::OPEN)?;
2387    let name = parser.consume_plain_identifier_unreserved()?;
2388    Ok(OpenCursor { open_span, name })
2389}
2390
2391fn parse_close_cursor<'a>(parser: &mut Parser<'a, '_>) -> Result<CloseCursor<'a>, ParseError> {
2392    let close_span = parser.consume_keyword(Keyword::CLOSE)?;
2393    let name = parser.consume_plain_identifier_unreserved()?;
2394    Ok(CloseCursor { close_span, name })
2395}
2396
2397fn parse_fetch_cursor<'a>(parser: &mut Parser<'a, '_>) -> Result<FetchCursor<'a>, ParseError> {
2398    let fetch_span = parser.consume_keyword(Keyword::FETCH)?;
2399    let next_span = parser.skip_keyword(Keyword::NEXT);
2400    let from_span = parser.skip_keyword(Keyword::FROM);
2401    let cursor = parser.consume_plain_identifier_unreserved()?;
2402    let into_span = parser.consume_keyword(Keyword::INTO)?;
2403    let mut variables = Vec::new();
2404    loop {
2405        variables.push(parser.consume_plain_identifier_unreserved()?);
2406        if parser.skip_token(Token::Comma).is_none() {
2407            break;
2408        }
2409    }
2410    Ok(FetchCursor {
2411        fetch_span,
2412        next_span,
2413        from_span,
2414        cursor,
2415        into_span,
2416        variables,
2417    })
2418}
2419
2420fn parse_leave<'a>(parser: &mut Parser<'a, '_>) -> Result<Leave<'a>, ParseError> {
2421    let leave_span = parser.consume_keyword(Keyword::LEAVE)?;
2422    let label = parser.consume_plain_identifier_unreserved()?;
2423    Ok(Leave { leave_span, label })
2424}
2425
2426fn parse_iterate<'a>(parser: &mut Parser<'a, '_>) -> Result<Iterate<'a>, ParseError> {
2427    let iterate_span = parser.consume_keyword(Keyword::ITERATE)?;
2428    let label = parser.consume_plain_identifier_unreserved()?;
2429    Ok(Iterate {
2430        iterate_span,
2431        label,
2432    })
2433}
2434
2435fn parse_loop<'a>(
2436    parser: &mut Parser<'a, '_>,
2437    label: Option<crate::Identifier<'a>>,
2438) -> Result<Loop<'a>, ParseError> {
2439    let loop_span = parser.consume_keyword(Keyword::LOOP)?;
2440    let mut body = Vec::new();
2441    parser.recovered(
2442        "'END'",
2443        &|t| matches!(t, Token::Ident(_, Keyword::END)),
2444        |parser| parse_statement_list(parser, &mut body),
2445    )?;
2446    let end_loop_span = parser.consume_keywords(&[Keyword::END, Keyword::LOOP])?;
2447    let end_label = if matches!(&parser.token, Token::Ident(_, Keyword::NOT_A_KEYWORD)) {
2448        Some(parser.consume_plain_identifier_unreserved()?)
2449    } else {
2450        None
2451    };
2452    Ok(Loop {
2453        label,
2454        loop_span,
2455        body,
2456        end_loop_span,
2457        end_label,
2458    })
2459}
2460
2461fn parse_while<'a>(
2462    parser: &mut Parser<'a, '_>,
2463    label: Option<crate::Identifier<'a>>,
2464) -> Result<While<'a>, ParseError> {
2465    let while_span = parser.consume_keyword(Keyword::WHILE)?;
2466    let condition = parse_expression_unreserved(parser, PRIORITY_MAX)?;
2467    let do_span = parser.consume_keyword(Keyword::DO)?;
2468    let mut body = Vec::new();
2469    parser.recovered(
2470        "'END'",
2471        &|t| matches!(t, Token::Ident(_, Keyword::END)),
2472        |parser| parse_statement_list(parser, &mut body),
2473    )?;
2474    let end_while_span = parser.consume_keywords(&[Keyword::END, Keyword::WHILE])?;
2475    let end_label = if matches!(&parser.token, Token::Ident(_, Keyword::NOT_A_KEYWORD)) {
2476        Some(parser.consume_plain_identifier_unreserved()?)
2477    } else {
2478        None
2479    };
2480    Ok(While {
2481        label,
2482        while_span,
2483        condition,
2484        do_span,
2485        body,
2486        end_while_span,
2487        end_label,
2488    })
2489}
2490
2491fn parse_repeat<'a>(
2492    parser: &mut Parser<'a, '_>,
2493    label: Option<crate::Identifier<'a>>,
2494) -> Result<Repeat<'a>, ParseError> {
2495    let repeat_span = parser.consume_keyword(Keyword::REPEAT)?;
2496    let mut body = Vec::new();
2497    parser.recovered(
2498        "'UNTIL'",
2499        &|t| matches!(t, Token::Ident(_, Keyword::UNTIL)),
2500        |parser| parse_statement_list(parser, &mut body),
2501    )?;
2502    let until_span = parser.consume_keyword(Keyword::UNTIL)?;
2503    let condition = parse_expression_unreserved(parser, PRIORITY_MAX)?;
2504    let end_repeat_span = parser.consume_keywords(&[Keyword::END, Keyword::REPEAT])?;
2505    let end_label = if matches!(&parser.token, Token::Ident(_, Keyword::NOT_A_KEYWORD)) {
2506        Some(parser.consume_plain_identifier_unreserved()?)
2507    } else {
2508        None
2509    };
2510    Ok(Repeat {
2511        label,
2512        repeat_span,
2513        body,
2514        until_span,
2515        condition,
2516        end_repeat_span,
2517        end_label,
2518    })
2519}
2520
2521/// PostgreSQL DECLARE cursor statement
2522#[derive(Clone, Debug)]
2523pub struct DeclareCursor<'a> {
2524    pub declare_span: Span,
2525    pub name: crate::Identifier<'a>,
2526    pub binary: Option<Span>,
2527    pub sensitivity: Option<CursorSensitivity>,
2528    pub scroll: Option<CursorScroll>,
2529    pub cursor_span: Span,
2530    pub hold: Option<CursorHold>,
2531    pub for_span: Span,
2532    pub query: Box<Statement<'a>>,
2533}
2534
2535impl<'a> Spanned for DeclareCursor<'a> {
2536    fn span(&self) -> Span {
2537        self.declare_span.join_span(&self.query)
2538    }
2539}
2540
2541fn parse_declare_cursor<'a>(parser: &mut Parser<'a, '_>) -> Result<DeclareCursor<'a>, ParseError> {
2542    let declare_span = parser.consume_keyword(Keyword::DECLARE)?;
2543    parser.postgres_only(&declare_span);
2544    let name = parser.consume_plain_identifier_unreserved()?;
2545    // Optional BINARY
2546    let binary = parser.skip_keyword(Keyword::BINARY);
2547    // Optional ASENSITIVE | INSENSITIVE
2548    let sensitivity = match &parser.token {
2549        Token::Ident(_, Keyword::ASENSITIVE) => {
2550            Some(CursorSensitivity::Asensitive(parser.consume()))
2551        }
2552        Token::Ident(_, Keyword::INSENSITIVE) => {
2553            Some(CursorSensitivity::Insensitive(parser.consume()))
2554        }
2555        _ => None,
2556    };
2557    // Optional [NO] SCROLL
2558    let scroll = if let Some(no_span) = parser.skip_keyword(Keyword::NO) {
2559        let scroll_span = parser.consume_keyword(Keyword::SCROLL)?;
2560        Some(CursorScroll::NoScroll(no_span.join_span(&scroll_span)))
2561    } else {
2562        parser
2563            .skip_keyword(Keyword::SCROLL)
2564            .map(CursorScroll::Scroll)
2565    };
2566    let cursor_span = parser.consume_keyword(Keyword::CURSOR)?;
2567    // Optional WITH HOLD | WITHOUT HOLD
2568    let hold = if let Some(without_span) = parser.skip_keyword(Keyword::WITHOUT) {
2569        let hold_span = parser.consume_keyword(Keyword::HOLD)?;
2570        Some(CursorHold::WithoutHold(without_span.join_span(&hold_span)))
2571    } else if let Some(with_span) = parser.skip_keyword(Keyword::WITH) {
2572        let hold_span = parser.consume_keyword(Keyword::HOLD)?;
2573        Some(CursorHold::WithHold(with_span.join_span(&hold_span)))
2574    } else {
2575        None
2576    };
2577    let for_span = parser.consume_keyword(Keyword::FOR)?;
2578    let query = match parse_statement(parser)? {
2579        Some(s) => s,
2580        None => parser.expected_failure("Query after FOR")?,
2581    };
2582    Ok(DeclareCursor {
2583        declare_span,
2584        name,
2585        binary,
2586        sensitivity,
2587        scroll,
2588        cursor_span,
2589        hold,
2590        for_span,
2591        query: Box::new(query),
2592    })
2593}
2594
2595/// PostgreSQL REFRESH MATERIALIZED VIEW statement
2596#[derive(Clone, Debug)]
2597pub struct RefreshMaterializedView<'a> {
2598    pub refresh_span: Span,
2599    pub concurrently: Option<Span>,
2600    pub view_name: crate::QualifiedName<'a>,
2601    /// WITH [ NO ] DATA: Some(true) = WITH DATA, Some(false) = WITH NO DATA, None = not specified
2602    pub with_data: Option<(Span, bool)>,
2603}
2604
2605impl<'a> Spanned for RefreshMaterializedView<'a> {
2606    fn span(&self) -> Span {
2607        self.refresh_span
2608            .join_span(&self.view_name)
2609            .join_span(&self.with_data.as_ref().map(|(s, _)| s.clone()))
2610    }
2611}
2612
2613fn parse_refresh_materialized_view<'a>(
2614    parser: &mut Parser<'a, '_>,
2615) -> Result<RefreshMaterializedView<'a>, ParseError> {
2616    let refresh_span = parser.consume_keyword(Keyword::REFRESH)?;
2617    parser.postgres_only(&refresh_span);
2618    parser.consume_keyword(Keyword::MATERIALIZED)?;
2619    parser.consume_keyword(Keyword::VIEW)?;
2620    let concurrently = parser.skip_keyword(Keyword::CONCURRENTLY);
2621    let view_name = parse_qualified_name_unreserved(parser)?;
2622    // Optional WITH [ NO ] DATA
2623    let with_data = if let Some(with_span) = parser.skip_keyword(Keyword::WITH) {
2624        if let Some(no_span) = parser.skip_keyword(Keyword::NO) {
2625            let data_span = parser.consume_keyword(Keyword::DATA)?;
2626            Some((with_span.join_span(&no_span).join_span(&data_span), false))
2627        } else {
2628            let data_span = parser.consume_keyword(Keyword::DATA)?;
2629            Some((with_span.join_span(&data_span), true))
2630        }
2631    } else {
2632        None
2633    };
2634    Ok(RefreshMaterializedView {
2635        refresh_span,
2636        concurrently,
2637        view_name,
2638        with_data,
2639    })
2640}
2641
2642/// PostgreSQL PREPARE statement
2643#[derive(Clone, Debug)]
2644pub struct Prepare<'a> {
2645    pub prepare_span: Span,
2646    pub name: crate::Identifier<'a>,
2647    pub param_types: Vec<crate::DataType<'a>>,
2648    pub as_span: Span,
2649    pub statement: Box<Statement<'a>>,
2650}
2651
2652impl<'a> Spanned for Prepare<'a> {
2653    fn span(&self) -> Span {
2654        self.prepare_span.join_span(&self.statement)
2655    }
2656}
2657
2658fn parse_prepare<'a>(parser: &mut Parser<'a, '_>) -> Result<Prepare<'a>, ParseError> {
2659    use crate::data_type::{DataTypeContext, parse_data_type};
2660    let prepare_span = parser.consume_keyword(Keyword::PREPARE)?;
2661    parser.postgres_only(&prepare_span);
2662    let name = parser.consume_plain_identifier_unreserved()?;
2663    // Optional (type, ...) parameter type list
2664    let mut param_types = Vec::new();
2665    if matches!(parser.token, Token::LParen) {
2666        parser.consume_token(Token::LParen)?;
2667        loop {
2668            parser.recovered(
2669                "')' or ','",
2670                &|t| matches!(t, Token::RParen | Token::Comma),
2671                |parser| {
2672                    param_types.push(parse_data_type(parser, DataTypeContext::TypeRef)?);
2673                    Ok(())
2674                },
2675            )?;
2676            if parser.skip_token(Token::Comma).is_none() {
2677                break;
2678            }
2679        }
2680        parser.consume_token(Token::RParen)?;
2681    }
2682    let as_span = parser.consume_keyword(Keyword::AS)?;
2683    let statement = match parse_statement(parser)? {
2684        Some(s) => s,
2685        None => parser.expected_failure("Statement after AS")?,
2686    };
2687    Ok(Prepare {
2688        prepare_span,
2689        name,
2690        param_types,
2691        as_span,
2692        statement: Box::new(statement),
2693    })
2694}
2695
2696/// When part of case statement
2697#[derive(Clone, Debug)]
2698pub struct WhenStatement<'a> {
2699    /// Span of "WHEN"
2700    pub when_span: Span,
2701    /// Expression who's match yields execution `then`
2702    pub when: Expression<'a>,
2703    /// Span of "THEN"
2704    pub then_span: Span,
2705    /// Statements to execute if `when` matches
2706    pub then: Vec<Statement<'a>>,
2707}
2708
2709impl<'a> Spanned for WhenStatement<'a> {
2710    fn span(&self) -> Span {
2711        self.when_span
2712            .join_span(&self.when)
2713            .join_span(&self.then_span)
2714            .join_span(&self.then)
2715    }
2716}
2717
2718/// Case statement
2719#[derive(Clone, Debug)]
2720pub struct CaseStatement<'a> {
2721    /// Span of "CASE"
2722    pub case_span: Span,
2723    /// Value to match against
2724    pub value: Option<Expression<'a>>,
2725    /// List of whens
2726    pub whens: Vec<WhenStatement<'a>>,
2727    /// Span of "ELSE" and statement to execute if specified
2728    pub else_: Option<(Span, Vec<Statement<'a>>)>,
2729    /// Span of "END"
2730    pub end_span: Span,
2731}
2732
2733impl<'a> Spanned for CaseStatement<'a> {
2734    fn span(&self) -> Span {
2735        self.case_span
2736            .join_span(&self.value)
2737            .join_span(&self.whens)
2738            .join_span(&self.else_)
2739            .join_span(&self.end_span)
2740    }
2741}
2742
2743pub(crate) fn parse_case_statement<'a>(
2744    parser: &mut Parser<'a, '_>,
2745) -> Result<CaseStatement<'a>, ParseError> {
2746    let case_span = parser.consume_keyword(Keyword::CASE)?;
2747    let value = if !matches!(parser.token, Token::Ident(_, Keyword::WHEN)) {
2748        Some(parse_expression_unreserved(parser, PRIORITY_MAX)?)
2749    } else {
2750        None
2751    };
2752
2753    let mut whens = Vec::new();
2754    let mut else_ = None;
2755    parser.recovered(
2756        "'END'",
2757        &|t| matches!(t, Token::Ident(_, Keyword::END)),
2758        |parser| {
2759            loop {
2760                let when_span = parser.consume_keyword(Keyword::WHEN)?;
2761                let when = parse_expression_unreserved(parser, PRIORITY_MAX)?;
2762                let then_span = parser.consume_keyword(Keyword::THEN)?;
2763                let mut then = Vec::new();
2764                parse_statement_list(parser, &mut then)?;
2765                whens.push(WhenStatement {
2766                    when_span,
2767                    when,
2768                    then_span,
2769                    then,
2770                });
2771                if !matches!(parser.token, Token::Ident(_, Keyword::WHEN)) {
2772                    break;
2773                }
2774            }
2775            if let Some(span) = parser.skip_keyword(Keyword::ELSE) {
2776                let mut e = Vec::new();
2777                parse_statement_list(parser, &mut e)?;
2778                else_ = Some((span, e))
2779            };
2780            Ok(())
2781        },
2782    )?;
2783    let end_span = parser.consume_keyword(Keyword::END)?;
2784    Ok(CaseStatement {
2785        case_span,
2786        value,
2787        whens,
2788        else_,
2789        end_span,
2790    })
2791}
2792
2793pub(crate) fn parse_compound_query_bottom<'a>(
2794    parser: &mut Parser<'a, '_>,
2795) -> Result<Statement<'a>, ParseError> {
2796    match &parser.token {
2797        Token::LParen => {
2798            let lp = parser.consume_token(Token::LParen)?;
2799            let s = parser.recovered("')'", &|t| t == &Token::RParen, |parser| {
2800                Ok(Some(parse_compound_query(parser)?))
2801            })?;
2802            parser.consume_token(Token::RParen)?;
2803            Ok(s.unwrap_or(Statement::Invalid(Box::new(Invalid { span: lp }))))
2804        }
2805        Token::Ident(_, Keyword::SELECT) => Ok(Statement::Select(Box::new(parse_select(parser)?))),
2806        Token::Ident(_, Keyword::VALUES) => Ok(Statement::Values(Box::new(parse_values(parser)?))),
2807        Token::Ident(_, Keyword::WITH) => {
2808            Ok(Statement::WithQuery(Box::new(parse_with_query(parser)?)))
2809        }
2810        _ => parser.expected_failure("'SELECT' or '('")?,
2811    }
2812}
2813
2814/// Quantifier for a compound-query operator
2815#[derive(Clone, Debug)]
2816pub enum CompoundQuantifier {
2817    All(Span),
2818    Distinct(Span),
2819    Default,
2820}
2821
2822impl OptSpanned for CompoundQuantifier {
2823    fn opt_span(&self) -> Option<Span> {
2824        match &self {
2825            CompoundQuantifier::All(v) => v.opt_span(),
2826            CompoundQuantifier::Distinct(v) => v.opt_span(),
2827            CompoundQuantifier::Default => None,
2828        }
2829    }
2830}
2831
2832/// Set operator used between compound query branches
2833#[derive(Clone, Debug, Copy, PartialEq, Eq)]
2834pub enum CompoundOperator {
2835    Union,
2836    Intersect,
2837    Except,
2838}
2839
2840/// Right hand side branch of a compound query
2841#[derive(Clone, Debug)]
2842pub struct CompoundQueryBranch<'a> {
2843    /// Operator used to combine this branch with the left side
2844    pub operator: CompoundOperator,
2845    /// Span of operator keyword (UNION/INTERSECT/EXCEPT)
2846    pub operator_span: Span,
2847    /// Optional quantifier (ALL / DISTINCT)
2848    pub quantifier: CompoundQuantifier,
2849    /// Statement for this branch
2850    pub statement: Box<Statement<'a>>,
2851}
2852
2853impl<'a> Spanned for CompoundQueryBranch<'a> {
2854    fn span(&self) -> Span {
2855        self.operator_span
2856            .join_span(&self.quantifier)
2857            .join_span(&self.statement)
2858    }
2859}
2860
2861/// Compound query statement
2862#[derive(Clone, Debug)]
2863pub struct CompoundQuery<'a> {
2864    /// Left side of compound query
2865    pub left: Box<Statement<'a>>,
2866    /// Branches combined with the left side
2867    pub with: Vec<CompoundQueryBranch<'a>>,
2868    /// Span of "ORDER BY", and list of ordering expressions and directions if specified
2869    pub order_by: Option<(Span, Vec<(Expression<'a>, OrderFlag)>)>,
2870    /// Span of "LIMIT", offset and count expressions if specified
2871    pub limit: Option<(Span, Option<Expression<'a>>, Expression<'a>)>,
2872}
2873
2874impl<'a> Spanned for CompoundQuery<'a> {
2875    fn span(&self) -> Span {
2876        self.left
2877            .join_span(&self.with)
2878            .join_span(&self.order_by)
2879            .join_span(&self.limit)
2880    }
2881}
2882
2883pub(crate) fn parse_compound_query<'a>(
2884    parser: &mut Parser<'a, '_>,
2885) -> Result<Statement<'a>, ParseError> {
2886    let q = parse_compound_query_bottom(parser)?;
2887    if !matches!(
2888        parser.token,
2889        Token::Ident(_, Keyword::UNION | Keyword::INTERSECT | Keyword::EXCEPT)
2890    ) {
2891        return Ok(q);
2892    };
2893    let mut with = Vec::new();
2894    loop {
2895        let (operator, operator_span) = match &parser.token {
2896            Token::Ident(_, Keyword::UNION) => (
2897                CompoundOperator::Union,
2898                parser.consume_keyword(Keyword::UNION)?,
2899            ),
2900            Token::Ident(_, Keyword::INTERSECT) => (
2901                CompoundOperator::Intersect,
2902                parser.consume_keyword(Keyword::INTERSECT)?,
2903            ),
2904            Token::Ident(_, Keyword::EXCEPT) => (
2905                CompoundOperator::Except,
2906                parser.consume_keyword(Keyword::EXCEPT)?,
2907            ),
2908            _ => parser.expected_failure("'UNION' | 'INTERSECT' | 'EXCEPT'")?,
2909        };
2910        let quantifier = match &parser.token {
2911            Token::Ident(_, Keyword::ALL) => {
2912                CompoundQuantifier::All(parser.consume_keyword(Keyword::ALL)?)
2913            }
2914            Token::Ident(_, Keyword::DISTINCT) => {
2915                CompoundQuantifier::Distinct(parser.consume_keyword(Keyword::DISTINCT)?)
2916            }
2917            _ => CompoundQuantifier::Default,
2918        };
2919        let statement = Box::new(parse_compound_query_bottom(parser)?);
2920        with.push(CompoundQueryBranch {
2921            operator,
2922            operator_span,
2923            quantifier,
2924            statement,
2925        });
2926        if !matches!(
2927            parser.token,
2928            Token::Ident(_, Keyword::UNION | Keyword::INTERSECT | Keyword::EXCEPT)
2929        ) {
2930            break;
2931        }
2932    }
2933
2934    let order_by = if let Some(span) = parser.skip_keyword(Keyword::ORDER) {
2935        let span = parser.consume_keyword(Keyword::BY)?.join_span(&span);
2936        let mut order = Vec::new();
2937        loop {
2938            let e = parse_expression_unreserved(parser, PRIORITY_MAX)?;
2939            let f = match &parser.token {
2940                Token::Ident(_, Keyword::ASC) => OrderFlag::Asc(parser.consume()),
2941                Token::Ident(_, Keyword::DESC) => OrderFlag::Desc(parser.consume()),
2942                _ => OrderFlag::None,
2943            };
2944            order.push((e, f));
2945            if parser.skip_token(Token::Comma).is_none() {
2946                break;
2947            }
2948        }
2949        Some((span, order))
2950    } else {
2951        None
2952    };
2953
2954    let limit = if let Some(span) = parser.skip_keyword(Keyword::LIMIT) {
2955        let n = parse_expression_unreserved(parser, PRIORITY_MAX)?;
2956        match parser.token {
2957            Token::Comma => {
2958                parser.consume();
2959                Some((
2960                    span,
2961                    Some(n),
2962                    parse_expression_unreserved(parser, PRIORITY_MAX)?,
2963                ))
2964            }
2965            Token::Ident(_, Keyword::OFFSET) => {
2966                parser.consume();
2967                Some((
2968                    span,
2969                    Some(parse_expression_unreserved(parser, PRIORITY_MAX)?),
2970                    n,
2971                ))
2972            }
2973            _ => Some((span, None, n)),
2974        }
2975    } else {
2976        None
2977    };
2978
2979    Ok(Statement::CompoundQuery(Box::new(CompoundQuery {
2980        left: Box::new(q),
2981        with,
2982        order_by,
2983        limit,
2984    })))
2985}
2986
2987pub(crate) fn parse_statements<'a>(parser: &mut Parser<'a, '_>) -> Vec<Statement<'a>> {
2988    let mut ans = Vec::new();
2989    loop {
2990        match &parser.token {
2991            Token::Delimiter => {
2992                parser.consume();
2993                continue;
2994            }
2995            Token::Eof => return ans,
2996            _ => (),
2997        }
2998
2999        if matches!(parser.token, Token::Ident(_, Keyword::DELIMITER)) {
3000            if let Err(e) = parser.lexer.update_mysql_delimitor() {
3001                parser.err("Invalid delimiter", &e);
3002            }
3003            parser.consume();
3004            continue;
3005        }
3006
3007        // PL/pgSQL DECLARE section: single DECLARE keyword introduces multiple variable
3008        // declarations (each terminated by `;`) before the BEGIN block.
3009        if parser.permit_compound_statements
3010            && parser.options.dialect.is_postgresql()
3011            && matches!(&parser.token, Token::Ident(_, Keyword::DECLARE))
3012        {
3013            match parse_plpgsql_declare_section(parser, &mut ans) {
3014                Ok(_) => {}
3015                Err(_) => {
3016                    // Error already recorded; recover to next delimiter
3017                    while !matches!(parser.token, Token::Delimiter | Token::Eof) {
3018                        parser.next();
3019                    }
3020                }
3021            }
3022            continue;
3023        }
3024
3025        let stmt = match parse_statement(parser) {
3026            Ok(Some(v)) => Ok(v),
3027            Ok(None) => parser.expected_failure("Statement"),
3028            Err(e) => Err(e),
3029        };
3030        let err = stmt.is_err();
3031        let mut from_stdin = false;
3032        if let Ok(stmt) = stmt {
3033            from_stdin = stmt.reads_from_stdin();
3034            ans.push(stmt);
3035        }
3036
3037        match &parser.token {
3038            Token::Delimiter => (),
3039            Token::Eof => return ans,
3040            _ => {
3041                if !err {
3042                    parser.expected_error(parser.lexer.delimiter_name());
3043                }
3044                // We use a custom recovery here as ; is not allowed in sub expressions, it always terminates outer most statements
3045                loop {
3046                    parser.next();
3047                    match &parser.token {
3048                        Token::Delimiter => break,
3049                        Token::Eof => return ans,
3050                        _ => (),
3051                    }
3052                }
3053            }
3054        }
3055        if from_stdin {
3056            let (s, span) = parser.read_from_stdin_and_next();
3057            ans.push(Statement::Stdin(Box::new(Stdin { span, input: s })));
3058        } else {
3059            parser
3060                .consume_token(Token::Delimiter)
3061                .unwrap_or_else(|_| panic!("{}", parser.lexer.delimiter_name()));
3062        }
3063    }
3064}