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::{Json2Options, 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        json2_options: Option<Json2Options>,
90    },
91    /// `MODIFY <column_name> JSON2 [json2_options]`
92    SetJsonSettings {
93        column_name: Ident,
94        json2_options: Option<Json2Options>,
95    },
96    /// `SET <table attrs key> = <table attr value>`
97    SetTableOptions {
98        options: Vec<KeyValueOption>,
99    },
100    /// `UNSET <table attrs key>`
101    UnsetTableOptions {
102        keys: Vec<String>,
103    },
104    /// `DROP COLUMN <name>`
105    DropColumn {
106        name: Ident,
107    },
108    /// `RENAME <new_table_name>`
109    RenameTable {
110        new_table_name: String,
111    },
112    SetIndex {
113        options: SetIndexOperation,
114    },
115    UnsetIndex {
116        options: UnsetIndexOperation,
117    },
118    DropDefaults {
119        columns: Vec<DropDefaultsOperation>,
120    },
121    /// `ALTER <column_name> SET DEFAULT <default_value>`
122    SetDefaults {
123        defaults: Vec<SetDefaultsOperation>,
124    },
125    /// `REPARTITION (...) INTO (...)`
126    Repartition {
127        operation: RepartitionOperation,
128    },
129    /// `PARTITION ON COLUMNS (...) (...)`
130    Partition {
131        partitions: Partitions,
132    },
133}
134
135#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
136/// `ALTER <column_name> DROP DEFAULT`
137pub struct DropDefaultsOperation(pub Ident);
138
139#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
140pub struct SetDefaultsOperation {
141    pub column_name: Ident,
142    pub default_constraint: Expr,
143}
144
145#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
146pub struct RepartitionOperation {
147    pub from_exprs: Vec<Expr>,
148    pub into_exprs: Vec<Expr>,
149    /// Optional new partition columns for `REPARTITION ... ON COLUMNS (...) INTO (...)` and
150    /// `SPLIT PARTITION ... ON COLUMNS (...) INTO (...)`.
151    ///
152    /// This is `Some` only when the statement explicitly carries `ON COLUMNS`.
153    /// Legacy `REPARTITION`, `SPLIT PARTITION`, and `MERGE PARTITION` keep this as `None`.
154    pub partition_columns: Option<Vec<Ident>>,
155}
156
157impl RepartitionOperation {
158    pub fn new(from_exprs: Vec<Expr>, into_exprs: Vec<Expr>) -> Self {
159        Self {
160            from_exprs,
161            into_exprs,
162            partition_columns: None,
163        }
164    }
165
166    pub fn with_partition_columns(
167        from_exprs: Vec<Expr>,
168        into_exprs: Vec<Expr>,
169        partition_columns: Vec<Ident>,
170    ) -> Self {
171        Self {
172            from_exprs,
173            into_exprs,
174            partition_columns: Some(partition_columns),
175        }
176    }
177}
178
179impl Display for RepartitionOperation {
180    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
181        let from = self
182            .from_exprs
183            .iter()
184            .map(|expr| expr.to_string())
185            .join(", ");
186        let into = self
187            .into_exprs
188            .iter()
189            .map(|expr| expr.to_string())
190            .join(", ");
191
192        if let Some(partition_columns) = &self.partition_columns {
193            let partition_columns = partition_columns
194                .iter()
195                .map(|ident| ident.to_string())
196                .join(", ");
197            write!(f, "({from}) ON COLUMNS ({partition_columns}) INTO ({into})")
198        } else {
199            write!(f, "({from}) INTO ({into})")
200        }
201    }
202}
203
204#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
205pub enum SetIndexOperation {
206    /// `MODIFY COLUMN <column_name> SET FULLTEXT INDEX [WITH <options>]`
207    Fulltext {
208        column_name: Ident,
209        options: FulltextOptions,
210    },
211    /// `MODIFY COLUMN <column_name> SET INVERTED INDEX`
212    Inverted { column_name: Ident },
213    /// `MODIFY COLUMN <column_name> SET SKIPPING INDEX`
214    Skipping {
215        column_name: Ident,
216        options: SkippingIndexOptions,
217    },
218}
219
220#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
221pub enum UnsetIndexOperation {
222    /// `MODIFY COLUMN <column_name> UNSET FULLTEXT INDEX`
223    Fulltext { column_name: Ident },
224    /// `MODIFY COLUMN <column_name> UNSET INVERTED INDEX`
225    Inverted { column_name: Ident },
226    /// `MODIFY COLUMN <column_name> UNSET SKIPPING INDEX`
227    Skipping { column_name: Ident },
228}
229
230#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
231pub struct AddColumn {
232    pub column_def: ColumnDef,
233    pub location: Option<AddColumnLocation>,
234    pub add_if_not_exists: bool,
235}
236
237impl Display for AddColumn {
238    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
239        if let Some(location) = &self.location {
240            write!(f, "{} {location}", self.column_def)
241        } else {
242            write!(f, "{}", self.column_def)
243        }
244    }
245}
246
247impl Display for AlterTableOperation {
248    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
249        match self {
250            AlterTableOperation::AddConstraint(constraint) => write!(f, r#"ADD {constraint}"#),
251            AlterTableOperation::AddColumns { add_columns } => {
252                let columns = add_columns
253                    .iter()
254                    .map(|add_column| format!("ADD COLUMN {add_column}"))
255                    .join(", ");
256                write!(f, "{columns}")
257            }
258            AlterTableOperation::DropColumn { name } => write!(f, r#"DROP COLUMN {name}"#),
259            AlterTableOperation::RenameTable { new_table_name } => {
260                write!(f, r#"RENAME {new_table_name}"#)
261            }
262            AlterTableOperation::ModifyColumnType {
263                column_name,
264                target_type,
265                json2_options,
266            } => {
267                write!(f, r#"MODIFY COLUMN {column_name} {target_type}"#)?;
268                if let Some(options) = json2_options {
269                    write!(f, "{options}")?;
270                }
271                Ok(())
272            }
273            AlterTableOperation::SetJsonSettings {
274                column_name,
275                json2_options,
276            } => {
277                write!(f, r#"MODIFY COLUMN {column_name} JSON2"#)?;
278                if let Some(options) = json2_options {
279                    write!(f, "{options}")?;
280                }
281                Ok(())
282            }
283            AlterTableOperation::SetTableOptions { options } => {
284                let kvs = options
285                    .iter()
286                    .map(|KeyValueOption { key, value }| {
287                        if !value.is_empty() {
288                            format!("'{key}'='{value}'")
289                        } else {
290                            format!("'{key}'=NULL")
291                        }
292                    })
293                    .join(",");
294
295                write!(f, "SET {kvs}")
296            }
297            AlterTableOperation::UnsetTableOptions { keys } => {
298                let keys = keys.iter().map(|k| format!("'{k}'")).join(",");
299                write!(f, "UNSET {keys}")
300            }
301            AlterTableOperation::Repartition { operation } => {
302                write!(f, "REPARTITION {operation}")
303            }
304            AlterTableOperation::Partition { partitions } => {
305                write!(f, "{partitions}")
306            }
307            AlterTableOperation::SetIndex { options } => match options {
308                SetIndexOperation::Fulltext {
309                    column_name,
310                    options,
311                } => {
312                    write!(
313                        f,
314                        "MODIFY COLUMN {column_name} SET FULLTEXT INDEX WITH(analyzer={0}, case_sensitive={1}, backend={2})",
315                        options.analyzer, options.case_sensitive, options.backend
316                    )
317                }
318                SetIndexOperation::Inverted { column_name } => {
319                    write!(f, "MODIFY COLUMN {column_name} SET INVERTED INDEX")
320                }
321                SetIndexOperation::Skipping {
322                    column_name,
323                    options,
324                } => {
325                    write!(
326                        f,
327                        "MODIFY COLUMN {column_name} SET SKIPPING INDEX WITH(granularity={0}, index_type={1})",
328                        options.granularity, options.index_type
329                    )
330                }
331            },
332            AlterTableOperation::UnsetIndex { options } => match options {
333                UnsetIndexOperation::Fulltext { column_name } => {
334                    write!(f, "MODIFY COLUMN {column_name} UNSET FULLTEXT INDEX")
335                }
336                UnsetIndexOperation::Inverted { column_name } => {
337                    write!(f, "MODIFY COLUMN {column_name} UNSET INVERTED INDEX")
338                }
339                UnsetIndexOperation::Skipping { column_name } => {
340                    write!(f, "MODIFY COLUMN {column_name} UNSET SKIPPING INDEX")
341                }
342            },
343            AlterTableOperation::DropDefaults { columns } => {
344                let columns = columns
345                    .iter()
346                    .map(|column| format!("MODIFY COLUMN {} DROP DEFAULT", column.0))
347                    .join(", ");
348                write!(f, "{columns}")
349            }
350            AlterTableOperation::SetDefaults { defaults } => {
351                let defaults = defaults
352                    .iter()
353                    .map(|column| {
354                        format!(
355                            "MODIFY COLUMN {} SET DEFAULT {}",
356                            column.column_name, column.default_constraint
357                        )
358                    })
359                    .join(", ");
360                write!(f, "{defaults}")
361            }
362        }
363    }
364}
365
366#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
367pub struct KeyValueOption {
368    pub key: String,
369    pub value: String,
370}
371
372impl From<KeyValueOption> for v1::Option {
373    fn from(c: KeyValueOption) -> Self {
374        v1::Option {
375            key: c.key,
376            value: c.value,
377        }
378    }
379}
380
381#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
382pub struct AlterDatabase {
383    pub database_name: ObjectName,
384    pub alter_operation: AlterDatabaseOperation,
385}
386
387impl AlterDatabase {
388    pub(crate) fn new(database_name: ObjectName, alter_operation: AlterDatabaseOperation) -> Self {
389        Self {
390            database_name,
391            alter_operation,
392        }
393    }
394
395    pub fn database_name(&self) -> &ObjectName {
396        &self.database_name
397    }
398
399    pub fn alter_operation(&self) -> &AlterDatabaseOperation {
400        &self.alter_operation
401    }
402}
403
404impl Display for AlterDatabase {
405    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
406        let database_name = self.database_name();
407        let alter_operation = self.alter_operation();
408        write!(f, r#"ALTER DATABASE {database_name} {alter_operation}"#)
409    }
410}
411
412#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
413pub enum AlterDatabaseOperation {
414    SetDatabaseOption { options: Vec<KeyValueOption> },
415    UnsetDatabaseOption { keys: Vec<String> },
416}
417
418impl Display for AlterDatabaseOperation {
419    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
420        match self {
421            AlterDatabaseOperation::SetDatabaseOption { options } => {
422                let kvs = options
423                    .iter()
424                    .map(|KeyValueOption { key, value }| {
425                        if !value.is_empty() {
426                            format!("'{key}'='{value}'")
427                        } else {
428                            format!("'{key}'=NULL")
429                        }
430                    })
431                    .join(",");
432
433                write!(f, "SET {kvs}")?;
434
435                Ok(())
436            }
437            AlterDatabaseOperation::UnsetDatabaseOption { keys } => {
438                let keys = keys.iter().map(|key| format!("'{key}'")).join(",");
439                write!(f, "UNSET {keys}")?;
440
441                Ok(())
442            }
443        }
444    }
445}
446
447#[cfg(test)]
448mod tests {
449    use std::assert_matches;
450
451    use super::AlterTableOperation;
452    use crate::dialect::GreptimeDbDialect;
453    use crate::parser::{ParseOptions, ParserContext};
454    use crate::statements::create::Json2Options;
455    use crate::statements::statement::Statement;
456
457    #[test]
458    fn test_display_alter() {
459        let sql = r"ALTER DATABASE db SET 'a' = 'b', 'c' = 'd'";
460        let stmts =
461            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
462                .unwrap();
463        assert_eq!(1, stmts.len());
464        assert_matches!(&stmts[0], Statement::AlterDatabase { .. });
465
466        match &stmts[0] {
467            Statement::AlterDatabase(set) => {
468                let new_sql = format!("\n{}", set);
469                assert_eq!(
470                    r#"
471ALTER DATABASE db SET 'a'='b','c'='d'"#,
472                    &new_sql
473                );
474            }
475            _ => {
476                unreachable!();
477            }
478        }
479
480        let sql = r"ALTER DATABASE db UNSET 'a', 'c'";
481        let stmts =
482            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
483                .unwrap();
484        assert_eq!(1, stmts.len());
485
486        match &stmts[0] {
487            Statement::AlterDatabase(set) => {
488                let new_sql = format!("\n{}", set);
489                assert_eq!(
490                    r#"
491ALTER DATABASE db UNSET 'a','c'"#,
492                    &new_sql
493                );
494            }
495            _ => {
496                unreachable!();
497            }
498        }
499
500        let sql =
501            r"alter table monitor add column app string default 'shop' primary key, add foo INT;";
502        let stmts =
503            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
504                .unwrap();
505        assert_eq!(1, stmts.len());
506        assert_matches!(&stmts[0], Statement::AlterTable { .. });
507
508        match &stmts[0] {
509            Statement::AlterTable(set) => {
510                let new_sql = format!("\n{}", set);
511                assert_eq!(
512                    r#"
513ALTER TABLE monitor ADD COLUMN app STRING DEFAULT 'shop' PRIMARY KEY, ADD COLUMN foo INT"#,
514                    &new_sql
515                );
516            }
517            _ => {
518                unreachable!();
519            }
520        }
521
522        let sql = r"alter table monitor modify column load_15 string;";
523        let mut stmts =
524            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
525                .unwrap();
526        assert_eq!(1, stmts.len());
527        assert_matches!(&stmts[0], Statement::AlterTable { .. });
528
529        match &stmts[0] {
530            Statement::AlterTable(set) => {
531                let new_sql = format!("\n{}", set);
532                assert_eq!(
533                    r#"
534ALTER TABLE monitor MODIFY COLUMN load_15 STRING"#,
535                    &new_sql
536                );
537            }
538            _ => {
539                unreachable!();
540            }
541        }
542
543        let Statement::AlterTable(alter_table) = &mut stmts[0] else {
544            unreachable!();
545        };
546        let AlterTableOperation::ModifyColumnType { json2_options, .. } =
547            alter_table.alter_operation_mut()
548        else {
549            unreachable!();
550        };
551        *json2_options = Some(Json2Options {
552            max_auto_expanded_paths: Some(1),
553            type_hints: vec![],
554        });
555        assert_eq!(
556            r#"ALTER TABLE monitor MODIFY COLUMN load_15 STRING(
557    max_auto_expanded_paths = 1
558  )"#,
559            alter_table.to_string()
560        );
561
562        let sql = r"alter table monitor drop column load_15;";
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 DROP COLUMN load_15"#,
575                    &new_sql
576                );
577            }
578            _ => {
579                unreachable!();
580            }
581        }
582
583        let sql = r"alter table monitor rename monitor_new;";
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 RENAME monitor_new"#,
596                    &new_sql
597                );
598            }
599            _ => {
600                unreachable!();
601            }
602        }
603
604        let sql = "ALTER TABLE monitor MODIFY COLUMN a SET FULLTEXT INDEX WITH(analyzer='English',case_sensitive='false',backend='bloom')";
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 FULLTEXT INDEX WITH(analyzer=English, case_sensitive=false, backend=bloom)"#,
617                    &new_sql
618                );
619            }
620            _ => {
621                unreachable!();
622            }
623        }
624
625        let sql = "ALTER TABLE monitor MODIFY COLUMN a UNSET FULLTEXT INDEX";
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 UNSET FULLTEXT INDEX"#,
638                    &new_sql
639                );
640            }
641            _ => {
642                unreachable!();
643            }
644        }
645
646        let sql = "ALTER TABLE monitor MODIFY COLUMN a SET INVERTED INDEX";
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 INVERTED INDEX"#,
659                    &new_sql
660                );
661            }
662            _ => {
663                unreachable!();
664            }
665        }
666
667        let sql = "ALTER TABLE monitor MODIFY COLUMN a DROP DEFAULT";
668        let stmts =
669            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
670                .unwrap();
671        assert_eq!(1, stmts.len());
672        assert_matches!(&stmts[0], Statement::AlterTable { .. });
673
674        match &stmts[0] {
675            Statement::AlterTable(set) => {
676                let new_sql = format!("\n{}", set);
677                assert_eq!(
678                    r#"
679ALTER TABLE monitor MODIFY COLUMN a DROP DEFAULT"#,
680                    &new_sql
681                );
682            }
683            _ => {
684                unreachable!();
685            }
686        }
687
688        let sql = "ALTER TABLE monitor MODIFY COLUMN a SET DEFAULT 'default_for_a'";
689        let stmts =
690            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
691                .unwrap();
692        assert_eq!(1, stmts.len());
693        assert_matches!(&stmts[0], Statement::AlterTable { .. });
694
695        match &stmts[0] {
696            Statement::AlterTable(set) => {
697                let new_sql = format!("\n{}", set);
698                assert_eq!(
699                    r#"
700ALTER TABLE monitor MODIFY COLUMN a SET DEFAULT 'default_for_a'"#,
701                    &new_sql
702                );
703            }
704            _ => {
705                unreachable!();
706            }
707        }
708    }
709}