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