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