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