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