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    /// `REPARTITION (...) INTO (...)`
106    Repartition {
107        operation: RepartitionOperation,
108    },
109}
110
111#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
112/// `ALTER <column_name> DROP DEFAULT`
113pub struct DropDefaultsOperation(pub Ident);
114
115#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
116pub struct SetDefaultsOperation {
117    pub column_name: Ident,
118    pub default_constraint: Expr,
119}
120
121#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
122pub struct RepartitionOperation {
123    pub from_exprs: Vec<Expr>,
124    pub into_exprs: Vec<Expr>,
125}
126
127impl RepartitionOperation {
128    pub fn new(from_exprs: Vec<Expr>, into_exprs: Vec<Expr>) -> Self {
129        Self {
130            from_exprs,
131            into_exprs,
132        }
133    }
134}
135
136impl Display for RepartitionOperation {
137    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
138        let from = self
139            .from_exprs
140            .iter()
141            .map(|expr| expr.to_string())
142            .join(", ");
143        let into = self
144            .into_exprs
145            .iter()
146            .map(|expr| expr.to_string())
147            .join(", ");
148
149        write!(f, "({from}) INTO ({into})")
150    }
151}
152
153#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
154pub enum SetIndexOperation {
155    /// `MODIFY COLUMN <column_name> SET FULLTEXT INDEX [WITH <options>]`
156    Fulltext {
157        column_name: Ident,
158        options: FulltextOptions,
159    },
160    /// `MODIFY COLUMN <column_name> SET INVERTED INDEX`
161    Inverted { column_name: Ident },
162    /// `MODIFY COLUMN <column_name> SET SKIPPING INDEX`
163    Skipping {
164        column_name: Ident,
165        options: SkippingIndexOptions,
166    },
167}
168
169#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
170pub enum UnsetIndexOperation {
171    /// `MODIFY COLUMN <column_name> UNSET FULLTEXT INDEX`
172    Fulltext { column_name: Ident },
173    /// `MODIFY COLUMN <column_name> UNSET INVERTED INDEX`
174    Inverted { column_name: Ident },
175    /// `MODIFY COLUMN <column_name> UNSET SKIPPING INDEX`
176    Skipping { column_name: Ident },
177}
178
179#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
180pub struct AddColumn {
181    pub column_def: ColumnDef,
182    pub location: Option<AddColumnLocation>,
183    pub add_if_not_exists: bool,
184}
185
186impl Display for AddColumn {
187    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
188        if let Some(location) = &self.location {
189            write!(f, "{} {location}", self.column_def)
190        } else {
191            write!(f, "{}", self.column_def)
192        }
193    }
194}
195
196impl Display for AlterTableOperation {
197    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
198        match self {
199            AlterTableOperation::AddConstraint(constraint) => write!(f, r#"ADD {constraint}"#),
200            AlterTableOperation::AddColumns { add_columns } => {
201                let columns = add_columns
202                    .iter()
203                    .map(|add_column| format!("ADD COLUMN {add_column}"))
204                    .join(", ");
205                write!(f, "{columns}")
206            }
207            AlterTableOperation::DropColumn { name } => write!(f, r#"DROP COLUMN {name}"#),
208            AlterTableOperation::RenameTable { new_table_name } => {
209                write!(f, r#"RENAME {new_table_name}"#)
210            }
211            AlterTableOperation::ModifyColumnType {
212                column_name,
213                target_type,
214            } => {
215                write!(f, r#"MODIFY COLUMN {column_name} {target_type}"#)
216            }
217            AlterTableOperation::SetTableOptions { options } => {
218                let kvs = options
219                    .iter()
220                    .map(|KeyValueOption { key, value }| {
221                        if !value.is_empty() {
222                            format!("'{key}'='{value}'")
223                        } else {
224                            format!("'{key}'=NULL")
225                        }
226                    })
227                    .join(",");
228
229                write!(f, "SET {kvs}")
230            }
231            AlterTableOperation::UnsetTableOptions { keys } => {
232                let keys = keys.iter().map(|k| format!("'{k}'")).join(",");
233                write!(f, "UNSET {keys}")
234            }
235            AlterTableOperation::Repartition { operation } => {
236                write!(f, "REPARTITION {operation}")
237            }
238            AlterTableOperation::SetIndex { options } => match options {
239                SetIndexOperation::Fulltext {
240                    column_name,
241                    options,
242                } => {
243                    write!(
244                        f,
245                        "MODIFY COLUMN {column_name} SET FULLTEXT INDEX WITH(analyzer={0}, case_sensitive={1}, backend={2})",
246                        options.analyzer, options.case_sensitive, options.backend
247                    )
248                }
249                SetIndexOperation::Inverted { column_name } => {
250                    write!(f, "MODIFY COLUMN {column_name} SET INVERTED INDEX")
251                }
252                SetIndexOperation::Skipping {
253                    column_name,
254                    options,
255                } => {
256                    write!(
257                        f,
258                        "MODIFY COLUMN {column_name} SET SKIPPING INDEX WITH(granularity={0}, index_type={1})",
259                        options.granularity, options.index_type
260                    )
261                }
262            },
263            AlterTableOperation::UnsetIndex { options } => match options {
264                UnsetIndexOperation::Fulltext { column_name } => {
265                    write!(f, "MODIFY COLUMN {column_name} UNSET FULLTEXT INDEX")
266                }
267                UnsetIndexOperation::Inverted { column_name } => {
268                    write!(f, "MODIFY COLUMN {column_name} UNSET INVERTED INDEX")
269                }
270                UnsetIndexOperation::Skipping { column_name } => {
271                    write!(f, "MODIFY COLUMN {column_name} UNSET SKIPPING INDEX")
272                }
273            },
274            AlterTableOperation::DropDefaults { columns } => {
275                let columns = columns
276                    .iter()
277                    .map(|column| format!("MODIFY COLUMN {} DROP DEFAULT", column.0))
278                    .join(", ");
279                write!(f, "{columns}")
280            }
281            AlterTableOperation::SetDefaults { defaults } => {
282                let defaults = defaults
283                    .iter()
284                    .map(|column| {
285                        format!(
286                            "MODIFY COLUMN {} SET DEFAULT {}",
287                            column.column_name, column.default_constraint
288                        )
289                    })
290                    .join(", ");
291                write!(f, "{defaults}")
292            }
293        }
294    }
295}
296
297#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
298pub struct KeyValueOption {
299    pub key: String,
300    pub value: String,
301}
302
303impl From<KeyValueOption> for v1::Option {
304    fn from(c: KeyValueOption) -> Self {
305        v1::Option {
306            key: c.key,
307            value: c.value,
308        }
309    }
310}
311
312#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
313pub struct AlterDatabase {
314    pub database_name: ObjectName,
315    pub alter_operation: AlterDatabaseOperation,
316}
317
318impl AlterDatabase {
319    pub(crate) fn new(database_name: ObjectName, alter_operation: AlterDatabaseOperation) -> Self {
320        Self {
321            database_name,
322            alter_operation,
323        }
324    }
325
326    pub fn database_name(&self) -> &ObjectName {
327        &self.database_name
328    }
329
330    pub fn alter_operation(&self) -> &AlterDatabaseOperation {
331        &self.alter_operation
332    }
333}
334
335impl Display for AlterDatabase {
336    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
337        let database_name = self.database_name();
338        let alter_operation = self.alter_operation();
339        write!(f, r#"ALTER DATABASE {database_name} {alter_operation}"#)
340    }
341}
342
343#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
344pub enum AlterDatabaseOperation {
345    SetDatabaseOption { options: Vec<KeyValueOption> },
346    UnsetDatabaseOption { keys: Vec<String> },
347}
348
349impl Display for AlterDatabaseOperation {
350    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
351        match self {
352            AlterDatabaseOperation::SetDatabaseOption { options } => {
353                let kvs = options
354                    .iter()
355                    .map(|KeyValueOption { key, value }| {
356                        if !value.is_empty() {
357                            format!("'{key}'='{value}'")
358                        } else {
359                            format!("'{key}'=NULL")
360                        }
361                    })
362                    .join(",");
363
364                write!(f, "SET {kvs}")?;
365
366                Ok(())
367            }
368            AlterDatabaseOperation::UnsetDatabaseOption { keys } => {
369                let keys = keys.iter().map(|key| format!("'{key}'")).join(",");
370                write!(f, "UNSET {keys}")?;
371
372                Ok(())
373            }
374        }
375    }
376}
377
378#[cfg(test)]
379mod tests {
380    use std::assert_matches::assert_matches;
381
382    use crate::dialect::GreptimeDbDialect;
383    use crate::parser::{ParseOptions, ParserContext};
384    use crate::statements::statement::Statement;
385
386    #[test]
387    fn test_display_alter() {
388        let sql = r"ALTER DATABASE db SET 'a' = 'b', 'c' = 'd'";
389        let stmts =
390            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
391                .unwrap();
392        assert_eq!(1, stmts.len());
393        assert_matches!(&stmts[0], Statement::AlterDatabase { .. });
394
395        match &stmts[0] {
396            Statement::AlterDatabase(set) => {
397                let new_sql = format!("\n{}", set);
398                assert_eq!(
399                    r#"
400ALTER DATABASE db SET 'a'='b','c'='d'"#,
401                    &new_sql
402                );
403            }
404            _ => {
405                unreachable!();
406            }
407        }
408
409        let sql = r"ALTER DATABASE db UNSET 'a', 'c'";
410        let stmts =
411            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
412                .unwrap();
413        assert_eq!(1, stmts.len());
414
415        match &stmts[0] {
416            Statement::AlterDatabase(set) => {
417                let new_sql = format!("\n{}", set);
418                assert_eq!(
419                    r#"
420ALTER DATABASE db UNSET 'a','c'"#,
421                    &new_sql
422                );
423            }
424            _ => {
425                unreachable!();
426            }
427        }
428
429        let sql =
430            r"alter table monitor add column app string default 'shop' primary key, add foo INT;";
431        let stmts =
432            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
433                .unwrap();
434        assert_eq!(1, stmts.len());
435        assert_matches!(&stmts[0], Statement::AlterTable { .. });
436
437        match &stmts[0] {
438            Statement::AlterTable(set) => {
439                let new_sql = format!("\n{}", set);
440                assert_eq!(
441                    r#"
442ALTER TABLE monitor ADD COLUMN app STRING DEFAULT 'shop' PRIMARY KEY, ADD COLUMN foo INT"#,
443                    &new_sql
444                );
445            }
446            _ => {
447                unreachable!();
448            }
449        }
450
451        let sql = r"alter table monitor modify column load_15 string;";
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 MODIFY COLUMN load_15 STRING"#,
464                    &new_sql
465                );
466            }
467            _ => {
468                unreachable!();
469            }
470        }
471
472        let sql = r"alter table monitor drop column load_15;";
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 DROP COLUMN load_15"#,
485                    &new_sql
486                );
487            }
488            _ => {
489                unreachable!();
490            }
491        }
492
493        let sql = r"alter table monitor rename monitor_new;";
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 RENAME monitor_new"#,
506                    &new_sql
507                );
508            }
509            _ => {
510                unreachable!();
511            }
512        }
513
514        let sql = "ALTER TABLE monitor MODIFY COLUMN a SET FULLTEXT INDEX WITH(analyzer='English',case_sensitive='false',backend='bloom')";
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 MODIFY COLUMN a SET FULLTEXT INDEX WITH(analyzer=English, case_sensitive=false, backend=bloom)"#,
527                    &new_sql
528                );
529            }
530            _ => {
531                unreachable!();
532            }
533        }
534
535        let sql = "ALTER TABLE monitor MODIFY COLUMN a UNSET FULLTEXT INDEX";
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 UNSET FULLTEXT INDEX"#,
548                    &new_sql
549                );
550            }
551            _ => {
552                unreachable!();
553            }
554        }
555
556        let sql = "ALTER TABLE monitor MODIFY COLUMN a SET INVERTED 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 SET INVERTED INDEX"#,
569                    &new_sql
570                );
571            }
572            _ => {
573                unreachable!();
574            }
575        }
576
577        let sql = "ALTER TABLE monitor MODIFY COLUMN a DROP DEFAULT";
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 DROP DEFAULT"#,
590                    &new_sql
591                );
592            }
593            _ => {
594                unreachable!();
595            }
596        }
597
598        let sql = "ALTER TABLE monitor MODIFY COLUMN a SET DEFAULT 'default_for_a'";
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 SET DEFAULT 'default_for_a'"#,
611                    &new_sql
612                );
613            }
614            _ => {
615                unreachable!();
616            }
617        }
618    }
619}