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::{ensure, ResultExt};
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!(add_columns[0]
646 .column_def
647 .options
648 .iter()
649 .any(|o| matches!(o.option, ColumnOption::Null)));
650 assert_eq!(&None, &add_columns[0].location);
651 }
652 _ => unreachable!(),
653 }
654 }
655 _ => unreachable!(),
656 }
657 }
658
659 #[test]
660 fn test_parse_alter_add_column_with_first() {
661 let sql = "ALTER TABLE my_metric_1 ADD tagk_i STRING Null FIRST;";
662 let mut result =
663 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
664 .unwrap();
665 assert_eq!(1, result.len());
666
667 let statement = result.remove(0);
668 assert_matches!(statement, Statement::AlterTable { .. });
669 match statement {
670 Statement::AlterTable(alter_table) => {
671 assert_eq!("my_metric_1", alter_table.table_name().0[0].to_string());
672
673 let alter_operation = alter_table.alter_operation();
674 assert_matches!(alter_operation, AlterTableOperation::AddColumns { .. });
675 match alter_operation {
676 AlterTableOperation::AddColumns { add_columns } => {
677 assert_eq!("tagk_i", add_columns[0].column_def.name.value);
678 assert_eq!(DataType::String(None), add_columns[0].column_def.data_type);
679 assert!(add_columns[0]
680 .column_def
681 .options
682 .iter()
683 .any(|o| matches!(o.option, ColumnOption::Null)));
684 assert_eq!(&Some(AddColumnLocation::First), &add_columns[0].location);
685 }
686 _ => unreachable!(),
687 }
688 }
689 _ => unreachable!(),
690 }
691 }
692
693 #[test]
694 fn test_parse_alter_add_column_with_after() {
695 let sql =
696 "ALTER TABLE my_metric_1 ADD tagk_i STRING Null AFTER ts, add column tagl_i String;";
697 let mut result =
698 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
699 .unwrap();
700 assert_eq!(1, result.len());
701
702 let statement = result.remove(0);
703 assert_matches!(statement, Statement::AlterTable { .. });
704 match statement {
705 Statement::AlterTable(alter_table) => {
706 assert_eq!("my_metric_1", alter_table.table_name().0[0].to_string());
707
708 let alter_operation = alter_table.alter_operation();
709 assert_matches!(alter_operation, AlterTableOperation::AddColumns { .. });
710 match alter_operation {
711 AlterTableOperation::AddColumns { add_columns } => {
712 let expecteds: Vec<(Option<AddColumnLocation>, ColumnDef)> = vec![
713 (
714 Some(AddColumnLocation::After {
715 column_name: "ts".to_string(),
716 }),
717 ColumnDef {
718 name: Ident::new("tagk_i"),
719 data_type: DataType::String(None),
720 options: vec![ColumnOptionDef {
721 name: None,
722 option: ColumnOption::Null,
723 }],
724 },
725 ),
726 (
727 None,
728 ColumnDef {
729 name: Ident::new("tagl_i"),
730 data_type: DataType::String(None),
731 options: vec![],
732 },
733 ),
734 ];
735 for (add_column, expected) in add_columns
736 .iter()
737 .zip(expecteds)
738 .collect::<Vec<(&AddColumn, (Option<AddColumnLocation>, ColumnDef))>>()
739 {
740 assert_eq!(add_column.column_def, expected.1);
741 assert_eq!(&expected.0, &add_column.location);
742 }
743 }
744 _ => unreachable!(),
745 }
746 }
747 _ => unreachable!(),
748 }
749 }
750
751 #[test]
752 fn test_parse_add_column_if_not_exists() {
753 let sql = "ALTER TABLE test ADD COLUMN IF NOT EXISTS a INTEGER, ADD COLUMN b STRING, ADD COLUMN IF NOT EXISTS c INT;";
754 let mut result =
755 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
756 .unwrap();
757 assert_eq!(result.len(), 1);
758 let statement = result.remove(0);
759 assert_matches!(statement, Statement::AlterTable { .. });
760 match statement {
761 Statement::AlterTable(alter) => {
762 assert_eq!(alter.table_name.0[0].to_string(), "test");
763 assert_matches!(
764 alter.alter_operation,
765 AlterTableOperation::AddColumns { .. }
766 );
767 match alter.alter_operation {
768 AlterTableOperation::AddColumns { add_columns } => {
769 let expected = vec![
770 AddColumn {
771 column_def: ColumnDef {
772 name: Ident::new("a"),
773 data_type: DataType::Integer(None),
774 options: vec![],
775 },
776 location: None,
777 add_if_not_exists: true,
778 },
779 AddColumn {
780 column_def: ColumnDef {
781 name: Ident::new("b"),
782 data_type: DataType::String(None),
783 options: vec![],
784 },
785 location: None,
786 add_if_not_exists: false,
787 },
788 AddColumn {
789 column_def: ColumnDef {
790 name: Ident::new("c"),
791 data_type: DataType::Int(None),
792 options: vec![],
793 },
794 location: None,
795 add_if_not_exists: true,
796 },
797 ];
798 for (idx, add_column) in add_columns.into_iter().enumerate() {
799 assert_eq!(add_column, expected[idx]);
800 }
801 }
802 _ => unreachable!(),
803 }
804 }
805 _ => unreachable!(),
806 }
807 }
808
809 #[test]
810 fn test_parse_alter_drop_column() {
811 let sql = "ALTER TABLE my_metric_1 DROP a";
812 let result =
813 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
814 .unwrap_err();
815 let err = result.output_msg();
816 assert_eq!(
817 err,
818 "Invalid SQL syntax: sql parser error: Expected: COLUMN, found: a at Line: 1, Column: 30"
819 );
820
821 let sql = "ALTER TABLE my_metric_1 DROP COLUMN a";
822 let mut result =
823 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
824 .unwrap();
825 assert_eq!(1, result.len());
826
827 let statement = result.remove(0);
828 assert_matches!(statement, Statement::AlterTable { .. });
829 match statement {
830 Statement::AlterTable(alter_table) => {
831 assert_eq!("my_metric_1", alter_table.table_name().0[0].to_string());
832
833 let alter_operation = alter_table.alter_operation();
834 assert_matches!(alter_operation, AlterTableOperation::DropColumn { .. });
835 match alter_operation {
836 AlterTableOperation::DropColumn { name } => {
837 assert_eq!("a", name.value);
838 }
839 _ => unreachable!(),
840 }
841 }
842 _ => unreachable!(),
843 }
844 }
845
846 #[test]
847 fn test_parse_alter_modify_column_type() {
848 let sql_1 = "ALTER TABLE my_metric_1 MODIFY COLUMN a STRING";
849 let result_1 = ParserContext::create_with_dialect(
850 sql_1,
851 &GreptimeDbDialect {},
852 ParseOptions::default(),
853 )
854 .unwrap();
855
856 let sql_2 = "ALTER TABLE my_metric_1 MODIFY COLUMN a STRING";
857 let mut result_2 = ParserContext::create_with_dialect(
858 sql_2,
859 &GreptimeDbDialect {},
860 ParseOptions::default(),
861 )
862 .unwrap();
863 assert_eq!(result_1, result_2);
864 assert_eq!(1, result_2.len());
865
866 let statement = result_2.remove(0);
867 assert_matches!(statement, Statement::AlterTable { .. });
868 match statement {
869 Statement::AlterTable(alter_table) => {
870 assert_eq!("my_metric_1", alter_table.table_name().0[0].to_string());
871
872 let alter_operation = alter_table.alter_operation();
873 assert_matches!(
874 alter_operation,
875 AlterTableOperation::ModifyColumnType { .. }
876 );
877 match alter_operation {
878 AlterTableOperation::ModifyColumnType {
879 column_name,
880 target_type,
881 } => {
882 assert_eq!("a", column_name.value);
883 assert_eq!(DataType::String(None), *target_type);
884 }
885 _ => unreachable!(),
886 }
887 }
888 _ => unreachable!(),
889 }
890 }
891
892 #[test]
893 fn test_parse_alter_change_column_alias_type() {
894 let sql_1 = "ALTER TABLE my_metric_1 MODIFY COLUMN a MediumText";
895 let mut result_1 = ParserContext::create_with_dialect(
896 sql_1,
897 &GreptimeDbDialect {},
898 ParseOptions::default(),
899 )
900 .unwrap();
901
902 match result_1.remove(0) {
903 Statement::AlterTable(alter_table) => {
904 assert_eq!("my_metric_1", alter_table.table_name().0[0].to_string());
905
906 let alter_operation = alter_table.alter_operation();
907 assert_matches!(
908 alter_operation,
909 AlterTableOperation::ModifyColumnType { .. }
910 );
911 match alter_operation {
912 AlterTableOperation::ModifyColumnType {
913 column_name,
914 target_type,
915 } => {
916 assert_eq!("a", column_name.value);
917 assert_eq!(DataType::MediumText, *target_type);
918 }
919 _ => unreachable!(),
920 }
921 }
922 _ => unreachable!(),
923 }
924
925 let sql_2 = "ALTER TABLE my_metric_1 MODIFY COLUMN a TIMESTAMP_US";
926 let mut result_2 = ParserContext::create_with_dialect(
927 sql_2,
928 &GreptimeDbDialect {},
929 ParseOptions::default(),
930 )
931 .unwrap();
932
933 match result_2.remove(0) {
934 Statement::AlterTable(alter_table) => {
935 assert_eq!("my_metric_1", alter_table.table_name().0[0].to_string());
936
937 let alter_operation = alter_table.alter_operation();
938 assert_matches!(
939 alter_operation,
940 AlterTableOperation::ModifyColumnType { .. }
941 );
942 match alter_operation {
943 AlterTableOperation::ModifyColumnType {
944 column_name,
945 target_type,
946 } => {
947 assert_eq!("a", column_name.value);
948 assert!(matches!(target_type, DataType::Timestamp(Some(6), _)));
949 }
950 _ => unreachable!(),
951 }
952 }
953 _ => unreachable!(),
954 }
955 }
956
957 #[test]
958 fn test_parse_alter_rename_table() {
959 let sql = "ALTER TABLE test_table table_t";
960 let result =
961 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
962 .unwrap_err();
963 let err = result.output_msg();
964 assert_eq!(err, "Invalid SQL syntax: sql parser error: Expected ADD or DROP or MODIFY or RENAME or SET after ALTER TABLE, found: table_t");
965
966 let sql = "ALTER TABLE test_table RENAME table_t";
967 let mut result =
968 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
969 .unwrap();
970 assert_eq!(1, result.len());
971
972 let statement = result.remove(0);
973 assert_matches!(statement, Statement::AlterTable { .. });
974 match statement {
975 Statement::AlterTable(alter_table) => {
976 assert_eq!("test_table", alter_table.table_name().0[0].to_string());
977
978 let alter_operation = alter_table.alter_operation();
979 assert_matches!(alter_operation, AlterTableOperation::RenameTable { .. });
980 match alter_operation {
981 AlterTableOperation::RenameTable { new_table_name } => {
982 assert_eq!("table_t", new_table_name);
983 }
984 _ => unreachable!(),
985 }
986 }
987 _ => unreachable!(),
988 }
989 }
990
991 fn check_parse_alter_table_set_options(sql: &str, expected: &[(&str, &str)]) {
992 let result =
993 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
994 .unwrap();
995 assert_eq!(1, result.len());
996 let Statement::AlterTable(alter) = &result[0] else {
997 unreachable!()
998 };
999 assert_eq!("test_table", alter.table_name.0[0].to_string());
1000 let AlterTableOperation::SetTableOptions { options } = &alter.alter_operation else {
1001 unreachable!()
1002 };
1003
1004 assert_eq!(sql, alter.to_string());
1005 let res = options
1006 .iter()
1007 .map(|o| (o.key.as_str(), o.value.as_str()))
1008 .collect::<Vec<_>>();
1009 assert_eq!(expected, &res);
1010 }
1011
1012 fn check_parse_alter_table_unset_options(sql: &str, expected: &[&str]) {
1013 let result =
1014 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
1015 .unwrap();
1016 assert_eq!(1, result.len());
1017 let Statement::AlterTable(alter) = &result[0] else {
1018 unreachable!()
1019 };
1020 assert_eq!("test_table", alter.table_name.0[0].to_string());
1021 let AlterTableOperation::UnsetTableOptions { keys } = &alter.alter_operation else {
1022 unreachable!()
1023 };
1024
1025 assert_eq!(sql, alter.to_string());
1026 let res = keys.iter().map(|o| o.to_string()).collect::<Vec<_>>();
1027 assert_eq!(expected, &res);
1028 }
1029
1030 #[test]
1031 fn test_parse_alter_table_set_options() {
1032 check_parse_alter_table_set_options("ALTER TABLE test_table SET 'a'='A'", &[("a", "A")]);
1033 check_parse_alter_table_set_options(
1034 "ALTER TABLE test_table SET 'a'='A','b'='B'",
1035 &[("a", "A"), ("b", "B")],
1036 );
1037 check_parse_alter_table_set_options(
1038 "ALTER TABLE test_table SET 'a'='A','b'='B','c'='C'",
1039 &[("a", "A"), ("b", "B"), ("c", "C")],
1040 );
1041 check_parse_alter_table_set_options("ALTER TABLE test_table SET 'a'=NULL", &[("a", "")]);
1042
1043 ParserContext::create_with_dialect(
1044 "ALTER TABLE test_table SET a INTEGER",
1045 &GreptimeDbDialect {},
1046 ParseOptions::default(),
1047 )
1048 .unwrap_err();
1049 }
1050
1051 #[test]
1052 fn test_parse_alter_table_unset_options() {
1053 check_parse_alter_table_unset_options("ALTER TABLE test_table UNSET 'a'", &["a"]);
1054 check_parse_alter_table_unset_options("ALTER TABLE test_table UNSET 'a','b'", &["a", "b"]);
1055 ParserContext::create_with_dialect(
1056 "ALTER TABLE test_table UNSET a INTEGER",
1057 &GreptimeDbDialect {},
1058 ParseOptions::default(),
1059 )
1060 .unwrap_err();
1061 }
1062
1063 #[test]
1064 fn test_parse_alter_column_fulltext() {
1065 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)";
1066 let mut result =
1067 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
1068 .unwrap();
1069
1070 assert_eq!(1, result.len());
1071 let statement = result.remove(0);
1072 assert_matches!(statement, Statement::AlterTable { .. });
1073 match statement {
1074 Statement::AlterTable(alter_table) => {
1075 assert_eq!("test_table", alter_table.table_name().0[0].to_string());
1076
1077 let alter_operation = alter_table.alter_operation();
1078 match alter_operation {
1079 AlterTableOperation::SetIndex {
1080 options:
1081 SetIndexOperation::Fulltext {
1082 column_name,
1083 options,
1084 },
1085 } => {
1086 assert_eq!("a", column_name.value);
1087 assert_eq!(
1088 FulltextOptions::new_unchecked(
1089 true,
1090 FulltextAnalyzer::English,
1091 false,
1092 FulltextBackend::Bloom,
1093 1000,
1094 0.01,
1095 ),
1096 *options
1097 );
1098 }
1099 _ => unreachable!(),
1100 };
1101 }
1102 _ => unreachable!(),
1103 }
1104
1105 let sql = "ALTER TABLE test_table MODIFY COLUMN a UNSET FULLTEXT INDEX";
1106 let mut result =
1107 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
1108 .unwrap();
1109 assert_eq!(1, result.len());
1110 let statement = result.remove(0);
1111 assert_matches!(statement, Statement::AlterTable { .. });
1112 match statement {
1113 Statement::AlterTable(alter_table) => {
1114 assert_eq!("test_table", alter_table.table_name().0[0].to_string());
1115
1116 let alter_operation = alter_table.alter_operation();
1117 assert_eq!(
1118 alter_operation,
1119 &AlterTableOperation::UnsetIndex {
1120 options: UnsetIndexOperation::Fulltext {
1121 column_name: Ident::new("a"),
1122 }
1123 }
1124 );
1125 }
1126 _ => unreachable!(),
1127 }
1128
1129 let invalid_sql =
1130 "ALTER TABLE test_table MODIFY COLUMN a SET FULLTEXT INDEX WITH('abcd'='true')";
1131 let result = ParserContext::create_with_dialect(
1132 invalid_sql,
1133 &GreptimeDbDialect {},
1134 ParseOptions::default(),
1135 )
1136 .unwrap_err();
1137 let err = result.to_string();
1138 assert_eq!(
1139 err,
1140 "Invalid column option, column name: a, error: invalid FULLTEXT option: abcd"
1141 );
1142 }
1143
1144 #[test]
1145 fn test_parse_alter_column_inverted() {
1146 let sql = "ALTER TABLE test_table MODIFY COLUMN a SET INVERTED INDEX";
1147 let mut result =
1148 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
1149 .unwrap();
1150
1151 assert_eq!(1, result.len());
1152 let statement = result.remove(0);
1153 assert_matches!(statement, Statement::AlterTable { .. });
1154 match statement {
1155 Statement::AlterTable(alter_table) => {
1156 assert_eq!("test_table", alter_table.table_name().0[0].to_string());
1157
1158 let alter_operation = alter_table.alter_operation();
1159 match alter_operation {
1160 AlterTableOperation::SetIndex {
1161 options: SetIndexOperation::Inverted { column_name },
1162 } => assert_eq!("a", column_name.value),
1163 _ => unreachable!(),
1164 };
1165 }
1166 _ => unreachable!(),
1167 }
1168
1169 let sql = "ALTER TABLE test_table MODIFY COLUMN a UNSET INVERTED INDEX";
1170 let mut result =
1171 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
1172 .unwrap();
1173 assert_eq!(1, result.len());
1174 let statement = result.remove(0);
1175 assert_matches!(statement, Statement::AlterTable { .. });
1176 match statement {
1177 Statement::AlterTable(alter_table) => {
1178 assert_eq!("test_table", alter_table.table_name().0[0].to_string());
1179
1180 let alter_operation = alter_table.alter_operation();
1181 assert_eq!(
1182 alter_operation,
1183 &AlterTableOperation::UnsetIndex {
1184 options: UnsetIndexOperation::Inverted {
1185 column_name: Ident::new("a"),
1186 }
1187 }
1188 );
1189 }
1190 _ => unreachable!(),
1191 }
1192
1193 let invalid_sql = "ALTER TABLE test_table MODIFY COLUMN a SET INVERTED";
1194 ParserContext::create_with_dialect(
1195 invalid_sql,
1196 &GreptimeDbDialect {},
1197 ParseOptions::default(),
1198 )
1199 .unwrap_err();
1200 }
1201
1202 #[test]
1203 fn test_parse_alter_with_numeric_value() {
1204 for sql in [
1205 "ALTER TABLE test SET 'compaction.twcs.trigger_file_num'=8;",
1206 "ALTER TABLE test SET 'compaction.twcs.trigger_file_num'='8';",
1207 ] {
1208 let mut result = ParserContext::create_with_dialect(
1209 sql,
1210 &GreptimeDbDialect {},
1211 ParseOptions::default(),
1212 )
1213 .unwrap();
1214 assert_eq!(1, result.len());
1215
1216 let statement = result.remove(0);
1217 assert_matches!(statement, Statement::AlterTable { .. });
1218 match statement {
1219 Statement::AlterTable(alter_table) => {
1220 let alter_operation = alter_table.alter_operation();
1221 assert_matches!(alter_operation, AlterTableOperation::SetTableOptions { .. });
1222 match alter_operation {
1223 AlterTableOperation::SetTableOptions { options } => {
1224 assert_eq!(options.len(), 1);
1225 assert_eq!(options[0].key, "compaction.twcs.trigger_file_num");
1226 assert_eq!(options[0].value, "8");
1227 }
1228 _ => unreachable!(),
1229 }
1230 }
1231 _ => unreachable!(),
1232 }
1233 }
1234 }
1235
1236 #[test]
1237 fn test_parse_alter_drop_default() {
1238 let columns = vec![vec!["a"], vec!["a", "b", "c"]];
1239 for col in columns {
1240 let sql = col
1241 .iter()
1242 .map(|x| format!("MODIFY COLUMN {x} DROP DEFAULT"))
1243 .collect::<Vec<String>>()
1244 .join(",");
1245 let sql = format!("ALTER TABLE test_table {sql}");
1246 let mut result = ParserContext::create_with_dialect(
1247 &sql,
1248 &GreptimeDbDialect {},
1249 ParseOptions::default(),
1250 )
1251 .unwrap();
1252 assert_eq!(1, result.len());
1253 let statement = result.remove(0);
1254 assert_matches!(statement, Statement::AlterTable { .. });
1255 match statement {
1256 Statement::AlterTable(alter_table) => {
1257 assert_eq!(
1258 "test_table",
1259 alter_table.table_name().0[0].to_string_unquoted()
1260 );
1261 let alter_operation = alter_table.alter_operation();
1262 match alter_operation {
1263 AlterTableOperation::DropDefaults { columns } => {
1264 assert_eq!(col.len(), columns.len());
1265 for i in 0..columns.len() {
1266 assert_eq!(col[i], columns[i].0.value);
1267 }
1268 }
1269 _ => unreachable!(),
1270 }
1271 }
1272 _ => unreachable!(),
1273 }
1274 }
1275 }
1276
1277 #[test]
1278 fn test_parse_alter_set_default() {
1279 let columns = vec![vec!["a"], vec!["a", "b"], vec!["a", "b", "c"]];
1280 for col in columns {
1281 let sql = col
1282 .iter()
1283 .map(|x| format!("MODIFY COLUMN {x} SET DEFAULT 100"))
1284 .collect::<Vec<String>>()
1285 .join(",");
1286 let sql = format!("ALTER TABLE test_table {sql}");
1287 let mut result = ParserContext::create_with_dialect(
1288 &sql,
1289 &GreptimeDbDialect {},
1290 ParseOptions::default(),
1291 )
1292 .unwrap();
1293 assert_eq!(1, result.len());
1294 let statement = result.remove(0);
1295 assert_matches!(statement, Statement::AlterTable { .. });
1296 match statement {
1297 Statement::AlterTable(alter_table) => {
1298 assert_eq!("test_table", alter_table.table_name().to_string());
1299 let alter_operation = alter_table.alter_operation();
1300 match alter_operation {
1301 AlterTableOperation::SetDefaults { defaults } => {
1302 assert_eq!(col.len(), defaults.len());
1303 for i in 0..defaults.len() {
1304 assert_eq!(col[i], defaults[i].column_name.to_string());
1305 assert_eq!(
1306 "100".to_string(),
1307 defaults[i].default_constraint.to_string()
1308 );
1309 }
1310 }
1311 _ => unreachable!(),
1312 }
1313 }
1314 _ => unreachable!(),
1315 }
1316 }
1317 }
1318
1319 #[test]
1320 fn test_parse_alter_set_default_invalid() {
1321 let sql = "ALTER TABLE test_table MODIFY COLUMN a SET 100;";
1322 let result =
1323 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
1324 .unwrap_err();
1325 let err = result.output_msg();
1326 assert_eq!(err, "Invalid SQL syntax: sql parser error: Expected FULLTEXT OR INVERTED OR SKIPPING INDEX, found: 100");
1327
1328 let sql = "ALTER TABLE test_table MODIFY COLUMN a SET DEFAULT 100, b SET DEFAULT 200";
1329 let result =
1330 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
1331 .unwrap_err();
1332 let err = result.output_msg();
1333 assert_eq!(err, "Invalid SQL syntax: sql parser error: Expected: MODIFY, found: b at Line: 1, Column: 57");
1334
1335 let sql = "ALTER TABLE test_table MODIFY COLUMN a SET DEFAULT 100, MODIFY COLUMN b DROP DEFAULT 200";
1336 let result =
1337 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
1338 .unwrap_err();
1339 let err = result.output_msg();
1340 assert_eq!(
1341 err,
1342 "Invalid SQL syntax: sql parser error: Unexpected keyword, expect SET, got: `DROP`"
1343 );
1344 }
1345}