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: QualifiedName<'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 = parse_qualified_name_unreserved(parser)?;
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 {
1640                        value,
1641                        span,
1642                        case_sensitive: false,
1643                    },
1644                }))
1645            }
1646            _ => Ok(None),
1647        }
1648    } else if matches!(parser.token, Token::Ident(_, _))
1649        && !matches!(
1650            parser.token,
1651            Token::Ident(_, Keyword::ASC | Keyword::DESC | Keyword::NULLS)
1652        )
1653        && *parser.peek() != Token::Comma
1654        && *parser.peek() != Token::RParen
1655    {
1656        // Try to parse as qualified name (for things like public.vector_cosine_ops)
1657        let qname = parse_qualified_name_unreserved(parser)?;
1658        parser.postgres_only(&qname);
1659        Ok(Some(qname))
1660    } else {
1661        Ok(None)
1662    }
1663}
1664
1665pub(crate) fn parse_index_cols<'a>(
1666    parser: &mut Parser<'a, '_>,
1667) -> Result<(Vec<IndexCol<'a>>, Span), ParseError> {
1668    parser.consume_token(Token::LParen)?;
1669    let mut ans = Vec::new();
1670    parser.recovered("')'", &|t| t == &Token::RParen, |parser| {
1671        loop {
1672            // Check if this is a functional index expression (starts with '(')
1673            let expr = if parser.token == Token::LParen {
1674                // Functional index: parse expression
1675                parser.consume_token(Token::LParen)?;
1676                let expression = parse_expression_unreserved(parser, PRIORITY_MAX)?;
1677                parser.consume_token(Token::RParen)?;
1678                IndexColExpr::Expression(expression)
1679            } else {
1680                // Regular column name
1681                let name = parser.consume_plain_identifier_unreserved()?;
1682                IndexColExpr::Column(name)
1683            };
1684
1685            let size = if parser.skip_token(Token::LParen).is_some() {
1686                let size = parser.recovered("')'", &|t| t == &Token::RParen, |parser| {
1687                    parser.consume_int()
1688                })?;
1689                parser.consume_token(Token::RParen)?;
1690                Some(size)
1691            } else {
1692                None
1693            };
1694
1695            // Parse optional operator class (PostgreSQL)
1696            let opclass = parse_operator_class(parser)?;
1697
1698            // Parse optional ASC | DESC
1699            let asc = parser.skip_keyword(Keyword::ASC);
1700            let desc = if asc.is_none() {
1701                parser.skip_keyword(Keyword::DESC)
1702            } else {
1703                None
1704            };
1705
1706            ans.push(IndexCol {
1707                expr,
1708                size,
1709                opclass,
1710                asc,
1711                desc,
1712            });
1713            if parser.skip_token(Token::Comma).is_none() {
1714                break;
1715            }
1716        }
1717        Ok(())
1718    })?;
1719    let r_paren_span = parser.consume_token(Token::RParen)?;
1720    Ok((ans, r_paren_span))
1721}
1722
1723fn parse_cols<'a>(parser: &mut Parser<'a, '_>) -> Result<(Vec<Identifier<'a>>, Span), ParseError> {
1724    parser.consume_token(Token::LParen)?;
1725    let mut ans = Vec::new();
1726    parser.recovered("')'", &|t| t == &Token::RParen, |parser| {
1727        loop {
1728            ans.push(parser.consume_plain_identifier_unreserved()?);
1729            if parser.skip_token(Token::Comma).is_none() {
1730                break;
1731            }
1732        }
1733        Ok(())
1734    })?;
1735    let r_paren_span = parser.consume_token(Token::RParen)?;
1736    Ok((ans, r_paren_span))
1737}
1738
1739fn parse_add_alter_specification<'a>(
1740    parser: &mut Parser<'a, '_>,
1741) -> Result<AlterSpecification<'a>, ParseError> {
1742    let add_span = parser.consume_keyword(Keyword::ADD)?;
1743    let constraint = if let Some(span) = parser.skip_keyword(Keyword::CONSTRAINT) {
1744        let v = match &parser.token {
1745            Token::Ident(_, kw)
1746                if !kw.restricted(parser.reserved()) || kw == &Keyword::QUOTED_IDENTIFIER =>
1747            {
1748                Some(parser.consume_plain_identifier_restrict(Restrict::EMPTY)?)
1749            }
1750            Token::String(_, StringType::DoubleQuoted)
1751                if parser.options.dialect.is_postgresql() =>
1752            {
1753                Some(parser.consume_plain_identifier_restrict(Restrict::EMPTY)?)
1754            }
1755            _ => None,
1756        };
1757        Some((span, v))
1758    } else {
1759        None
1760    };
1761    // Peek ahead to check if PRIMARY is followed by KEY (for distinguishing table constraints)
1762    let primary_followed_by_key = matches!(&parser.token, Token::Ident(_, Keyword::PRIMARY))
1763        && matches!(parser.peek(), Token::Ident(_, Keyword::KEY));
1764
1765    match &parser.token {
1766        // Check for table constraints (UNIQUE/PRIMARY KEY without explicit INDEX/KEY keyword)
1767        Token::Ident(_, Keyword::UNIQUE) if constraint.is_some() => {
1768            // This is ADD CONSTRAINT ... UNIQUE (...) - a table constraint, not an index
1769            let unique_span = parser.consume_keyword(Keyword::UNIQUE)?;
1770            parser.postgres_only(&unique_span);
1771            // Parse optional NULLS [NOT] DISTINCT
1772            let nulls_clause = if let Some(nulls_span) = parser.skip_keyword(Keyword::NULLS) {
1773                let not_span = parser.skip_keyword(Keyword::NOT);
1774                parser.consume_keyword(Keyword::DISTINCT)?;
1775                Some((nulls_span, not_span))
1776            } else {
1777                None
1778            };
1779            let (cols, r_paren) = parse_cols(parser)?;
1780            let not_valid = if let Some(span) = parser.skip_keyword(Keyword::NOT) {
1781                Some(span.join_span(&parser.consume_keyword(Keyword::VALID)?))
1782            } else {
1783                None
1784            };
1785            Ok(AlterSpecification::AddTableConstraint(AddTableConstraint {
1786                add_span,
1787                constraint,
1788                constraint_type: TableConstraintType::Unique {
1789                    unique_span,
1790                    nulls_clause,
1791                    cols,
1792                    r_paren,
1793                },
1794                not_valid,
1795            }))
1796        }
1797        Token::Ident(_, Keyword::PRIMARY) if constraint.is_some() && primary_followed_by_key => {
1798            // This is ADD CONSTRAINT ... PRIMARY KEY (...) - a table constraint
1799            let primary_span = parser.consume_keyword(Keyword::PRIMARY)?;
1800            parser.postgres_only(&primary_span);
1801            let key_span = parser.consume_keyword(Keyword::KEY)?;
1802            let (cols, r_paren) = parse_cols(parser)?;
1803            let not_valid = if let Some(span) = parser.skip_keyword(Keyword::NOT) {
1804                Some(span.join_span(&parser.consume_keyword(Keyword::VALID)?))
1805            } else {
1806                None
1807            };
1808            Ok(AlterSpecification::AddTableConstraint(AddTableConstraint {
1809                add_span,
1810                constraint,
1811                constraint_type: TableConstraintType::PrimaryKey {
1812                    primary_span,
1813                    key_span,
1814                    cols,
1815                    r_paren,
1816                },
1817                not_valid,
1818            }))
1819        }
1820        Token::Ident(_, Keyword::CHECK) if constraint.is_some() => {
1821            // This is ADD CONSTRAINT ... CHECK (...)
1822            let check_span = parser.consume_keyword(Keyword::CHECK)?;
1823            parser.postgres_only(&check_span);
1824            parser.consume_token(Token::LParen)?;
1825            let expr = parse_expression_unreserved(parser, PRIORITY_MAX)?;
1826            parser.consume_token(Token::RParen)?;
1827            let not_valid = if let Some(span) = parser.skip_keyword(Keyword::NOT) {
1828                Some(span.join_span(&parser.consume_keyword(Keyword::VALID)?))
1829            } else {
1830                None
1831            };
1832            Ok(AlterSpecification::AddTableConstraint(AddTableConstraint {
1833                add_span,
1834                constraint,
1835                constraint_type: TableConstraintType::Check { check_span, expr },
1836                not_valid,
1837            }))
1838        }
1839        Token::Ident(_, Keyword::FOREIGN) => Ok(AlterSpecification::AddForeignKey(
1840            parse_add_foreign_key(parser, add_span, constraint)?,
1841        )),
1842        Token::Ident(
1843            _,
1844            Keyword::PRIMARY
1845            | Keyword::INDEX
1846            | Keyword::KEY
1847            | Keyword::FULLTEXT
1848            | Keyword::UNIQUE
1849            | Keyword::SPATIAL,
1850        ) => Ok(AlterSpecification::AddIndex(parse_add_index(
1851            parser, add_span, constraint,
1852        )?)),
1853        Token::Ident(_, Keyword::COLUMN) => Ok(AlterSpecification::AddColumn(parse_add_column(
1854            parser, add_span,
1855        )?)),
1856        _ => parser.expected_failure("addable"),
1857    }
1858}
1859
1860fn parse_rename_alter_specification<'a>(
1861    parser: &mut Parser<'a, '_>,
1862) -> Result<AlterSpecification<'a>, ParseError> {
1863    let rename_span = parser.consume_keyword(Keyword::RENAME)?;
1864
1865    match parser.token {
1866        Token::Ident(_, Keyword::COLUMN) => Ok(AlterSpecification::RenameColumn(
1867            parse_rename_column(parser, rename_span)?,
1868        )),
1869        Token::Ident(_, Keyword::INDEX | Keyword::KEY) => Ok(AlterSpecification::RenameIndex(
1870            parse_rename_index(parser, rename_span)?,
1871        )),
1872        Token::Ident(_, Keyword::CONSTRAINT) => Ok(AlterSpecification::RenameConstraint(
1873            parse_rename_constraint(parser, rename_span)?,
1874        )),
1875        Token::Ident(_, Keyword::TO | Keyword::AS) => Ok(AlterSpecification::RenameTo(
1876            parse_rename_to(parser, rename_span)?,
1877        )),
1878        _ => parser.expected_failure("'COLUMN', 'INDEX', 'CONSTRAINT' or 'TO'")?,
1879    }
1880}
1881
1882fn parse_drop<'a>(parser: &mut Parser<'a, '_>) -> Result<AlterSpecification<'a>, ParseError> {
1883    let drop_span = parser.consume_keyword(Keyword::DROP)?;
1884    match parser.token {
1885        Token::Ident(_, Keyword::INDEX | Keyword::KEY) => Ok(AlterSpecification::DropIndex(
1886            parse_drop_index(parser, drop_span)?,
1887        )),
1888        Token::Ident(_, Keyword::FOREIGN) => Ok(AlterSpecification::DropForeignKey(
1889            parse_drop_foreign_key(parser, drop_span)?,
1890        )),
1891        Token::Ident(_, Keyword::PRIMARY) => Ok(AlterSpecification::DropPrimaryKey(
1892            parse_drop_primary_key(parser, drop_span)?,
1893        )),
1894        Token::Ident(_, Keyword::COLUMN) => Ok(AlterSpecification::DropColumn(parse_drop_column(
1895            parser, drop_span,
1896        )?)),
1897        _ => parser.expected_failure("'COLUMN' or 'INDEX'")?,
1898    }
1899}
1900
1901/// Represent an alter table statement
1902/// ```
1903/// # use qusql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statements, AlterTable, Statement, Issues};
1904/// let options = ParseOptions::new().dialect(SQLDialect::MariaDB);
1905///
1906/// let sql = "ALTER TABLE `t1`
1907///     MODIFY `id` int(11) NOT NULL AUTO_INCREMENT,
1908///     ADD CONSTRAINT `t1_t2` FOREIGN KEY (`two`) REFERENCES `t2` (`id`);";
1909///
1910/// let mut issues = Issues::new(sql);
1911/// let mut stmts = parse_statements(sql, &mut issues, &options);
1912///
1913/// # assert!(issues.is_ok());
1914/// let alter: AlterTable = match stmts.pop() {
1915///     Some(Statement::AlterTable(a)) => *a,
1916///     _ => panic!("We should get an alter table statement")
1917/// };
1918///
1919/// assert!(alter.table.identifier.as_str() == "t1");
1920/// println!("{:#?}", alter.alter_specifications);
1921///
1922/// let options = ParseOptions::new().dialect(SQLDialect::PostgreSQL);
1923/// let sql = "ALTER TABLE t1
1924///     ALTER COLUMN id DROP NOT NULL,
1925///     ALTER COLUMN id SET NOT NULL,
1926///     ALTER COLUMN id SET DEFAULT 47,
1927///     ALTER COLUMN id DROP DEFAULT,
1928///     ALTER COLUMN id TYPE int;";
1929///
1930/// let mut issues = Issues::new(sql);
1931/// let mut stmts = parse_statements(sql, &mut issues, &options);
1932///
1933/// # assert!(issues.is_ok());
1934/// let alter: AlterTable = match stmts.pop() {
1935///     Some(Statement::AlterTable(a)) => *a,
1936///     _ => panic!("We should get an alter table statement")
1937/// };
1938///
1939#[derive(Clone, Debug)]
1940pub struct AlterTable<'a> {
1941    /// Span of "ALTER"
1942    pub alter_span: Span,
1943    /// Span of "ONLINE" if specified
1944    pub online: Option<Span>,
1945    /// Span of "IGNORE" if specified
1946    pub ignore: Option<Span>,
1947    /// Span of "TABLE"
1948    pub table_span: Span,
1949    /// Span of "IF EXISTS" if specified
1950    pub if_exists: Option<Span>,
1951    /// Span of "ONLY" if specified after IF EXISTS
1952    pub only: Option<Span>,
1953    /// The identifier of the table to alter
1954    pub table: QualifiedName<'a>,
1955    /// List of alterations to do
1956    pub alter_specifications: Vec<AlterSpecification<'a>>,
1957}
1958
1959impl<'a> Spanned for AlterTable<'a> {
1960    fn span(&self) -> Span {
1961        self.alter_span
1962            .join_span(&self.online)
1963            .join_span(&self.ignore)
1964            .join_span(&self.table_span)
1965            .join_span(&self.if_exists)
1966            .join_span(&self.only)
1967            .join_span(&self.table)
1968            .join_span(&self.alter_specifications)
1969    }
1970}
1971
1972pub(crate) fn parse_alter_table<'a>(
1973    parser: &mut Parser<'a, '_>,
1974    alter_span: Span,
1975    online: Option<Span>,
1976    ignore: Option<Span>,
1977) -> Result<AlterTable<'a>, ParseError> {
1978    // ONLINE and IGNORE are MariaDB/MySQL-specific
1979    if let Some(span) = &online {
1980        parser.maria_only(span);
1981    }
1982    if let Some(span) = &ignore {
1983        parser.maria_only(span);
1984    }
1985
1986    let table_span = parser.consume_keyword(Keyword::TABLE)?;
1987    let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
1988        Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&span))
1989    } else {
1990        None
1991    };
1992    let only = if let Some(span) = parser.skip_keyword(Keyword::ONLY) {
1993        parser.postgres_only(&span);
1994        Some(span)
1995    } else {
1996        None
1997    };
1998    let table = parse_qualified_name_unreserved(parser)?;
1999    let delimeter_name = parser.lexer.delimiter_name();
2000    let mut alter_specifications = Vec::new();
2001    parser.recovered(
2002        delimeter_name,
2003        &|t| matches!(t, Token::Delimiter | Token::Eof),
2004        |parser| {
2005            loop {
2006                alter_specifications.push(match parser.token {
2007                    Token::Ident(_, Keyword::ADD) => parse_add_alter_specification(parser)?,
2008                    Token::Ident(_, Keyword::MODIFY) => {
2009                        let modify_span = parser.consume_keyword(Keyword::MODIFY)?;
2010                        parser.maria_only(&modify_span);
2011                        AlterSpecification::Modify(parse_modify_column(parser, modify_span)?)
2012                    }
2013                    Token::Ident(_, Keyword::OWNER) => {
2014                        let span = parser.consume_keywords(&[Keyword::OWNER, Keyword::TO])?;
2015                        parser.postgres_only(&span);
2016                        AlterSpecification::OwnerTo(parse_owner_to(parser, span)?)
2017                    }
2018                    Token::Ident(_, Keyword::DROP) => parse_drop(parser)?,
2019                    Token::Ident(_, Keyword::ALTER) => {
2020                        let span = parser.consume_keywords(&[Keyword::ALTER, Keyword::COLUMN])?;
2021                        parser.postgres_only(&span);
2022                        let column = parser.consume_plain_identifier_unreserved()?;
2023
2024                        let alter_column_action = match parser.token {
2025                            Token::Ident(_, Keyword::SET) => {
2026                                let set_span = parser.consume();
2027                                match parser.token {
2028                                    Token::Ident(_, Keyword::DEFAULT) => {
2029                                        let set_default_span =
2030                                            parser.consume().join_span(&set_span);
2031                                        let value =
2032                                            parse_expression_unreserved(parser, PRIORITY_MAX)?;
2033                                        AlterColumnAction::SetDefault {
2034                                            set_default_span,
2035                                            value,
2036                                        }
2037                                    }
2038                                    Token::Ident(_, Keyword::NOT) => {
2039                                        let set_not_null_span =
2040                                            set_span.join_span(&parser.consume_keywords(&[
2041                                                Keyword::NOT,
2042                                                Keyword::NULL,
2043                                            ])?);
2044                                        AlterColumnAction::SetNotNull { set_not_null_span }
2045                                    }
2046                                    Token::Ident(_, Keyword::DATA) => {
2047                                        // SET DATA TYPE
2048                                        parser.consume_keyword(Keyword::DATA)?;
2049                                        let type_span = parser.consume_keyword(Keyword::TYPE)?;
2050                                        let type_span = set_span.join_span(&type_span);
2051                                        let type_ =
2052                                            parse_data_type(parser, DataTypeContext::Column)?;
2053                                        let using = if let Some(using_span) =
2054                                            parser.skip_keyword(Keyword::USING)
2055                                        {
2056                                            let expr =
2057                                                parse_expression_unreserved(parser, PRIORITY_MAX)?;
2058                                            Some((using_span, expr))
2059                                        } else {
2060                                            None
2061                                        };
2062                                        AlterColumnAction::Type {
2063                                            type_span,
2064                                            type_,
2065                                            using,
2066                                        }
2067                                    }
2068                                    _ => parser
2069                                        .expected_failure("'DEFAULT', 'NOT NULL', or 'DATA'")?,
2070                                }
2071                            }
2072                            Token::Ident(_, Keyword::DROP) => {
2073                                let set_span = parser.consume();
2074                                match parser.token {
2075                                    Token::Ident(_, Keyword::DEFAULT) => {
2076                                        let drop_default_span =
2077                                            parser.consume().join_span(&set_span);
2078                                        AlterColumnAction::DropDefault { drop_default_span }
2079                                    }
2080                                    Token::Ident(_, Keyword::NOT) => {
2081                                        let drop_not_null_span =
2082                                            set_span.join_span(&parser.consume_keywords(&[
2083                                                Keyword::NOT,
2084                                                Keyword::NULL,
2085                                            ])?);
2086                                        AlterColumnAction::DropNotNull { drop_not_null_span }
2087                                    }
2088                                    _ => parser.expected_failure("'DEFAULT' or 'NOT NULL'")?,
2089                                }
2090                            }
2091                            Token::Ident(_, Keyword::TYPE) => {
2092                                let type_span = parser.consume();
2093                                let type_ = parse_data_type(parser, DataTypeContext::Column)?;
2094                                let using = if let Some(using_span) =
2095                                    parser.skip_keyword(Keyword::USING)
2096                                {
2097                                    let expr = parse_expression_unreserved(parser, PRIORITY_MAX)?;
2098                                    Some((using_span, expr))
2099                                } else {
2100                                    None
2101                                };
2102                                AlterColumnAction::Type {
2103                                    type_span,
2104                                    type_,
2105                                    using,
2106                                }
2107                            }
2108                            Token::Ident(_, Keyword::ADD) => {
2109                                let add_span = parser.consume_keyword(Keyword::ADD)?;
2110                                let generated_span = parser.consume_keyword(Keyword::GENERATED)?;
2111                                // Parse optional ALWAYS or BY DEFAULT
2112                                let always_or_default = if let Some(always_span) =
2113                                    parser.skip_keyword(Keyword::ALWAYS)
2114                                {
2115                                    Some((always_span.clone(), always_span))
2116                                } else if let Some(by_span) = parser.skip_keyword(Keyword::BY) {
2117                                    let default_span = parser.consume_keyword(Keyword::DEFAULT)?;
2118                                    Some((by_span, default_span))
2119                                } else {
2120                                    None
2121                                };
2122                                let as_span = parser.consume_keyword(Keyword::AS)?;
2123                                let identity_span = parser.consume_keyword(Keyword::IDENTITY)?;
2124                                // Parse optional sequence options in parentheses
2125                                let sequence_options = if parser.skip_token(Token::LParen).is_some()
2126                                {
2127                                    let options = parse_sequence_options(parser)?;
2128                                    if options.is_empty() {
2129                                        parser.expected_failure("sequence option")?;
2130                                    }
2131                                    parser.consume_token(Token::RParen)?;
2132                                    options
2133                                } else {
2134                                    Vec::new()
2135                                };
2136                                AlterColumnAction::AddGenerated {
2137                                    add_span,
2138                                    generated_span,
2139                                    always_or_default,
2140                                    as_span,
2141                                    identity_span,
2142                                    sequence_options,
2143                                }
2144                            }
2145                            _ => parser.expected_failure("alter column action")?,
2146                        };
2147                        AlterSpecification::AlterColumn(AlterColumn {
2148                            alter_column_span: span,
2149                            column,
2150                            alter_column_action,
2151                        })
2152                    }
2153                    Token::Ident(_, Keyword::LOCK) => {
2154                        let lock_span = parser.consume_keyword(Keyword::LOCK)?;
2155                        parser.maria_only(&lock_span);
2156                        AlterSpecification::Lock(parse_lock(parser, lock_span)?)
2157                    }
2158                    Token::Ident(_, Keyword::ALGORITHM) => {
2159                        let algorithm_span = parser.consume_keyword(Keyword::ALGORITHM)?;
2160                        parser.maria_only(&algorithm_span);
2161                        AlterSpecification::Algorithm(parse_algorithm(parser, algorithm_span)?)
2162                    }
2163                    Token::Ident(_, Keyword::AUTO_INCREMENT) => {
2164                        let auto_increment_span =
2165                            parser.consume_keyword(Keyword::AUTO_INCREMENT)?;
2166                        parser.maria_only(&auto_increment_span);
2167                        AlterSpecification::AutoIncrement(parse_auto_increment(
2168                            parser,
2169                            auto_increment_span,
2170                        )?)
2171                    }
2172                    Token::Ident(_, Keyword::RENAME) => parse_rename_alter_specification(parser)?,
2173                    Token::Ident(_, Keyword::CHANGE) => {
2174                        let change_span = parser.consume_keyword(Keyword::CHANGE)?;
2175                        parser.maria_only(&change_span);
2176                        AlterSpecification::Change(parse_change(parser, change_span)?)
2177                    }
2178                    Token::Ident(_, Keyword::REPLICA) => {
2179                        let replica_span = parser.consume_keyword(Keyword::REPLICA)?;
2180                        parser.postgres_only(&replica_span);
2181                        let identity_span = parser.consume_keyword(Keyword::IDENTITY)?;
2182                        let option = match &parser.token {
2183                            Token::Ident(_, Keyword::DEFAULT) => ReplicaIdentityOption::Default(
2184                                parser.consume_keyword(Keyword::DEFAULT)?,
2185                            ),
2186                            Token::Ident(_, Keyword::FULL) => {
2187                                ReplicaIdentityOption::Full(parser.consume_keyword(Keyword::FULL)?)
2188                            }
2189                            Token::Ident(_, Keyword::NOTHING) => ReplicaIdentityOption::Nothing(
2190                                parser.consume_keyword(Keyword::NOTHING)?,
2191                            ),
2192                            Token::Ident(_, Keyword::USING) => {
2193                                let using_span = parser.consume_keyword(Keyword::USING)?;
2194                                let index_span = parser.consume_keyword(Keyword::INDEX)?;
2195                                let name = parser.consume_plain_identifier_unreserved()?;
2196                                ReplicaIdentityOption::UsingIndex {
2197                                    using_span,
2198                                    index_span,
2199                                    name,
2200                                }
2201                            }
2202                            _ => parser.expected_failure("REPLICA IDENTITY option")?,
2203                        };
2204                        AlterSpecification::ReplicaIdentity(ReplicaIdentity {
2205                            replica_span,
2206                            identity_span,
2207                            option,
2208                        })
2209                    }
2210                    Token::Ident(_, Keyword::VALIDATE) => {
2211                        let validate_span = parser.consume_keyword(Keyword::VALIDATE)?;
2212                        parser.postgres_only(&validate_span);
2213                        AlterSpecification::ValidateConstraint(parse_validate_constraint(
2214                            parser,
2215                            validate_span,
2216                        )?)
2217                    }
2218                    Token::Ident(_, Keyword::DISABLE) => {
2219                        let disable_span = parser.consume_keyword(Keyword::DISABLE)?;
2220                        parser.postgres_only(&disable_span);
2221                        match &parser.token {
2222                            Token::Ident(_, Keyword::TRIGGER) => {
2223                                let trigger_span = parser.consume_keyword(Keyword::TRIGGER)?;
2224                                let trigger_name = match &parser.token {
2225                                    Token::Ident(_, Keyword::ALL) => {
2226                                        TriggerName::All(parser.consume_keyword(Keyword::ALL)?)
2227                                    }
2228                                    Token::Ident(_, Keyword::USER) => {
2229                                        TriggerName::User(parser.consume_keyword(Keyword::USER)?)
2230                                    }
2231                                    _ => TriggerName::Named(
2232                                        parser.consume_plain_identifier_unreserved()?,
2233                                    ),
2234                                };
2235                                AlterSpecification::DisableTrigger(DisableTrigger {
2236                                    disable_span,
2237                                    trigger_span,
2238                                    trigger_name,
2239                                })
2240                            }
2241                            Token::Ident(_, Keyword::RULE) => {
2242                                let rule_span = parser.consume_keyword(Keyword::RULE)?;
2243                                let rule_name = parser.consume_plain_identifier_unreserved()?;
2244                                AlterSpecification::DisableRule(DisableRule {
2245                                    disable_span,
2246                                    rule_span,
2247                                    rule_name,
2248                                })
2249                            }
2250                            Token::Ident(_, Keyword::ROW) => {
2251                                let row_span = parser.consume_keyword(Keyword::ROW)?;
2252                                let level_span = parser.consume_keyword(Keyword::LEVEL)?;
2253                                let security_span = parser.consume_keyword(Keyword::SECURITY)?;
2254                                AlterSpecification::DisableRowLevelSecurity(
2255                                    DisableRowLevelSecurity {
2256                                        disable_span,
2257                                        row_span,
2258                                        level_span,
2259                                        security_span,
2260                                    },
2261                                )
2262                            }
2263                            _ => parser.expected_failure("'TRIGGER', 'RULE', or 'ROW'")?,
2264                        }
2265                    }
2266                    Token::Ident(_, Keyword::ENABLE) => {
2267                        let enable_span = parser.consume_keyword(Keyword::ENABLE)?;
2268                        parser.postgres_only(&enable_span);
2269                        let modifier = if let Some(span) = parser.skip_keyword(Keyword::REPLICA) {
2270                            Some(span)
2271                        } else {
2272                            parser.skip_keyword(Keyword::ALWAYS)
2273                        };
2274                        match &parser.token {
2275                            Token::Ident(_, Keyword::TRIGGER) => {
2276                                let trigger_span = parser.consume_keyword(Keyword::TRIGGER)?;
2277                                let trigger_name = match &parser.token {
2278                                    Token::Ident(_, Keyword::ALL) => {
2279                                        TriggerName::All(parser.consume_keyword(Keyword::ALL)?)
2280                                    }
2281                                    Token::Ident(_, Keyword::USER) => {
2282                                        TriggerName::User(parser.consume_keyword(Keyword::USER)?)
2283                                    }
2284                                    _ => TriggerName::Named(
2285                                        parser.consume_plain_identifier_unreserved()?,
2286                                    ),
2287                                };
2288                                AlterSpecification::EnableTrigger(EnableTrigger {
2289                                    enable_span,
2290                                    modifier,
2291                                    trigger_span,
2292                                    trigger_name,
2293                                })
2294                            }
2295                            Token::Ident(_, Keyword::RULE) => {
2296                                let rule_span = parser.consume_keyword(Keyword::RULE)?;
2297                                let rule_name = parser.consume_plain_identifier_unreserved()?;
2298                                AlterSpecification::EnableRule(EnableRule {
2299                                    enable_span,
2300                                    modifier,
2301                                    rule_span,
2302                                    rule_name,
2303                                })
2304                            }
2305                            Token::Ident(_, Keyword::ROW) => {
2306                                let row_span = parser.consume_keyword(Keyword::ROW)?;
2307                                let level_span = parser.consume_keyword(Keyword::LEVEL)?;
2308                                let security_span = parser.consume_keyword(Keyword::SECURITY)?;
2309                                AlterSpecification::EnableRowLevelSecurity(EnableRowLevelSecurity {
2310                                    enable_span,
2311                                    row_span,
2312                                    level_span,
2313                                    security_span,
2314                                })
2315                            }
2316                            _ => parser.expected_failure("'TRIGGER', 'RULE', or 'ROW'")?,
2317                        }
2318                    }
2319                    Token::Ident(_, Keyword::FORCE) => {
2320                        let force_span = parser.consume_keyword(Keyword::FORCE)?;
2321                        parser.postgres_only(&force_span);
2322                        let row_span = parser.consume_keyword(Keyword::ROW)?;
2323                        let level_span = parser.consume_keyword(Keyword::LEVEL)?;
2324                        let security_span = parser.consume_keyword(Keyword::SECURITY)?;
2325                        AlterSpecification::ForceRowLevelSecurity(ForceRowLevelSecurity {
2326                            force_span,
2327                            row_span,
2328                            level_span,
2329                            security_span,
2330                        })
2331                    }
2332                    Token::Ident(_, Keyword::NO) => {
2333                        let no_span = parser.consume_keyword(Keyword::NO)?;
2334                        parser.postgres_only(&no_span);
2335                        let force_span = parser.consume_keyword(Keyword::FORCE)?;
2336                        let row_span = parser.consume_keyword(Keyword::ROW)?;
2337                        let level_span = parser.consume_keyword(Keyword::LEVEL)?;
2338                        let security_span = parser.consume_keyword(Keyword::SECURITY)?;
2339                        AlterSpecification::NoForceRowLevelSecurity(NoForceRowLevelSecurity {
2340                            no_span,
2341                            force_span,
2342                            row_span,
2343                            level_span,
2344                            security_span,
2345                        })
2346                    }
2347                    _ => parser.expected_failure("alter specification")?,
2348                });
2349                if parser.skip_token(Token::Comma).is_none() {
2350                    break;
2351                }
2352            }
2353            Ok(())
2354        },
2355    )?;
2356    Ok(AlterTable {
2357        alter_span,
2358        online,
2359        ignore,
2360        table_span,
2361        if_exists,
2362        only,
2363        table,
2364        alter_specifications,
2365    })
2366}