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