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
28#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
29pub struct AlterTable {
30    pub table_name: ObjectName,
31    pub alter_operation: AlterTableOperation,
32}
33
34impl AlterTable {
35    pub(crate) fn new(table_name: ObjectName, alter_operation: AlterTableOperation) -> Self {
36        Self {
37            table_name,
38            alter_operation,
39        }
40    }
41
42    pub fn table_name(&self) -> &ObjectName {
43        &self.table_name
44    }
45
46    pub fn alter_operation(&self) -> &AlterTableOperation {
47        &self.alter_operation
48    }
49
50    pub fn alter_operation_mut(&mut self) -> &mut AlterTableOperation {
51        &mut self.alter_operation
52    }
53}
54
55impl Display for AlterTable {
56    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57        let table_name = self.table_name();
58        let alter_operation = self.alter_operation();
59        write!(f, r#"ALTER TABLE {table_name} {alter_operation}"#)
60    }
61}
62
63#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
64pub enum AlterTableOperation {
65    /// `ADD <table_constraint>`
66    AddConstraint(TableConstraint),
67    /// `ADD [ COLUMN ] <column_def> [location]`
68    AddColumns {
69        add_columns: Vec<AddColumn>,
70    },
71    /// `MODIFY <column_name> [target_type]`
72    ModifyColumnType {
73        column_name: Ident,
74        target_type: DataType,
75    },
76    /// `SET <table attrs key> = <table attr value>`
77    SetTableOptions {
78        options: Vec<KeyValueOption>,
79    },
80    /// `UNSET <table attrs key>`
81    UnsetTableOptions {
82        keys: Vec<String>,
83    },
84    /// `DROP COLUMN <name>`
85    DropColumn {
86        name: Ident,
87    },
88    /// `RENAME <new_table_name>`
89    RenameTable {
90        new_table_name: String,
91    },
92    SetIndex {
93        options: SetIndexOperation,
94    },
95    UnsetIndex {
96        options: UnsetIndexOperation,
97    },
98    DropDefaults {
99        columns: Vec<DropDefaultsOperation>,
100    },
101    /// `ALTER <column_name> SET DEFAULT <default_value>`
102    SetDefaults {
103        defaults: Vec<SetDefaultsOperation>,
104    },
105}
106
107#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
108/// `ALTER <column_name> DROP DEFAULT`
109pub struct DropDefaultsOperation(pub Ident);
110
111#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
112pub struct SetDefaultsOperation {
113    pub column_name: Ident,
114    pub default_constraint: Expr,
115}
116
117#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
118pub enum SetIndexOperation {
119    /// `MODIFY COLUMN <column_name> SET FULLTEXT INDEX [WITH <options>]`
120    Fulltext {
121        column_name: Ident,
122        options: FulltextOptions,
123    },
124    /// `MODIFY COLUMN <column_name> SET INVERTED INDEX`
125    Inverted { column_name: Ident },
126    /// `MODIFY COLUMN <column_name> SET SKIPPING INDEX`
127    Skipping {
128        column_name: Ident,
129        options: SkippingIndexOptions,
130    },
131}
132
133#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
134pub enum UnsetIndexOperation {
135    /// `MODIFY COLUMN <column_name> UNSET FULLTEXT INDEX`
136    Fulltext { column_name: Ident },
137    /// `MODIFY COLUMN <column_name> UNSET INVERTED INDEX`
138    Inverted { column_name: Ident },
139    /// `MODIFY COLUMN <column_name> UNSET SKIPPING INDEX`
140    Skipping { column_name: Ident },
141}
142
143#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
144pub struct AddColumn {
145    pub column_def: ColumnDef,
146    pub location: Option<AddColumnLocation>,
147    pub add_if_not_exists: bool,
148}
149
150impl Display for AddColumn {
151    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
152        if let Some(location) = &self.location {
153            write!(f, "{} {location}", self.column_def)
154        } else {
155            write!(f, "{}", self.column_def)
156        }
157    }
158}
159
160impl Display for AlterTableOperation {
161    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
162        match self {
163            AlterTableOperation::AddConstraint(constraint) => write!(f, r#"ADD {constraint}"#),
164            AlterTableOperation::AddColumns { add_columns } => {
165                let columns = add_columns
166                    .iter()
167                    .map(|add_column| format!("ADD COLUMN {add_column}"))
168                    .join(", ");
169                write!(f, "{columns}")
170            }
171            AlterTableOperation::DropColumn { name } => write!(f, r#"DROP COLUMN {name}"#),
172            AlterTableOperation::RenameTable { new_table_name } => {
173                write!(f, r#"RENAME {new_table_name}"#)
174            }
175            AlterTableOperation::ModifyColumnType {
176                column_name,
177                target_type,
178            } => {
179                write!(f, r#"MODIFY COLUMN {column_name} {target_type}"#)
180            }
181            AlterTableOperation::SetTableOptions { options } => {
182                let kvs = options
183                    .iter()
184                    .map(|KeyValueOption { key, value }| {
185                        if !value.is_empty() {
186                            format!("'{key}'='{value}'")
187                        } else {
188                            format!("'{key}'=NULL")
189                        }
190                    })
191                    .join(",");
192
193                write!(f, "SET {kvs}")
194            }
195            AlterTableOperation::UnsetTableOptions { keys } => {
196                let keys = keys.iter().map(|k| format!("'{k}'")).join(",");
197                write!(f, "UNSET {keys}")
198            }
199            AlterTableOperation::SetIndex { options } => match options {
200                SetIndexOperation::Fulltext {
201                    column_name,
202                    options,
203                } => {
204                    write!(
205                        f,
206                        "MODIFY COLUMN {column_name} SET FULLTEXT INDEX WITH(analyzer={0}, case_sensitive={1}, backend={2})",
207                        options.analyzer, options.case_sensitive, options.backend
208                    )
209                }
210                SetIndexOperation::Inverted { column_name } => {
211                    write!(f, "MODIFY COLUMN {column_name} SET INVERTED INDEX")
212                }
213                SetIndexOperation::Skipping {
214                    column_name,
215                    options,
216                } => {
217                    write!(
218                        f,
219                        "MODIFY COLUMN {column_name} SET SKIPPING INDEX WITH(granularity={0}, index_type={1})",
220                        options.granularity, options.index_type
221                    )
222                }
223            },
224            AlterTableOperation::UnsetIndex { options } => match options {
225                UnsetIndexOperation::Fulltext { column_name } => {
226                    write!(f, "MODIFY COLUMN {column_name} UNSET FULLTEXT INDEX")
227                }
228                UnsetIndexOperation::Inverted { column_name } => {
229                    write!(f, "MODIFY COLUMN {column_name} UNSET INVERTED INDEX")
230                }
231                UnsetIndexOperation::Skipping { column_name } => {
232                    write!(f, "MODIFY COLUMN {column_name} UNSET SKIPPING INDEX")
233                }
234            },
235            AlterTableOperation::DropDefaults { columns } => {
236                let columns = columns
237                    .iter()
238                    .map(|column| format!("MODIFY COLUMN {} DROP DEFAULT", column.0))
239                    .join(", ");
240                write!(f, "{columns}")
241            }
242            AlterTableOperation::SetDefaults { defaults } => {
243                let defaults = defaults
244                    .iter()
245                    .map(|column| {
246                        format!(
247                            "MODIFY COLUMN {} SET DEFAULT {}",
248                            column.column_name, column.default_constraint
249                        )
250                    })
251                    .join(", ");
252                write!(f, "{defaults}")
253            }
254        }
255    }
256}
257
258#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
259pub struct KeyValueOption {
260    pub key: String,
261    pub value: String,
262}
263
264impl From<KeyValueOption> for v1::Option {
265    fn from(c: KeyValueOption) -> Self {
266        v1::Option {
267            key: c.key,
268            value: c.value,
269        }
270    }
271}
272
273#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
274pub struct AlterDatabase {
275    pub database_name: ObjectName,
276    pub alter_operation: AlterDatabaseOperation,
277}
278
279impl AlterDatabase {
280    pub(crate) fn new(database_name: ObjectName, alter_operation: AlterDatabaseOperation) -> Self {
281        Self {
282            database_name,
283            alter_operation,
284        }
285    }
286
287    pub fn database_name(&self) -> &ObjectName {
288        &self.database_name
289    }
290
291    pub fn alter_operation(&self) -> &AlterDatabaseOperation {
292        &self.alter_operation
293    }
294}
295
296impl Display for AlterDatabase {
297    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
298        let database_name = self.database_name();
299        let alter_operation = self.alter_operation();
300        write!(f, r#"ALTER DATABASE {database_name} {alter_operation}"#)
301    }
302}
303
304#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
305pub enum AlterDatabaseOperation {
306    SetDatabaseOption { options: Vec<KeyValueOption> },
307    UnsetDatabaseOption { keys: Vec<String> },
308}
309
310impl Display for AlterDatabaseOperation {
311    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
312        match self {
313            AlterDatabaseOperation::SetDatabaseOption { options } => {
314                let kvs = options
315                    .iter()
316                    .map(|KeyValueOption { key, value }| {
317                        if !value.is_empty() {
318                            format!("'{key}'='{value}'")
319                        } else {
320                            format!("'{key}'=NULL")
321                        }
322                    })
323                    .join(",");
324
325                write!(f, "SET {kvs}")?;
326
327                Ok(())
328            }
329            AlterDatabaseOperation::UnsetDatabaseOption { keys } => {
330                let keys = keys.iter().map(|key| format!("'{key}'")).join(",");
331                write!(f, "UNSET {keys}")?;
332
333                Ok(())
334            }
335        }
336    }
337}
338
339#[cfg(test)]
340mod tests {
341    use std::assert_matches::assert_matches;
342
343    use crate::dialect::GreptimeDbDialect;
344    use crate::parser::{ParseOptions, ParserContext};
345    use crate::statements::statement::Statement;
346
347    #[test]
348    fn test_display_alter() {
349        let sql = r"ALTER DATABASE db SET 'a' = 'b', 'c' = 'd'";
350        let stmts =
351            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
352                .unwrap();
353        assert_eq!(1, stmts.len());
354        assert_matches!(&stmts[0], Statement::AlterDatabase { .. });
355
356        match &stmts[0] {
357            Statement::AlterDatabase(set) => {
358                let new_sql = format!("\n{}", set);
359                assert_eq!(
360                    r#"
361ALTER DATABASE db SET 'a'='b','c'='d'"#,
362                    &new_sql
363                );
364            }
365            _ => {
366                unreachable!();
367            }
368        }
369
370        let sql = r"ALTER DATABASE db UNSET 'a', 'c'";
371        let stmts =
372            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
373                .unwrap();
374        assert_eq!(1, stmts.len());
375
376        match &stmts[0] {
377            Statement::AlterDatabase(set) => {
378                let new_sql = format!("\n{}", set);
379                assert_eq!(
380                    r#"
381ALTER DATABASE db UNSET 'a','c'"#,
382                    &new_sql
383                );
384            }
385            _ => {
386                unreachable!();
387            }
388        }
389
390        let sql =
391            r"alter table monitor add column app string default 'shop' primary key, add foo INT;";
392        let stmts =
393            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
394                .unwrap();
395        assert_eq!(1, stmts.len());
396        assert_matches!(&stmts[0], Statement::AlterTable { .. });
397
398        match &stmts[0] {
399            Statement::AlterTable(set) => {
400                let new_sql = format!("\n{}", set);
401                assert_eq!(
402                    r#"
403ALTER TABLE monitor ADD COLUMN app STRING DEFAULT 'shop' PRIMARY KEY, ADD COLUMN foo INT"#,
404                    &new_sql
405                );
406            }
407            _ => {
408                unreachable!();
409            }
410        }
411
412        let sql = r"alter table monitor modify column load_15 string;";
413        let stmts =
414            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
415                .unwrap();
416        assert_eq!(1, stmts.len());
417        assert_matches!(&stmts[0], Statement::AlterTable { .. });
418
419        match &stmts[0] {
420            Statement::AlterTable(set) => {
421                let new_sql = format!("\n{}", set);
422                assert_eq!(
423                    r#"
424ALTER TABLE monitor MODIFY COLUMN load_15 STRING"#,
425                    &new_sql
426                );
427            }
428            _ => {
429                unreachable!();
430            }
431        }
432
433        let sql = r"alter table monitor drop column load_15;";
434        let stmts =
435            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
436                .unwrap();
437        assert_eq!(1, stmts.len());
438        assert_matches!(&stmts[0], Statement::AlterTable { .. });
439
440        match &stmts[0] {
441            Statement::AlterTable(set) => {
442                let new_sql = format!("\n{}", set);
443                assert_eq!(
444                    r#"
445ALTER TABLE monitor DROP COLUMN load_15"#,
446                    &new_sql
447                );
448            }
449            _ => {
450                unreachable!();
451            }
452        }
453
454        let sql = r"alter table monitor rename monitor_new;";
455        let stmts =
456            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
457                .unwrap();
458        assert_eq!(1, stmts.len());
459        assert_matches!(&stmts[0], Statement::AlterTable { .. });
460
461        match &stmts[0] {
462            Statement::AlterTable(set) => {
463                let new_sql = format!("\n{}", set);
464                assert_eq!(
465                    r#"
466ALTER TABLE monitor RENAME monitor_new"#,
467                    &new_sql
468                );
469            }
470            _ => {
471                unreachable!();
472            }
473        }
474
475        let sql = "ALTER TABLE monitor MODIFY COLUMN a SET FULLTEXT INDEX WITH(analyzer='English',case_sensitive='false',backend='bloom')";
476        let stmts =
477            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
478                .unwrap();
479        assert_eq!(1, stmts.len());
480        assert_matches!(&stmts[0], Statement::AlterTable { .. });
481
482        match &stmts[0] {
483            Statement::AlterTable(set) => {
484                let new_sql = format!("\n{}", set);
485                assert_eq!(
486                    r#"
487ALTER TABLE monitor MODIFY COLUMN a SET FULLTEXT INDEX WITH(analyzer=English, case_sensitive=false, backend=bloom)"#,
488                    &new_sql
489                );
490            }
491            _ => {
492                unreachable!();
493            }
494        }
495
496        let sql = "ALTER TABLE monitor MODIFY COLUMN a UNSET FULLTEXT INDEX";
497        let stmts =
498            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
499                .unwrap();
500        assert_eq!(1, stmts.len());
501        assert_matches!(&stmts[0], Statement::AlterTable { .. });
502
503        match &stmts[0] {
504            Statement::AlterTable(set) => {
505                let new_sql = format!("\n{}", set);
506                assert_eq!(
507                    r#"
508ALTER TABLE monitor MODIFY COLUMN a UNSET FULLTEXT INDEX"#,
509                    &new_sql
510                );
511            }
512            _ => {
513                unreachable!();
514            }
515        }
516
517        let sql = "ALTER TABLE monitor MODIFY COLUMN a SET INVERTED INDEX";
518        let stmts =
519            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
520                .unwrap();
521        assert_eq!(1, stmts.len());
522        assert_matches!(&stmts[0], Statement::AlterTable { .. });
523
524        match &stmts[0] {
525            Statement::AlterTable(set) => {
526                let new_sql = format!("\n{}", set);
527                assert_eq!(
528                    r#"
529ALTER TABLE monitor MODIFY COLUMN a SET INVERTED INDEX"#,
530                    &new_sql
531                );
532            }
533            _ => {
534                unreachable!();
535            }
536        }
537
538        let sql = "ALTER TABLE monitor MODIFY COLUMN a DROP DEFAULT";
539        let stmts =
540            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
541                .unwrap();
542        assert_eq!(1, stmts.len());
543        assert_matches!(&stmts[0], Statement::AlterTable { .. });
544
545        match &stmts[0] {
546            Statement::AlterTable(set) => {
547                let new_sql = format!("\n{}", set);
548                assert_eq!(
549                    r#"
550ALTER TABLE monitor MODIFY COLUMN a DROP DEFAULT"#,
551                    &new_sql
552                );
553            }
554            _ => {
555                unreachable!();
556            }
557        }
558
559        let sql = "ALTER TABLE monitor MODIFY COLUMN a SET DEFAULT 'default_for_a'";
560        let stmts =
561            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
562                .unwrap();
563        assert_eq!(1, stmts.len());
564        assert_matches!(&stmts[0], Statement::AlterTable { .. });
565
566        match &stmts[0] {
567            Statement::AlterTable(set) => {
568                let new_sql = format!("\n{}", set);
569                assert_eq!(
570                    r#"
571ALTER TABLE monitor MODIFY COLUMN a SET DEFAULT 'default_for_a'"#,
572                    &new_sql
573                );
574            }
575            _ => {
576                unreachable!();
577            }
578        }
579    }
580}