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