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