Skip to main content

sql/statements/
alter.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#[cfg(feature = "enterprise")]
16pub mod trigger;
17
18use std::fmt::{Debug, Display};
19
20use api::v1;
21use common_query::AddColumnLocation;
22use datatypes::schema::{FulltextOptions, SkippingIndexOptions};
23use itertools::Itertools;
24use serde::Serialize;
25use sqlparser::ast::{ColumnDef, DataType, Expr, Ident, ObjectName, TableConstraint};
26use sqlparser_derive::{Visit, VisitMut};
27
28use crate::statements::OptionMap;
29use crate::statements::create::Partitions;
30
31#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
32pub struct AlterTable {
33    pub table_name: ObjectName,
34    pub alter_operation: AlterTableOperation,
35    /// Table options in `WITH`. All keys are lowercase.
36    pub options: OptionMap,
37}
38
39impl AlterTable {
40    pub(crate) fn new(
41        table_name: ObjectName,
42        alter_operation: AlterTableOperation,
43        options: OptionMap,
44    ) -> Self {
45        Self {
46            table_name,
47            alter_operation,
48            options,
49        }
50    }
51
52    pub fn table_name(&self) -> &ObjectName {
53        &self.table_name
54    }
55
56    pub fn alter_operation(&self) -> &AlterTableOperation {
57        &self.alter_operation
58    }
59
60    pub fn options(&self) -> &OptionMap {
61        &self.options
62    }
63
64    pub fn alter_operation_mut(&mut self) -> &mut AlterTableOperation {
65        &mut self.alter_operation
66    }
67}
68
69impl Display for AlterTable {
70    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
71        let table_name = self.table_name();
72        let alter_operation = self.alter_operation();
73        write!(f, r#"ALTER TABLE {table_name} {alter_operation}"#)
74    }
75}
76
77#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
78pub enum AlterTableOperation {
79    /// `ADD <table_constraint>`
80    AddConstraint(TableConstraint),
81    /// `ADD [ COLUMN ] <column_def> [location]`
82    AddColumns {
83        add_columns: Vec<AddColumn>,
84    },
85    /// `MODIFY <column_name> [target_type]`
86    ModifyColumnType {
87        column_name: Ident,
88        target_type: DataType,
89    },
90    /// `SET <table attrs key> = <table attr value>`
91    SetTableOptions {
92        options: Vec<KeyValueOption>,
93    },
94    /// `UNSET <table attrs key>`
95    UnsetTableOptions {
96        keys: Vec<String>,
97    },
98    /// `DROP COLUMN <name>`
99    DropColumn {
100        name: Ident,
101    },
102    /// `RENAME <new_table_name>`
103    RenameTable {
104        new_table_name: String,
105    },
106    SetIndex {
107        options: SetIndexOperation,
108    },
109    UnsetIndex {
110        options: UnsetIndexOperation,
111    },
112    DropDefaults {
113        columns: Vec<DropDefaultsOperation>,
114    },
115    /// `ALTER <column_name> SET DEFAULT <default_value>`
116    SetDefaults {
117        defaults: Vec<SetDefaultsOperation>,
118    },
119    /// `REPARTITION (...) INTO (...)`
120    Repartition {
121        operation: RepartitionOperation,
122    },
123    /// `PARTITION ON COLUMNS (...) (...)`
124    Partition {
125        partitions: Partitions,
126    },
127}
128
129#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
130/// `ALTER <column_name> DROP DEFAULT`
131pub struct DropDefaultsOperation(pub Ident);
132
133#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
134pub struct SetDefaultsOperation {
135    pub column_name: Ident,
136    pub default_constraint: Expr,
137}
138
139#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
140pub struct RepartitionOperation {
141    pub from_exprs: Vec<Expr>,
142    pub into_exprs: Vec<Expr>,
143    /// Optional new partition columns for `REPARTITION ... ON COLUMNS (...) INTO (...)` and
144    /// `SPLIT PARTITION ... ON COLUMNS (...) INTO (...)`.
145    ///
146    /// This is `Some` only when the statement explicitly carries `ON COLUMNS`.
147    /// Legacy `REPARTITION`, `SPLIT PARTITION`, and `MERGE PARTITION` keep this as `None`.
148    pub partition_columns: Option<Vec<Ident>>,
149}
150
151impl RepartitionOperation {
152    pub fn new(from_exprs: Vec<Expr>, into_exprs: Vec<Expr>) -> Self {
153        Self {
154            from_exprs,
155            into_exprs,
156            partition_columns: None,
157        }
158    }
159
160    pub fn with_partition_columns(
161        from_exprs: Vec<Expr>,
162        into_exprs: Vec<Expr>,
163        partition_columns: Vec<Ident>,
164    ) -> Self {
165        Self {
166            from_exprs,
167            into_exprs,
168            partition_columns: Some(partition_columns),
169        }
170    }
171}
172
173impl Display for RepartitionOperation {
174    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
175        let from = self
176            .from_exprs
177            .iter()
178            .map(|expr| expr.to_string())
179            .join(", ");
180        let into = self
181            .into_exprs
182            .iter()
183            .map(|expr| expr.to_string())
184            .join(", ");
185
186        if let Some(partition_columns) = &self.partition_columns {
187            let partition_columns = partition_columns
188                .iter()
189                .map(|ident| ident.to_string())
190                .join(", ");
191            write!(f, "({from}) ON COLUMNS ({partition_columns}) INTO ({into})")
192        } else {
193            write!(f, "({from}) INTO ({into})")
194        }
195    }
196}
197
198#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
199pub enum SetIndexOperation {
200    /// `MODIFY COLUMN <column_name> SET FULLTEXT INDEX [WITH <options>]`
201    Fulltext {
202        column_name: Ident,
203        options: FulltextOptions,
204    },
205    /// `MODIFY COLUMN <column_name> SET INVERTED INDEX`
206    Inverted { column_name: Ident },
207    /// `MODIFY COLUMN <column_name> SET SKIPPING INDEX`
208    Skipping {
209        column_name: Ident,
210        options: SkippingIndexOptions,
211    },
212}
213
214#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
215pub enum UnsetIndexOperation {
216    /// `MODIFY COLUMN <column_name> UNSET FULLTEXT INDEX`
217    Fulltext { column_name: Ident },
218    /// `MODIFY COLUMN <column_name> UNSET INVERTED INDEX`
219    Inverted { column_name: Ident },
220    /// `MODIFY COLUMN <column_name> UNSET SKIPPING INDEX`
221    Skipping { column_name: Ident },
222}
223
224#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
225pub struct AddColumn {
226    pub column_def: ColumnDef,
227    pub location: Option<AddColumnLocation>,
228    pub add_if_not_exists: bool,
229}
230
231impl Display for AddColumn {
232    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
233        if let Some(location) = &self.location {
234            write!(f, "{} {location}", self.column_def)
235        } else {
236            write!(f, "{}", self.column_def)
237        }
238    }
239}
240
241impl Display for AlterTableOperation {
242    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
243        match self {
244            AlterTableOperation::AddConstraint(constraint) => write!(f, r#"ADD {constraint}"#),
245            AlterTableOperation::AddColumns { add_columns } => {
246                let columns = add_columns
247                    .iter()
248                    .map(|add_column| format!("ADD COLUMN {add_column}"))
249                    .join(", ");
250                write!(f, "{columns}")
251            }
252            AlterTableOperation::DropColumn { name } => write!(f, r#"DROP COLUMN {name}"#),
253            AlterTableOperation::RenameTable { new_table_name } => {
254                write!(f, r#"RENAME {new_table_name}"#)
255            }
256            AlterTableOperation::ModifyColumnType {
257                column_name,
258                target_type,
259            } => {
260                write!(f, r#"MODIFY COLUMN {column_name} {target_type}"#)
261            }
262            AlterTableOperation::SetTableOptions { options } => {
263                let kvs = options
264                    .iter()
265                    .map(|KeyValueOption { key, value }| {
266                        if !value.is_empty() {
267                            format!("'{key}'='{value}'")
268                        } else {
269                            format!("'{key}'=NULL")
270                        }
271                    })
272                    .join(",");
273
274                write!(f, "SET {kvs}")
275            }
276            AlterTableOperation::UnsetTableOptions { keys } => {
277                let keys = keys.iter().map(|k| format!("'{k}'")).join(",");
278                write!(f, "UNSET {keys}")
279            }
280            AlterTableOperation::Repartition { operation } => {
281                write!(f, "REPARTITION {operation}")
282            }
283            AlterTableOperation::Partition { partitions } => {
284                write!(f, "{partitions}")
285            }
286            AlterTableOperation::SetIndex { options } => match options {
287                SetIndexOperation::Fulltext {
288                    column_name,
289                    options,
290                } => {
291                    write!(
292                        f,
293                        "MODIFY COLUMN {column_name} SET FULLTEXT INDEX WITH(analyzer={0}, case_sensitive={1}, backend={2})",
294                        options.analyzer, options.case_sensitive, options.backend
295                    )
296                }
297                SetIndexOperation::Inverted { column_name } => {
298                    write!(f, "MODIFY COLUMN {column_name} SET INVERTED INDEX")
299                }
300                SetIndexOperation::Skipping {
301                    column_name,
302                    options,
303                } => {
304                    write!(
305                        f,
306                        "MODIFY COLUMN {column_name} SET SKIPPING INDEX WITH(granularity={0}, index_type={1})",
307                        options.granularity, options.index_type
308                    )
309                }
310            },
311            AlterTableOperation::UnsetIndex { options } => match options {
312                UnsetIndexOperation::Fulltext { column_name } => {
313                    write!(f, "MODIFY COLUMN {column_name} UNSET FULLTEXT INDEX")
314                }
315                UnsetIndexOperation::Inverted { column_name } => {
316                    write!(f, "MODIFY COLUMN {column_name} UNSET INVERTED INDEX")
317                }
318                UnsetIndexOperation::Skipping { column_name } => {
319                    write!(f, "MODIFY COLUMN {column_name} UNSET SKIPPING INDEX")
320                }
321            },
322            AlterTableOperation::DropDefaults { columns } => {
323                let columns = columns
324                    .iter()
325                    .map(|column| format!("MODIFY COLUMN {} DROP DEFAULT", column.0))
326                    .join(", ");
327                write!(f, "{columns}")
328            }
329            AlterTableOperation::SetDefaults { defaults } => {
330                let defaults = defaults
331                    .iter()
332                    .map(|column| {
333                        format!(
334                            "MODIFY COLUMN {} SET DEFAULT {}",
335                            column.column_name, column.default_constraint
336                        )
337                    })
338                    .join(", ");
339                write!(f, "{defaults}")
340            }
341        }
342    }
343}
344
345#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
346pub struct KeyValueOption {
347    pub key: String,
348    pub value: String,
349}
350
351impl From<KeyValueOption> for v1::Option {
352    fn from(c: KeyValueOption) -> Self {
353        v1::Option {
354            key: c.key,
355            value: c.value,
356        }
357    }
358}
359
360#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
361pub struct AlterDatabase {
362    pub database_name: ObjectName,
363    pub alter_operation: AlterDatabaseOperation,
364}
365
366impl AlterDatabase {
367    pub(crate) fn new(database_name: ObjectName, alter_operation: AlterDatabaseOperation) -> Self {
368        Self {
369            database_name,
370            alter_operation,
371        }
372    }
373
374    pub fn database_name(&self) -> &ObjectName {
375        &self.database_name
376    }
377
378    pub fn alter_operation(&self) -> &AlterDatabaseOperation {
379        &self.alter_operation
380    }
381}
382
383impl Display for AlterDatabase {
384    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
385        let database_name = self.database_name();
386        let alter_operation = self.alter_operation();
387        write!(f, r#"ALTER DATABASE {database_name} {alter_operation}"#)
388    }
389}
390
391#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
392pub enum AlterDatabaseOperation {
393    SetDatabaseOption { options: Vec<KeyValueOption> },
394    UnsetDatabaseOption { keys: Vec<String> },
395}
396
397impl Display for AlterDatabaseOperation {
398    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
399        match self {
400            AlterDatabaseOperation::SetDatabaseOption { options } => {
401                let kvs = options
402                    .iter()
403                    .map(|KeyValueOption { key, value }| {
404                        if !value.is_empty() {
405                            format!("'{key}'='{value}'")
406                        } else {
407                            format!("'{key}'=NULL")
408                        }
409                    })
410                    .join(",");
411
412                write!(f, "SET {kvs}")?;
413
414                Ok(())
415            }
416            AlterDatabaseOperation::UnsetDatabaseOption { keys } => {
417                let keys = keys.iter().map(|key| format!("'{key}'")).join(",");
418                write!(f, "UNSET {keys}")?;
419
420                Ok(())
421            }
422        }
423    }
424}
425
426#[cfg(test)]
427mod tests {
428    use std::assert_matches;
429
430    use crate::dialect::GreptimeDbDialect;
431    use crate::parser::{ParseOptions, ParserContext};
432    use crate::statements::statement::Statement;
433
434    #[test]
435    fn test_display_alter() {
436        let sql = r"ALTER DATABASE db SET 'a' = 'b', 'c' = 'd'";
437        let stmts =
438            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
439                .unwrap();
440        assert_eq!(1, stmts.len());
441        assert_matches!(&stmts[0], Statement::AlterDatabase { .. });
442
443        match &stmts[0] {
444            Statement::AlterDatabase(set) => {
445                let new_sql = format!("\n{}", set);
446                assert_eq!(
447                    r#"
448ALTER DATABASE db SET 'a'='b','c'='d'"#,
449                    &new_sql
450                );
451            }
452            _ => {
453                unreachable!();
454            }
455        }
456
457        let sql = r"ALTER DATABASE db UNSET 'a', 'c'";
458        let stmts =
459            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
460                .unwrap();
461        assert_eq!(1, stmts.len());
462
463        match &stmts[0] {
464            Statement::AlterDatabase(set) => {
465                let new_sql = format!("\n{}", set);
466                assert_eq!(
467                    r#"
468ALTER DATABASE db UNSET 'a','c'"#,
469                    &new_sql
470                );
471            }
472            _ => {
473                unreachable!();
474            }
475        }
476
477        let sql =
478            r"alter table monitor add column app string default 'shop' primary key, add foo INT;";
479        let stmts =
480            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
481                .unwrap();
482        assert_eq!(1, stmts.len());
483        assert_matches!(&stmts[0], Statement::AlterTable { .. });
484
485        match &stmts[0] {
486            Statement::AlterTable(set) => {
487                let new_sql = format!("\n{}", set);
488                assert_eq!(
489                    r#"
490ALTER TABLE monitor ADD COLUMN app STRING DEFAULT 'shop' PRIMARY KEY, ADD COLUMN foo INT"#,
491                    &new_sql
492                );
493            }
494            _ => {
495                unreachable!();
496            }
497        }
498
499        let sql = r"alter table monitor modify column load_15 string;";
500        let stmts =
501            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
502                .unwrap();
503        assert_eq!(1, stmts.len());
504        assert_matches!(&stmts[0], Statement::AlterTable { .. });
505
506        match &stmts[0] {
507            Statement::AlterTable(set) => {
508                let new_sql = format!("\n{}", set);
509                assert_eq!(
510                    r#"
511ALTER TABLE monitor MODIFY COLUMN load_15 STRING"#,
512                    &new_sql
513                );
514            }
515            _ => {
516                unreachable!();
517            }
518        }
519
520        let sql = r"alter table monitor drop column load_15;";
521        let stmts =
522            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
523                .unwrap();
524        assert_eq!(1, stmts.len());
525        assert_matches!(&stmts[0], Statement::AlterTable { .. });
526
527        match &stmts[0] {
528            Statement::AlterTable(set) => {
529                let new_sql = format!("\n{}", set);
530                assert_eq!(
531                    r#"
532ALTER TABLE monitor DROP COLUMN load_15"#,
533                    &new_sql
534                );
535            }
536            _ => {
537                unreachable!();
538            }
539        }
540
541        let sql = r"alter table monitor rename monitor_new;";
542        let stmts =
543            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
544                .unwrap();
545        assert_eq!(1, stmts.len());
546        assert_matches!(&stmts[0], Statement::AlterTable { .. });
547
548        match &stmts[0] {
549            Statement::AlterTable(set) => {
550                let new_sql = format!("\n{}", set);
551                assert_eq!(
552                    r#"
553ALTER TABLE monitor RENAME monitor_new"#,
554                    &new_sql
555                );
556            }
557            _ => {
558                unreachable!();
559            }
560        }
561
562        let sql = "ALTER TABLE monitor MODIFY COLUMN a SET FULLTEXT INDEX WITH(analyzer='English',case_sensitive='false',backend='bloom')";
563        let stmts =
564            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
565                .unwrap();
566        assert_eq!(1, stmts.len());
567        assert_matches!(&stmts[0], Statement::AlterTable { .. });
568
569        match &stmts[0] {
570            Statement::AlterTable(set) => {
571                let new_sql = format!("\n{}", set);
572                assert_eq!(
573                    r#"
574ALTER TABLE monitor MODIFY COLUMN a SET FULLTEXT INDEX WITH(analyzer=English, case_sensitive=false, backend=bloom)"#,
575                    &new_sql
576                );
577            }
578            _ => {
579                unreachable!();
580            }
581        }
582
583        let sql = "ALTER TABLE monitor MODIFY COLUMN a UNSET FULLTEXT INDEX";
584        let stmts =
585            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
586                .unwrap();
587        assert_eq!(1, stmts.len());
588        assert_matches!(&stmts[0], Statement::AlterTable { .. });
589
590        match &stmts[0] {
591            Statement::AlterTable(set) => {
592                let new_sql = format!("\n{}", set);
593                assert_eq!(
594                    r#"
595ALTER TABLE monitor MODIFY COLUMN a UNSET FULLTEXT INDEX"#,
596                    &new_sql
597                );
598            }
599            _ => {
600                unreachable!();
601            }
602        }
603
604        let sql = "ALTER TABLE monitor MODIFY COLUMN a SET INVERTED INDEX";
605        let stmts =
606            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
607                .unwrap();
608        assert_eq!(1, stmts.len());
609        assert_matches!(&stmts[0], Statement::AlterTable { .. });
610
611        match &stmts[0] {
612            Statement::AlterTable(set) => {
613                let new_sql = format!("\n{}", set);
614                assert_eq!(
615                    r#"
616ALTER TABLE monitor MODIFY COLUMN a SET INVERTED INDEX"#,
617                    &new_sql
618                );
619            }
620            _ => {
621                unreachable!();
622            }
623        }
624
625        let sql = "ALTER TABLE monitor MODIFY COLUMN a DROP DEFAULT";
626        let stmts =
627            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
628                .unwrap();
629        assert_eq!(1, stmts.len());
630        assert_matches!(&stmts[0], Statement::AlterTable { .. });
631
632        match &stmts[0] {
633            Statement::AlterTable(set) => {
634                let new_sql = format!("\n{}", set);
635                assert_eq!(
636                    r#"
637ALTER TABLE monitor MODIFY COLUMN a DROP DEFAULT"#,
638                    &new_sql
639                );
640            }
641            _ => {
642                unreachable!();
643            }
644        }
645
646        let sql = "ALTER TABLE monitor MODIFY COLUMN a SET DEFAULT 'default_for_a'";
647        let stmts =
648            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
649                .unwrap();
650        assert_eq!(1, stmts.len());
651        assert_matches!(&stmts[0], Statement::AlterTable { .. });
652
653        match &stmts[0] {
654            Statement::AlterTable(set) => {
655                let new_sql = format!("\n{}", set);
656                assert_eq!(
657                    r#"
658ALTER TABLE monitor MODIFY COLUMN a SET DEFAULT 'default_for_a'"#,
659                    &new_sql
660                );
661            }
662            _ => {
663                unreachable!();
664            }
665        }
666    }
667}