Skip to main content

qusql_parse/
alter_type.rs

1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License at
4//
5// http://www.apache.org/licenses/LICENSE-2.0
6//
7// Unless required by applicable law or agreed to in writing, software
8// distributed under the License is distributed on an "AS IS" BASIS,
9// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10// See the License for the specific language governing permissions and
11// limitations under the License.
12
13use alloc::vec::Vec;
14
15use crate::{
16    Identifier, OptSpanned, QualifiedName, SString, Span, Spanned,
17    alter_table::AlterTableOwner,
18    data_type::{DataType, DataTypeContext, parse_data_type},
19    drop::{CascadeOrRestrict, parse_cascade_or_restrict},
20    expression::{Expression, PRIORITY_MAX, parse_expression_unreserved},
21    keywords::Keyword,
22    lexer::Token,
23    parser::{ParseError, Parser},
24    qualified_name::parse_qualified_name_unreserved,
25};
26
27/// ALTER TYPE actions
28#[derive(Clone, Debug)]
29pub enum AlterTypeAction<'a> {
30    /// OWNER TO new_owner
31    OwnerTo {
32        owner_to_span: Span,
33        new_owner: AlterTableOwner<'a>,
34    },
35    /// RENAME TO new_name
36    RenameTo {
37        rename_to_span: Span,
38        new_name: Identifier<'a>,
39    },
40    /// SET SCHEMA new_schema
41    SetSchema {
42        set_schema_span: Span,
43        new_schema: QualifiedName<'a>,
44    },
45    /// RENAME ATTRIBUTE attribute_name TO new_attribute_name [ CASCADE | RESTRICT ]
46    RenameAttribute {
47        rename_attribute_span: Span,
48        attribute_name: Identifier<'a>,
49        to_span: Span,
50        new_attribute_name: Identifier<'a>,
51        cascade_or_restrict: Option<CascadeOrRestrict>,
52    },
53    /// ADD VALUE [ IF NOT EXISTS ] new_enum_value [ { BEFORE | AFTER } neighbor_enum_value ]
54    AddValue {
55        add_value_span: Span,
56        if_not_exists_span: Option<Span>, // IF NOT EXISTS
57        new_enum_value: SString<'a>,
58        placement: Option<(Span, SString<'a>)>, // (BEFORE/AFTER span, neighbor value)
59    },
60    /// RENAME VALUE existing_enum_value TO new_enum_value
61    RenameValue {
62        rename_value_span: Span,
63        existing_enum_value: SString<'a>,
64        to_span: Span,
65        new_enum_value: SString<'a>,
66    },
67    /// ADD ATTRIBUTE attribute_name data_type [ COLLATE collation ] [ CASCADE | RESTRICT ]
68    /// DROP ATTRIBUTE [ IF EXISTS ] attribute_name [ CASCADE | RESTRICT ]
69    /// ALTER ATTRIBUTE attribute_name [ SET DATA ] TYPE data_type [ COLLATE collation ] [ CASCADE | RESTRICT ]
70    Attributes { items: Vec<AttributeAction<'a>> },
71    /// SET ( property = value [, ... ] )
72    SetProperties {
73        set_span: Span,
74        properties: Vec<(Identifier<'a>, Expression<'a>)>,
75    },
76}
77
78impl<'a> Spanned for AlterTypeAction<'a> {
79    fn span(&self) -> Span {
80        match self {
81            AlterTypeAction::OwnerTo {
82                owner_to_span,
83                new_owner,
84            } => owner_to_span.join_span(new_owner),
85            AlterTypeAction::RenameTo {
86                rename_to_span,
87                new_name,
88            } => rename_to_span.join_span(new_name),
89            AlterTypeAction::SetSchema {
90                set_schema_span,
91                new_schema,
92            } => set_schema_span.join_span(new_schema),
93            AlterTypeAction::RenameAttribute {
94                rename_attribute_span,
95                attribute_name,
96                to_span,
97                new_attribute_name,
98                cascade_or_restrict,
99            } => rename_attribute_span
100                .join_span(attribute_name)
101                .join_span(to_span)
102                .join_span(new_attribute_name)
103                .join_span(cascade_or_restrict),
104            AlterTypeAction::AddValue {
105                add_value_span,
106                if_not_exists_span,
107                new_enum_value,
108                placement,
109            } => add_value_span
110                .join_span(if_not_exists_span)
111                .join_span(new_enum_value)
112                .join_span(placement),
113            AlterTypeAction::RenameValue {
114                rename_value_span,
115                existing_enum_value,
116                to_span,
117                new_enum_value,
118            } => rename_value_span
119                .join_span(existing_enum_value)
120                .join_span(to_span)
121                .join_span(new_enum_value),
122            AlterTypeAction::Attributes { items } => items.opt_span().expect("Empty attributes"),
123            AlterTypeAction::SetProperties {
124                set_span,
125                properties,
126            } => set_span.join_span(properties),
127        }
128    }
129}
130
131/// Attribute actions for composite types
132#[derive(Clone, Debug)]
133pub enum AttributeAction<'a> {
134    /// ADD ATTRIBUTE attribute_name data_type [ COLLATE collation ] [ CASCADE | RESTRICT ]
135    Add {
136        add_attribute_span: Span,
137        attribute_name: Identifier<'a>,
138        data_type: DataType<'a>,
139        collate: Option<(Span, QualifiedName<'a>)>,
140        cascade_or_restrict: Option<CascadeOrRestrict>,
141    },
142    /// DROP ATTRIBUTE [ IF EXISTS ] attribute_name [ CASCADE | RESTRICT ]
143    Drop {
144        drop_attribute_span: Span,
145        if_exists_span: Option<Span>, // IF EXISTS
146        attribute_name: Identifier<'a>,
147        cascade_or_restrict: Option<CascadeOrRestrict>,
148    },
149    /// ALTER ATTRIBUTE attribute_name [ SET DATA ] TYPE data_type [ COLLATE collation ] [ CASCADE | RESTRICT ]
150    Alter {
151        alter_attribute_span: Span,
152        attribute_name: Identifier<'a>,
153        set_data_span: Option<Span>, // SET DATA
154        type_span: Span,
155        data_type: DataType<'a>,
156        collate: Option<(Span, QualifiedName<'a>)>,
157        cascade_or_restrict: Option<CascadeOrRestrict>,
158    },
159}
160
161impl<'a> Spanned for AttributeAction<'a> {
162    fn span(&self) -> Span {
163        match self {
164            AttributeAction::Add {
165                add_attribute_span,
166                attribute_name,
167                data_type,
168                collate,
169                cascade_or_restrict,
170            } => add_attribute_span
171                .join_span(attribute_name)
172                .join_span(data_type)
173                .join_span(collate)
174                .join_span(cascade_or_restrict),
175            AttributeAction::Drop {
176                drop_attribute_span,
177                if_exists_span,
178                attribute_name,
179                cascade_or_restrict,
180            } => drop_attribute_span
181                .join_span(if_exists_span)
182                .join_span(attribute_name)
183                .join_span(cascade_or_restrict),
184            AttributeAction::Alter {
185                alter_attribute_span,
186                attribute_name,
187                set_data_span,
188                type_span,
189                data_type,
190                collate,
191                cascade_or_restrict,
192            } => alter_attribute_span
193                .join_span(attribute_name)
194                .join_span(set_data_span)
195                .join_span(type_span)
196                .join_span(data_type)
197                .join_span(collate)
198                .join_span(cascade_or_restrict),
199        }
200    }
201}
202
203/// ALTER TYPE statement (PostgreSQL)
204#[derive(Clone, Debug)]
205pub struct AlterType<'a> {
206    /// Span of "ALTER TYPE"
207    pub alter_type_span: Span,
208    /// Name of the type (possibly schema-qualified)
209    pub name: QualifiedName<'a>,
210    /// Action to perform
211    pub action: AlterTypeAction<'a>,
212}
213
214impl<'a> Spanned for AlterType<'a> {
215    fn span(&self) -> Span {
216        self.alter_type_span
217            .join_span(&self.name)
218            .join_span(&self.action)
219    }
220}
221
222pub(crate) fn parse_alter_type<'a>(
223    parser: &mut Parser<'a, '_>,
224    alter_type_span: Span,
225) -> Result<AlterType<'a>, ParseError> {
226    parser.postgres_only(&alter_type_span);
227    let name = parse_qualified_name_unreserved(parser)?;
228
229    let action = match &parser.token {
230        Token::Ident(_, Keyword::OWNER) => {
231            let owner_to_span = parser.consume_keywords(&[Keyword::OWNER, Keyword::TO])?;
232            let new_owner = crate::alter_table::parse_alter_owner(parser)?;
233            AlterTypeAction::OwnerTo {
234                owner_to_span,
235                new_owner,
236            }
237        }
238        Token::Ident(_, Keyword::RENAME) => {
239            let rename_span = parser.consume_keyword(Keyword::RENAME)?;
240            match &parser.token {
241                Token::Ident(_, Keyword::TO) => {
242                    // RENAME TO new_name
243                    let to_span = parser.consume_keyword(Keyword::TO)?;
244                    let rename_to_span = rename_span.join_span(&to_span);
245                    let new_name = parser.consume_plain_identifier_unreserved()?;
246                    AlterTypeAction::RenameTo {
247                        rename_to_span,
248                        new_name,
249                    }
250                }
251                Token::Ident(_, Keyword::ATTRIBUTE) => {
252                    // RENAME ATTRIBUTE attribute_name TO new_attribute_name
253                    let attribute_span = parser.consume_keyword(Keyword::ATTRIBUTE)?;
254                    let rename_attribute_span = rename_span.join_span(&attribute_span);
255                    let attribute_name = parser.consume_plain_identifier_unreserved()?;
256                    let to_span = parser.consume_keyword(Keyword::TO)?;
257                    let new_attribute_name = parser.consume_plain_identifier_unreserved()?;
258                    let cascade_or_restrict = parse_cascade_or_restrict(parser);
259                    AlterTypeAction::RenameAttribute {
260                        rename_attribute_span,
261                        attribute_name,
262                        to_span,
263                        new_attribute_name,
264                        cascade_or_restrict,
265                    }
266                }
267                Token::Ident(_, Keyword::VALUE) => {
268                    // RENAME VALUE existing_enum_value TO new_enum_value
269                    let value_span = parser.consume_keyword(Keyword::VALUE)?;
270                    let rename_value_span = rename_span.join_span(&value_span);
271                    let existing_enum_value = parser.consume_string()?;
272                    let to_span = parser.consume_keyword(Keyword::TO)?;
273                    let new_enum_value = parser.consume_string()?;
274                    AlterTypeAction::RenameValue {
275                        rename_value_span,
276                        existing_enum_value,
277                        to_span,
278                        new_enum_value,
279                    }
280                }
281                _ => parser.expected_failure("'TO', 'ATTRIBUTE', or 'VALUE' after 'RENAME'")?,
282            }
283        }
284        Token::Ident(_, Keyword::SET) => {
285            let set_span = parser.consume_keyword(Keyword::SET)?;
286            match &parser.token {
287                Token::Ident(_, Keyword::SCHEMA) => {
288                    // SET SCHEMA new_schema
289                    let schema_span = parser.consume_keyword(Keyword::SCHEMA)?;
290                    let set_schema_span = set_span.join_span(&schema_span);
291                    let new_schema = parse_qualified_name_unreserved(parser)?;
292                    AlterTypeAction::SetSchema {
293                        set_schema_span,
294                        new_schema,
295                    }
296                }
297                Token::LParen => {
298                    // SET ( property = value [, ... ] )
299                    parser.consume_token(Token::LParen)?;
300                    let mut properties = Vec::new();
301                    loop {
302                        let property = parser.consume_plain_identifier_unreserved()?;
303                        parser.consume_token(Token::Eq)?;
304                        let value = parse_expression_unreserved(parser, PRIORITY_MAX)?;
305                        properties.push((property, value));
306                        if parser.skip_token(Token::Comma).is_none() {
307                            break;
308                        }
309                    }
310                    parser.consume_token(Token::RParen)?;
311                    AlterTypeAction::SetProperties {
312                        set_span,
313                        properties,
314                    }
315                }
316                _ => parser.expected_failure("'SCHEMA' or '(' after 'SET'")?,
317            }
318        }
319        Token::Ident(_, Keyword::ADD) => {
320            let add_span = parser.consume_keyword(Keyword::ADD)?;
321            match &parser.token {
322                Token::Ident(_, Keyword::VALUE) => {
323                    // ADD VALUE [ IF NOT EXISTS ] new_enum_value [ { BEFORE | AFTER } neighbor_enum_value ]
324                    let value_span = parser.consume_keyword(Keyword::VALUE)?;
325                    let add_value_span = add_span.join_span(&value_span);
326                    let if_not_exists_span = if let Some(if_span) = parser.skip_keyword(Keyword::IF)
327                    {
328                        Some(
329                            parser
330                                .consume_keywords(&[Keyword::NOT, Keyword::EXISTS])?
331                                .join_span(&if_span),
332                        )
333                    } else {
334                        None
335                    };
336                    let new_enum_value = parser.consume_string()?;
337                    let placement = if let Some(before_span) = parser.skip_keyword(Keyword::BEFORE)
338                    {
339                        let neighbor = parser.consume_string()?;
340                        Some((before_span, neighbor))
341                    } else if let Some(after_span) = parser.skip_keyword(Keyword::AFTER) {
342                        let neighbor = parser.consume_string()?;
343                        Some((after_span, neighbor))
344                    } else {
345                        None
346                    };
347                    AlterTypeAction::AddValue {
348                        add_value_span,
349                        if_not_exists_span,
350                        new_enum_value,
351                        placement,
352                    }
353                }
354                Token::Ident(_, Keyword::ATTRIBUTE) => {
355                    // ADD ATTRIBUTE or composite type operations with multiple items
356                    let mut items = Vec::new();
357                    loop {
358                        items.push(parse_attribute_action(parser)?);
359                        if parser.skip_token(Token::Comma).is_none() {
360                            break;
361                        }
362                    }
363                    AlterTypeAction::Attributes { items }
364                }
365                _ => parser.expected_failure("'VALUE' or 'ATTRIBUTE' after 'ADD'")?,
366            }
367        }
368        Token::Ident(_, Keyword::DROP) => {
369            // DROP ATTRIBUTE or multiple operations
370            let mut items = Vec::new();
371            loop {
372                items.push(parse_attribute_action(parser)?);
373                if parser.skip_token(Token::Comma).is_none() {
374                    break;
375                }
376            }
377            AlterTypeAction::Attributes { items }
378        }
379        Token::Ident(_, Keyword::ALTER) => {
380            // ALTER ATTRIBUTE or multiple operations
381            let mut items = Vec::new();
382            loop {
383                items.push(parse_attribute_action(parser)?);
384                if parser.skip_token(Token::Comma).is_none() {
385                    break;
386                }
387            }
388            AlterTypeAction::Attributes { items }
389        }
390        _ => parser.expected_failure(
391            "'OWNER', 'RENAME', 'SET', 'ADD', 'DROP', or 'ALTER' after type name",
392        )?,
393    };
394
395    Ok(AlterType {
396        alter_type_span,
397        name,
398        action,
399    })
400}
401
402fn parse_attribute_action<'a>(
403    parser: &mut Parser<'a, '_>,
404) -> Result<AttributeAction<'a>, ParseError> {
405    match &parser.token {
406        Token::Ident(_, Keyword::ADD) => {
407            // ADD ATTRIBUTE attribute_name data_type [ COLLATE collation ] [ CASCADE | RESTRICT ]
408            let add_attribute_span =
409                parser.consume_keywords(&[Keyword::ADD, Keyword::ATTRIBUTE])?;
410            let attribute_name = parser.consume_plain_identifier_unreserved()?;
411            let data_type = parse_data_type(parser, DataTypeContext::Column)?;
412            let collate = if let Some(collate_span) = parser.skip_keyword(Keyword::COLLATE) {
413                let collation = parse_qualified_name_unreserved(parser)?;
414                Some((collate_span, collation))
415            } else {
416                None
417            };
418            let cascade_or_restrict = parse_cascade_or_restrict(parser);
419            Ok(AttributeAction::Add {
420                add_attribute_span,
421                attribute_name,
422                data_type,
423                collate,
424                cascade_or_restrict,
425            })
426        }
427        Token::Ident(_, Keyword::DROP) => {
428            // DROP ATTRIBUTE [ IF EXISTS ] attribute_name [ CASCADE | RESTRICT ]
429            let drop_attribute_span =
430                parser.consume_keywords(&[Keyword::DROP, Keyword::ATTRIBUTE])?;
431            let if_exists_span = if let Some(if_span) = parser.skip_keyword(Keyword::IF) {
432                Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&if_span))
433            } else {
434                None
435            };
436            let attribute_name = parser.consume_plain_identifier_unreserved()?;
437            let cascade_or_restrict = parse_cascade_or_restrict(parser);
438            Ok(AttributeAction::Drop {
439                drop_attribute_span,
440                if_exists_span,
441                attribute_name,
442                cascade_or_restrict,
443            })
444        }
445        Token::Ident(_, Keyword::ALTER) => {
446            // ALTER ATTRIBUTE attribute_name [ SET DATA ] TYPE data_type [ COLLATE collation ] [ CASCADE | RESTRICT ]
447            let alter_attribute_span =
448                parser.consume_keywords(&[Keyword::ALTER, Keyword::ATTRIBUTE])?;
449            let attribute_name = parser.consume_plain_identifier_unreserved()?;
450            let set_data_span = if let Some(set_span) = parser.skip_keyword(Keyword::SET) {
451                Some(parser.consume_keyword(Keyword::DATA)?.join_span(&set_span))
452            } else {
453                None
454            };
455            let type_span = parser.consume_keyword(Keyword::TYPE)?;
456            let data_type = parse_data_type(parser, DataTypeContext::Column)?;
457            let collate = if let Some(collate_span) = parser.skip_keyword(Keyword::COLLATE) {
458                let collation = parse_qualified_name_unreserved(parser)?;
459                Some((collate_span, collation))
460            } else {
461                None
462            };
463            let cascade_or_restrict = parse_cascade_or_restrict(parser);
464            Ok(AttributeAction::Alter {
465                alter_attribute_span,
466                attribute_name,
467                set_data_span,
468                type_span,
469                data_type,
470                collate,
471                cascade_or_restrict,
472            })
473        }
474        _ => parser.expected_failure("'ADD', 'DROP', or 'ALTER' for attribute action"),
475    }
476}