Skip to main content

qusql_parse/
alter_table.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 crate::create::parse_sequence_options;
14use crate::qualified_name::parse_qualified_name_unreserved;
15use crate::{
16    DataType, Expression, Identifier, QualifiedName, SString, SequenceOption, Span, Spanned,
17    data_type::{DataTypeContext, parse_data_type},
18    expression::{PRIORITY_MAX, parse_expression_unreserved},
19    keywords::{Keyword, Restrict},
20    lexer::{StringType, Token},
21    parser::{ParseError, Parser},
22};
23use alloc::vec::Vec;
24
25/// Parse OWNER TO ... for ALTER TABLE/ALTER OPERATOR CLASS (PostgreSQL)
26pub(crate) fn parse_alter_owner<'a>(
27    parser: &mut Parser<'a, '_>,
28) -> Result<AlterTableOwner<'a>, ParseError> {
29    // In PostgreSQL, CURRENT_ROLE, CURRENT_USER, and SESSION_USER are valid without quotes
30    match &parser.token {
31        Token::Ident(_, Keyword::CURRENT_ROLE) => {
32            Ok(AlterTableOwner::CurrentRole(parser.consume()))
33        }
34        Token::Ident(_, Keyword::CURRENT_USER) => {
35            Ok(AlterTableOwner::CurrentUser(parser.consume()))
36        }
37        Token::Ident(_, Keyword::SESSION_USER) => {
38            Ok(AlterTableOwner::SessionUser(parser.consume()))
39        }
40        _ => Ok(AlterTableOwner::Identifier(
41            parser.consume_plain_identifier_unreserved()?,
42        )),
43    }
44}
45
46/// Option on an index
47#[derive(Clone, Debug)]
48pub enum IndexOption<'a> {
49    /// The index should be a BTree
50    IndexTypeBTree(Span),
51    /// The index should be hashed
52    IndexTypeHash(Span),
53    /// The index should be an RTree
54    IndexTypeRTree(Span),
55    /// Attach a comment to the index
56    Comment(SString<'a>),
57}
58
59impl<'a> Spanned for IndexOption<'a> {
60    fn span(&self) -> Span {
61        match &self {
62            IndexOption::IndexTypeBTree(v) => v.span(),
63            IndexOption::IndexTypeHash(v) => v.span(),
64            IndexOption::IndexTypeRTree(v) => v.span(),
65            IndexOption::Comment(v) => v.span(),
66        }
67    }
68}
69
70/// Type of index to add
71#[derive(Clone, Debug)]
72pub enum IndexType {
73    Index(Span),
74    Primary(Span),
75    Unique(Span),
76    FullText(Span),
77    Spatial(Span),
78}
79
80impl Spanned for IndexType {
81    fn span(&self) -> Span {
82        match &self {
83            IndexType::Index(v) => v.span(),
84            IndexType::Primary(v) => v.span(),
85            IndexType::Unique(v) => v.span(),
86            IndexType::FullText(v) => v.span(),
87            IndexType::Spatial(v) => v.span(),
88        }
89    }
90}
91
92/// When to take a foreign key action
93#[derive(Clone, Debug)]
94pub enum ForeignKeyOnType {
95    Update(Span),
96    Delete(Span),
97}
98
99impl Spanned for ForeignKeyOnType {
100    fn span(&self) -> Span {
101        match &self {
102            ForeignKeyOnType::Update(v) => v.span(),
103            ForeignKeyOnType::Delete(v) => v.span(),
104        }
105    }
106}
107
108/// Action to take on event for foreign key
109#[derive(Clone, Debug)]
110pub enum ForeignKeyOnAction {
111    Restrict(Span),
112    Cascade(Span),
113    SetNull(Span),
114    NoAction(Span),
115    SetDefault(Span),
116}
117
118impl Spanned for ForeignKeyOnAction {
119    fn span(&self) -> Span {
120        match &self {
121            ForeignKeyOnAction::Restrict(v) => v.span(),
122            ForeignKeyOnAction::Cascade(v) => v.span(),
123            ForeignKeyOnAction::SetNull(v) => v.span(),
124            ForeignKeyOnAction::NoAction(v) => v.span(),
125            ForeignKeyOnAction::SetDefault(v) => v.span(),
126        }
127    }
128}
129
130/// MATCH type for a foreign key reference
131#[derive(Clone, Debug)]
132pub enum ForeignKeyMatch {
133    Full(Span),
134    Simple(Span),
135    Partial(Span),
136}
137
138impl Spanned for ForeignKeyMatch {
139    fn span(&self) -> Span {
140        match self {
141            ForeignKeyMatch::Full(v) => v.span(),
142            ForeignKeyMatch::Simple(v) => v.span(),
143            ForeignKeyMatch::Partial(v) => v.span(),
144        }
145    }
146}
147
148/// Action to perform on events on foreign keys
149#[derive(Clone, Debug)]
150pub struct ForeignKeyOn {
151    pub type_: ForeignKeyOnType,
152    pub action: ForeignKeyOnAction,
153}
154
155impl Spanned for ForeignKeyOn {
156    fn span(&self) -> Span {
157        self.type_.join_span(&self.action)
158    }
159}
160
161/// Column or expression specification for an index
162#[derive(Clone, Debug)]
163pub enum IndexColExpr<'a> {
164    /// Regular column name
165    Column(Identifier<'a>),
166    /// Functional index expression (wrapped in parentheses)
167    Expression(Expression<'a>),
168}
169
170impl<'a> Spanned for IndexColExpr<'a> {
171    fn span(&self) -> Span {
172        match self {
173            IndexColExpr::Column(id) => id.span(),
174            IndexColExpr::Expression(expr) => expr.span(),
175        }
176    }
177}
178
179/// Specify a column for an index, together with a with
180#[derive(Clone, Debug)]
181pub struct IndexCol<'a> {
182    /// The column name or expression
183    pub expr: IndexColExpr<'a>,
184    /// Optional width of index together with its span
185    pub size: Option<(u32, Span)>,
186    /// Optional operator class (PostgreSQL)
187    pub opclass: Option<QualifiedName<'a>>,
188    /// Optional ASC ordering
189    pub asc: Option<Span>,
190    /// Optional DESC ordering
191    pub desc: Option<Span>,
192}
193
194impl<'a> Spanned for IndexCol<'a> {
195    fn span(&self) -> Span {
196        self.expr
197            .join_span(&self.size)
198            .join_span(&self.opclass)
199            .join_span(&self.asc)
200            .join_span(&self.desc)
201    }
202}
203
204/// Enum of alterations to perform on a column
205#[derive(Clone, Debug)]
206pub enum AlterColumnAction<'a> {
207    SetDefault {
208        set_default_span: Span,
209        value: Expression<'a>,
210    },
211    DropDefault {
212        drop_default_span: Span,
213    },
214    Type {
215        type_span: Span,
216        type_: DataType<'a>,
217        using: Option<(Span, Expression<'a>)>,
218    },
219    SetNotNull {
220        set_not_null_span: Span,
221    },
222    DropNotNull {
223        drop_not_null_span: Span,
224    },
225    AddGenerated {
226        add_span: Span,
227        generated_span: Span,
228        always_or_default: Option<(Span, Span)>, // (ALWAYS|BY, DEFAULT)
229        as_span: Span,
230        identity_span: Span,
231        sequence_options: Vec<SequenceOption<'a>>,
232    },
233}
234
235impl<'a> Spanned for AlterColumnAction<'a> {
236    fn span(&self) -> Span {
237        match self {
238            AlterColumnAction::SetDefault {
239                set_default_span,
240                value,
241            } => set_default_span.join_span(value),
242            AlterColumnAction::DropDefault { drop_default_span } => drop_default_span.clone(),
243            AlterColumnAction::Type {
244                type_span,
245                type_,
246                using,
247            } => type_span.join_span(type_).join_span(using),
248            AlterColumnAction::SetNotNull { set_not_null_span } => set_not_null_span.clone(),
249            AlterColumnAction::DropNotNull { drop_not_null_span } => drop_not_null_span.clone(),
250            AlterColumnAction::AddGenerated {
251                add_span,
252                generated_span,
253                always_or_default,
254                as_span,
255                identity_span,
256                sequence_options,
257            } => add_span
258                .join_span(generated_span)
259                .join_span(always_or_default)
260                .join_span(as_span)
261                .join_span(identity_span)
262                .join_span(sequence_options),
263        }
264    }
265}
266
267#[derive(Clone, Debug)]
268pub enum AlterLock {
269    Default(Span),
270    None(Span),
271    Shared(Span),
272    Exclusive(Span),
273}
274
275impl Spanned for AlterLock {
276    fn span(&self) -> Span {
277        match self {
278            AlterLock::Default(v) => v.span(),
279            AlterLock::None(v) => v.span(),
280            AlterLock::Shared(v) => v.span(),
281            AlterLock::Exclusive(v) => v.span(),
282        }
283    }
284}
285
286#[derive(Clone, Debug)]
287pub enum AlterAlgorithm {
288    Default(Span),
289    Instant(Span),
290    Inplace(Span),
291    Copy(Span),
292}
293
294impl Spanned for AlterAlgorithm {
295    fn span(&self) -> Span {
296        match self {
297            AlterAlgorithm::Default(v) => v.span(),
298            AlterAlgorithm::Instant(v) => v.span(),
299            AlterAlgorithm::Inplace(v) => v.span(),
300            AlterAlgorithm::Copy(v) => v.span(),
301        }
302    }
303}
304
305/// Owner value for ALTER TABLE OWNER TO
306#[derive(Clone, Debug)]
307pub enum AlterTableOwner<'a> {
308    /// Regular identifier (role name)
309    Identifier(Identifier<'a>),
310    /// CURRENT_ROLE keyword
311    CurrentRole(Span),
312    /// CURRENT_USER keyword
313    CurrentUser(Span),
314    /// SESSION_USER keyword
315    SessionUser(Span),
316}
317
318impl<'a> Spanned for AlterTableOwner<'a> {
319    fn span(&self) -> Span {
320        match self {
321            AlterTableOwner::Identifier(i) => i.span(),
322            AlterTableOwner::CurrentRole(s) => s.span(),
323            AlterTableOwner::CurrentUser(s) => s.span(),
324            AlterTableOwner::SessionUser(s) => s.span(),
325        }
326    }
327}
328
329/// ADD COLUMN specification
330#[derive(Clone, Debug)]
331pub struct AddColumn<'a> {
332    pub add_span: Span,
333    pub if_not_exists_span: Option<Span>,
334    pub identifier: Identifier<'a>,
335    pub data_type: DataType<'a>,
336    /// Optional "FIRST"
337    pub first: Option<Span>,
338    /// Optional "AFTER col_name"
339    pub after: Option<(Span, Identifier<'a>)>,
340}
341
342impl<'a> Spanned for AddColumn<'a> {
343    fn span(&self) -> Span {
344        self.add_span
345            .join_span(&self.if_not_exists_span)
346            .join_span(&self.identifier)
347            .join_span(&self.data_type)
348            .join_span(&self.first)
349            .join_span(&self.after)
350    }
351}
352
353fn parse_add_column<'a>(
354    parser: &mut Parser<'a, '_>,
355    add_span: Span,
356) -> Result<AddColumn<'a>, ParseError> {
357    parser.consume_keyword(Keyword::COLUMN)?;
358    let mut if_not_exists_span = None;
359    if matches!(parser.token, Token::Ident(_, Keyword::IF)) {
360        if_not_exists_span =
361            Some(parser.consume_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS])?);
362    }
363
364    parser.postgres_only(&if_not_exists_span);
365
366    let identifier = parser.consume_plain_identifier_unreserved()?;
367    let data_type = parse_data_type(parser, DataTypeContext::Column)?;
368
369    let mut first = None;
370    let mut after = None;
371    match &parser.token {
372        Token::Ident(_, Keyword::FIRST) => {
373            first = Some(parser.consume_keyword(Keyword::FIRST)?);
374        }
375        Token::Ident(_, Keyword::AFTER) => {
376            let after_span = parser.consume_keyword(Keyword::AFTER)?;
377            let after_col = parser.consume_plain_identifier_unreserved()?;
378            after = Some((after_span, after_col));
379        }
380        _ => {}
381    }
382
383    Ok(AddColumn {
384        add_span,
385        if_not_exists_span,
386        identifier,
387        data_type,
388        first,
389        after,
390    })
391}
392
393/// Add an index
394#[derive(Clone, Debug)]
395pub struct AddIndex<'a> {
396    /// Span of "ADD"
397    pub add_span: Span,
398    /// The type of index to add
399    pub index_type: IndexType,
400    /// Span of "IF NOT EXISTS" if specified
401    pub if_not_exists: Option<Span>,
402    /// Named of index if specified
403    pub name: Option<Identifier<'a>>,
404    /// Optional "CONSTRAINT" with symbol if specified
405    pub constraint: Option<(Span, Option<Identifier<'a>>)>,
406    /// Columns to add the index over
407    pub cols: Vec<IndexCol<'a>>,
408    /// Span of ")" closing the cols list
409    pub cols_r_paren: Span,
410    /// Options on the index
411    pub index_options: Vec<IndexOption<'a>>,
412}
413
414impl<'a> Spanned for AddIndex<'a> {
415    fn span(&self) -> Span {
416        self.add_span
417            .join_span(&self.index_type)
418            .join_span(&self.if_not_exists)
419            .join_span(&self.name)
420            .join_span(&self.constraint)
421            .join_span(&self.cols)
422            .join_span(&self.cols_r_paren)
423            .join_span(&self.index_options)
424    }
425}
426
427fn parse_add_index<'a>(
428    parser: &mut Parser<'a, '_>,
429    add_span: Span,
430    constraint: Option<(Span, Option<Identifier<'a>>)>,
431) -> Result<AddIndex<'a>, ParseError> {
432    let index_type = match &parser.token {
433        Token::Ident(_, Keyword::PRIMARY) => {
434            IndexType::Primary(parser.consume_keywords(&[Keyword::PRIMARY, Keyword::KEY])?)
435        }
436        Token::Ident(_, Keyword::INDEX | Keyword::KEY) => IndexType::Index(parser.consume()),
437        Token::Ident(_, Keyword::FULLTEXT) => {
438            let s = parser.consume_keyword(Keyword::FULLTEXT)?;
439            match &parser.token {
440                Token::Ident(_, kw @ Keyword::INDEX | kw @ Keyword::KEY) => {
441                    let kw = *kw;
442                    IndexType::FullText(parser.consume_keyword(kw)?.join_span(&s))
443                }
444                _ => parser.expected_failure("'KEY' or 'INDEX'")?,
445            }
446        }
447        Token::Ident(_, Keyword::SPATIAL) => {
448            let s = parser.consume_keyword(Keyword::SPATIAL)?;
449            match &parser.token {
450                Token::Ident(_, kw @ Keyword::INDEX | kw @ Keyword::KEY) => {
451                    let kw = *kw;
452                    IndexType::Spatial(parser.consume_keyword(kw)?.join_span(&s))
453                }
454                _ => parser.expected_failure("'KEY' or 'INDEX'")?,
455            }
456        }
457        Token::Ident(_, Keyword::UNIQUE) => {
458            let s = parser.consume_keyword(Keyword::UNIQUE)?;
459            match &parser.token {
460                Token::Ident(_, kw @ Keyword::INDEX | kw @ Keyword::KEY) => {
461                    let kw = *kw;
462                    IndexType::Unique(parser.consume_keyword(kw)?.join_span(&s))
463                }
464                _ => parser.expected_failure("'KEY' or 'INDEX'")?,
465            }
466        }
467        _ => parser.ice(file!(), line!())?,
468    };
469
470    let if_not_exists = if let Some(s) = parser.skip_keyword(Keyword::IF) {
471        Some(
472            parser
473                .consume_keywords(&[Keyword::NOT, Keyword::EXISTS])?
474                .join_span(&s),
475        )
476    } else {
477        None
478    };
479
480    let name = match &parser.token {
481        Token::Ident(_, kw) if !kw.restricted(parser.reserved()) => {
482            Some(parser.consume_plain_identifier_unreserved()?)
483        }
484        _ => None,
485    };
486
487    let mut index_options = Vec::new();
488    if matches!(parser.token, Token::Ident(_, Keyword::USING)) {
489        parse_index_type(parser, &mut index_options)?;
490    }
491    let (cols, cols_r_paren) = parse_index_cols(parser)?;
492    parse_index_options(parser, &mut index_options)?;
493
494    Ok(AddIndex {
495        add_span,
496        index_type,
497        if_not_exists,
498        name,
499        constraint,
500        cols,
501        cols_r_paren,
502        index_options,
503    })
504}
505
506/// Add a foreign key
507#[derive(Clone, Debug)]
508pub struct AddForeignKey<'a> {
509    /// Span of "ADD"
510    pub add_span: Span,
511    /// Optional "CONSTRAINT" with symbol if specified
512    pub constraint: Option<(Span, Option<Identifier<'a>>)>,
513    /// Span of "FOREIGN KEY"
514    pub foreign_key_span: Span,
515    /// Span of "IF NOT EXISTS" if specified
516    pub if_not_exists: Option<Span>,
517    /// Named of index if specified
518    pub name: Option<Identifier<'a>>,
519    /// Columns to add the index over
520    pub cols: Vec<IndexCol<'a>>,
521    /// Span of ")" closing the cols list
522    pub cols_r_paren: Span,
523    /// Span of "REFERENCES"
524    pub references_span: Span,
525    /// Refereed table
526    pub references_table: Identifier<'a>,
527    /// Columns in referred table
528    pub references_cols: Vec<Identifier<'a>>,
529    /// Span of ")" closing the references_cols list, if specified
530    pub references_cols_r_paren: Option<Span>,
531    /// List of what should happen at specified events
532    pub ons: Vec<ForeignKeyOn>,
533    /// Span of "NOT VALID" if specified
534    pub not_valid: Option<Span>,
535}
536
537impl<'a> Spanned for AddForeignKey<'a> {
538    fn span(&self) -> Span {
539        self.add_span
540            .join_span(&self.constraint)
541            .join_span(&self.foreign_key_span)
542            .join_span(&self.if_not_exists)
543            .join_span(&self.name)
544            .join_span(&self.cols)
545            .join_span(&self.cols_r_paren)
546            .join_span(&self.references_span)
547            .join_span(&self.references_table)
548            .join_span(&self.references_cols)
549            .join_span(&self.references_cols_r_paren)
550            .join_span(&self.not_valid)
551            .join_span(&self.ons)
552    }
553}
554
555fn parse_add_foreign_key<'a>(
556    parser: &mut Parser<'a, '_>,
557    add_span: Span,
558    constraint: Option<(Span, Option<Identifier<'a>>)>,
559) -> Result<AddForeignKey<'a>, ParseError> {
560    let foregin_key_span = parser.consume_keywords(&[Keyword::FOREIGN, Keyword::KEY])?;
561    let if_not_exists = if let Some(s) = parser.skip_keyword(Keyword::IF) {
562        Some(
563            parser
564                .consume_keywords(&[Keyword::NOT, Keyword::EXISTS])?
565                .join_span(&s),
566        )
567    } else {
568        None
569    };
570    let name = match &parser.token {
571        Token::Ident(_, kw) if !kw.restricted(parser.reserved()) => {
572            Some(parser.consume_plain_identifier_unreserved()?)
573        }
574        _ => None,
575    };
576
577    let (cols, cols_r_paren) = parse_index_cols(parser)?;
578    let references_span = parser.consume_keyword(Keyword::REFERENCES)?;
579    let references_table = parser.consume_plain_identifier_unreserved()?;
580    // Reference columns are optional (omitting uses the referenced table's primary key)
581    let (references_cols, references_cols_r_paren) = if matches!(parser.token, Token::LParen) {
582        let (c, s) = parse_cols(parser)?;
583        (c, Some(s))
584    } else {
585        (Vec::new(), None)
586    };
587    let mut ons = Vec::new();
588    while let Some(on) = parser.skip_keyword(Keyword::ON) {
589        let type_ = match parser.token {
590            Token::Ident(_, Keyword::UPDATE) => {
591                ForeignKeyOnType::Update(parser.consume_keyword(Keyword::UPDATE)?.join_span(&on))
592            }
593            Token::Ident(_, Keyword::DELETE) => {
594                ForeignKeyOnType::Delete(parser.consume_keyword(Keyword::DELETE)?.join_span(&on))
595            }
596            _ => parser.expected_failure("'UPDATE' or 'DELETE'")?,
597        };
598
599        let action = match parser.token {
600            Token::Ident(_, Keyword::RESTRICT) => {
601                ForeignKeyOnAction::Restrict(parser.consume_keyword(Keyword::RESTRICT)?)
602            }
603            Token::Ident(_, Keyword::CASCADE) => {
604                ForeignKeyOnAction::Cascade(parser.consume_keyword(Keyword::CASCADE)?)
605            }
606            Token::Ident(_, Keyword::SET) => {
607                let set = parser.consume_keyword(Keyword::SET)?;
608                match parser.token {
609                    Token::Ident(_, Keyword::NULL) => ForeignKeyOnAction::SetNull(
610                        parser.consume_keyword(Keyword::NULL)?.join_span(&set),
611                    ),
612                    Token::Ident(_, Keyword::DELETE) => ForeignKeyOnAction::SetDefault(
613                        parser.consume_keyword(Keyword::DEFAULT)?.join_span(&set),
614                    ),
615                    _ => parser.expected_failure("'NULL' or 'DEFAULT'")?,
616                }
617            }
618            Token::Ident(_, Keyword::NO) => ForeignKeyOnAction::SetNull(
619                parser.consume_keywords(&[Keyword::NO, Keyword::ACTION])?,
620            ),
621            _ => parser.expected_failure("'RESTRICT' or 'CASCADE', 'SET' or 'NO")?,
622        };
623        ons.push(ForeignKeyOn { type_, action })
624    }
625    // Parse optional NOT VALID
626    let not_valid = if let Some(span) = parser.skip_keyword(Keyword::NOT) {
627        Some(span.join_span(&parser.consume_keyword(Keyword::VALID)?))
628    } else {
629        None
630    };
631    Ok(AddForeignKey {
632        add_span,
633        constraint,
634        foreign_key_span: foregin_key_span,
635        if_not_exists,
636        name,
637        cols,
638        cols_r_paren,
639        references_span,
640        references_table,
641        references_cols,
642        references_cols_r_paren,
643        ons,
644        not_valid,
645    })
646}
647
648/// Modify a column
649#[derive(Clone, Debug)]
650pub struct ModifyColumn<'a> {
651    /// Span of "MODIFY"
652    pub modify_span: Span,
653    /// Span of "IF EXISTS" if specified
654    pub if_exists: Option<Span>,
655    /// Name of column to modify
656    pub col: Identifier<'a>,
657    /// New definition of column
658    pub definition: DataType<'a>,
659    /// Optional "FIRST"
660    pub first: Option<Span>,
661    /// Optional "AFTER col_name"
662    pub after: Option<(Span, Identifier<'a>)>,
663}
664
665impl<'a> Spanned for ModifyColumn<'a> {
666    fn span(&self) -> Span {
667        self.modify_span
668            .join_span(&self.if_exists)
669            .join_span(&self.col)
670            .join_span(&self.definition)
671            .join_span(&self.first)
672            .join_span(&self.after)
673    }
674}
675
676fn parse_modify_column<'a>(
677    parser: &mut Parser<'a, '_>,
678    mut modify_span: Span,
679) -> Result<ModifyColumn<'a>, ParseError> {
680    parser.maria_only(&modify_span);
681    if let Some(v) = parser.skip_keyword(Keyword::COLUMN) {
682        modify_span = modify_span.join_span(&v);
683    }
684    let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
685        Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&span))
686    } else {
687        None
688    };
689    let col = parser.consume_plain_identifier_unreserved()?;
690    let definition = parse_data_type(parser, DataTypeContext::Column)?;
691
692    let mut first = None;
693    let mut after = None;
694    match parser.token {
695        Token::Ident(_, Keyword::FIRST) => {
696            let first_span = parser.consume_keyword(Keyword::FIRST)?;
697            parser.maria_only(&first_span);
698            first = Some(first_span);
699        }
700        Token::Ident(_, Keyword::AFTER) => {
701            let after_span = parser.consume_keyword(Keyword::AFTER)?;
702            parser.maria_only(&after_span);
703            let col = parser.consume_plain_identifier_unreserved()?;
704            after = Some((after_span, col));
705        }
706        _ => {}
707    }
708
709    Ok(ModifyColumn {
710        modify_span,
711        if_exists,
712        col,
713        definition,
714        first,
715        after,
716    })
717}
718
719/// DROP COLUMN specification
720#[derive(Clone, Debug)]
721pub struct DropColumn<'a> {
722    /// Span of "DROP COLUMN"
723    pub drop_column_span: Span,
724    /// Span of "IF EXISTS" if specified (PostgreSQL)
725    pub if_exists: Option<Span>,
726    /// Name of column to drop
727    pub column: Identifier<'a>,
728    /// Span of "CASCADE" if specified
729    pub cascade: Option<Span>,
730}
731
732impl<'a> Spanned for DropColumn<'a> {
733    fn span(&self) -> Span {
734        self.drop_column_span
735            .join_span(&self.if_exists)
736            .join_span(&self.column)
737            .join_span(&self.cascade)
738    }
739}
740
741fn parse_drop_column<'a>(
742    parser: &mut Parser<'a, '_>,
743    drop_span: Span,
744) -> Result<DropColumn<'a>, ParseError> {
745    let drop_column_span = drop_span.join_span(&parser.consume_keyword(Keyword::COLUMN)?);
746    let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
747        let exists_span = parser.consume_keyword(Keyword::EXISTS)?.join_span(&span);
748        parser.postgres_only(&exists_span);
749        Some(exists_span)
750    } else {
751        None
752    };
753    let column = parser.consume_plain_identifier_unreserved()?;
754    let cascade = parser.skip_keyword(Keyword::CASCADE);
755    if let Some(span) = &cascade {
756        parser.postgres_only(span);
757    }
758    Ok(DropColumn {
759        drop_column_span,
760        if_exists,
761        column,
762        cascade,
763    })
764}
765
766/// DROP INDEX specification
767#[derive(Clone, Debug)]
768pub struct DropIndex<'a> {
769    /// Span of "DROP INDEX"
770    pub drop_index_span: Span,
771    /// Name of index to drop
772    pub name: Identifier<'a>,
773}
774
775impl<'a> Spanned for DropIndex<'a> {
776    fn span(&self) -> Span {
777        self.drop_index_span.join_span(&self.name)
778    }
779}
780
781fn parse_drop_index<'a>(
782    parser: &mut Parser<'a, '_>,
783    drop_span: Span,
784) -> Result<DropIndex<'a>, ParseError> {
785    let index_span = parser.consume();
786    let name = parser.consume_plain_identifier_unreserved()?;
787    Ok(DropIndex {
788        drop_index_span: drop_span.join_span(&index_span).join_span(&name),
789        name,
790    })
791}
792
793/// DROP FOREIGN KEY specification
794#[derive(Clone, Debug)]
795pub struct DropForeignKey<'a> {
796    /// Span of "DROP FOREIGN KEY"
797    pub drop_foreign_key_span: Span,
798    /// Name of foreign key to drop
799    pub name: Identifier<'a>,
800}
801
802impl<'a> Spanned for DropForeignKey<'a> {
803    fn span(&self) -> Span {
804        self.drop_foreign_key_span.join_span(&self.name)
805    }
806}
807
808fn parse_drop_foreign_key<'a>(
809    parser: &mut Parser<'a, '_>,
810    drop_span: Span,
811) -> Result<DropForeignKey<'a>, ParseError> {
812    let foreign_span = parser.consume_keywords(&[Keyword::FOREIGN, Keyword::KEY])?;
813    let name = parser.consume_plain_identifier_unreserved()?;
814    Ok(DropForeignKey {
815        drop_foreign_key_span: drop_span.join_span(&foreign_span).join_span(&name),
816        name,
817    })
818}
819
820/// DROP PRIMARY KEY specification
821#[derive(Clone, Debug)]
822pub struct DropPrimaryKey {
823    /// Span of "DROP PRIMARY KEY"
824    pub drop_primary_key_span: Span,
825}
826
827impl Spanned for DropPrimaryKey {
828    fn span(&self) -> Span {
829        self.drop_primary_key_span.clone()
830    }
831}
832
833fn parse_drop_primary_key(
834    parser: &mut Parser<'_, '_>,
835    drop_span: Span,
836) -> Result<DropPrimaryKey, ParseError> {
837    let primary_key_span = parser.consume_keywords(&[Keyword::PRIMARY, Keyword::KEY])?;
838    Ok(DropPrimaryKey {
839        drop_primary_key_span: drop_span.join_span(&primary_key_span),
840    })
841}
842
843/// ALTER COLUMN specification
844#[derive(Clone, Debug)]
845pub struct AlterColumn<'a> {
846    /// Span of "ALTER COLUMN"
847    pub alter_column_span: Span,
848    /// Name of column to alter
849    pub column: Identifier<'a>,
850    pub alter_column_action: AlterColumnAction<'a>,
851}
852
853impl<'a> Spanned for AlterColumn<'a> {
854    fn span(&self) -> Span {
855        self.alter_column_span
856            .join_span(&self.column)
857            .join_span(&self.alter_column_action)
858    }
859}
860
861// Note: parse_alter_column is complex and stays in parse_alter_table
862
863/// OWNER TO specification
864#[derive(Clone, Debug)]
865pub struct OwnerTo<'a> {
866    /// Span of "OWNER TO"
867    pub span: Span,
868    /// Name of owner
869    pub owner: AlterTableOwner<'a>,
870}
871
872impl<'a> Spanned for OwnerTo<'a> {
873    fn span(&self) -> Span {
874        self.span.join_span(&self.owner)
875    }
876}
877
878fn parse_owner_to<'a>(parser: &mut Parser<'a, '_>, span: Span) -> Result<OwnerTo<'a>, ParseError> {
879    let owner = parse_alter_owner(parser)?;
880    Ok(OwnerTo { span, owner })
881}
882
883/// LOCK specification
884#[derive(Clone, Debug)]
885pub struct Lock {
886    /// Span of "LOCK"
887    pub lock_span: Span,
888    pub lock: AlterLock,
889}
890
891impl Spanned for Lock {
892    fn span(&self) -> Span {
893        self.lock_span.join_span(&self.lock)
894    }
895}
896
897fn parse_lock(parser: &mut Parser<'_, '_>, lock_span: Span) -> Result<Lock, ParseError> {
898    parser.skip_token(Token::Eq);
899    let lock = match &parser.token {
900        Token::Ident(_, Keyword::DEFAULT) => {
901            AlterLock::Default(parser.consume_keyword(Keyword::DEFAULT)?)
902        }
903        Token::Ident(_, Keyword::NONE) => AlterLock::None(parser.consume_keyword(Keyword::NONE)?),
904        Token::Ident(_, Keyword::SHARED) => {
905            AlterLock::Shared(parser.consume_keyword(Keyword::SHARED)?)
906        }
907        Token::Ident(_, Keyword::EXCLUSIVE) => {
908            AlterLock::Exclusive(parser.consume_keyword(Keyword::EXCLUSIVE)?)
909        }
910        _ => parser.expected_failure("'DEFAULT', 'NONE', 'SHARED' or 'EXCLUSIVE'")?,
911    };
912    Ok(Lock { lock_span, lock })
913}
914
915/// RENAME COLUMN specification
916#[derive(Clone, Debug)]
917pub struct RenameColumn<'a> {
918    /// Span of "RENAME COLUMN"
919    pub rename_column_span: Span,
920    /// Old name of column
921    pub old_col_name: Identifier<'a>,
922    /// Span of "TO"
923    pub to_span: Span,
924    /// New name of column
925    pub new_col_name: Identifier<'a>,
926}
927
928impl<'a> Spanned for RenameColumn<'a> {
929    fn span(&self) -> Span {
930        self.rename_column_span
931            .join_span(&self.old_col_name)
932            .join_span(&self.to_span)
933            .join_span(&self.new_col_name)
934    }
935}
936
937fn parse_rename_column<'a>(
938    parser: &mut Parser<'a, '_>,
939    rename_span: Span,
940) -> Result<RenameColumn<'a>, ParseError> {
941    let column_span = parser.consume_keyword(Keyword::COLUMN)?;
942    let old_col_name = parser.consume_plain_identifier_unreserved()?;
943    let to_span = parser.consume_keyword(Keyword::TO)?;
944    let new_col_name = parser.consume_plain_identifier_unreserved()?;
945    Ok(RenameColumn {
946        rename_column_span: rename_span.join_span(&column_span),
947        old_col_name,
948        to_span,
949        new_col_name,
950    })
951}
952
953/// RENAME INDEX specification
954#[derive(Clone, Debug)]
955pub struct RenameIndex<'a> {
956    /// Span of "RENAME INDEX" or "RENAME KEY"
957    pub rename_index_span: Span,
958    /// Old name of index
959    pub old_index_name: Identifier<'a>,
960    /// Span of "TO"
961    pub to_span: Span,
962    /// New name of index
963    pub new_index_name: Identifier<'a>,
964}
965
966impl<'a> Spanned for RenameIndex<'a> {
967    fn span(&self) -> Span {
968        self.rename_index_span
969            .join_span(&self.old_index_name)
970            .join_span(&self.to_span)
971            .join_span(&self.new_index_name)
972    }
973}
974
975fn parse_rename_index<'a>(
976    parser: &mut Parser<'a, '_>,
977    rename_span: Span,
978) -> Result<RenameIndex<'a>, ParseError> {
979    let index_span = parser.consume();
980    let old_index_name = parser.consume_plain_identifier_unreserved()?;
981    let to_span = parser.consume_keyword(Keyword::TO)?;
982    let new_index_name = parser.consume_plain_identifier_unreserved()?;
983    Ok(RenameIndex {
984        rename_index_span: rename_span.join_span(&index_span),
985        old_index_name,
986        to_span,
987        new_index_name,
988    })
989}
990
991/// RENAME CONSTRAINT specification
992#[derive(Clone, Debug)]
993pub struct RenameConstraint<'a> {
994    /// Span of "RENAME CONSTRAINT"
995    pub rename_constraint_span: Span,
996    /// Old name of constraint
997    pub old_constraint_name: Identifier<'a>,
998    /// Span of "TO"
999    pub to_span: Span,
1000    /// New name of constraint
1001    pub new_constraint_name: Identifier<'a>,
1002}
1003
1004impl<'a> Spanned for RenameConstraint<'a> {
1005    fn span(&self) -> Span {
1006        self.rename_constraint_span
1007            .join_span(&self.old_constraint_name)
1008            .join_span(&self.to_span)
1009            .join_span(&self.new_constraint_name)
1010    }
1011}
1012
1013fn parse_rename_constraint<'a>(
1014    parser: &mut Parser<'a, '_>,
1015    rename_span: Span,
1016) -> Result<RenameConstraint<'a>, ParseError> {
1017    let constraint_span = parser.consume_keyword(Keyword::CONSTRAINT)?;
1018    parser.postgres_only(&constraint_span);
1019    let old_constraint_name = parser.consume_plain_identifier_unreserved()?;
1020    let to_span = parser.consume_keyword(Keyword::TO)?;
1021    let new_constraint_name = parser.consume_plain_identifier_unreserved()?;
1022    Ok(RenameConstraint {
1023        rename_constraint_span: rename_span.join_span(&constraint_span),
1024        old_constraint_name,
1025        to_span,
1026        new_constraint_name,
1027    })
1028}
1029
1030/// RENAME TO specification
1031#[derive(Clone, Debug)]
1032pub struct RenameTo<'a> {
1033    /// Span of "RENAME"
1034    pub rename_span: Span,
1035    /// Span of "TO" or "AS"
1036    pub to_span: Span,
1037    /// New name of table
1038    pub new_table_name: Identifier<'a>,
1039}
1040
1041impl<'a> Spanned for RenameTo<'a> {
1042    fn span(&self) -> Span {
1043        self.rename_span
1044            .join_span(&self.to_span)
1045            .join_span(&self.new_table_name)
1046    }
1047}
1048
1049fn parse_rename_to<'a>(
1050    parser: &mut Parser<'a, '_>,
1051    rename_span: Span,
1052) -> Result<RenameTo<'a>, ParseError> {
1053    let to_span = parser.consume();
1054    let new_table_name = parser.consume_plain_identifier_unreserved()?;
1055    Ok(RenameTo {
1056        rename_span,
1057        to_span,
1058        new_table_name,
1059    })
1060}
1061
1062/// ALGORITHM specification
1063#[derive(Clone, Debug)]
1064pub struct Algorithm {
1065    /// Span of "ALGORITHM"
1066    pub algorithm_span: Span,
1067    pub algorithm: AlterAlgorithm,
1068}
1069
1070impl Spanned for Algorithm {
1071    fn span(&self) -> Span {
1072        self.algorithm_span.join_span(&self.algorithm)
1073    }
1074}
1075
1076fn parse_algorithm(
1077    parser: &mut Parser<'_, '_>,
1078    algorithm_span: Span,
1079) -> Result<Algorithm, ParseError> {
1080    parser.skip_token(Token::Eq);
1081    let algorithm = match &parser.token {
1082        Token::Ident(_, Keyword::DEFAULT) => {
1083            AlterAlgorithm::Default(parser.consume_keyword(Keyword::DEFAULT)?)
1084        }
1085        Token::Ident(_, Keyword::INSTANT) => {
1086            AlterAlgorithm::Instant(parser.consume_keyword(Keyword::INSTANT)?)
1087        }
1088        Token::Ident(_, Keyword::INPLACE) => {
1089            AlterAlgorithm::Inplace(parser.consume_keyword(Keyword::INPLACE)?)
1090        }
1091        Token::Ident(_, Keyword::COPY) => {
1092            AlterAlgorithm::Copy(parser.consume_keyword(Keyword::COPY)?)
1093        }
1094        _ => parser.expected_failure("'DEFAULT', 'INSTANT', 'INPLACE' or 'COPY'")?,
1095    };
1096    Ok(Algorithm {
1097        algorithm_span,
1098        algorithm,
1099    })
1100}
1101
1102/// AUTO_INCREMENT specification
1103#[derive(Clone, Debug)]
1104pub struct AutoIncrement {
1105    /// Span of "AUTO_INCREMENT"
1106    pub auto_increment_span: Span,
1107    pub value_span: Span,
1108    /// New value for auto_increment
1109    pub value: u64,
1110}
1111
1112impl Spanned for AutoIncrement {
1113    fn span(&self) -> Span {
1114        self.auto_increment_span.join_span(&self.value_span)
1115    }
1116}
1117
1118fn parse_auto_increment(
1119    parser: &mut Parser<'_, '_>,
1120    auto_increment_span: Span,
1121) -> Result<AutoIncrement, ParseError> {
1122    parser.skip_token(Token::Eq);
1123    let (value, value_span) = parser.consume_int()?;
1124    Ok(AutoIncrement {
1125        auto_increment_span,
1126        value_span,
1127        value,
1128    })
1129}
1130
1131/// CHANGE specification
1132#[derive(Clone, Debug)]
1133pub struct Change<'a> {
1134    /// Span of "CHANGE"
1135    pub change_span: Span,
1136    /// Optional span of "COLUMN"
1137    pub column_span: Option<Span>,
1138    /// Old name of column
1139    pub column: Identifier<'a>,
1140    /// New name of column
1141    pub new_column: Identifier<'a>,
1142    /// New definition of column
1143    pub definition: DataType<'a>,
1144    /// Optional "FIRST"
1145    pub first: Option<Span>,
1146    /// Optional "AFTER col_name"
1147    pub after: Option<(Span, Identifier<'a>)>,
1148}
1149
1150impl<'a> Spanned for Change<'a> {
1151    fn span(&self) -> Span {
1152        self.change_span
1153            .join_span(&self.column_span)
1154            .join_span(&self.column)
1155            .join_span(&self.new_column)
1156            .join_span(&self.definition)
1157            .join_span(&self.first)
1158            .join_span(&self.after)
1159    }
1160}
1161
1162fn parse_change<'a>(
1163    parser: &mut Parser<'a, '_>,
1164    change_span: Span,
1165) -> Result<Change<'a>, ParseError> {
1166    let column_span = parser.skip_keyword(Keyword::COLUMN);
1167
1168    let column = parser.consume_plain_identifier_unreserved()?;
1169    let new_column = parser.consume_plain_identifier_unreserved()?;
1170    let definition = parse_data_type(parser, DataTypeContext::Column)?;
1171
1172    let mut first = None;
1173    let mut after = None;
1174    match parser.token {
1175        Token::Ident(_, Keyword::FIRST) => {
1176            let first_span = parser.consume_keyword(Keyword::FIRST)?;
1177            parser.maria_only(&first_span);
1178            first = Some(first_span);
1179        }
1180        Token::Ident(_, Keyword::AFTER) => {
1181            let after_span = parser.consume_keyword(Keyword::AFTER)?;
1182            parser.maria_only(&after_span);
1183            let col = parser.consume_plain_identifier_unreserved()?;
1184            after = Some((after_span, col));
1185        }
1186        _ => {}
1187    }
1188
1189    Ok(Change {
1190        change_span,
1191        column_span,
1192        column,
1193        new_column,
1194        definition,
1195        first,
1196        after,
1197    })
1198}
1199
1200/// PostgreSQL: REPLICA IDENTITY { DEFAULT | USING INDEX <name> | FULL | NOTHING }
1201#[derive(Clone, Debug)]
1202pub struct ReplicaIdentity<'a> {
1203    pub replica_span: Span,
1204    pub identity_span: Span,
1205    pub option: ReplicaIdentityOption<'a>,
1206}
1207
1208impl<'a> Spanned for ReplicaIdentity<'a> {
1209    fn span(&self) -> Span {
1210        self.replica_span
1211            .join_span(&self.identity_span)
1212            .join_span(&match &self.option {
1213                ReplicaIdentityOption::Default(s) => s.clone(),
1214                ReplicaIdentityOption::Full(s) => s.clone(),
1215                ReplicaIdentityOption::Nothing(s) => s.clone(),
1216                ReplicaIdentityOption::UsingIndex {
1217                    using_span,
1218                    index_span,
1219                    name,
1220                } => using_span.join_span(index_span).join_span(name),
1221            })
1222    }
1223}
1224
1225// Note: parse_replica_identity stays inline in parse_alter_table due to complexity
1226
1227/// PostgreSQL: VALIDATE CONSTRAINT constraint_name
1228#[derive(Clone, Debug)]
1229pub struct ValidateConstraint<'a> {
1230    pub validate_span: Span,
1231    pub constraint_span: Span,
1232    pub constraint_name: Identifier<'a>,
1233}
1234
1235impl<'a> Spanned for ValidateConstraint<'a> {
1236    fn span(&self) -> Span {
1237        self.validate_span
1238            .join_span(&self.constraint_span)
1239            .join_span(&self.constraint_name)
1240    }
1241}
1242
1243fn parse_validate_constraint<'a>(
1244    parser: &mut Parser<'a, '_>,
1245    validate_span: Span,
1246) -> Result<ValidateConstraint<'a>, ParseError> {
1247    let constraint_span = parser.consume_keyword(Keyword::CONSTRAINT)?;
1248    let constraint_name = parser.consume_plain_identifier_unreserved()?;
1249    Ok(ValidateConstraint {
1250        validate_span,
1251        constraint_span,
1252        constraint_name,
1253    })
1254}
1255
1256/// PostgreSQL: ADD CONSTRAINT ... UNIQUE/PRIMARY KEY/CHECK
1257#[derive(Clone, Debug)]
1258pub struct AddTableConstraint<'a> {
1259    pub add_span: Span,
1260    pub constraint: Option<(Span, Option<Identifier<'a>>)>,
1261    pub constraint_type: TableConstraintType<'a>,
1262    pub not_valid: Option<Span>,
1263}
1264
1265impl<'a> Spanned for AddTableConstraint<'a> {
1266    fn span(&self) -> Span {
1267        let type_span = match &self.constraint_type {
1268            TableConstraintType::Unique {
1269                unique_span,
1270                nulls_clause,
1271                cols,
1272                r_paren,
1273            } => unique_span
1274                .join_span(nulls_clause)
1275                .join_span(cols)
1276                .join_span(r_paren),
1277            TableConstraintType::PrimaryKey {
1278                primary_span,
1279                key_span,
1280                cols,
1281                r_paren,
1282            } => primary_span
1283                .join_span(key_span)
1284                .join_span(cols)
1285                .join_span(r_paren),
1286            TableConstraintType::Check { check_span, expr } => check_span.join_span(expr),
1287        };
1288        self.add_span
1289            .join_span(&self.constraint)
1290            .join_span(&type_span)
1291            .join_span(&self.not_valid)
1292    }
1293}
1294
1295// Note: parse_add_table_constraint variants stay inline in parse_add_alter_specification
1296
1297/// PostgreSQL: DISABLE TRIGGER { trigger_name | ALL | USER }
1298#[derive(Clone, Debug)]
1299pub struct DisableTrigger<'a> {
1300    pub disable_span: Span,
1301    pub trigger_span: Span,
1302    pub trigger_name: TriggerName<'a>,
1303}
1304
1305impl<'a> Spanned for DisableTrigger<'a> {
1306    fn span(&self) -> Span {
1307        let name_span = match &self.trigger_name {
1308            TriggerName::Named(n) => n.span(),
1309            TriggerName::All(s) => s.clone(),
1310            TriggerName::User(s) => s.clone(),
1311        };
1312        self.disable_span
1313            .join_span(&self.trigger_span)
1314            .join_span(&name_span)
1315    }
1316}
1317
1318// Note: parse_disable_trigger stays inline due to DISABLE/ENABLE branching logic
1319
1320/// PostgreSQL: ENABLE [ REPLICA | ALWAYS ] TRIGGER { trigger_name | ALL | USER }
1321#[derive(Clone, Debug)]
1322pub struct EnableTrigger<'a> {
1323    pub enable_span: Span,
1324    pub modifier: Option<Span>, // REPLICA or ALWAYS
1325    pub trigger_span: Span,
1326    pub trigger_name: TriggerName<'a>,
1327}
1328
1329impl<'a> Spanned for EnableTrigger<'a> {
1330    fn span(&self) -> Span {
1331        let name_span = match &self.trigger_name {
1332            TriggerName::Named(n) => n.span(),
1333            TriggerName::All(s) => s.clone(),
1334            TriggerName::User(s) => s.clone(),
1335        };
1336        self.enable_span
1337            .join_span(&self.modifier)
1338            .join_span(&self.trigger_span)
1339            .join_span(&name_span)
1340    }
1341}
1342
1343// Note: parse_enable_trigger stays inline due to DISABLE/ENABLE branching logic
1344
1345/// PostgreSQL: DISABLE RULE rule_name
1346#[derive(Clone, Debug)]
1347pub struct DisableRule<'a> {
1348    pub disable_span: Span,
1349    pub rule_span: Span,
1350    pub rule_name: Identifier<'a>,
1351}
1352
1353impl<'a> Spanned for DisableRule<'a> {
1354    fn span(&self) -> Span {
1355        self.disable_span
1356            .join_span(&self.rule_span)
1357            .join_span(&self.rule_name)
1358    }
1359}
1360
1361// Note: parse_disable_rule stays inline due to DISABLE/ENABLE branching logic
1362
1363/// PostgreSQL: ENABLE [ REPLICA | ALWAYS ] RULE rule_name
1364#[derive(Clone, Debug)]
1365pub struct EnableRule<'a> {
1366    pub enable_span: Span,
1367    pub modifier: Option<Span>, // REPLICA or ALWAYS
1368    pub rule_span: Span,
1369    pub rule_name: Identifier<'a>,
1370}
1371
1372impl<'a> Spanned for EnableRule<'a> {
1373    fn span(&self) -> Span {
1374        self.enable_span
1375            .join_span(&self.modifier)
1376            .join_span(&self.rule_span)
1377            .join_span(&self.rule_name)
1378    }
1379}
1380
1381// Note: parse_enable_rule stays inline due to DISABLE/ENABLE branching logic
1382
1383/// PostgreSQL: DISABLE ROW LEVEL SECURITY
1384#[derive(Clone, Debug)]
1385pub struct DisableRowLevelSecurity {
1386    pub disable_span: Span,
1387    pub row_span: Span,
1388    pub level_span: Span,
1389    pub security_span: Span,
1390}
1391
1392impl Spanned for DisableRowLevelSecurity {
1393    fn span(&self) -> Span {
1394        self.disable_span
1395            .join_span(&self.row_span)
1396            .join_span(&self.level_span)
1397            .join_span(&self.security_span)
1398    }
1399}
1400
1401// Note: parse_disable_row_level_security stays inline due to DISABLE/ENABLE branching logic
1402
1403/// PostgreSQL: ENABLE ROW LEVEL SECURITY
1404#[derive(Clone, Debug)]
1405pub struct EnableRowLevelSecurity {
1406    pub enable_span: Span,
1407    pub row_span: Span,
1408    pub level_span: Span,
1409    pub security_span: Span,
1410}
1411
1412impl Spanned for EnableRowLevelSecurity {
1413    fn span(&self) -> Span {
1414        self.enable_span
1415            .join_span(&self.row_span)
1416            .join_span(&self.level_span)
1417            .join_span(&self.security_span)
1418    }
1419}
1420
1421// Note: parse_enable_row_level_security stays inline due to DISABLE/ENABLE branching logic
1422
1423/// PostgreSQL: FORCE ROW LEVEL SECURITY
1424#[derive(Clone, Debug)]
1425pub struct ForceRowLevelSecurity {
1426    pub force_span: Span,
1427    pub row_span: Span,
1428    pub level_span: Span,
1429    pub security_span: Span,
1430}
1431
1432impl Spanned for ForceRowLevelSecurity {
1433    fn span(&self) -> Span {
1434        self.force_span
1435            .join_span(&self.row_span)
1436            .join_span(&self.level_span)
1437            .join_span(&self.security_span)
1438    }
1439}
1440
1441// Note: parse_force_row_level_security stays inline due to FORCE/NO FORCE branching
1442
1443/// PostgreSQL: NO FORCE ROW LEVEL SECURITY
1444#[derive(Clone, Debug)]
1445pub struct NoForceRowLevelSecurity {
1446    pub no_span: Span,
1447    pub force_span: Span,
1448    pub row_span: Span,
1449    pub level_span: Span,
1450    pub security_span: Span,
1451}
1452
1453impl Spanned for NoForceRowLevelSecurity {
1454    fn span(&self) -> Span {
1455        self.no_span
1456            .join_span(&self.force_span)
1457            .join_span(&self.row_span)
1458            .join_span(&self.level_span)
1459            .join_span(&self.security_span)
1460    }
1461}
1462
1463// Note: parse_no_force_row_level_security stays inline due to FORCE/NO FORCE branching
1464
1465/// Enum of alterations to perform on a table
1466#[derive(Clone, Debug)]
1467pub enum AlterSpecification<'a> {
1468    AddColumn(AddColumn<'a>),
1469    AddIndex(AddIndex<'a>),
1470    AddForeignKey(AddForeignKey<'a>),
1471    Modify(ModifyColumn<'a>),
1472    DropColumn(DropColumn<'a>),
1473    DropIndex(DropIndex<'a>),
1474    DropForeignKey(DropForeignKey<'a>),
1475    DropPrimaryKey(DropPrimaryKey),
1476    AlterColumn(AlterColumn<'a>),
1477    OwnerTo(OwnerTo<'a>),
1478    Lock(Lock),
1479    RenameColumn(RenameColumn<'a>),
1480    RenameIndex(RenameIndex<'a>),
1481    RenameConstraint(RenameConstraint<'a>),
1482    RenameTo(RenameTo<'a>),
1483    Algorithm(Algorithm),
1484    AutoIncrement(AutoIncrement),
1485    Change(Change<'a>),
1486    ReplicaIdentity(ReplicaIdentity<'a>),
1487    ValidateConstraint(ValidateConstraint<'a>),
1488    AddTableConstraint(AddTableConstraint<'a>),
1489    DisableTrigger(DisableTrigger<'a>),
1490    EnableTrigger(EnableTrigger<'a>),
1491    DisableRule(DisableRule<'a>),
1492    EnableRule(EnableRule<'a>),
1493    DisableRowLevelSecurity(DisableRowLevelSecurity),
1494    EnableRowLevelSecurity(EnableRowLevelSecurity),
1495    ForceRowLevelSecurity(ForceRowLevelSecurity),
1496    NoForceRowLevelSecurity(NoForceRowLevelSecurity),
1497}
1498
1499/// Options for REPLICA IDENTITY
1500#[derive(Clone, Debug)]
1501pub enum ReplicaIdentityOption<'a> {
1502    Default(Span),
1503    Full(Span),
1504    Nothing(Span),
1505    UsingIndex {
1506        using_span: Span,
1507        index_span: Span,
1508        name: Identifier<'a>,
1509    },
1510}
1511
1512/// Table constraint types for ADD CONSTRAINT
1513#[derive(Clone, Debug)]
1514pub enum TableConstraintType<'a> {
1515    Unique {
1516        unique_span: Span,
1517        nulls_clause: Option<(Span, Option<Span>)>, // (NULLS, NOT?)
1518        cols: Vec<Identifier<'a>>,
1519        r_paren: Span,
1520    },
1521    PrimaryKey {
1522        primary_span: Span,
1523        key_span: Span,
1524        cols: Vec<Identifier<'a>>,
1525        r_paren: Span,
1526    },
1527    Check {
1528        check_span: Span,
1529        expr: Expression<'a>,
1530    },
1531}
1532
1533/// Trigger name variants for ENABLE/DISABLE TRIGGER
1534#[derive(Clone, Debug)]
1535pub enum TriggerName<'a> {
1536    Named(Identifier<'a>),
1537    All(Span),
1538    User(Span),
1539}
1540
1541impl<'a> Spanned for AlterSpecification<'a> {
1542    fn span(&self) -> Span {
1543        match self {
1544            AlterSpecification::AddColumn(v) => v.span(),
1545            AlterSpecification::AddIndex(v) => v.span(),
1546            AlterSpecification::AddForeignKey(v) => v.span(),
1547            AlterSpecification::Modify(v) => v.span(),
1548            AlterSpecification::DropColumn(v) => v.span(),
1549            AlterSpecification::DropIndex(v) => v.span(),
1550            AlterSpecification::DropForeignKey(v) => v.span(),
1551            AlterSpecification::DropPrimaryKey(v) => v.span(),
1552            AlterSpecification::AlterColumn(v) => v.span(),
1553            AlterSpecification::OwnerTo(v) => v.span(),
1554            AlterSpecification::Lock(v) => v.span(),
1555            AlterSpecification::RenameColumn(v) => v.span(),
1556            AlterSpecification::RenameIndex(v) => v.span(),
1557            AlterSpecification::RenameConstraint(v) => v.span(),
1558            AlterSpecification::RenameTo(v) => v.span(),
1559            AlterSpecification::Algorithm(v) => v.span(),
1560            AlterSpecification::AutoIncrement(v) => v.span(),
1561            AlterSpecification::Change(v) => v.span(),
1562            AlterSpecification::ReplicaIdentity(v) => v.span(),
1563            AlterSpecification::ValidateConstraint(v) => v.span(),
1564            AlterSpecification::AddTableConstraint(v) => v.span(),
1565            AlterSpecification::DisableTrigger(v) => v.span(),
1566            AlterSpecification::EnableTrigger(v) => v.span(),
1567            AlterSpecification::DisableRule(v) => v.span(),
1568            AlterSpecification::EnableRule(v) => v.span(),
1569            AlterSpecification::DisableRowLevelSecurity(v) => v.span(),
1570            AlterSpecification::EnableRowLevelSecurity(v) => v.span(),
1571            AlterSpecification::ForceRowLevelSecurity(v) => v.span(),
1572            AlterSpecification::NoForceRowLevelSecurity(v) => v.span(),
1573        }
1574    }
1575}
1576
1577pub(crate) fn parse_index_type<'a>(
1578    parser: &mut Parser<'a, '_>,
1579    out: &mut Vec<IndexOption<'a>>,
1580) -> Result<(), ParseError> {
1581    parser.consume_keyword(Keyword::USING)?;
1582    out.push(match &parser.token {
1583        Token::Ident(_, Keyword::BTREE) => {
1584            IndexOption::IndexTypeBTree(parser.consume_keyword(Keyword::BTREE)?)
1585        }
1586        Token::Ident(_, Keyword::HASH) => {
1587            IndexOption::IndexTypeHash(parser.consume_keyword(Keyword::HASH)?)
1588        }
1589        Token::Ident(_, Keyword::RTREE) => {
1590            IndexOption::IndexTypeRTree(parser.consume_keyword(Keyword::RTREE)?)
1591        }
1592        _ => parser.expected_failure("'BTREE', 'RTREE' or 'HASH'")?,
1593    });
1594    Ok(())
1595}
1596
1597pub(crate) fn parse_index_options<'a>(
1598    parser: &mut Parser<'a, '_>,
1599    out: &mut Vec<IndexOption<'a>>,
1600) -> Result<(), ParseError> {
1601    loop {
1602        match &parser.token {
1603            Token::Ident(_, Keyword::USING) => parse_index_type(parser, out)?,
1604            Token::Ident(_, Keyword::COMMENT) => {
1605                parser.consume_keyword(Keyword::COMMENT)?;
1606                out.push(IndexOption::Comment(parser.consume_string()?))
1607            }
1608            _ => break,
1609        }
1610    }
1611    Ok(())
1612}
1613
1614/// Parse optional operator class (PostgreSQL)
1615/// This can be a qualified name like public.vector_cosine_ops or a known pattern_ops keyword
1616pub(crate) fn parse_operator_class<'a>(
1617    parser: &mut Parser<'a, '_>,
1618) -> Result<Option<QualifiedName<'a>>, ParseError> {
1619    if matches!(
1620        parser.token,
1621        Token::Ident(
1622            _,
1623            Keyword::TEXT_PATTERN_OPS
1624                | Keyword::VARCHAR_PATTERN_OPS
1625                | Keyword::BPCHAR_PATTERN_OPS
1626                | Keyword::INT8_OPS
1627                | Keyword::INT4_OPS
1628                | Keyword::INT2_OPS
1629        )
1630    ) {
1631        // Known pattern_ops keywords
1632        match parser.token {
1633            Token::Ident(v, _) => {
1634                let value = v;
1635                let span = parser.consume();
1636                parser.postgres_only(&span);
1637                Ok(Some(QualifiedName {
1638                    prefix: Vec::new(),
1639                    identifier: Identifier { value, span },
1640                }))
1641            }
1642            _ => Ok(None),
1643        }
1644    } else if matches!(parser.token, Token::Ident(_, _))
1645        && !matches!(
1646            parser.token,
1647            Token::Ident(_, Keyword::ASC | Keyword::DESC | Keyword::NULLS)
1648        )
1649        && *parser.peek() != Token::Comma
1650        && *parser.peek() != Token::RParen
1651    {
1652        // Try to parse as qualified name (for things like public.vector_cosine_ops)
1653        let qname = parse_qualified_name_unreserved(parser)?;
1654        parser.postgres_only(&qname);
1655        Ok(Some(qname))
1656    } else {
1657        Ok(None)
1658    }
1659}
1660
1661pub(crate) fn parse_index_cols<'a>(
1662    parser: &mut Parser<'a, '_>,
1663) -> Result<(Vec<IndexCol<'a>>, Span), ParseError> {
1664    parser.consume_token(Token::LParen)?;
1665    let mut ans = Vec::new();
1666    parser.recovered("')'", &|t| t == &Token::RParen, |parser| {
1667        loop {
1668            // Check if this is a functional index expression (starts with '(')
1669            let expr = if parser.token == Token::LParen {
1670                // Functional index: parse expression
1671                parser.consume_token(Token::LParen)?;
1672                let expression = parse_expression_unreserved(parser, PRIORITY_MAX)?;
1673                parser.consume_token(Token::RParen)?;
1674                IndexColExpr::Expression(expression)
1675            } else {
1676                // Regular column name
1677                let name = parser.consume_plain_identifier_unreserved()?;
1678                IndexColExpr::Column(name)
1679            };
1680
1681            let size = if parser.skip_token(Token::LParen).is_some() {
1682                let size = parser.recovered("')'", &|t| t == &Token::RParen, |parser| {
1683                    parser.consume_int()
1684                })?;
1685                parser.consume_token(Token::RParen)?;
1686                Some(size)
1687            } else {
1688                None
1689            };
1690
1691            // Parse optional operator class (PostgreSQL)
1692            let opclass = parse_operator_class(parser)?;
1693
1694            // Parse optional ASC | DESC
1695            let asc = parser.skip_keyword(Keyword::ASC);
1696            let desc = if asc.is_none() {
1697                parser.skip_keyword(Keyword::DESC)
1698            } else {
1699                None
1700            };
1701
1702            ans.push(IndexCol {
1703                expr,
1704                size,
1705                opclass,
1706                asc,
1707                desc,
1708            });
1709            if parser.skip_token(Token::Comma).is_none() {
1710                break;
1711            }
1712        }
1713        Ok(())
1714    })?;
1715    let r_paren_span = parser.consume_token(Token::RParen)?;
1716    Ok((ans, r_paren_span))
1717}
1718
1719fn parse_cols<'a>(parser: &mut Parser<'a, '_>) -> Result<(Vec<Identifier<'a>>, Span), ParseError> {
1720    parser.consume_token(Token::LParen)?;
1721    let mut ans = Vec::new();
1722    parser.recovered("')'", &|t| t == &Token::RParen, |parser| {
1723        loop {
1724            ans.push(parser.consume_plain_identifier_unreserved()?);
1725            if parser.skip_token(Token::Comma).is_none() {
1726                break;
1727            }
1728        }
1729        Ok(())
1730    })?;
1731    let r_paren_span = parser.consume_token(Token::RParen)?;
1732    Ok((ans, r_paren_span))
1733}
1734
1735fn parse_add_alter_specification<'a>(
1736    parser: &mut Parser<'a, '_>,
1737) -> Result<AlterSpecification<'a>, ParseError> {
1738    let add_span = parser.consume_keyword(Keyword::ADD)?;
1739    let constraint = if let Some(span) = parser.skip_keyword(Keyword::CONSTRAINT) {
1740        let v = match &parser.token {
1741            Token::Ident(_, kw)
1742                if !kw.restricted(parser.reserved()) || kw == &Keyword::QUOTED_IDENTIFIER =>
1743            {
1744                Some(parser.consume_plain_identifier_restrict(Restrict::EMPTY)?)
1745            }
1746            Token::String(_, StringType::DoubleQuoted)
1747                if parser.options.dialect.is_postgresql() =>
1748            {
1749                Some(parser.consume_plain_identifier_restrict(Restrict::EMPTY)?)
1750            }
1751            _ => None,
1752        };
1753        Some((span, v))
1754    } else {
1755        None
1756    };
1757    // Peek ahead to check if PRIMARY is followed by KEY (for distinguishing table constraints)
1758    let primary_followed_by_key = matches!(&parser.token, Token::Ident(_, Keyword::PRIMARY))
1759        && matches!(parser.peek(), Token::Ident(_, Keyword::KEY));
1760
1761    match &parser.token {
1762        // Check for table constraints (UNIQUE/PRIMARY KEY without explicit INDEX/KEY keyword)
1763        Token::Ident(_, Keyword::UNIQUE) if constraint.is_some() => {
1764            // This is ADD CONSTRAINT ... UNIQUE (...) - a table constraint, not an index
1765            let unique_span = parser.consume_keyword(Keyword::UNIQUE)?;
1766            parser.postgres_only(&unique_span);
1767            // Parse optional NULLS [NOT] DISTINCT
1768            let nulls_clause = if let Some(nulls_span) = parser.skip_keyword(Keyword::NULLS) {
1769                let not_span = parser.skip_keyword(Keyword::NOT);
1770                parser.consume_keyword(Keyword::DISTINCT)?;
1771                Some((nulls_span, not_span))
1772            } else {
1773                None
1774            };
1775            let (cols, r_paren) = parse_cols(parser)?;
1776            let not_valid = if let Some(span) = parser.skip_keyword(Keyword::NOT) {
1777                Some(span.join_span(&parser.consume_keyword(Keyword::VALID)?))
1778            } else {
1779                None
1780            };
1781            Ok(AlterSpecification::AddTableConstraint(AddTableConstraint {
1782                add_span,
1783                constraint,
1784                constraint_type: TableConstraintType::Unique {
1785                    unique_span,
1786                    nulls_clause,
1787                    cols,
1788                    r_paren,
1789                },
1790                not_valid,
1791            }))
1792        }
1793        Token::Ident(_, Keyword::PRIMARY) if constraint.is_some() && primary_followed_by_key => {
1794            // This is ADD CONSTRAINT ... PRIMARY KEY (...) - a table constraint
1795            let primary_span = parser.consume_keyword(Keyword::PRIMARY)?;
1796            parser.postgres_only(&primary_span);
1797            let key_span = parser.consume_keyword(Keyword::KEY)?;
1798            let (cols, r_paren) = parse_cols(parser)?;
1799            let not_valid = if let Some(span) = parser.skip_keyword(Keyword::NOT) {
1800                Some(span.join_span(&parser.consume_keyword(Keyword::VALID)?))
1801            } else {
1802                None
1803            };
1804            Ok(AlterSpecification::AddTableConstraint(AddTableConstraint {
1805                add_span,
1806                constraint,
1807                constraint_type: TableConstraintType::PrimaryKey {
1808                    primary_span,
1809                    key_span,
1810                    cols,
1811                    r_paren,
1812                },
1813                not_valid,
1814            }))
1815        }
1816        Token::Ident(_, Keyword::CHECK) if constraint.is_some() => {
1817            // This is ADD CONSTRAINT ... CHECK (...)
1818            let check_span = parser.consume_keyword(Keyword::CHECK)?;
1819            parser.postgres_only(&check_span);
1820            parser.consume_token(Token::LParen)?;
1821            let expr = parse_expression_unreserved(parser, PRIORITY_MAX)?;
1822            parser.consume_token(Token::RParen)?;
1823            let not_valid = if let Some(span) = parser.skip_keyword(Keyword::NOT) {
1824                Some(span.join_span(&parser.consume_keyword(Keyword::VALID)?))
1825            } else {
1826                None
1827            };
1828            Ok(AlterSpecification::AddTableConstraint(AddTableConstraint {
1829                add_span,
1830                constraint,
1831                constraint_type: TableConstraintType::Check { check_span, expr },
1832                not_valid,
1833            }))
1834        }
1835        Token::Ident(_, Keyword::FOREIGN) => Ok(AlterSpecification::AddForeignKey(
1836            parse_add_foreign_key(parser, add_span, constraint)?,
1837        )),
1838        Token::Ident(
1839            _,
1840            Keyword::PRIMARY
1841            | Keyword::INDEX
1842            | Keyword::KEY
1843            | Keyword::FULLTEXT
1844            | Keyword::UNIQUE
1845            | Keyword::SPATIAL,
1846        ) => Ok(AlterSpecification::AddIndex(parse_add_index(
1847            parser, add_span, constraint,
1848        )?)),
1849        Token::Ident(_, Keyword::COLUMN) => Ok(AlterSpecification::AddColumn(parse_add_column(
1850            parser, add_span,
1851        )?)),
1852        _ => parser.expected_failure("addable"),
1853    }
1854}
1855
1856fn parse_rename_alter_specification<'a>(
1857    parser: &mut Parser<'a, '_>,
1858) -> Result<AlterSpecification<'a>, ParseError> {
1859    let rename_span = parser.consume_keyword(Keyword::RENAME)?;
1860
1861    match parser.token {
1862        Token::Ident(_, Keyword::COLUMN) => Ok(AlterSpecification::RenameColumn(
1863            parse_rename_column(parser, rename_span)?,
1864        )),
1865        Token::Ident(_, Keyword::INDEX | Keyword::KEY) => Ok(AlterSpecification::RenameIndex(
1866            parse_rename_index(parser, rename_span)?,
1867        )),
1868        Token::Ident(_, Keyword::CONSTRAINT) => Ok(AlterSpecification::RenameConstraint(
1869            parse_rename_constraint(parser, rename_span)?,
1870        )),
1871        Token::Ident(_, Keyword::TO | Keyword::AS) => Ok(AlterSpecification::RenameTo(
1872            parse_rename_to(parser, rename_span)?,
1873        )),
1874        _ => parser.expected_failure("'COLUMN', 'INDEX', 'CONSTRAINT' or 'TO'")?,
1875    }
1876}
1877
1878fn parse_drop<'a>(parser: &mut Parser<'a, '_>) -> Result<AlterSpecification<'a>, ParseError> {
1879    let drop_span = parser.consume_keyword(Keyword::DROP)?;
1880    match parser.token {
1881        Token::Ident(_, Keyword::INDEX | Keyword::KEY) => Ok(AlterSpecification::DropIndex(
1882            parse_drop_index(parser, drop_span)?,
1883        )),
1884        Token::Ident(_, Keyword::FOREIGN) => Ok(AlterSpecification::DropForeignKey(
1885            parse_drop_foreign_key(parser, drop_span)?,
1886        )),
1887        Token::Ident(_, Keyword::PRIMARY) => Ok(AlterSpecification::DropPrimaryKey(
1888            parse_drop_primary_key(parser, drop_span)?,
1889        )),
1890        Token::Ident(_, Keyword::COLUMN) => Ok(AlterSpecification::DropColumn(parse_drop_column(
1891            parser, drop_span,
1892        )?)),
1893        _ => parser.expected_failure("'COLUMN' or 'INDEX'")?,
1894    }
1895}
1896
1897/// Represent an alter table statement
1898/// ```
1899/// # use qusql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statements, AlterTable, Statement, Issues};
1900/// let options = ParseOptions::new().dialect(SQLDialect::MariaDB);
1901///
1902/// let sql = "ALTER TABLE `t1`
1903///     MODIFY `id` int(11) NOT NULL AUTO_INCREMENT,
1904///     ADD CONSTRAINT `t1_t2` FOREIGN KEY (`two`) REFERENCES `t2` (`id`);";
1905///
1906/// let mut issues = Issues::new(sql);
1907/// let mut stmts = parse_statements(sql, &mut issues, &options);
1908///
1909/// # assert!(issues.is_ok());
1910/// let alter: AlterTable = match stmts.pop() {
1911///     Some(Statement::AlterTable(a)) => *a,
1912///     _ => panic!("We should get an alter table statement")
1913/// };
1914///
1915/// assert!(alter.table.identifier.as_str() == "t1");
1916/// println!("{:#?}", alter.alter_specifications);
1917///
1918/// let options = ParseOptions::new().dialect(SQLDialect::PostgreSQL);
1919/// let sql = "ALTER TABLE t1
1920///     ALTER COLUMN id DROP NOT NULL,
1921///     ALTER COLUMN id SET NOT NULL,
1922///     ALTER COLUMN id SET DEFAULT 47,
1923///     ALTER COLUMN id DROP DEFAULT,
1924///     ALTER COLUMN id TYPE int;";
1925///
1926/// let mut issues = Issues::new(sql);
1927/// let mut stmts = parse_statements(sql, &mut issues, &options);
1928///
1929/// # assert!(issues.is_ok());
1930/// let alter: AlterTable = match stmts.pop() {
1931///     Some(Statement::AlterTable(a)) => *a,
1932///     _ => panic!("We should get an alter table statement")
1933/// };
1934///
1935#[derive(Clone, Debug)]
1936pub struct AlterTable<'a> {
1937    /// Span of "ALTER"
1938    pub alter_span: Span,
1939    /// Span of "ONLINE" if specified
1940    pub online: Option<Span>,
1941    /// Span of "IGNORE" if specified
1942    pub ignore: Option<Span>,
1943    /// Span of "TABLE"
1944    pub table_span: Span,
1945    /// Span of "IF EXISTS" if specified
1946    pub if_exists: Option<Span>,
1947    /// Span of "ONLY" if specified after IF EXISTS
1948    pub only: Option<Span>,
1949    /// The identifier of the table to alter
1950    pub table: QualifiedName<'a>,
1951    /// List of alterations to do
1952    pub alter_specifications: Vec<AlterSpecification<'a>>,
1953}
1954
1955impl<'a> Spanned for AlterTable<'a> {
1956    fn span(&self) -> Span {
1957        self.alter_span
1958            .join_span(&self.online)
1959            .join_span(&self.ignore)
1960            .join_span(&self.table_span)
1961            .join_span(&self.if_exists)
1962            .join_span(&self.only)
1963            .join_span(&self.table)
1964            .join_span(&self.alter_specifications)
1965    }
1966}
1967
1968pub(crate) fn parse_alter_table<'a>(
1969    parser: &mut Parser<'a, '_>,
1970    alter_span: Span,
1971    online: Option<Span>,
1972    ignore: Option<Span>,
1973) -> Result<AlterTable<'a>, ParseError> {
1974    // ONLINE and IGNORE are MariaDB/MySQL-specific
1975    if let Some(span) = &online {
1976        parser.maria_only(span);
1977    }
1978    if let Some(span) = &ignore {
1979        parser.maria_only(span);
1980    }
1981
1982    let table_span = parser.consume_keyword(Keyword::TABLE)?;
1983    let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
1984        Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&span))
1985    } else {
1986        None
1987    };
1988    let only = if let Some(span) = parser.skip_keyword(Keyword::ONLY) {
1989        parser.postgres_only(&span);
1990        Some(span)
1991    } else {
1992        None
1993    };
1994    let table = parse_qualified_name_unreserved(parser)?;
1995    let delimeter_name = parser.lexer.delimiter_name();
1996    let mut alter_specifications = Vec::new();
1997    parser.recovered(
1998        delimeter_name,
1999        &|t| matches!(t, Token::Delimiter | Token::Eof),
2000        |parser| {
2001            loop {
2002                alter_specifications.push(match parser.token {
2003                    Token::Ident(_, Keyword::ADD) => parse_add_alter_specification(parser)?,
2004                    Token::Ident(_, Keyword::MODIFY) => {
2005                        let modify_span = parser.consume_keyword(Keyword::MODIFY)?;
2006                        parser.maria_only(&modify_span);
2007                        AlterSpecification::Modify(parse_modify_column(parser, modify_span)?)
2008                    }
2009                    Token::Ident(_, Keyword::OWNER) => {
2010                        let span = parser.consume_keywords(&[Keyword::OWNER, Keyword::TO])?;
2011                        parser.postgres_only(&span);
2012                        AlterSpecification::OwnerTo(parse_owner_to(parser, span)?)
2013                    }
2014                    Token::Ident(_, Keyword::DROP) => parse_drop(parser)?,
2015                    Token::Ident(_, Keyword::ALTER) => {
2016                        let span = parser.consume_keywords(&[Keyword::ALTER, Keyword::COLUMN])?;
2017                        parser.postgres_only(&span);
2018                        let column = parser.consume_plain_identifier_unreserved()?;
2019
2020                        let alter_column_action = match parser.token {
2021                            Token::Ident(_, Keyword::SET) => {
2022                                let set_span = parser.consume();
2023                                match parser.token {
2024                                    Token::Ident(_, Keyword::DEFAULT) => {
2025                                        let set_default_span =
2026                                            parser.consume().join_span(&set_span);
2027                                        let value =
2028                                            parse_expression_unreserved(parser, PRIORITY_MAX)?;
2029                                        AlterColumnAction::SetDefault {
2030                                            set_default_span,
2031                                            value,
2032                                        }
2033                                    }
2034                                    Token::Ident(_, Keyword::NOT) => {
2035                                        let set_not_null_span =
2036                                            set_span.join_span(&parser.consume_keywords(&[
2037                                                Keyword::NOT,
2038                                                Keyword::NULL,
2039                                            ])?);
2040                                        AlterColumnAction::SetNotNull { set_not_null_span }
2041                                    }
2042                                    Token::Ident(_, Keyword::DATA) => {
2043                                        // SET DATA TYPE
2044                                        parser.consume_keyword(Keyword::DATA)?;
2045                                        let type_span = parser.consume_keyword(Keyword::TYPE)?;
2046                                        let type_span = set_span.join_span(&type_span);
2047                                        let type_ =
2048                                            parse_data_type(parser, DataTypeContext::Column)?;
2049                                        let using = if let Some(using_span) =
2050                                            parser.skip_keyword(Keyword::USING)
2051                                        {
2052                                            let expr =
2053                                                parse_expression_unreserved(parser, PRIORITY_MAX)?;
2054                                            Some((using_span, expr))
2055                                        } else {
2056                                            None
2057                                        };
2058                                        AlterColumnAction::Type {
2059                                            type_span,
2060                                            type_,
2061                                            using,
2062                                        }
2063                                    }
2064                                    _ => parser
2065                                        .expected_failure("'DEFAULT', 'NOT NULL', or 'DATA'")?,
2066                                }
2067                            }
2068                            Token::Ident(_, Keyword::DROP) => {
2069                                let set_span = parser.consume();
2070                                match parser.token {
2071                                    Token::Ident(_, Keyword::DEFAULT) => {
2072                                        let drop_default_span =
2073                                            parser.consume().join_span(&set_span);
2074                                        AlterColumnAction::DropDefault { drop_default_span }
2075                                    }
2076                                    Token::Ident(_, Keyword::NOT) => {
2077                                        let drop_not_null_span =
2078                                            set_span.join_span(&parser.consume_keywords(&[
2079                                                Keyword::NOT,
2080                                                Keyword::NULL,
2081                                            ])?);
2082                                        AlterColumnAction::DropNotNull { drop_not_null_span }
2083                                    }
2084                                    _ => parser.expected_failure("'DEFAULT' or 'NOT NULL'")?,
2085                                }
2086                            }
2087                            Token::Ident(_, Keyword::TYPE) => {
2088                                let type_span = parser.consume();
2089                                let type_ = parse_data_type(parser, DataTypeContext::Column)?;
2090                                let using = if let Some(using_span) =
2091                                    parser.skip_keyword(Keyword::USING)
2092                                {
2093                                    let expr = parse_expression_unreserved(parser, PRIORITY_MAX)?;
2094                                    Some((using_span, expr))
2095                                } else {
2096                                    None
2097                                };
2098                                AlterColumnAction::Type {
2099                                    type_span,
2100                                    type_,
2101                                    using,
2102                                }
2103                            }
2104                            Token::Ident(_, Keyword::ADD) => {
2105                                let add_span = parser.consume_keyword(Keyword::ADD)?;
2106                                let generated_span = parser.consume_keyword(Keyword::GENERATED)?;
2107                                // Parse optional ALWAYS or BY DEFAULT
2108                                let always_or_default = if let Some(always_span) =
2109                                    parser.skip_keyword(Keyword::ALWAYS)
2110                                {
2111                                    Some((always_span.clone(), always_span))
2112                                } else if let Some(by_span) = parser.skip_keyword(Keyword::BY) {
2113                                    let default_span = parser.consume_keyword(Keyword::DEFAULT)?;
2114                                    Some((by_span, default_span))
2115                                } else {
2116                                    None
2117                                };
2118                                let as_span = parser.consume_keyword(Keyword::AS)?;
2119                                let identity_span = parser.consume_keyword(Keyword::IDENTITY)?;
2120                                // Parse optional sequence options in parentheses
2121                                let sequence_options = if parser.skip_token(Token::LParen).is_some()
2122                                {
2123                                    let options = parse_sequence_options(parser)?;
2124                                    if options.is_empty() {
2125                                        parser.expected_failure("sequence option")?;
2126                                    }
2127                                    parser.consume_token(Token::RParen)?;
2128                                    options
2129                                } else {
2130                                    Vec::new()
2131                                };
2132                                AlterColumnAction::AddGenerated {
2133                                    add_span,
2134                                    generated_span,
2135                                    always_or_default,
2136                                    as_span,
2137                                    identity_span,
2138                                    sequence_options,
2139                                }
2140                            }
2141                            _ => parser.expected_failure("alter column action")?,
2142                        };
2143                        AlterSpecification::AlterColumn(AlterColumn {
2144                            alter_column_span: span,
2145                            column,
2146                            alter_column_action,
2147                        })
2148                    }
2149                    Token::Ident(_, Keyword::LOCK) => {
2150                        let lock_span = parser.consume_keyword(Keyword::LOCK)?;
2151                        parser.maria_only(&lock_span);
2152                        AlterSpecification::Lock(parse_lock(parser, lock_span)?)
2153                    }
2154                    Token::Ident(_, Keyword::ALGORITHM) => {
2155                        let algorithm_span = parser.consume_keyword(Keyword::ALGORITHM)?;
2156                        parser.maria_only(&algorithm_span);
2157                        AlterSpecification::Algorithm(parse_algorithm(parser, algorithm_span)?)
2158                    }
2159                    Token::Ident(_, Keyword::AUTO_INCREMENT) => {
2160                        let auto_increment_span =
2161                            parser.consume_keyword(Keyword::AUTO_INCREMENT)?;
2162                        parser.maria_only(&auto_increment_span);
2163                        AlterSpecification::AutoIncrement(parse_auto_increment(
2164                            parser,
2165                            auto_increment_span,
2166                        )?)
2167                    }
2168                    Token::Ident(_, Keyword::RENAME) => parse_rename_alter_specification(parser)?,
2169                    Token::Ident(_, Keyword::CHANGE) => {
2170                        let change_span = parser.consume_keyword(Keyword::CHANGE)?;
2171                        parser.maria_only(&change_span);
2172                        AlterSpecification::Change(parse_change(parser, change_span)?)
2173                    }
2174                    Token::Ident(_, Keyword::REPLICA) => {
2175                        let replica_span = parser.consume_keyword(Keyword::REPLICA)?;
2176                        parser.postgres_only(&replica_span);
2177                        let identity_span = parser.consume_keyword(Keyword::IDENTITY)?;
2178                        let option = match &parser.token {
2179                            Token::Ident(_, Keyword::DEFAULT) => ReplicaIdentityOption::Default(
2180                                parser.consume_keyword(Keyword::DEFAULT)?,
2181                            ),
2182                            Token::Ident(_, Keyword::FULL) => {
2183                                ReplicaIdentityOption::Full(parser.consume_keyword(Keyword::FULL)?)
2184                            }
2185                            Token::Ident(_, Keyword::NOTHING) => ReplicaIdentityOption::Nothing(
2186                                parser.consume_keyword(Keyword::NOTHING)?,
2187                            ),
2188                            Token::Ident(_, Keyword::USING) => {
2189                                let using_span = parser.consume_keyword(Keyword::USING)?;
2190                                let index_span = parser.consume_keyword(Keyword::INDEX)?;
2191                                let name = parser.consume_plain_identifier_unreserved()?;
2192                                ReplicaIdentityOption::UsingIndex {
2193                                    using_span,
2194                                    index_span,
2195                                    name,
2196                                }
2197                            }
2198                            _ => parser.expected_failure("REPLICA IDENTITY option")?,
2199                        };
2200                        AlterSpecification::ReplicaIdentity(ReplicaIdentity {
2201                            replica_span,
2202                            identity_span,
2203                            option,
2204                        })
2205                    }
2206                    Token::Ident(_, Keyword::VALIDATE) => {
2207                        let validate_span = parser.consume_keyword(Keyword::VALIDATE)?;
2208                        parser.postgres_only(&validate_span);
2209                        AlterSpecification::ValidateConstraint(parse_validate_constraint(
2210                            parser,
2211                            validate_span,
2212                        )?)
2213                    }
2214                    Token::Ident(_, Keyword::DISABLE) => {
2215                        let disable_span = parser.consume_keyword(Keyword::DISABLE)?;
2216                        parser.postgres_only(&disable_span);
2217                        match &parser.token {
2218                            Token::Ident(_, Keyword::TRIGGER) => {
2219                                let trigger_span = parser.consume_keyword(Keyword::TRIGGER)?;
2220                                let trigger_name = match &parser.token {
2221                                    Token::Ident(_, Keyword::ALL) => {
2222                                        TriggerName::All(parser.consume_keyword(Keyword::ALL)?)
2223                                    }
2224                                    Token::Ident(_, Keyword::USER) => {
2225                                        TriggerName::User(parser.consume_keyword(Keyword::USER)?)
2226                                    }
2227                                    _ => TriggerName::Named(
2228                                        parser.consume_plain_identifier_unreserved()?,
2229                                    ),
2230                                };
2231                                AlterSpecification::DisableTrigger(DisableTrigger {
2232                                    disable_span,
2233                                    trigger_span,
2234                                    trigger_name,
2235                                })
2236                            }
2237                            Token::Ident(_, Keyword::RULE) => {
2238                                let rule_span = parser.consume_keyword(Keyword::RULE)?;
2239                                let rule_name = parser.consume_plain_identifier_unreserved()?;
2240                                AlterSpecification::DisableRule(DisableRule {
2241                                    disable_span,
2242                                    rule_span,
2243                                    rule_name,
2244                                })
2245                            }
2246                            Token::Ident(_, Keyword::ROW) => {
2247                                let row_span = parser.consume_keyword(Keyword::ROW)?;
2248                                let level_span = parser.consume_keyword(Keyword::LEVEL)?;
2249                                let security_span = parser.consume_keyword(Keyword::SECURITY)?;
2250                                AlterSpecification::DisableRowLevelSecurity(
2251                                    DisableRowLevelSecurity {
2252                                        disable_span,
2253                                        row_span,
2254                                        level_span,
2255                                        security_span,
2256                                    },
2257                                )
2258                            }
2259                            _ => parser.expected_failure("'TRIGGER', 'RULE', or 'ROW'")?,
2260                        }
2261                    }
2262                    Token::Ident(_, Keyword::ENABLE) => {
2263                        let enable_span = parser.consume_keyword(Keyword::ENABLE)?;
2264                        parser.postgres_only(&enable_span);
2265                        let modifier = if let Some(span) = parser.skip_keyword(Keyword::REPLICA) {
2266                            Some(span)
2267                        } else {
2268                            parser.skip_keyword(Keyword::ALWAYS)
2269                        };
2270                        match &parser.token {
2271                            Token::Ident(_, Keyword::TRIGGER) => {
2272                                let trigger_span = parser.consume_keyword(Keyword::TRIGGER)?;
2273                                let trigger_name = match &parser.token {
2274                                    Token::Ident(_, Keyword::ALL) => {
2275                                        TriggerName::All(parser.consume_keyword(Keyword::ALL)?)
2276                                    }
2277                                    Token::Ident(_, Keyword::USER) => {
2278                                        TriggerName::User(parser.consume_keyword(Keyword::USER)?)
2279                                    }
2280                                    _ => TriggerName::Named(
2281                                        parser.consume_plain_identifier_unreserved()?,
2282                                    ),
2283                                };
2284                                AlterSpecification::EnableTrigger(EnableTrigger {
2285                                    enable_span,
2286                                    modifier,
2287                                    trigger_span,
2288                                    trigger_name,
2289                                })
2290                            }
2291                            Token::Ident(_, Keyword::RULE) => {
2292                                let rule_span = parser.consume_keyword(Keyword::RULE)?;
2293                                let rule_name = parser.consume_plain_identifier_unreserved()?;
2294                                AlterSpecification::EnableRule(EnableRule {
2295                                    enable_span,
2296                                    modifier,
2297                                    rule_span,
2298                                    rule_name,
2299                                })
2300                            }
2301                            Token::Ident(_, Keyword::ROW) => {
2302                                let row_span = parser.consume_keyword(Keyword::ROW)?;
2303                                let level_span = parser.consume_keyword(Keyword::LEVEL)?;
2304                                let security_span = parser.consume_keyword(Keyword::SECURITY)?;
2305                                AlterSpecification::EnableRowLevelSecurity(EnableRowLevelSecurity {
2306                                    enable_span,
2307                                    row_span,
2308                                    level_span,
2309                                    security_span,
2310                                })
2311                            }
2312                            _ => parser.expected_failure("'TRIGGER', 'RULE', or 'ROW'")?,
2313                        }
2314                    }
2315                    Token::Ident(_, Keyword::FORCE) => {
2316                        let force_span = parser.consume_keyword(Keyword::FORCE)?;
2317                        parser.postgres_only(&force_span);
2318                        let row_span = parser.consume_keyword(Keyword::ROW)?;
2319                        let level_span = parser.consume_keyword(Keyword::LEVEL)?;
2320                        let security_span = parser.consume_keyword(Keyword::SECURITY)?;
2321                        AlterSpecification::ForceRowLevelSecurity(ForceRowLevelSecurity {
2322                            force_span,
2323                            row_span,
2324                            level_span,
2325                            security_span,
2326                        })
2327                    }
2328                    Token::Ident(_, Keyword::NO) => {
2329                        let no_span = parser.consume_keyword(Keyword::NO)?;
2330                        parser.postgres_only(&no_span);
2331                        let force_span = parser.consume_keyword(Keyword::FORCE)?;
2332                        let row_span = parser.consume_keyword(Keyword::ROW)?;
2333                        let level_span = parser.consume_keyword(Keyword::LEVEL)?;
2334                        let security_span = parser.consume_keyword(Keyword::SECURITY)?;
2335                        AlterSpecification::NoForceRowLevelSecurity(NoForceRowLevelSecurity {
2336                            no_span,
2337                            force_span,
2338                            row_span,
2339                            level_span,
2340                            security_span,
2341                        })
2342                    }
2343                    _ => parser.expected_failure("alter specification")?,
2344                });
2345                if parser.skip_token(Token::Comma).is_none() {
2346                    break;
2347                }
2348            }
2349            Ok(())
2350        },
2351    )?;
2352    Ok(AlterTable {
2353        alter_span,
2354        online,
2355        ignore,
2356        table_span,
2357        if_exists,
2358        only,
2359        table,
2360        alter_specifications,
2361    })
2362}