1#[cfg(feature = "enterprise")]
16pub mod trigger;
17
18use std::collections::HashMap;
19
20use common_query::AddColumnLocation;
21use datatypes::schema::COLUMN_FULLTEXT_CHANGE_OPT_KEY_ENABLE;
22use snafu::{ResultExt, ensure};
23use sqlparser::ast::Ident;
24use sqlparser::keywords::Keyword;
25use sqlparser::parser::{Parser, ParserError};
26use sqlparser::tokenizer::{Token, TokenWithSpan};
27
28use crate::ast::ObjectNamePartExt;
29use crate::error::{self, InvalidColumnOptionSnafu, Result, SetFulltextOptionSnafu};
30use crate::parser::ParserContext;
31use crate::parsers::create_parser::INVERTED;
32use crate::parsers::utils::{
33 validate_column_fulltext_create_option, validate_column_skipping_index_create_option,
34};
35use crate::statements::alter::{
36 AddColumn, AlterDatabase, AlterDatabaseOperation, AlterTable, AlterTableOperation,
37 DropDefaultsOperation, KeyValueOption, SetDefaultsOperation, SetIndexOperation,
38 UnsetIndexOperation,
39};
40use crate::statements::statement::Statement;
41use crate::util::parse_option_string;
42
43impl ParserContext<'_> {
44 pub(crate) fn parse_alter(&mut self) -> Result<Statement> {
45 let _ = self.parser.expect_keyword(Keyword::ALTER);
46 match self.parser.peek_token().token {
47 Token::Word(w) => match w.keyword {
48 Keyword::DATABASE => self.parse_alter_database().map(Statement::AlterDatabase),
49 Keyword::TABLE => self.parse_alter_table().map(Statement::AlterTable),
50 #[cfg(feature = "enterprise")]
51 Keyword::TRIGGER => {
52 self.parser.next_token();
53 self.parse_alter_trigger()
54 }
55 _ => self.expected("DATABASE or TABLE after ALTER", self.parser.peek_token()),
56 },
57 unexpected => self.unsupported(unexpected.to_string()),
58 }
59 }
60
61 fn parse_alter_database(&mut self) -> Result<AlterDatabase> {
62 self.parser
63 .expect_keyword(Keyword::DATABASE)
64 .context(error::SyntaxSnafu)?;
65
66 let database_name = self
67 .parser
68 .parse_object_name(false)
69 .context(error::SyntaxSnafu)?;
70 let database_name = Self::canonicalize_object_name(database_name);
71
72 match self.parser.peek_token().token {
73 Token::Word(w) => {
74 if w.value.eq_ignore_ascii_case("UNSET") {
75 let _ = self.parser.next_token();
76 let keys = self
77 .parser
78 .parse_comma_separated(parse_string_option_names)
79 .context(error::SyntaxSnafu)?
80 .into_iter()
81 .map(|name| name.to_string())
82 .collect();
83 Ok(AlterDatabase::new(
84 database_name,
85 AlterDatabaseOperation::UnsetDatabaseOption { keys },
86 ))
87 } else if w.keyword == Keyword::SET {
88 let _ = self.parser.next_token();
89 let options = self
90 .parser
91 .parse_comma_separated(parse_string_options)
92 .context(error::SyntaxSnafu)?
93 .into_iter()
94 .map(|(key, value)| KeyValueOption { key, value })
95 .collect();
96 Ok(AlterDatabase::new(
97 database_name,
98 AlterDatabaseOperation::SetDatabaseOption { options },
99 ))
100 } else {
101 self.expected(
102 "SET or UNSET after ALTER DATABASE",
103 self.parser.peek_token(),
104 )
105 }
106 }
107 unexpected => self.unsupported(unexpected.to_string()),
108 }
109 }
110
111 fn parse_alter_table(&mut self) -> Result<AlterTable> {
112 self.parser
113 .expect_keyword(Keyword::TABLE)
114 .context(error::SyntaxSnafu)?;
115
116 let raw_table_name = self
117 .parser
118 .parse_object_name(false)
119 .context(error::SyntaxSnafu)?;
120 let table_name = Self::canonicalize_object_name(raw_table_name);
121
122 let alter_operation = match self.parser.peek_token().token {
123 Token::Word(w) => {
124 if w.value.eq_ignore_ascii_case("MODIFY") {
125 self.parse_alter_table_modify()?
126 } else if w.value.eq_ignore_ascii_case("UNSET") {
127 self.parse_alter_table_unset()?
128 } else {
129 match w.keyword {
130 Keyword::ADD => self.parse_alter_table_add()?,
131 Keyword::DROP => {
132 let _ = self.parser.next_token();
133 self.parser
134 .expect_keyword(Keyword::COLUMN)
135 .context(error::SyntaxSnafu)?;
136 let name = Self::canonicalize_identifier(
137 self.parser.parse_identifier().context(error::SyntaxSnafu)?,
138 );
139 AlterTableOperation::DropColumn { name }
140 }
141 Keyword::RENAME => {
142 let _ = self.parser.next_token();
143 let new_table_name_obj_raw =
144 self.parse_object_name().context(error::SyntaxSnafu)?;
145 let new_table_name_obj =
146 Self::canonicalize_object_name(new_table_name_obj_raw);
147 let new_table_name = match &new_table_name_obj.0[..] {
148 [table] => table.to_string_unquoted(),
149 _ => {
150 return Err(ParserError::ParserError(format!(
151 "expect table name, actual: {new_table_name_obj}"
152 )))
153 .context(error::SyntaxSnafu);
154 }
155 };
156 AlterTableOperation::RenameTable { new_table_name }
157 }
158 Keyword::SET => {
159 let _ = self.parser.next_token();
160 let options = self
161 .parser
162 .parse_comma_separated(parse_string_options)
163 .context(error::SyntaxSnafu)?
164 .into_iter()
165 .map(|(key, value)| KeyValueOption { key, value })
166 .collect();
167 AlterTableOperation::SetTableOptions { options }
168 }
169 _ => self.expected(
170 "ADD or DROP or MODIFY or RENAME or SET after ALTER TABLE",
171 self.parser.peek_token(),
172 )?,
173 }
174 }
175 }
176 unexpected => self.unsupported(unexpected.to_string())?,
177 };
178 Ok(AlterTable::new(table_name, alter_operation))
179 }
180
181 fn parse_alter_table_unset(&mut self) -> Result<AlterTableOperation> {
182 let _ = self.parser.next_token();
183 let keys = self
184 .parser
185 .parse_comma_separated(parse_string_option_names)
186 .context(error::SyntaxSnafu)?
187 .into_iter()
188 .collect();
189
190 Ok(AlterTableOperation::UnsetTableOptions { keys })
191 }
192
193 fn parse_alter_table_add(&mut self) -> Result<AlterTableOperation> {
194 let _ = self.parser.next_token();
195 if let Some(constraint) = self
196 .parser
197 .parse_optional_table_constraint()
198 .context(error::SyntaxSnafu)?
199 {
200 Ok(AlterTableOperation::AddConstraint(constraint))
201 } else {
202 self.parser.prev_token();
203 let add_columns = self
204 .parser
205 .parse_comma_separated(parse_add_columns)
206 .context(error::SyntaxSnafu)?;
207 Ok(AlterTableOperation::AddColumns { add_columns })
208 }
209 }
210
211 fn parse_alter_table_drop_default(
212 &mut self,
213 column_name: Ident,
214 ) -> Result<AlterTableOperation> {
215 let drop_default = DropDefaultsOperation(column_name);
216 if self.parser.consume_token(&Token::Comma) {
217 let mut columns = self
218 .parser
219 .parse_comma_separated(parse_alter_column_drop_default)
220 .context(error::SyntaxSnafu)?;
221 columns.insert(0, drop_default);
222 Ok(AlterTableOperation::DropDefaults { columns })
223 } else {
224 Ok(AlterTableOperation::DropDefaults {
225 columns: vec![drop_default],
226 })
227 }
228 }
229
230 fn parse_alter_table_set_default(&mut self, column_name: Ident) -> Result<AlterTableOperation> {
231 let default_constraint = self.parser.parse_expr().context(error::SyntaxSnafu)?;
232 let set_default = SetDefaultsOperation {
233 column_name,
234 default_constraint,
235 };
236 if self.parser.consume_token(&Token::Comma) {
237 let mut defaults = self
238 .parser
239 .parse_comma_separated(parse_alter_column_set_default)
240 .context(error::SyntaxSnafu)?;
241 defaults.insert(0, set_default);
242 Ok(AlterTableOperation::SetDefaults { defaults })
243 } else {
244 Ok(AlterTableOperation::SetDefaults {
245 defaults: vec![set_default],
246 })
247 }
248 }
249
250 fn parse_alter_table_modify(&mut self) -> Result<AlterTableOperation> {
251 let _ = self.parser.next_token();
252 self.parser
253 .expect_keyword(Keyword::COLUMN)
254 .context(error::SyntaxSnafu)?;
255 let column_name = Self::canonicalize_identifier(
256 self.parser.parse_identifier().context(error::SyntaxSnafu)?,
257 );
258
259 match self.parser.peek_token().token {
260 Token::Word(w) => {
261 if w.value.eq_ignore_ascii_case("UNSET") {
262 self.parser.next_token();
264 self.parse_alter_column_unset_index(column_name)
265 } else if w.keyword == Keyword::SET {
266 self.parser.next_token();
268 if let Token::Word(w) = self.parser.peek_token().token
269 && matches!(w.keyword, Keyword::DEFAULT)
270 {
271 self.parser
272 .expect_keyword(Keyword::DEFAULT)
273 .context(error::SyntaxSnafu)?;
274 self.parse_alter_table_set_default(column_name)
275 } else {
276 self.parse_alter_column_set_index(column_name)
277 }
278 } else if w.keyword == Keyword::DROP {
279 self.parser.next_token();
281 self.parser
282 .expect_keyword(Keyword::DEFAULT)
283 .context(error::SyntaxSnafu)?;
284 self.parse_alter_table_drop_default(column_name)
285 } else {
286 let data_type = self.parser.parse_data_type().context(error::SyntaxSnafu)?;
287 Ok(AlterTableOperation::ModifyColumnType {
288 column_name,
289 target_type: data_type,
290 })
291 }
292 }
293 _ => self.expected(
294 "SET or UNSET or data type after MODIFY COLUMN",
295 self.parser.peek_token(),
296 )?,
297 }
298 }
299
300 fn parse_alter_column_unset_index(
301 &mut self,
302 column_name: Ident,
303 ) -> Result<AlterTableOperation> {
304 match self.parser.next_token() {
305 TokenWithSpan {
306 token: Token::Word(w),
307 ..
308 } if w.keyword == Keyword::FULLTEXT => {
309 self.parser
310 .expect_keyword(Keyword::INDEX)
311 .context(error::SyntaxSnafu)?;
312 Ok(AlterTableOperation::UnsetIndex {
313 options: UnsetIndexOperation::Fulltext { column_name },
314 })
315 }
316
317 TokenWithSpan {
318 token: Token::Word(w),
319 ..
320 } if w.value.eq_ignore_ascii_case(INVERTED) => {
321 self.parser
322 .expect_keyword(Keyword::INDEX)
323 .context(error::SyntaxSnafu)?;
324 Ok(AlterTableOperation::UnsetIndex {
325 options: UnsetIndexOperation::Inverted { column_name },
326 })
327 }
328
329 TokenWithSpan {
330 token: Token::Word(w),
331 ..
332 } if w.value.eq_ignore_ascii_case("SKIPPING") => {
333 self.parser
334 .expect_keyword(Keyword::INDEX)
335 .context(error::SyntaxSnafu)?;
336 Ok(AlterTableOperation::UnsetIndex {
337 options: UnsetIndexOperation::Skipping { column_name },
338 })
339 }
340 _ => self.expected(
341 format!(
342 "{:?} OR INVERTED INDEX OR SKIPPING INDEX",
343 Keyword::FULLTEXT
344 )
345 .as_str(),
346 self.parser.peek_token(),
347 ),
348 }
349 }
350
351 fn parse_alter_column_set_index(&mut self, column_name: Ident) -> Result<AlterTableOperation> {
352 match self.parser.next_token() {
353 TokenWithSpan {
354 token: Token::Word(w),
355 ..
356 } if w.keyword == Keyword::FULLTEXT => {
357 self.parser
358 .expect_keyword(Keyword::INDEX)
359 .context(error::SyntaxSnafu)?;
360 self.parse_alter_column_fulltext(column_name)
361 }
362
363 TokenWithSpan {
364 token: Token::Word(w),
365 ..
366 } if w.value.eq_ignore_ascii_case(INVERTED) => {
367 self.parser
368 .expect_keyword(Keyword::INDEX)
369 .context(error::SyntaxSnafu)?;
370 Ok(AlterTableOperation::SetIndex {
371 options: SetIndexOperation::Inverted { column_name },
372 })
373 }
374
375 TokenWithSpan {
376 token: Token::Word(w),
377 ..
378 } if w.value.eq_ignore_ascii_case("SKIPPING") => {
379 self.parser
380 .expect_keyword(Keyword::INDEX)
381 .context(error::SyntaxSnafu)?;
382 self.parse_alter_column_skipping(column_name)
383 }
384 t => self.expected(
385 format!("{:?} OR INVERTED OR SKIPPING INDEX", Keyword::FULLTEXT).as_str(),
386 t,
387 ),
388 }
389 }
390
391 fn parse_alter_column_fulltext(&mut self, column_name: Ident) -> Result<AlterTableOperation> {
392 let mut options = self
393 .parser
394 .parse_options(Keyword::WITH)
395 .context(error::SyntaxSnafu)?
396 .into_iter()
397 .map(parse_option_string)
398 .collect::<Result<HashMap<String, String>>>()?;
399
400 for key in options.keys() {
401 ensure!(
402 validate_column_fulltext_create_option(key),
403 InvalidColumnOptionSnafu {
404 name: column_name.to_string(),
405 msg: format!("invalid FULLTEXT option: {key}"),
406 }
407 );
408 }
409
410 options.insert(
411 COLUMN_FULLTEXT_CHANGE_OPT_KEY_ENABLE.to_string(),
412 "true".to_string(),
413 );
414
415 Ok(AlterTableOperation::SetIndex {
416 options: SetIndexOperation::Fulltext {
417 column_name,
418 options: options.try_into().context(SetFulltextOptionSnafu)?,
419 },
420 })
421 }
422
423 fn parse_alter_column_skipping(&mut self, column_name: Ident) -> Result<AlterTableOperation> {
424 let options = self
425 .parser
426 .parse_options(Keyword::WITH)
427 .context(error::SyntaxSnafu)?
428 .into_iter()
429 .map(parse_option_string)
430 .collect::<Result<HashMap<String, String>>>()?;
431
432 for key in options.keys() {
433 ensure!(
434 validate_column_skipping_index_create_option(key),
435 InvalidColumnOptionSnafu {
436 name: column_name.to_string(),
437 msg: format!("invalid SKIPPING INDEX option: {key}"),
438 }
439 );
440 }
441
442 Ok(AlterTableOperation::SetIndex {
443 options: SetIndexOperation::Skipping {
444 column_name,
445 options: options
446 .try_into()
447 .context(error::SetSkippingIndexOptionSnafu)?,
448 },
449 })
450 }
451}
452
453fn parse_alter_column_drop_default(
454 parser: &mut Parser,
455) -> std::result::Result<DropDefaultsOperation, ParserError> {
456 parser.expect_keywords(&[Keyword::MODIFY, Keyword::COLUMN])?;
457 let column_name = ParserContext::canonicalize_identifier(parser.parse_identifier()?);
458 let t = parser.next_token();
459 match t.token {
460 Token::Word(w) if w.keyword == Keyword::DROP => {
461 parser.expect_keyword(Keyword::DEFAULT)?;
462 Ok(DropDefaultsOperation(column_name))
463 }
464 _ => Err(ParserError::ParserError(format!(
465 "Unexpected keyword, expect DROP, got: `{t}`"
466 ))),
467 }
468}
469
470fn parse_alter_column_set_default(
471 parser: &mut Parser,
472) -> std::result::Result<SetDefaultsOperation, ParserError> {
473 parser.expect_keywords(&[Keyword::MODIFY, Keyword::COLUMN])?;
474 let column_name = ParserContext::canonicalize_identifier(parser.parse_identifier()?);
475 let t = parser.next_token();
476 match t.token {
477 Token::Word(w) if w.keyword == Keyword::SET => {
478 parser.expect_keyword(Keyword::DEFAULT)?;
479 if let Ok(default_constraint) = parser.parse_expr() {
480 Ok(SetDefaultsOperation {
481 column_name,
482 default_constraint,
483 })
484 } else {
485 Err(ParserError::ParserError(format!(
486 "Invalid default value after SET DEFAULT, got: `{}`",
487 parser.peek_token()
488 )))
489 }
490 }
491 _ => Err(ParserError::ParserError(format!(
492 "Unexpected keyword, expect SET, got: `{t}`"
493 ))),
494 }
495}
496
497fn parse_string_options(parser: &mut Parser) -> std::result::Result<(String, String), ParserError> {
499 let name = parser.parse_literal_string()?;
500 parser.expect_token(&Token::Eq)?;
501 let value = if parser.parse_keyword(Keyword::NULL) {
502 "".to_string()
503 } else {
504 let next_token = parser.peek_token();
505 if let Token::Number(number_as_string, _) = next_token.token {
506 parser.advance_token();
507 number_as_string
508 } else {
509 parser.parse_literal_string().map_err(|_|{
510 ParserError::ParserError(format!("Unexpected option value for alter table statements, expect string literal, numeric literal or NULL, got: `{}`", next_token))
511 })?
512 }
513 };
514 Ok((name, value))
515}
516
517fn parse_add_columns(parser: &mut Parser) -> std::result::Result<AddColumn, ParserError> {
518 parser.expect_keyword(Keyword::ADD)?;
519 let _ = parser.parse_keyword(Keyword::COLUMN);
520 let add_if_not_exists = parser.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
521 let mut column_def = parser.parse_column_def()?;
522 column_def.name = ParserContext::canonicalize_identifier(column_def.name);
523 let location = if parser.parse_keyword(Keyword::FIRST) {
524 Some(AddColumnLocation::First)
525 } else if let Token::Word(word) = parser.peek_token().token {
526 if word.value.eq_ignore_ascii_case("AFTER") {
527 let _ = parser.next_token();
528 let name = ParserContext::canonicalize_identifier(parser.parse_identifier()?);
529 Some(AddColumnLocation::After {
530 column_name: name.value,
531 })
532 } else {
533 None
534 }
535 } else {
536 None
537 };
538 Ok(AddColumn {
539 column_def,
540 location,
541 add_if_not_exists,
542 })
543}
544
545fn parse_string_option_names(parser: &mut Parser) -> std::result::Result<String, ParserError> {
547 parser.parse_literal_string()
548}
549
550#[cfg(test)]
551mod tests {
552 use std::assert_matches::assert_matches;
553
554 use common_error::ext::ErrorExt;
555 use datatypes::schema::{FulltextAnalyzer, FulltextBackend, FulltextOptions};
556 use sqlparser::ast::{ColumnDef, ColumnOption, ColumnOptionDef, DataType};
557
558 use super::*;
559 use crate::ast::ObjectNamePartExt;
560 use crate::dialect::GreptimeDbDialect;
561 use crate::parser::ParseOptions;
562 use crate::statements::alter::AlterDatabaseOperation;
563
564 #[test]
565 fn test_parse_alter_database() {
566 let sql = "ALTER DATABASE test_db SET 'a'='A', 'b' = 'B'";
567 let mut result =
568 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
569 .unwrap();
570 assert_eq!(1, result.len());
571
572 let statement = result.remove(0);
573 assert_matches!(statement, Statement::AlterDatabase { .. });
574 match statement {
575 Statement::AlterDatabase(alter_database) => {
576 assert_eq!("test_db", alter_database.database_name().0[0].to_string());
577
578 let alter_operation = alter_database.alter_operation();
579 assert_matches!(
580 alter_operation,
581 AlterDatabaseOperation::SetDatabaseOption { .. }
582 );
583 match alter_operation {
584 AlterDatabaseOperation::SetDatabaseOption { options } => {
585 assert_eq!(2, options.len());
586 assert_eq!("a", options[0].key);
587 assert_eq!("A", options[0].value);
588 assert_eq!("b", options[1].key);
589 assert_eq!("B", options[1].value);
590 }
591 _ => unreachable!(),
592 }
593 }
594 _ => unreachable!(),
595 }
596 let sql = "ALTER DATABASE test_db UNSET 'a', 'b'";
597 let mut result =
598 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
599 .unwrap();
600 assert_eq!(1, result.len());
601 let statement = result.remove(0);
602 assert_matches!(statement, Statement::AlterDatabase { .. });
603 match statement {
604 Statement::AlterDatabase(alter_database) => {
605 assert_eq!("test_db", alter_database.database_name().0[0].to_string());
606 let alter_operation = alter_database.alter_operation();
607 assert_matches!(
608 alter_operation,
609 AlterDatabaseOperation::UnsetDatabaseOption { .. }
610 );
611 match alter_operation {
612 AlterDatabaseOperation::UnsetDatabaseOption { keys } => {
613 assert_eq!(2, keys.len());
614 assert_eq!("a", keys[0]);
615 assert_eq!("b", keys[1]);
616 }
617 _ => unreachable!(),
618 }
619 }
620 _ => unreachable!(),
621 }
622 }
623
624 #[test]
625 fn test_parse_alter_add_column() {
626 let sql = "ALTER TABLE my_metric_1 ADD tagk_i STRING Null;";
627 let mut result =
628 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
629 .unwrap();
630 assert_eq!(1, result.len());
631
632 let statement = result.remove(0);
633 assert_matches!(statement, Statement::AlterTable { .. });
634 match statement {
635 Statement::AlterTable(alter_table) => {
636 assert_eq!("my_metric_1", alter_table.table_name().0[0].to_string());
637
638 let alter_operation = alter_table.alter_operation();
639 assert_matches!(alter_operation, AlterTableOperation::AddColumns { .. });
640 match alter_operation {
641 AlterTableOperation::AddColumns { add_columns } => {
642 assert_eq!(add_columns.len(), 1);
643 assert_eq!("tagk_i", add_columns[0].column_def.name.value);
644 assert_eq!(DataType::String(None), add_columns[0].column_def.data_type);
645 assert!(
646 add_columns[0]
647 .column_def
648 .options
649 .iter()
650 .any(|o| matches!(o.option, ColumnOption::Null))
651 );
652 assert_eq!(&None, &add_columns[0].location);
653 }
654 _ => unreachable!(),
655 }
656 }
657 _ => unreachable!(),
658 }
659 }
660
661 #[test]
662 fn test_parse_alter_add_column_with_first() {
663 let sql = "ALTER TABLE my_metric_1 ADD tagk_i STRING Null FIRST;";
664 let mut result =
665 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
666 .unwrap();
667 assert_eq!(1, result.len());
668
669 let statement = result.remove(0);
670 assert_matches!(statement, Statement::AlterTable { .. });
671 match statement {
672 Statement::AlterTable(alter_table) => {
673 assert_eq!("my_metric_1", alter_table.table_name().0[0].to_string());
674
675 let alter_operation = alter_table.alter_operation();
676 assert_matches!(alter_operation, AlterTableOperation::AddColumns { .. });
677 match alter_operation {
678 AlterTableOperation::AddColumns { add_columns } => {
679 assert_eq!("tagk_i", add_columns[0].column_def.name.value);
680 assert_eq!(DataType::String(None), add_columns[0].column_def.data_type);
681 assert!(
682 add_columns[0]
683 .column_def
684 .options
685 .iter()
686 .any(|o| matches!(o.option, ColumnOption::Null))
687 );
688 assert_eq!(&Some(AddColumnLocation::First), &add_columns[0].location);
689 }
690 _ => unreachable!(),
691 }
692 }
693 _ => unreachable!(),
694 }
695 }
696
697 #[test]
698 fn test_parse_alter_add_column_with_after() {
699 let sql =
700 "ALTER TABLE my_metric_1 ADD tagk_i STRING Null AFTER ts, add column tagl_i String;";
701 let mut result =
702 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
703 .unwrap();
704 assert_eq!(1, result.len());
705
706 let statement = result.remove(0);
707 assert_matches!(statement, Statement::AlterTable { .. });
708 match statement {
709 Statement::AlterTable(alter_table) => {
710 assert_eq!("my_metric_1", alter_table.table_name().0[0].to_string());
711
712 let alter_operation = alter_table.alter_operation();
713 assert_matches!(alter_operation, AlterTableOperation::AddColumns { .. });
714 match alter_operation {
715 AlterTableOperation::AddColumns { add_columns } => {
716 let expecteds: Vec<(Option<AddColumnLocation>, ColumnDef)> = vec![
717 (
718 Some(AddColumnLocation::After {
719 column_name: "ts".to_string(),
720 }),
721 ColumnDef {
722 name: Ident::new("tagk_i"),
723 data_type: DataType::String(None),
724 options: vec![ColumnOptionDef {
725 name: None,
726 option: ColumnOption::Null,
727 }],
728 },
729 ),
730 (
731 None,
732 ColumnDef {
733 name: Ident::new("tagl_i"),
734 data_type: DataType::String(None),
735 options: vec![],
736 },
737 ),
738 ];
739 for (add_column, expected) in add_columns
740 .iter()
741 .zip(expecteds)
742 .collect::<Vec<(&AddColumn, (Option<AddColumnLocation>, ColumnDef))>>()
743 {
744 assert_eq!(add_column.column_def, expected.1);
745 assert_eq!(&expected.0, &add_column.location);
746 }
747 }
748 _ => unreachable!(),
749 }
750 }
751 _ => unreachable!(),
752 }
753 }
754
755 #[test]
756 fn test_parse_add_column_if_not_exists() {
757 let sql = "ALTER TABLE test ADD COLUMN IF NOT EXISTS a INTEGER, ADD COLUMN b STRING, ADD COLUMN IF NOT EXISTS c INT;";
758 let mut result =
759 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
760 .unwrap();
761 assert_eq!(result.len(), 1);
762 let statement = result.remove(0);
763 assert_matches!(statement, Statement::AlterTable { .. });
764 match statement {
765 Statement::AlterTable(alter) => {
766 assert_eq!(alter.table_name.0[0].to_string(), "test");
767 assert_matches!(
768 alter.alter_operation,
769 AlterTableOperation::AddColumns { .. }
770 );
771 match alter.alter_operation {
772 AlterTableOperation::AddColumns { add_columns } => {
773 let expected = vec![
774 AddColumn {
775 column_def: ColumnDef {
776 name: Ident::new("a"),
777 data_type: DataType::Integer(None),
778 options: vec![],
779 },
780 location: None,
781 add_if_not_exists: true,
782 },
783 AddColumn {
784 column_def: ColumnDef {
785 name: Ident::new("b"),
786 data_type: DataType::String(None),
787 options: vec![],
788 },
789 location: None,
790 add_if_not_exists: false,
791 },
792 AddColumn {
793 column_def: ColumnDef {
794 name: Ident::new("c"),
795 data_type: DataType::Int(None),
796 options: vec![],
797 },
798 location: None,
799 add_if_not_exists: true,
800 },
801 ];
802 for (idx, add_column) in add_columns.into_iter().enumerate() {
803 assert_eq!(add_column, expected[idx]);
804 }
805 }
806 _ => unreachable!(),
807 }
808 }
809 _ => unreachable!(),
810 }
811 }
812
813 #[test]
814 fn test_parse_alter_drop_column() {
815 let sql = "ALTER TABLE my_metric_1 DROP a";
816 let result =
817 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
818 .unwrap_err();
819 let err = result.output_msg();
820 assert_eq!(
821 err,
822 "Invalid SQL syntax: sql parser error: Expected: COLUMN, found: a at Line: 1, Column: 30"
823 );
824
825 let sql = "ALTER TABLE my_metric_1 DROP COLUMN a";
826 let mut result =
827 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
828 .unwrap();
829 assert_eq!(1, result.len());
830
831 let statement = result.remove(0);
832 assert_matches!(statement, Statement::AlterTable { .. });
833 match statement {
834 Statement::AlterTable(alter_table) => {
835 assert_eq!("my_metric_1", alter_table.table_name().0[0].to_string());
836
837 let alter_operation = alter_table.alter_operation();
838 assert_matches!(alter_operation, AlterTableOperation::DropColumn { .. });
839 match alter_operation {
840 AlterTableOperation::DropColumn { name } => {
841 assert_eq!("a", name.value);
842 }
843 _ => unreachable!(),
844 }
845 }
846 _ => unreachable!(),
847 }
848 }
849
850 #[test]
851 fn test_parse_alter_modify_column_type() {
852 let sql_1 = "ALTER TABLE my_metric_1 MODIFY COLUMN a STRING";
853 let result_1 = ParserContext::create_with_dialect(
854 sql_1,
855 &GreptimeDbDialect {},
856 ParseOptions::default(),
857 )
858 .unwrap();
859
860 let sql_2 = "ALTER TABLE my_metric_1 MODIFY COLUMN a STRING";
861 let mut result_2 = ParserContext::create_with_dialect(
862 sql_2,
863 &GreptimeDbDialect {},
864 ParseOptions::default(),
865 )
866 .unwrap();
867 assert_eq!(result_1, result_2);
868 assert_eq!(1, result_2.len());
869
870 let statement = result_2.remove(0);
871 assert_matches!(statement, Statement::AlterTable { .. });
872 match statement {
873 Statement::AlterTable(alter_table) => {
874 assert_eq!("my_metric_1", alter_table.table_name().0[0].to_string());
875
876 let alter_operation = alter_table.alter_operation();
877 assert_matches!(
878 alter_operation,
879 AlterTableOperation::ModifyColumnType { .. }
880 );
881 match alter_operation {
882 AlterTableOperation::ModifyColumnType {
883 column_name,
884 target_type,
885 } => {
886 assert_eq!("a", column_name.value);
887 assert_eq!(DataType::String(None), *target_type);
888 }
889 _ => unreachable!(),
890 }
891 }
892 _ => unreachable!(),
893 }
894 }
895
896 #[test]
897 fn test_parse_alter_change_column_alias_type() {
898 let sql_1 = "ALTER TABLE my_metric_1 MODIFY COLUMN a MediumText";
899 let mut result_1 = ParserContext::create_with_dialect(
900 sql_1,
901 &GreptimeDbDialect {},
902 ParseOptions::default(),
903 )
904 .unwrap();
905
906 match result_1.remove(0) {
907 Statement::AlterTable(alter_table) => {
908 assert_eq!("my_metric_1", alter_table.table_name().0[0].to_string());
909
910 let alter_operation = alter_table.alter_operation();
911 assert_matches!(
912 alter_operation,
913 AlterTableOperation::ModifyColumnType { .. }
914 );
915 match alter_operation {
916 AlterTableOperation::ModifyColumnType {
917 column_name,
918 target_type,
919 } => {
920 assert_eq!("a", column_name.value);
921 assert_eq!(DataType::MediumText, *target_type);
922 }
923 _ => unreachable!(),
924 }
925 }
926 _ => unreachable!(),
927 }
928
929 let sql_2 = "ALTER TABLE my_metric_1 MODIFY COLUMN a TIMESTAMP_US";
930 let mut result_2 = ParserContext::create_with_dialect(
931 sql_2,
932 &GreptimeDbDialect {},
933 ParseOptions::default(),
934 )
935 .unwrap();
936
937 match result_2.remove(0) {
938 Statement::AlterTable(alter_table) => {
939 assert_eq!("my_metric_1", alter_table.table_name().0[0].to_string());
940
941 let alter_operation = alter_table.alter_operation();
942 assert_matches!(
943 alter_operation,
944 AlterTableOperation::ModifyColumnType { .. }
945 );
946 match alter_operation {
947 AlterTableOperation::ModifyColumnType {
948 column_name,
949 target_type,
950 } => {
951 assert_eq!("a", column_name.value);
952 assert!(matches!(target_type, DataType::Timestamp(Some(6), _)));
953 }
954 _ => unreachable!(),
955 }
956 }
957 _ => unreachable!(),
958 }
959 }
960
961 #[test]
962 fn test_parse_alter_rename_table() {
963 let sql = "ALTER TABLE test_table table_t";
964 let result =
965 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
966 .unwrap_err();
967 let err = result.output_msg();
968 assert_eq!(
969 err,
970 "Invalid SQL syntax: sql parser error: Expected ADD or DROP or MODIFY or RENAME or SET after ALTER TABLE, found: table_t"
971 );
972
973 let sql = "ALTER TABLE test_table RENAME table_t";
974 let mut result =
975 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
976 .unwrap();
977 assert_eq!(1, result.len());
978
979 let statement = result.remove(0);
980 assert_matches!(statement, Statement::AlterTable { .. });
981 match statement {
982 Statement::AlterTable(alter_table) => {
983 assert_eq!("test_table", alter_table.table_name().0[0].to_string());
984
985 let alter_operation = alter_table.alter_operation();
986 assert_matches!(alter_operation, AlterTableOperation::RenameTable { .. });
987 match alter_operation {
988 AlterTableOperation::RenameTable { new_table_name } => {
989 assert_eq!("table_t", new_table_name);
990 }
991 _ => unreachable!(),
992 }
993 }
994 _ => unreachable!(),
995 }
996 }
997
998 fn check_parse_alter_table_set_options(sql: &str, expected: &[(&str, &str)]) {
999 let result =
1000 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
1001 .unwrap();
1002 assert_eq!(1, result.len());
1003 let Statement::AlterTable(alter) = &result[0] else {
1004 unreachable!()
1005 };
1006 assert_eq!("test_table", alter.table_name.0[0].to_string());
1007 let AlterTableOperation::SetTableOptions { options } = &alter.alter_operation else {
1008 unreachable!()
1009 };
1010
1011 assert_eq!(sql, alter.to_string());
1012 let res = options
1013 .iter()
1014 .map(|o| (o.key.as_str(), o.value.as_str()))
1015 .collect::<Vec<_>>();
1016 assert_eq!(expected, &res);
1017 }
1018
1019 fn check_parse_alter_table_unset_options(sql: &str, expected: &[&str]) {
1020 let result =
1021 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
1022 .unwrap();
1023 assert_eq!(1, result.len());
1024 let Statement::AlterTable(alter) = &result[0] else {
1025 unreachable!()
1026 };
1027 assert_eq!("test_table", alter.table_name.0[0].to_string());
1028 let AlterTableOperation::UnsetTableOptions { keys } = &alter.alter_operation else {
1029 unreachable!()
1030 };
1031
1032 assert_eq!(sql, alter.to_string());
1033 let res = keys.iter().map(|o| o.to_string()).collect::<Vec<_>>();
1034 assert_eq!(expected, &res);
1035 }
1036
1037 #[test]
1038 fn test_parse_alter_table_set_options() {
1039 check_parse_alter_table_set_options("ALTER TABLE test_table SET 'a'='A'", &[("a", "A")]);
1040 check_parse_alter_table_set_options(
1041 "ALTER TABLE test_table SET 'a'='A','b'='B'",
1042 &[("a", "A"), ("b", "B")],
1043 );
1044 check_parse_alter_table_set_options(
1045 "ALTER TABLE test_table SET 'a'='A','b'='B','c'='C'",
1046 &[("a", "A"), ("b", "B"), ("c", "C")],
1047 );
1048 check_parse_alter_table_set_options("ALTER TABLE test_table SET 'a'=NULL", &[("a", "")]);
1049
1050 ParserContext::create_with_dialect(
1051 "ALTER TABLE test_table SET a INTEGER",
1052 &GreptimeDbDialect {},
1053 ParseOptions::default(),
1054 )
1055 .unwrap_err();
1056 }
1057
1058 #[test]
1059 fn test_parse_alter_table_unset_options() {
1060 check_parse_alter_table_unset_options("ALTER TABLE test_table UNSET 'a'", &["a"]);
1061 check_parse_alter_table_unset_options("ALTER TABLE test_table UNSET 'a','b'", &["a", "b"]);
1062 ParserContext::create_with_dialect(
1063 "ALTER TABLE test_table UNSET a INTEGER",
1064 &GreptimeDbDialect {},
1065 ParseOptions::default(),
1066 )
1067 .unwrap_err();
1068 }
1069
1070 #[test]
1071 fn test_parse_alter_column_fulltext() {
1072 let sql = "ALTER TABLE test_table MODIFY COLUMN a SET FULLTEXT INDEX WITH(analyzer='English',case_sensitive='false',backend='bloom',granularity=1000,false_positive_rate=0.01)";
1073 let mut result =
1074 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
1075 .unwrap();
1076
1077 assert_eq!(1, result.len());
1078 let statement = result.remove(0);
1079 assert_matches!(statement, Statement::AlterTable { .. });
1080 match statement {
1081 Statement::AlterTable(alter_table) => {
1082 assert_eq!("test_table", alter_table.table_name().0[0].to_string());
1083
1084 let alter_operation = alter_table.alter_operation();
1085 match alter_operation {
1086 AlterTableOperation::SetIndex {
1087 options:
1088 SetIndexOperation::Fulltext {
1089 column_name,
1090 options,
1091 },
1092 } => {
1093 assert_eq!("a", column_name.value);
1094 assert_eq!(
1095 FulltextOptions::new_unchecked(
1096 true,
1097 FulltextAnalyzer::English,
1098 false,
1099 FulltextBackend::Bloom,
1100 1000,
1101 0.01,
1102 ),
1103 *options
1104 );
1105 }
1106 _ => unreachable!(),
1107 };
1108 }
1109 _ => unreachable!(),
1110 }
1111
1112 let sql = "ALTER TABLE test_table MODIFY COLUMN a UNSET FULLTEXT INDEX";
1113 let mut result =
1114 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
1115 .unwrap();
1116 assert_eq!(1, result.len());
1117 let statement = result.remove(0);
1118 assert_matches!(statement, Statement::AlterTable { .. });
1119 match statement {
1120 Statement::AlterTable(alter_table) => {
1121 assert_eq!("test_table", alter_table.table_name().0[0].to_string());
1122
1123 let alter_operation = alter_table.alter_operation();
1124 assert_eq!(
1125 alter_operation,
1126 &AlterTableOperation::UnsetIndex {
1127 options: UnsetIndexOperation::Fulltext {
1128 column_name: Ident::new("a"),
1129 }
1130 }
1131 );
1132 }
1133 _ => unreachable!(),
1134 }
1135
1136 let invalid_sql =
1137 "ALTER TABLE test_table MODIFY COLUMN a SET FULLTEXT INDEX WITH('abcd'='true')";
1138 let result = ParserContext::create_with_dialect(
1139 invalid_sql,
1140 &GreptimeDbDialect {},
1141 ParseOptions::default(),
1142 )
1143 .unwrap_err();
1144 let err = result.to_string();
1145 assert_eq!(
1146 err,
1147 "Invalid column option, column name: a, error: invalid FULLTEXT option: abcd"
1148 );
1149 }
1150
1151 #[test]
1152 fn test_parse_alter_column_inverted() {
1153 let sql = "ALTER TABLE test_table MODIFY COLUMN a SET INVERTED INDEX";
1154 let mut result =
1155 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
1156 .unwrap();
1157
1158 assert_eq!(1, result.len());
1159 let statement = result.remove(0);
1160 assert_matches!(statement, Statement::AlterTable { .. });
1161 match statement {
1162 Statement::AlterTable(alter_table) => {
1163 assert_eq!("test_table", alter_table.table_name().0[0].to_string());
1164
1165 let alter_operation = alter_table.alter_operation();
1166 match alter_operation {
1167 AlterTableOperation::SetIndex {
1168 options: SetIndexOperation::Inverted { column_name },
1169 } => assert_eq!("a", column_name.value),
1170 _ => unreachable!(),
1171 };
1172 }
1173 _ => unreachable!(),
1174 }
1175
1176 let sql = "ALTER TABLE test_table MODIFY COLUMN a UNSET INVERTED INDEX";
1177 let mut result =
1178 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
1179 .unwrap();
1180 assert_eq!(1, result.len());
1181 let statement = result.remove(0);
1182 assert_matches!(statement, Statement::AlterTable { .. });
1183 match statement {
1184 Statement::AlterTable(alter_table) => {
1185 assert_eq!("test_table", alter_table.table_name().0[0].to_string());
1186
1187 let alter_operation = alter_table.alter_operation();
1188 assert_eq!(
1189 alter_operation,
1190 &AlterTableOperation::UnsetIndex {
1191 options: UnsetIndexOperation::Inverted {
1192 column_name: Ident::new("a"),
1193 }
1194 }
1195 );
1196 }
1197 _ => unreachable!(),
1198 }
1199
1200 let invalid_sql = "ALTER TABLE test_table MODIFY COLUMN a SET INVERTED";
1201 ParserContext::create_with_dialect(
1202 invalid_sql,
1203 &GreptimeDbDialect {},
1204 ParseOptions::default(),
1205 )
1206 .unwrap_err();
1207 }
1208
1209 #[test]
1210 fn test_parse_alter_with_numeric_value() {
1211 for sql in [
1212 "ALTER TABLE test SET 'compaction.twcs.trigger_file_num'=8;",
1213 "ALTER TABLE test SET 'compaction.twcs.trigger_file_num'='8';",
1214 ] {
1215 let mut result = ParserContext::create_with_dialect(
1216 sql,
1217 &GreptimeDbDialect {},
1218 ParseOptions::default(),
1219 )
1220 .unwrap();
1221 assert_eq!(1, result.len());
1222
1223 let statement = result.remove(0);
1224 assert_matches!(statement, Statement::AlterTable { .. });
1225 match statement {
1226 Statement::AlterTable(alter_table) => {
1227 let alter_operation = alter_table.alter_operation();
1228 assert_matches!(alter_operation, AlterTableOperation::SetTableOptions { .. });
1229 match alter_operation {
1230 AlterTableOperation::SetTableOptions { options } => {
1231 assert_eq!(options.len(), 1);
1232 assert_eq!(options[0].key, "compaction.twcs.trigger_file_num");
1233 assert_eq!(options[0].value, "8");
1234 }
1235 _ => unreachable!(),
1236 }
1237 }
1238 _ => unreachable!(),
1239 }
1240 }
1241 }
1242
1243 #[test]
1244 fn test_parse_alter_drop_default() {
1245 let columns = vec![vec!["a"], vec!["a", "b", "c"]];
1246 for col in columns {
1247 let sql = col
1248 .iter()
1249 .map(|x| format!("MODIFY COLUMN {x} DROP DEFAULT"))
1250 .collect::<Vec<String>>()
1251 .join(",");
1252 let sql = format!("ALTER TABLE test_table {sql}");
1253 let mut result = ParserContext::create_with_dialect(
1254 &sql,
1255 &GreptimeDbDialect {},
1256 ParseOptions::default(),
1257 )
1258 .unwrap();
1259 assert_eq!(1, result.len());
1260 let statement = result.remove(0);
1261 assert_matches!(statement, Statement::AlterTable { .. });
1262 match statement {
1263 Statement::AlterTable(alter_table) => {
1264 assert_eq!(
1265 "test_table",
1266 alter_table.table_name().0[0].to_string_unquoted()
1267 );
1268 let alter_operation = alter_table.alter_operation();
1269 match alter_operation {
1270 AlterTableOperation::DropDefaults { columns } => {
1271 assert_eq!(col.len(), columns.len());
1272 for i in 0..columns.len() {
1273 assert_eq!(col[i], columns[i].0.value);
1274 }
1275 }
1276 _ => unreachable!(),
1277 }
1278 }
1279 _ => unreachable!(),
1280 }
1281 }
1282 }
1283
1284 #[test]
1285 fn test_parse_alter_set_default() {
1286 let columns = vec![vec!["a"], vec!["a", "b"], vec!["a", "b", "c"]];
1287 for col in columns {
1288 let sql = col
1289 .iter()
1290 .map(|x| format!("MODIFY COLUMN {x} SET DEFAULT 100"))
1291 .collect::<Vec<String>>()
1292 .join(",");
1293 let sql = format!("ALTER TABLE test_table {sql}");
1294 let mut result = ParserContext::create_with_dialect(
1295 &sql,
1296 &GreptimeDbDialect {},
1297 ParseOptions::default(),
1298 )
1299 .unwrap();
1300 assert_eq!(1, result.len());
1301 let statement = result.remove(0);
1302 assert_matches!(statement, Statement::AlterTable { .. });
1303 match statement {
1304 Statement::AlterTable(alter_table) => {
1305 assert_eq!("test_table", alter_table.table_name().to_string());
1306 let alter_operation = alter_table.alter_operation();
1307 match alter_operation {
1308 AlterTableOperation::SetDefaults { defaults } => {
1309 assert_eq!(col.len(), defaults.len());
1310 for i in 0..defaults.len() {
1311 assert_eq!(col[i], defaults[i].column_name.to_string());
1312 assert_eq!(
1313 "100".to_string(),
1314 defaults[i].default_constraint.to_string()
1315 );
1316 }
1317 }
1318 _ => unreachable!(),
1319 }
1320 }
1321 _ => unreachable!(),
1322 }
1323 }
1324 }
1325
1326 #[test]
1327 fn test_parse_alter_set_default_invalid() {
1328 let sql = "ALTER TABLE test_table MODIFY COLUMN a SET 100;";
1329 let result =
1330 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
1331 .unwrap_err();
1332 let err = result.output_msg();
1333 assert_eq!(
1334 err,
1335 "Invalid SQL syntax: sql parser error: Expected FULLTEXT OR INVERTED OR SKIPPING INDEX, found: 100"
1336 );
1337
1338 let sql = "ALTER TABLE test_table MODIFY COLUMN a SET DEFAULT 100, b SET DEFAULT 200";
1339 let result =
1340 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
1341 .unwrap_err();
1342 let err = result.output_msg();
1343 assert_eq!(
1344 err,
1345 "Invalid SQL syntax: sql parser error: Expected: MODIFY, found: b at Line: 1, Column: 57"
1346 );
1347
1348 let sql = "ALTER TABLE test_table MODIFY COLUMN a SET DEFAULT 100, MODIFY COLUMN b DROP DEFAULT 200";
1349 let result =
1350 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
1351 .unwrap_err();
1352 let err = result.output_msg();
1353 assert_eq!(
1354 err,
1355 "Invalid SQL syntax: sql parser error: Unexpected keyword, expect SET, got: `DROP`"
1356 );
1357 }
1358}