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