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!(f, "MODIFY COLUMN {column_name} SET FULLTEXT INDEX WITH(analyzer={0}, case_sensitive={1}, backend={2})", options.analyzer, options.case_sensitive, options.backend)
205                }
206                SetIndexOperation::Inverted { column_name } => {
207                    write!(f, "MODIFY COLUMN {column_name} SET INVERTED INDEX")
208                }
209                SetIndexOperation::Skipping {
210                    column_name,
211                    options,
212                } => {
213                    write!(f, "MODIFY COLUMN {column_name} SET SKIPPING INDEX WITH(granularity={0}, index_type={1})", options.granularity, options.index_type)
214                }
215            },
216            AlterTableOperation::UnsetIndex { options } => match options {
217                UnsetIndexOperation::Fulltext { column_name } => {
218                    write!(f, "MODIFY COLUMN {column_name} UNSET FULLTEXT INDEX")
219                }
220                UnsetIndexOperation::Inverted { column_name } => {
221                    write!(f, "MODIFY COLUMN {column_name} UNSET INVERTED INDEX")
222                }
223                UnsetIndexOperation::Skipping { column_name } => {
224                    write!(f, "MODIFY COLUMN {column_name} UNSET SKIPPING INDEX")
225                }
226            },
227            AlterTableOperation::DropDefaults { columns } => {
228                let columns = columns
229                    .iter()
230                    .map(|column| format!("MODIFY COLUMN {} DROP DEFAULT", column.0))
231                    .join(", ");
232                write!(f, "{columns}")
233            }
234            AlterTableOperation::SetDefaults { defaults } => {
235                let defaults = defaults
236                    .iter()
237                    .map(|column| {
238                        format!(
239                            "MODIFY COLUMN {} SET DEFAULT {}",
240                            column.column_name, column.default_constraint
241                        )
242                    })
243                    .join(", ");
244                write!(f, "{defaults}")
245            }
246        }
247    }
248}
249
250#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
251pub struct KeyValueOption {
252    pub key: String,
253    pub value: String,
254}
255
256impl From<KeyValueOption> for v1::Option {
257    fn from(c: KeyValueOption) -> Self {
258        v1::Option {
259            key: c.key,
260            value: c.value,
261        }
262    }
263}
264
265#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
266pub struct AlterDatabase {
267    pub database_name: ObjectName,
268    pub alter_operation: AlterDatabaseOperation,
269}
270
271impl AlterDatabase {
272    pub(crate) fn new(database_name: ObjectName, alter_operation: AlterDatabaseOperation) -> Self {
273        Self {
274            database_name,
275            alter_operation,
276        }
277    }
278
279    pub fn database_name(&self) -> &ObjectName {
280        &self.database_name
281    }
282
283    pub fn alter_operation(&self) -> &AlterDatabaseOperation {
284        &self.alter_operation
285    }
286}
287
288impl Display for AlterDatabase {
289    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
290        let database_name = self.database_name();
291        let alter_operation = self.alter_operation();
292        write!(f, r#"ALTER DATABASE {database_name} {alter_operation}"#)
293    }
294}
295
296#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
297pub enum AlterDatabaseOperation {
298    SetDatabaseOption { options: Vec<KeyValueOption> },
299    UnsetDatabaseOption { keys: Vec<String> },
300}
301
302impl Display for AlterDatabaseOperation {
303    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
304        match self {
305            AlterDatabaseOperation::SetDatabaseOption { options } => {
306                let kvs = options
307                    .iter()
308                    .map(|KeyValueOption { key, value }| {
309                        if !value.is_empty() {
310                            format!("'{key}'='{value}'")
311                        } else {
312                            format!("'{key}'=NULL")
313                        }
314                    })
315                    .join(",");
316
317                write!(f, "SET {kvs}")?;
318
319                Ok(())
320            }
321            AlterDatabaseOperation::UnsetDatabaseOption { keys } => {
322                let keys = keys.iter().map(|key| format!("'{key}'")).join(",");
323                write!(f, "UNSET {keys}")?;
324
325                Ok(())
326            }
327        }
328    }
329}
330
331#[cfg(test)]
332mod tests {
333    use std::assert_matches::assert_matches;
334
335    use crate::dialect::GreptimeDbDialect;
336    use crate::parser::{ParseOptions, ParserContext};
337    use crate::statements::statement::Statement;
338
339    #[test]
340    fn test_display_alter() {
341        let sql = r"ALTER DATABASE db SET 'a' = 'b', 'c' = 'd'";
342        let stmts =
343            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
344                .unwrap();
345        assert_eq!(1, stmts.len());
346        assert_matches!(&stmts[0], Statement::AlterDatabase { .. });
347
348        match &stmts[0] {
349            Statement::AlterDatabase(set) => {
350                let new_sql = format!("\n{}", set);
351                assert_eq!(
352                    r#"
353ALTER DATABASE db SET 'a'='b','c'='d'"#,
354                    &new_sql
355                );
356            }
357            _ => {
358                unreachable!();
359            }
360        }
361
362        let sql = r"ALTER DATABASE db UNSET 'a', 'c'";
363        let stmts =
364            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
365                .unwrap();
366        assert_eq!(1, stmts.len());
367
368        match &stmts[0] {
369            Statement::AlterDatabase(set) => {
370                let new_sql = format!("\n{}", set);
371                assert_eq!(
372                    r#"
373ALTER DATABASE db UNSET 'a','c'"#,
374                    &new_sql
375                );
376            }
377            _ => {
378                unreachable!();
379            }
380        }
381
382        let sql =
383            r"alter table monitor add column app string default 'shop' primary key, add foo INT;";
384        let stmts =
385            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
386                .unwrap();
387        assert_eq!(1, stmts.len());
388        assert_matches!(&stmts[0], Statement::AlterTable { .. });
389
390        match &stmts[0] {
391            Statement::AlterTable(set) => {
392                let new_sql = format!("\n{}", set);
393                assert_eq!(
394                    r#"
395ALTER TABLE monitor ADD COLUMN app STRING DEFAULT 'shop' PRIMARY KEY, ADD COLUMN foo INT"#,
396                    &new_sql
397                );
398            }
399            _ => {
400                unreachable!();
401            }
402        }
403
404        let sql = r"alter table monitor modify column load_15 string;";
405        let stmts =
406            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
407                .unwrap();
408        assert_eq!(1, stmts.len());
409        assert_matches!(&stmts[0], Statement::AlterTable { .. });
410
411        match &stmts[0] {
412            Statement::AlterTable(set) => {
413                let new_sql = format!("\n{}", set);
414                assert_eq!(
415                    r#"
416ALTER TABLE monitor MODIFY COLUMN load_15 STRING"#,
417                    &new_sql
418                );
419            }
420            _ => {
421                unreachable!();
422            }
423        }
424
425        let sql = r"alter table monitor drop column load_15;";
426        let stmts =
427            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
428                .unwrap();
429        assert_eq!(1, stmts.len());
430        assert_matches!(&stmts[0], Statement::AlterTable { .. });
431
432        match &stmts[0] {
433            Statement::AlterTable(set) => {
434                let new_sql = format!("\n{}", set);
435                assert_eq!(
436                    r#"
437ALTER TABLE monitor DROP COLUMN load_15"#,
438                    &new_sql
439                );
440            }
441            _ => {
442                unreachable!();
443            }
444        }
445
446        let sql = r"alter table monitor rename monitor_new;";
447        let stmts =
448            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
449                .unwrap();
450        assert_eq!(1, stmts.len());
451        assert_matches!(&stmts[0], Statement::AlterTable { .. });
452
453        match &stmts[0] {
454            Statement::AlterTable(set) => {
455                let new_sql = format!("\n{}", set);
456                assert_eq!(
457                    r#"
458ALTER TABLE monitor RENAME monitor_new"#,
459                    &new_sql
460                );
461            }
462            _ => {
463                unreachable!();
464            }
465        }
466
467        let sql = "ALTER TABLE monitor MODIFY COLUMN a SET FULLTEXT INDEX WITH(analyzer='English',case_sensitive='false',backend='bloom')";
468        let stmts =
469            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
470                .unwrap();
471        assert_eq!(1, stmts.len());
472        assert_matches!(&stmts[0], Statement::AlterTable { .. });
473
474        match &stmts[0] {
475            Statement::AlterTable(set) => {
476                let new_sql = format!("\n{}", set);
477                assert_eq!(
478                    r#"
479ALTER TABLE monitor MODIFY COLUMN a SET FULLTEXT INDEX WITH(analyzer=English, case_sensitive=false, backend=bloom)"#,
480                    &new_sql
481                );
482            }
483            _ => {
484                unreachable!();
485            }
486        }
487
488        let sql = "ALTER TABLE monitor MODIFY COLUMN a UNSET FULLTEXT INDEX";
489        let stmts =
490            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
491                .unwrap();
492        assert_eq!(1, stmts.len());
493        assert_matches!(&stmts[0], Statement::AlterTable { .. });
494
495        match &stmts[0] {
496            Statement::AlterTable(set) => {
497                let new_sql = format!("\n{}", set);
498                assert_eq!(
499                    r#"
500ALTER TABLE monitor MODIFY COLUMN a UNSET FULLTEXT INDEX"#,
501                    &new_sql
502                );
503            }
504            _ => {
505                unreachable!();
506            }
507        }
508
509        let sql = "ALTER TABLE monitor MODIFY COLUMN a SET INVERTED INDEX";
510        let stmts =
511            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
512                .unwrap();
513        assert_eq!(1, stmts.len());
514        assert_matches!(&stmts[0], Statement::AlterTable { .. });
515
516        match &stmts[0] {
517            Statement::AlterTable(set) => {
518                let new_sql = format!("\n{}", set);
519                assert_eq!(
520                    r#"
521ALTER TABLE monitor MODIFY COLUMN a SET INVERTED INDEX"#,
522                    &new_sql
523                );
524            }
525            _ => {
526                unreachable!();
527            }
528        }
529
530        let sql = "ALTER TABLE monitor MODIFY COLUMN a DROP DEFAULT";
531        let stmts =
532            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
533                .unwrap();
534        assert_eq!(1, stmts.len());
535        assert_matches!(&stmts[0], Statement::AlterTable { .. });
536
537        match &stmts[0] {
538            Statement::AlterTable(set) => {
539                let new_sql = format!("\n{}", set);
540                assert_eq!(
541                    r#"
542ALTER TABLE monitor MODIFY COLUMN a DROP DEFAULT"#,
543                    &new_sql
544                );
545            }
546            _ => {
547                unreachable!();
548            }
549        }
550
551        let sql = "ALTER TABLE monitor MODIFY COLUMN a SET DEFAULT 'default_for_a'";
552        let stmts =
553            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
554                .unwrap();
555        assert_eq!(1, stmts.len());
556        assert_matches!(&stmts[0], Statement::AlterTable { .. });
557
558        match &stmts[0] {
559            Statement::AlterTable(set) => {
560                let new_sql = format!("\n{}", set);
561                assert_eq!(
562                    r#"
563ALTER TABLE monitor MODIFY COLUMN a SET DEFAULT 'default_for_a'"#,
564                    &new_sql
565                );
566            }
567            _ => {
568                unreachable!();
569            }
570        }
571    }
572}