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::{BinaryOperator, Expr, Ident};
24use sqlparser::keywords::Keyword;
25use sqlparser::parser::IsOptional::Mandatory;
26use sqlparser::parser::{Parser, ParserError};
27use sqlparser::tokenizer::{Token, TokenWithSpan};
28
29use crate::ast::ObjectNamePartExt;
30use crate::error::{self, InvalidColumnOptionSnafu, Result, SetFulltextOptionSnafu};
31use crate::parser::ParserContext;
32use crate::parsers::create_parser::{INVERTED, parse_json2_type_and_options};
33use crate::parsers::utils::{
34 parse_with_options, validate_column_fulltext_create_option,
35 validate_column_skipping_index_create_option,
36};
37use crate::statements::OptionMap;
38use crate::statements::alter::{
39 AddColumn, AlterDatabase, AlterDatabaseOperation, AlterTable, AlterTableOperation,
40 DropDefaultsOperation, KeyValueOption, RepartitionOperation, SetDefaultsOperation,
41 SetIndexOperation, UnsetIndexOperation,
42};
43use crate::statements::statement::Statement;
44use crate::util::{OptionValue, parse_option_string};
45
46impl ParserContext<'_> {
47 pub(crate) fn parse_alter(&mut self) -> Result<Statement> {
48 let _ = self.parser.expect_keyword(Keyword::ALTER);
49 match self.parser.peek_token().token {
50 Token::Word(w) => match w.keyword {
51 Keyword::DATABASE => self.parse_alter_database().map(Statement::AlterDatabase),
52 Keyword::TABLE => self.parse_alter_table().map(Statement::AlterTable),
53 #[cfg(feature = "enterprise")]
54 Keyword::TRIGGER => {
55 self.parser.next_token();
56 self.parse_alter_trigger()
57 }
58 _ => self.expected("DATABASE or TABLE after ALTER", self.parser.peek_token()),
59 },
60 unexpected => self.unsupported(unexpected.to_string()),
61 }
62 }
63
64 fn parse_alter_database(&mut self) -> Result<AlterDatabase> {
65 self.parser
66 .expect_keyword(Keyword::DATABASE)
67 .context(error::SyntaxSnafu)?;
68
69 let database_name = self
70 .parser
71 .parse_object_name(false)
72 .context(error::SyntaxSnafu)?;
73 let database_name = Self::canonicalize_object_name(database_name)?;
74
75 match self.parser.peek_token().token {
76 Token::Word(w) => {
77 if w.value.eq_ignore_ascii_case("UNSET") {
78 let _ = self.parser.next_token();
79 let keys = self
80 .parser
81 .parse_comma_separated(parse_string_option_names)
82 .context(error::SyntaxSnafu)?
83 .into_iter()
84 .collect();
85 Ok(AlterDatabase::new(
86 database_name,
87 AlterDatabaseOperation::UnsetDatabaseOption { keys },
88 ))
89 } else if w.keyword == Keyword::SET {
90 let _ = self.parser.next_token();
91 let options = self
92 .parser
93 .parse_comma_separated(parse_string_options)
94 .context(error::SyntaxSnafu)?
95 .into_iter()
96 .map(|(key, value)| KeyValueOption { key, value })
97 .collect();
98 Ok(AlterDatabase::new(
99 database_name,
100 AlterDatabaseOperation::SetDatabaseOption { options },
101 ))
102 } else {
103 self.expected(
104 "SET or UNSET after ALTER DATABASE",
105 self.parser.peek_token(),
106 )
107 }
108 }
109 unexpected => self.unsupported(unexpected.to_string()),
110 }
111 }
112
113 fn parse_alter_table(&mut self) -> Result<AlterTable> {
114 self.parser
115 .expect_keyword(Keyword::TABLE)
116 .context(error::SyntaxSnafu)?;
117
118 let raw_table_name = self
119 .parser
120 .parse_object_name(false)
121 .context(error::SyntaxSnafu)?;
122 let table_name = Self::canonicalize_object_name(raw_table_name)?;
123
124 let alter_operation = match self.parser.peek_token().token {
125 Token::Word(w) => {
126 if w.value.eq_ignore_ascii_case("MODIFY") {
127 self.parse_alter_table_modify()?
128 } else if w.value.eq_ignore_ascii_case("UNSET") {
129 self.parse_alter_table_unset()?
130 } else if w.value.eq_ignore_ascii_case("REPARTITION") {
131 self.parse_alter_table_repartition()?
132 } else if w.value.eq_ignore_ascii_case("SPLIT") {
133 self.parse_alter_table_split_partition()?
134 } else if w.value.eq_ignore_ascii_case("MERGE") {
135 self.parse_alter_table_merge_partition()?
136 } else {
137 match w.keyword {
138 Keyword::PARTITION => self.parse_alter_table_partition()?,
139 Keyword::ADD => self.parse_alter_table_add()?,
140 Keyword::DROP => {
141 let _ = self.parser.next_token();
142 self.parser
143 .expect_keyword(Keyword::COLUMN)
144 .context(error::SyntaxSnafu)?;
145 let name = Self::canonicalize_identifier(
146 self.parser.parse_identifier().context(error::SyntaxSnafu)?,
147 );
148 AlterTableOperation::DropColumn { name }
149 }
150 Keyword::RENAME => {
151 let _ = self.parser.next_token();
152 let new_table_name_obj_raw =
153 self.parse_object_name().context(error::SyntaxSnafu)?;
154 let new_table_name_obj =
155 Self::canonicalize_object_name(new_table_name_obj_raw)?;
156 let new_table_name = match &new_table_name_obj.0[..] {
157 [table] => table.to_string_unquoted(),
158 _ => {
159 return Err(ParserError::ParserError(format!(
160 "expect table name, actual: {new_table_name_obj}"
161 )))
162 .context(error::SyntaxSnafu);
163 }
164 };
165 AlterTableOperation::RenameTable { new_table_name }
166 }
167 Keyword::SET => {
168 let _ = self.parser.next_token();
169 let options = self
170 .parser
171 .parse_comma_separated(parse_string_options)
172 .context(error::SyntaxSnafu)?
173 .into_iter()
174 .map(|(key, value)| KeyValueOption { key, value })
175 .collect();
176 AlterTableOperation::SetTableOptions { options }
177 }
178 _ => self.expected(
179 "ADD or DROP or MODIFY or RENAME or SET or UNSET or REPARTITION or SPLIT or MERGE or PARTITION after ALTER TABLE",
180 self.parser.peek_token(),
181 )?,
182 }
183 }
184 }
185 unexpected => self.unsupported(unexpected.to_string())?,
186 };
187
188 let options = parse_with_options(&mut self.parser)?;
189 Ok(AlterTable::new(table_name, alter_operation, options))
191 }
192
193 fn parse_alter_table_unset(&mut self) -> Result<AlterTableOperation> {
194 let _ = self.parser.next_token();
195 let keys = self
196 .parser
197 .parse_comma_separated(parse_string_option_names)
198 .context(error::SyntaxSnafu)?
199 .into_iter()
200 .collect();
201
202 Ok(AlterTableOperation::UnsetTableOptions { keys })
203 }
204
205 fn parse_alter_table_repartition(&mut self) -> Result<AlterTableOperation> {
206 let _ = self.parser.next_token();
207
208 let from_exprs = self.parse_repartition_expr_list()?;
209 let partition_columns = self.parse_optional_repartition_columns()?;
210
211 self.parser
212 .expect_keyword(Keyword::INTO)
213 .context(error::SyntaxSnafu)?;
214 let into_exprs = self.parse_repartition_expr_list()?;
215
216 if matches!(self.parser.peek_token().token, Token::Comma) {
217 return self.expected("end of REPARTITION clause", self.parser.peek_token());
218 }
219
220 Ok(AlterTableOperation::Repartition {
221 operation: match partition_columns {
222 Some(partition_columns) => RepartitionOperation::with_partition_columns(
223 from_exprs,
224 into_exprs,
225 partition_columns,
226 ),
227 None => RepartitionOperation::new(from_exprs, into_exprs),
228 },
229 })
230 }
231
232 fn parse_alter_table_partition(&mut self) -> Result<AlterTableOperation> {
233 let _ = self.parser.next_token();
234 let partitions = self.parse_partition_on_columns()?;
235 if partitions.exprs.is_empty() {
236 return Err(ParserError::ParserError(
237 "PARTITION ON COLUMNS requires at least one partition expression".to_string(),
238 ))
239 .context(error::SyntaxSnafu);
240 }
241
242 Ok(AlterTableOperation::Partition { partitions })
243 }
244
245 fn parse_alter_table_split_partition(&mut self) -> Result<AlterTableOperation> {
246 let _ = self.parser.next_token();
247 self.parser
248 .expect_keyword(Keyword::PARTITION)
249 .context(error::SyntaxSnafu)?;
250
251 let from_exprs = self.parse_repartition_expr_list()?;
252 if from_exprs.len() != 1 {
253 return self.expected(
254 "single partition expression inside SPLIT PARTITION clause",
255 self.parser.peek_token(),
256 );
257 }
258
259 let partition_columns = self.parse_optional_repartition_columns()?;
260
261 self.parser
262 .expect_keyword(Keyword::INTO)
263 .context(error::SyntaxSnafu)?;
264 let into_exprs = self.parse_repartition_expr_list()?;
265
266 if matches!(self.parser.peek_token().token, Token::Comma) {
267 return self.expected("end of SPLIT PARTITION clause", self.parser.peek_token());
268 }
269 if matches!(&self.parser.peek_token().token, Token::Word(w) if w.keyword == Keyword::ON) {
270 return self.expected("end of SPLIT PARTITION clause", self.parser.peek_token());
271 }
272
273 Ok(AlterTableOperation::Repartition {
274 operation: match partition_columns {
275 Some(partition_columns) => RepartitionOperation::with_partition_columns(
276 from_exprs,
277 into_exprs,
278 partition_columns,
279 ),
280 None => RepartitionOperation::new(from_exprs, into_exprs),
281 },
282 })
283 }
284
285 fn parse_optional_repartition_columns(&mut self) -> Result<Option<Vec<Ident>>> {
286 if !self.parser.parse_keywords(&[Keyword::ON, Keyword::COLUMNS]) {
287 return Ok(None);
288 }
289
290 let raw_column_list = self
291 .parser
292 .parse_parenthesized_column_list(Mandatory, false)
293 .context(error::SyntaxSnafu)?;
294 let column_list = raw_column_list
295 .into_iter()
296 .map(Self::canonicalize_identifier)
297 .collect();
298
299 Ok(Some(column_list))
300 }
301
302 fn parse_alter_table_merge_partition(&mut self) -> Result<AlterTableOperation> {
303 let _ = self.parser.next_token();
304 self.parser
305 .expect_keyword(Keyword::PARTITION)
306 .context(error::SyntaxSnafu)?;
307
308 let from_exprs = self.parse_repartition_expr_list()?;
309 let mut expr_iter = from_exprs.iter().cloned();
310 let Some(first) = expr_iter.next() else {
311 return self.expected(
312 "expression inside MERGE PARTITION clause",
313 self.parser.peek_token(),
314 );
315 };
316 let merged_expr = expr_iter.fold(first, |left, right| Expr::BinaryOp {
317 left: Box::new(left),
318 op: BinaryOperator::Or,
319 right: Box::new(right),
320 });
321
322 if matches!(self.parser.peek_token().token, Token::Comma) {
323 return self.expected("end of MERGE PARTITION clause", self.parser.peek_token());
324 }
325
326 Ok(AlterTableOperation::Repartition {
327 operation: RepartitionOperation::new(from_exprs, vec![merged_expr]),
328 })
329 }
330
331 fn parse_repartition_expr_list(&mut self) -> Result<Vec<Expr>> {
332 self.parser
333 .expect_token(&Token::LParen)
334 .context(error::SyntaxSnafu)?;
335
336 if matches!(self.parser.peek_token().token, Token::RParen) {
337 return self.expected(
338 "expression inside REPARTITION clause",
339 self.parser.peek_token(),
340 );
341 }
342
343 let mut exprs = Vec::new();
344 loop {
345 let expr = self.parser.parse_expr().context(error::SyntaxSnafu)?;
346 exprs.push(expr);
347
348 match self.parser.peek_token().token {
349 Token::Comma => {
350 self.parser.next_token();
351 if matches!(self.parser.peek_token().token, Token::RParen) {
352 self.parser.next_token();
353 break;
354 }
355 }
356 Token::RParen => {
357 self.parser.next_token();
358 break;
359 }
360 _ => {
361 return self.expected(
362 "comma or right parenthesis after repartition expression",
363 self.parser.peek_token(),
364 );
365 }
366 }
367 }
368
369 Ok(exprs)
370 }
371
372 fn parse_alter_table_add(&mut self) -> Result<AlterTableOperation> {
373 let _ = self.parser.next_token();
374 if let Some(constraint) = self
375 .parser
376 .parse_optional_table_constraint()
377 .context(error::SyntaxSnafu)?
378 {
379 Ok(AlterTableOperation::AddConstraint(constraint))
380 } else {
381 self.parser.prev_token();
382 let add_columns = self
383 .parser
384 .parse_comma_separated(parse_add_columns)
385 .context(error::SyntaxSnafu)?;
386 Ok(AlterTableOperation::AddColumns { add_columns })
387 }
388 }
389
390 fn parse_alter_table_drop_default(
391 &mut self,
392 column_name: Ident,
393 ) -> Result<AlterTableOperation> {
394 let drop_default = DropDefaultsOperation(column_name);
395 if self.parser.consume_token(&Token::Comma) {
396 let mut columns = self
397 .parser
398 .parse_comma_separated(parse_alter_column_drop_default)
399 .context(error::SyntaxSnafu)?;
400 columns.insert(0, drop_default);
401 Ok(AlterTableOperation::DropDefaults { columns })
402 } else {
403 Ok(AlterTableOperation::DropDefaults {
404 columns: vec![drop_default],
405 })
406 }
407 }
408
409 fn parse_alter_table_set_default(&mut self, column_name: Ident) -> Result<AlterTableOperation> {
410 let default_constraint = self.parser.parse_expr().context(error::SyntaxSnafu)?;
411 let set_default = SetDefaultsOperation {
412 column_name,
413 default_constraint,
414 };
415 if self.parser.consume_token(&Token::Comma) {
416 let mut defaults = self
417 .parser
418 .parse_comma_separated(parse_alter_column_set_default)
419 .context(error::SyntaxSnafu)?;
420 defaults.insert(0, set_default);
421 Ok(AlterTableOperation::SetDefaults { defaults })
422 } else {
423 Ok(AlterTableOperation::SetDefaults {
424 defaults: vec![set_default],
425 })
426 }
427 }
428
429 fn parse_alter_table_modify(&mut self) -> Result<AlterTableOperation> {
430 let _ = self.parser.next_token();
431 self.parser
432 .expect_keyword(Keyword::COLUMN)
433 .context(error::SyntaxSnafu)?;
434 let column_name = Self::canonicalize_identifier(
435 self.parser.parse_identifier().context(error::SyntaxSnafu)?,
436 );
437
438 match self.parser.peek_token().token {
439 Token::Word(w) => {
440 if w.value.eq_ignore_ascii_case("UNSET") {
441 self.parser.next_token();
443 self.parse_alter_column_unset_index(column_name)
444 } else if w.keyword == Keyword::SET {
445 self.parser.next_token();
447 if let Token::Word(w) = self.parser.peek_token().token
448 && matches!(w.keyword, Keyword::DEFAULT)
449 {
450 self.parser
451 .expect_keyword(Keyword::DEFAULT)
452 .context(error::SyntaxSnafu)?;
453 self.parse_alter_table_set_default(column_name)
454 } else {
455 self.parse_alter_column_set_index(column_name)
456 }
457 } else if w.keyword == Keyword::DROP {
458 self.parser.next_token();
460 self.parser
461 .expect_keyword(Keyword::DEFAULT)
462 .context(error::SyntaxSnafu)?;
463 self.parse_alter_table_drop_default(column_name)
464 } else {
465 if let Some((_, json2_options)) =
466 parse_json2_type_and_options(&mut self.parser)?
467 {
468 return Ok(AlterTableOperation::SetJsonSettings {
469 column_name,
470 json2_options,
471 });
472 }
473
474 Ok(AlterTableOperation::ModifyColumnType {
475 column_name,
476 target_type: self.parser.parse_data_type().context(error::SyntaxSnafu)?,
477 json2_options: None,
478 })
479 }
480 }
481 _ => self.expected(
482 "SET or UNSET or data type after MODIFY COLUMN",
483 self.parser.peek_token(),
484 )?,
485 }
486 }
487
488 fn parse_alter_column_unset_index(
489 &mut self,
490 column_name: Ident,
491 ) -> Result<AlterTableOperation> {
492 match self.parser.next_token() {
493 TokenWithSpan {
494 token: Token::Word(w),
495 ..
496 } if w.keyword == Keyword::FULLTEXT => {
497 self.parser
498 .expect_keyword(Keyword::INDEX)
499 .context(error::SyntaxSnafu)?;
500 Ok(AlterTableOperation::UnsetIndex {
501 options: UnsetIndexOperation::Fulltext { column_name },
502 })
503 }
504
505 TokenWithSpan {
506 token: Token::Word(w),
507 ..
508 } if w.value.eq_ignore_ascii_case(INVERTED) => {
509 self.parser
510 .expect_keyword(Keyword::INDEX)
511 .context(error::SyntaxSnafu)?;
512 Ok(AlterTableOperation::UnsetIndex {
513 options: UnsetIndexOperation::Inverted { column_name },
514 })
515 }
516
517 TokenWithSpan {
518 token: Token::Word(w),
519 ..
520 } if w.value.eq_ignore_ascii_case("SKIPPING") => {
521 self.parser
522 .expect_keyword(Keyword::INDEX)
523 .context(error::SyntaxSnafu)?;
524 Ok(AlterTableOperation::UnsetIndex {
525 options: UnsetIndexOperation::Skipping { column_name },
526 })
527 }
528 _ => self.expected(
529 format!(
530 "{:?} OR INVERTED INDEX OR SKIPPING INDEX",
531 Keyword::FULLTEXT
532 )
533 .as_str(),
534 self.parser.peek_token(),
535 ),
536 }
537 }
538
539 fn parse_alter_column_set_index(&mut self, column_name: Ident) -> Result<AlterTableOperation> {
540 match self.parser.next_token() {
541 TokenWithSpan {
542 token: Token::Word(w),
543 ..
544 } if w.keyword == Keyword::FULLTEXT => {
545 self.parser
546 .expect_keyword(Keyword::INDEX)
547 .context(error::SyntaxSnafu)?;
548 self.parse_alter_column_fulltext(column_name)
549 }
550
551 TokenWithSpan {
552 token: Token::Word(w),
553 ..
554 } if w.value.eq_ignore_ascii_case(INVERTED) => {
555 self.parser
556 .expect_keyword(Keyword::INDEX)
557 .context(error::SyntaxSnafu)?;
558 Ok(AlterTableOperation::SetIndex {
559 options: SetIndexOperation::Inverted { column_name },
560 })
561 }
562
563 TokenWithSpan {
564 token: Token::Word(w),
565 ..
566 } if w.value.eq_ignore_ascii_case("SKIPPING") => {
567 self.parser
568 .expect_keyword(Keyword::INDEX)
569 .context(error::SyntaxSnafu)?;
570 self.parse_alter_column_skipping(column_name)
571 }
572 t => self.expected(
573 format!("{:?} OR INVERTED OR SKIPPING INDEX", Keyword::FULLTEXT).as_str(),
574 t,
575 ),
576 }
577 }
578
579 fn parse_alter_column_fulltext(&mut self, column_name: Ident) -> Result<AlterTableOperation> {
580 let mut options = self
581 .parser
582 .parse_options(Keyword::WITH)
583 .context(error::SyntaxSnafu)?
584 .into_iter()
585 .map(parse_option_string)
586 .collect::<Result<HashMap<String, OptionValue>>>()?;
587
588 for key in options.keys() {
589 ensure!(
590 validate_column_fulltext_create_option(key),
591 InvalidColumnOptionSnafu {
592 name: column_name.to_string(),
593 msg: format!("invalid FULLTEXT option: {key}"),
594 }
595 );
596 }
597
598 options.insert(
599 COLUMN_FULLTEXT_CHANGE_OPT_KEY_ENABLE.to_string(),
600 "true".to_string().into(),
601 );
602
603 let options = OptionMap::new(options).into_map();
604 Ok(AlterTableOperation::SetIndex {
605 options: SetIndexOperation::Fulltext {
606 column_name,
607 options: options.try_into().context(SetFulltextOptionSnafu)?,
608 },
609 })
610 }
611
612 fn parse_alter_column_skipping(&mut self, column_name: Ident) -> Result<AlterTableOperation> {
613 let options = self
614 .parser
615 .parse_options(Keyword::WITH)
616 .context(error::SyntaxSnafu)?
617 .into_iter()
618 .map(parse_option_string)
619 .collect::<Result<Vec<_>>>()?;
620
621 for (key, _) in options.iter() {
622 ensure!(
623 validate_column_skipping_index_create_option(key),
624 InvalidColumnOptionSnafu {
625 name: column_name.to_string(),
626 msg: format!("invalid SKIPPING INDEX option: {key}"),
627 }
628 );
629 }
630
631 let options = OptionMap::new(options).into_map();
632 Ok(AlterTableOperation::SetIndex {
633 options: SetIndexOperation::Skipping {
634 column_name,
635 options: options
636 .try_into()
637 .context(error::SetSkippingIndexOptionSnafu)?,
638 },
639 })
640 }
641}
642
643fn parse_alter_column_drop_default(
644 parser: &mut Parser,
645) -> std::result::Result<DropDefaultsOperation, ParserError> {
646 parser.expect_keywords(&[Keyword::MODIFY, Keyword::COLUMN])?;
647 let column_name = ParserContext::canonicalize_identifier(parser.parse_identifier()?);
648 let t = parser.next_token();
649 match t.token {
650 Token::Word(w) if w.keyword == Keyword::DROP => {
651 parser.expect_keyword(Keyword::DEFAULT)?;
652 Ok(DropDefaultsOperation(column_name))
653 }
654 _ => Err(ParserError::ParserError(format!(
655 "Unexpected keyword, expect DROP, got: `{t}`"
656 ))),
657 }
658}
659
660fn parse_alter_column_set_default(
661 parser: &mut Parser,
662) -> std::result::Result<SetDefaultsOperation, ParserError> {
663 parser.expect_keywords(&[Keyword::MODIFY, Keyword::COLUMN])?;
664 let column_name = ParserContext::canonicalize_identifier(parser.parse_identifier()?);
665 let t = parser.next_token();
666 match t.token {
667 Token::Word(w) if w.keyword == Keyword::SET => {
668 parser.expect_keyword(Keyword::DEFAULT)?;
669 if let Ok(default_constraint) = parser.parse_expr() {
670 Ok(SetDefaultsOperation {
671 column_name,
672 default_constraint,
673 })
674 } else {
675 Err(ParserError::ParserError(format!(
676 "Invalid default value after SET DEFAULT, got: `{}`",
677 parser.peek_token()
678 )))
679 }
680 }
681 _ => Err(ParserError::ParserError(format!(
682 "Unexpected keyword, expect SET, got: `{t}`"
683 ))),
684 }
685}
686
687fn parse_string_options(parser: &mut Parser) -> std::result::Result<(String, String), ParserError> {
689 let name = parser.parse_literal_string()?;
690 parser.expect_token(&Token::Eq)?;
691 let value = if parser.parse_keyword(Keyword::NULL) {
692 "".to_string()
693 } else {
694 let next_token = parser.peek_token();
695 if let Token::Number(number_as_string, _) = next_token.token {
696 parser.advance_token();
697 number_as_string
698 } else {
699 parser.parse_literal_string().map_err(|_|{
700 ParserError::ParserError(format!("Unexpected option value for alter table statements, expect string literal, numeric literal or NULL, got: `{}`", next_token))
701 })?
702 }
703 };
704 Ok((name, value))
705}
706
707fn parse_add_columns(parser: &mut Parser) -> std::result::Result<AddColumn, ParserError> {
708 parser.expect_keyword(Keyword::ADD)?;
709 let _ = parser.parse_keyword(Keyword::COLUMN);
710 let add_if_not_exists = parser.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
711 let mut column_def = parser.parse_column_def()?;
712 column_def.name = ParserContext::canonicalize_identifier(column_def.name);
713 let location = if parser.parse_keyword(Keyword::FIRST) {
714 Some(AddColumnLocation::First)
715 } else if let Token::Word(word) = parser.peek_token().token {
716 if word.value.eq_ignore_ascii_case("AFTER") {
717 let _ = parser.next_token();
718 let name = ParserContext::canonicalize_identifier(parser.parse_identifier()?);
719 Some(AddColumnLocation::After {
720 column_name: name.value,
721 })
722 } else {
723 None
724 }
725 } else {
726 None
727 };
728 Ok(AddColumn {
729 column_def,
730 location,
731 add_if_not_exists,
732 })
733}
734
735fn parse_string_option_names(parser: &mut Parser) -> std::result::Result<String, ParserError> {
737 parser.parse_literal_string()
738}
739
740#[cfg(test)]
741mod tests {
742 use std::assert_matches;
743
744 use common_error::ext::ErrorExt;
745 use datatypes::schema::{FulltextAnalyzer, FulltextBackend, FulltextOptions};
746 use sqlparser::ast::{ColumnDef, ColumnOption, ColumnOptionDef, DataType};
747
748 use super::*;
749 use crate::ast::ObjectNamePartExt;
750 use crate::dialect::GreptimeDbDialect;
751 use crate::parser::ParseOptions;
752 use crate::statements::alter::AlterDatabaseOperation;
753
754 #[test]
755 fn test_parse_alter_database() {
756 let sql = "ALTER DATABASE test_db SET 'a'='A', 'b' = 'B'";
757 let mut result =
758 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
759 .unwrap();
760 assert_eq!(1, result.len());
761
762 let statement = result.remove(0);
763 assert_matches!(statement, Statement::AlterDatabase { .. });
764 match statement {
765 Statement::AlterDatabase(alter_database) => {
766 assert_eq!("test_db", alter_database.database_name().0[0].to_string());
767
768 let alter_operation = alter_database.alter_operation();
769 assert_matches!(
770 alter_operation,
771 AlterDatabaseOperation::SetDatabaseOption { .. }
772 );
773 match alter_operation {
774 AlterDatabaseOperation::SetDatabaseOption { options } => {
775 assert_eq!(2, options.len());
776 assert_eq!("a", options[0].key);
777 assert_eq!("A", options[0].value);
778 assert_eq!("b", options[1].key);
779 assert_eq!("B", options[1].value);
780 }
781 _ => unreachable!(),
782 }
783 }
784 _ => unreachable!(),
785 }
786 let sql = "ALTER DATABASE test_db UNSET 'a', 'b'";
787 let mut result =
788 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
789 .unwrap();
790 assert_eq!(1, result.len());
791 let statement = result.remove(0);
792 assert_matches!(statement, Statement::AlterDatabase { .. });
793 match statement {
794 Statement::AlterDatabase(alter_database) => {
795 assert_eq!("test_db", alter_database.database_name().0[0].to_string());
796 let alter_operation = alter_database.alter_operation();
797 assert_matches!(
798 alter_operation,
799 AlterDatabaseOperation::UnsetDatabaseOption { .. }
800 );
801 match alter_operation {
802 AlterDatabaseOperation::UnsetDatabaseOption { keys } => {
803 assert_eq!(2, keys.len());
804 assert_eq!("a", keys[0]);
805 assert_eq!("b", keys[1]);
806 }
807 _ => unreachable!(),
808 }
809 }
810 _ => unreachable!(),
811 }
812 }
813
814 #[test]
815 fn test_parse_alter_add_column() {
816 let sql = "ALTER TABLE my_metric_1 ADD tagk_i STRING Null;";
817 let mut result =
818 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
819 .unwrap();
820 assert_eq!(1, result.len());
821
822 let statement = result.remove(0);
823 assert_matches!(statement, Statement::AlterTable { .. });
824 match statement {
825 Statement::AlterTable(alter_table) => {
826 assert_eq!("my_metric_1", alter_table.table_name().0[0].to_string());
827
828 let alter_operation = alter_table.alter_operation();
829 assert_matches!(alter_operation, AlterTableOperation::AddColumns { .. });
830 match alter_operation {
831 AlterTableOperation::AddColumns { add_columns } => {
832 assert_eq!(add_columns.len(), 1);
833 assert_eq!("tagk_i", add_columns[0].column_def.name.value);
834 assert_eq!(DataType::String(None), add_columns[0].column_def.data_type);
835 assert!(
836 add_columns[0]
837 .column_def
838 .options
839 .iter()
840 .any(|o| matches!(o.option, ColumnOption::Null))
841 );
842 assert_eq!(&None, &add_columns[0].location);
843 }
844 _ => unreachable!(),
845 }
846 }
847 _ => unreachable!(),
848 }
849 }
850
851 #[test]
852 fn test_parse_alter_add_column_with_first() {
853 let sql = "ALTER TABLE my_metric_1 ADD tagk_i STRING Null FIRST;";
854 let mut result =
855 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
856 .unwrap();
857 assert_eq!(1, result.len());
858
859 let statement = result.remove(0);
860 assert_matches!(statement, Statement::AlterTable { .. });
861 match statement {
862 Statement::AlterTable(alter_table) => {
863 assert_eq!("my_metric_1", alter_table.table_name().0[0].to_string());
864
865 let alter_operation = alter_table.alter_operation();
866 assert_matches!(alter_operation, AlterTableOperation::AddColumns { .. });
867 match alter_operation {
868 AlterTableOperation::AddColumns { add_columns } => {
869 assert_eq!("tagk_i", add_columns[0].column_def.name.value);
870 assert_eq!(DataType::String(None), add_columns[0].column_def.data_type);
871 assert!(
872 add_columns[0]
873 .column_def
874 .options
875 .iter()
876 .any(|o| matches!(o.option, ColumnOption::Null))
877 );
878 assert_eq!(&Some(AddColumnLocation::First), &add_columns[0].location);
879 }
880 _ => unreachable!(),
881 }
882 }
883 _ => unreachable!(),
884 }
885 }
886
887 #[test]
888 fn test_parse_alter_add_column_with_after() {
889 let sql =
890 "ALTER TABLE my_metric_1 ADD tagk_i STRING Null AFTER ts, add column tagl_i String;";
891 let mut result =
892 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
893 .unwrap();
894 assert_eq!(1, result.len());
895
896 let statement = result.remove(0);
897 assert_matches!(statement, Statement::AlterTable { .. });
898 match statement {
899 Statement::AlterTable(alter_table) => {
900 assert_eq!("my_metric_1", alter_table.table_name().0[0].to_string());
901
902 let alter_operation = alter_table.alter_operation();
903 assert_matches!(alter_operation, AlterTableOperation::AddColumns { .. });
904 match alter_operation {
905 AlterTableOperation::AddColumns { add_columns } => {
906 let expecteds: Vec<(Option<AddColumnLocation>, ColumnDef)> = vec![
907 (
908 Some(AddColumnLocation::After {
909 column_name: "ts".to_string(),
910 }),
911 ColumnDef {
912 name: Ident::new("tagk_i"),
913 data_type: DataType::String(None),
914 options: vec![ColumnOptionDef {
915 name: None,
916 option: ColumnOption::Null,
917 }],
918 },
919 ),
920 (
921 None,
922 ColumnDef {
923 name: Ident::new("tagl_i"),
924 data_type: DataType::String(None),
925 options: vec![],
926 },
927 ),
928 ];
929 for (add_column, expected) in add_columns
930 .iter()
931 .zip(expecteds)
932 .collect::<Vec<(&AddColumn, (Option<AddColumnLocation>, ColumnDef))>>()
933 {
934 assert_eq!(add_column.column_def, expected.1);
935 assert_eq!(&expected.0, &add_column.location);
936 }
937 }
938 _ => unreachable!(),
939 }
940 }
941 _ => unreachable!(),
942 }
943 }
944
945 #[test]
946 fn test_parse_add_column_if_not_exists() {
947 let sql = "ALTER TABLE test ADD COLUMN IF NOT EXISTS a INTEGER, ADD COLUMN b STRING, ADD COLUMN IF NOT EXISTS c INT;";
948 let mut result =
949 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
950 .unwrap();
951 assert_eq!(result.len(), 1);
952 let statement = result.remove(0);
953 assert_matches!(statement, Statement::AlterTable { .. });
954 match statement {
955 Statement::AlterTable(alter) => {
956 assert_eq!(alter.table_name.0[0].to_string(), "test");
957 assert_matches!(
958 alter.alter_operation,
959 AlterTableOperation::AddColumns { .. }
960 );
961 match alter.alter_operation {
962 AlterTableOperation::AddColumns { add_columns } => {
963 let expected = [
964 AddColumn {
965 column_def: ColumnDef {
966 name: Ident::new("a"),
967 data_type: DataType::Integer(None),
968 options: vec![],
969 },
970 location: None,
971 add_if_not_exists: true,
972 },
973 AddColumn {
974 column_def: ColumnDef {
975 name: Ident::new("b"),
976 data_type: DataType::String(None),
977 options: vec![],
978 },
979 location: None,
980 add_if_not_exists: false,
981 },
982 AddColumn {
983 column_def: ColumnDef {
984 name: Ident::new("c"),
985 data_type: DataType::Int(None),
986 options: vec![],
987 },
988 location: None,
989 add_if_not_exists: true,
990 },
991 ];
992 for (idx, add_column) in add_columns.into_iter().enumerate() {
993 assert_eq!(add_column, expected[idx]);
994 }
995 }
996 _ => unreachable!(),
997 }
998 }
999 _ => unreachable!(),
1000 }
1001 }
1002
1003 #[test]
1004 fn test_parse_alter_table_repartition() {
1005 let sql = r#"
1006ALTER TABLE t REPARTITION (
1007 device_id < 100
1008) INTO (
1009 device_id < 100 AND area < 'South',
1010 device_id < 100 AND area >= 'South',
1011);"#;
1012 let mut result =
1013 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
1014 .unwrap();
1015 assert_eq!(1, result.len());
1016
1017 let statement = result.remove(0);
1018 assert_matches!(statement, Statement::AlterTable { .. });
1019 if let Statement::AlterTable(alter_table) = statement {
1020 assert_matches!(
1021 alter_table.alter_operation(),
1022 AlterTableOperation::Repartition { .. }
1023 );
1024
1025 if let AlterTableOperation::Repartition { operation } = alter_table.alter_operation() {
1026 assert_eq!(operation.from_exprs.len(), 1);
1027 assert_eq!(operation.from_exprs[0].to_string(), "device_id < 100");
1028 assert_eq!(operation.into_exprs.len(), 2);
1029 assert!(operation.partition_columns.is_none());
1030 assert_eq!(
1031 operation.into_exprs[0].to_string(),
1032 "device_id < 100 AND area < 'South'"
1033 );
1034 assert_eq!(
1035 operation.into_exprs[1].to_string(),
1036 "device_id < 100 AND area >= 'South'"
1037 );
1038 }
1039 }
1040 }
1041
1042 #[test]
1043 fn test_parse_alter_table_repartition_on_columns() {
1044 let sql = r#"
1045ALTER TABLE t REPARTITION (
1046 device_id < 100
1047)
1048ON COLUMNS (device_id, area)
1049INTO (
1050 device_id < 100 AND area < 'South',
1051 device_id < 100 AND area >= 'South'
1052);"#;
1053 let mut result =
1054 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
1055 .unwrap();
1056 assert_eq!(1, result.len());
1057
1058 let statement = result.remove(0);
1059 assert_matches!(statement, Statement::AlterTable { .. });
1060 if let Statement::AlterTable(alter_table) = statement {
1061 assert_matches!(
1062 alter_table.alter_operation(),
1063 AlterTableOperation::Repartition { .. }
1064 );
1065
1066 if let AlterTableOperation::Repartition { operation } = alter_table.alter_operation() {
1067 assert_eq!(operation.from_exprs.len(), 1);
1068 assert_eq!(operation.from_exprs[0].to_string(), "device_id < 100");
1069 assert_eq!(operation.into_exprs.len(), 2);
1070 assert_eq!(
1071 operation
1072 .partition_columns
1073 .as_ref()
1074 .unwrap()
1075 .iter()
1076 .map(|ident| ident.value.as_str())
1077 .collect::<Vec<_>>(),
1078 vec!["device_id", "area"]
1079 );
1080 assert_eq!(
1081 operation.to_string(),
1082 "(device_id < 100) ON COLUMNS (device_id, area) INTO (device_id < 100 AND area < 'South', device_id < 100 AND area >= 'South')"
1083 );
1084 }
1085 }
1086 }
1087
1088 #[test]
1089 fn test_parse_alter_table_repartition_on_columns_with_options() {
1090 let sql = r#"
1091ALTER TABLE t REPARTITION (
1092 device_id < 100
1093)
1094ON COLUMNS (device_id, area)
1095INTO (
1096 device_id < 100 AND area < 'South',
1097 device_id < 100 AND area >= 'South'
1098)
1099WITH (
1100 TIMEOUT = '5m',
1101 WAIT = false
1102);"#;
1103 let mut result =
1104 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
1105 .unwrap();
1106 assert_eq!(1, result.len());
1107
1108 let statement = result.remove(0);
1109 assert_matches!(statement, Statement::AlterTable { .. });
1110 if let Statement::AlterTable(alter_table) = statement {
1111 assert_matches!(
1112 alter_table.alter_operation(),
1113 AlterTableOperation::Repartition { .. }
1114 );
1115
1116 if let AlterTableOperation::Repartition { operation } = alter_table.alter_operation() {
1117 assert_eq!(
1118 operation
1119 .partition_columns
1120 .as_ref()
1121 .unwrap()
1122 .iter()
1123 .map(|ident| ident.value.as_str())
1124 .collect::<Vec<_>>(),
1125 vec!["device_id", "area"]
1126 );
1127 }
1128
1129 let options = alter_table.options().to_str_map();
1130 assert_eq!(options.get("timeout").unwrap(), &"5m");
1131 assert_eq!(options.get("wait").unwrap(), &"false");
1132 assert_eq!(options.len(), 2);
1133 }
1134 }
1135
1136 #[test]
1137 fn test_parse_alter_table_partition_on_columns() {
1138 let sql = r#"
1139ALTER TABLE sensor_readings PARTITION ON COLUMNS (device_id, area) (
1140 device_id < 100 AND area < 'South',
1141 device_id < 100 AND area >= 'South',
1142 device_id >= 100 AND area <= 'East',
1143 device_id >= 100 AND area > 'East'
1144);"#;
1145 let mut result =
1146 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
1147 .unwrap();
1148 assert_eq!(1, result.len());
1149
1150 let statement = result.remove(0);
1151 assert_matches!(statement, Statement::AlterTable { .. });
1152 if let Statement::AlterTable(alter_table) = statement {
1153 assert_matches!(
1154 alter_table.alter_operation(),
1155 AlterTableOperation::Partition { .. }
1156 );
1157
1158 if let AlterTableOperation::Partition { partitions } = alter_table.alter_operation() {
1159 assert_eq!(partitions.column_list.len(), 2);
1160 assert_eq!(partitions.column_list[0].value, "device_id");
1161 assert_eq!(partitions.column_list[1].value, "area");
1162 assert_eq!(partitions.exprs.len(), 4);
1163 assert_eq!(
1164 partitions.exprs[0].to_string(),
1165 "device_id < 100 AND area < 'South'"
1166 );
1167 assert_eq!(
1168 partitions.exprs[3].to_string(),
1169 "device_id >= 100 AND area > 'East'"
1170 );
1171 }
1172 }
1173 }
1174
1175 #[test]
1176 fn test_parse_alter_table_partition_on_columns_with_options() {
1177 let sql = r#"
1178ALTER TABLE sensor_readings PARTITION ON COLUMNS (device_id) (
1179 device_id < 100,
1180 device_id >= 100
1181) WITH (
1182 TIMEOUT = '5m',
1183 WAIT = false
1184);"#;
1185 let mut result =
1186 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
1187 .unwrap();
1188 assert_eq!(1, result.len());
1189
1190 let statement = result.remove(0);
1191 assert_matches!(statement, Statement::AlterTable { .. });
1192 if let Statement::AlterTable(alter_table) = statement {
1193 assert_matches!(
1194 alter_table.alter_operation(),
1195 AlterTableOperation::Partition { .. }
1196 );
1197 let options = alter_table.options().to_str_map();
1198 assert_eq!(options.get("timeout").unwrap(), &"5m");
1199 assert_eq!(options.get("wait").unwrap(), &"false");
1200 assert_eq!(options.len(), 2);
1201 }
1202 }
1203
1204 #[test]
1205 fn test_parse_alter_table_partition_on_columns_empty_columns() {
1206 let sql = r#"
1207ALTER TABLE sensor_readings PARTITION ON COLUMNS () (
1208 device_id < 100
1209);"#;
1210 let result =
1211 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1212
1213 assert!(result.is_err());
1214 }
1215
1216 #[test]
1217 fn test_parse_alter_table_partition_on_columns_empty_exprs() {
1218 let sql = r#"
1219ALTER TABLE sensor_readings PARTITION ON COLUMNS (device_id) ();"#;
1220 let result =
1221 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
1222 .unwrap_err();
1223
1224 assert_eq!(
1225 result.output_msg(),
1226 "Invalid SQL syntax: sql parser error: PARTITION ON COLUMNS requires at least one partition expression"
1227 );
1228 }
1229
1230 #[test]
1231 fn test_parse_alter_table_split_partition() {
1232 let sql = r#"
1233ALTER TABLE metrics SPLIT PARTITION (
1234 device_id < 100
1235) INTO (
1236 device_id < 100 AND area < 'South',
1237 device_id < 100 AND area >= 'South'
1238);"#;
1239 let mut result =
1240 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
1241 .unwrap();
1242 assert_eq!(1, result.len());
1243
1244 let statement = result.remove(0);
1245 assert_matches!(statement, Statement::AlterTable { .. });
1246 if let Statement::AlterTable(alter_table) = statement {
1247 assert_matches!(
1248 alter_table.alter_operation(),
1249 AlterTableOperation::Repartition { .. }
1250 );
1251
1252 if let AlterTableOperation::Repartition { operation } = alter_table.alter_operation() {
1253 assert_eq!(operation.from_exprs.len(), 1);
1254 assert_eq!(operation.from_exprs[0].to_string(), "device_id < 100");
1255 assert_eq!(operation.into_exprs.len(), 2);
1256 assert!(operation.partition_columns.is_none());
1257 assert_eq!(
1258 operation.into_exprs[0].to_string(),
1259 "device_id < 100 AND area < 'South'"
1260 );
1261 assert_eq!(
1262 operation.into_exprs[1].to_string(),
1263 "device_id < 100 AND area >= 'South'"
1264 );
1265 }
1266 }
1267 }
1268
1269 #[test]
1270 fn test_parse_alter_table_split_partition_on_columns() {
1271 let sql = r#"
1272ALTER TABLE metrics SPLIT PARTITION (
1273 device_id < 100
1274)
1275ON COLUMNS (device_id, area)
1276INTO (
1277 device_id < 100 AND area < 'South',
1278 device_id < 100 AND area >= 'South'
1279);"#;
1280 let mut result =
1281 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
1282 .unwrap();
1283 assert_eq!(1, result.len());
1284
1285 let statement = result.remove(0);
1286 assert_matches!(statement, Statement::AlterTable { .. });
1287 if let Statement::AlterTable(alter_table) = statement {
1288 assert_matches!(
1289 alter_table.alter_operation(),
1290 AlterTableOperation::Repartition { .. }
1291 );
1292
1293 if let AlterTableOperation::Repartition { operation } = alter_table.alter_operation() {
1294 assert_eq!(operation.from_exprs.len(), 1);
1295 assert_eq!(operation.from_exprs[0].to_string(), "device_id < 100");
1296 assert_eq!(operation.into_exprs.len(), 2);
1297 assert_eq!(
1298 operation
1299 .partition_columns
1300 .as_ref()
1301 .unwrap()
1302 .iter()
1303 .map(|ident| ident.value.as_str())
1304 .collect::<Vec<_>>(),
1305 vec!["device_id", "area"]
1306 );
1307 assert_eq!(
1308 operation.to_string(),
1309 "(device_id < 100) ON COLUMNS (device_id, area) INTO (device_id < 100 AND area < 'South', device_id < 100 AND area >= 'South')"
1310 );
1311 }
1312 }
1313 }
1314
1315 #[test]
1316 fn test_parse_alter_table_split_partition_on_columns_empty_columns() {
1317 let sql = r#"
1318ALTER TABLE metrics SPLIT PARTITION (
1319 device_id < 100
1320)
1321ON COLUMNS ()
1322INTO (
1323 device_id < 100 AND area < 'South',
1324 device_id < 100 AND area >= 'South'
1325);"#;
1326 let result =
1327 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1328
1329 assert!(result.is_err());
1330 }
1331
1332 #[test]
1333 fn test_parse_alter_table_split_partition_on_columns_wrong_order() {
1334 let sql = r#"
1335ALTER TABLE metrics SPLIT PARTITION (
1336 device_id < 100
1337)
1338INTO (
1339 device_id < 100 AND area < 'South',
1340 device_id < 100 AND area >= 'South'
1341)
1342ON COLUMNS (device_id, area);"#;
1343 let result =
1344 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
1345 .unwrap_err();
1346
1347 assert_eq!(
1348 result.output_msg(),
1349 "Invalid SQL syntax: sql parser error: Expected end of SPLIT PARTITION clause, found: ON"
1350 );
1351 }
1352
1353 #[test]
1354 fn test_parse_alter_table_merge_partition() {
1355 let sql = r#"
1356ALTER TABLE metrics MERGE PARTITION (
1357 device_id < 100,
1358 device_id >= 100
1359);"#;
1360 let mut result =
1361 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
1362 .unwrap();
1363 assert_eq!(1, result.len());
1364
1365 let statement = result.remove(0);
1366 assert_matches!(statement, Statement::AlterTable { .. });
1367 if let Statement::AlterTable(alter_table) = statement {
1368 assert_matches!(
1369 alter_table.alter_operation(),
1370 AlterTableOperation::Repartition { .. }
1371 );
1372
1373 if let AlterTableOperation::Repartition { operation } = alter_table.alter_operation() {
1374 assert_eq!(operation.from_exprs.len(), 2);
1375 assert_eq!(operation.from_exprs[0].to_string(), "device_id < 100");
1376 assert_eq!(operation.from_exprs[1].to_string(), "device_id >= 100");
1377 assert_eq!(operation.into_exprs.len(), 1);
1378 assert_eq!(
1379 operation.into_exprs[0].to_string(),
1380 "device_id < 100 OR device_id >= 100"
1381 );
1382 }
1383 }
1384 }
1385
1386 #[test]
1387 fn test_parse_alter_table_merge_partition_on_columns_rejected() {
1388 let sql = r#"
1389ALTER TABLE metrics MERGE PARTITION (
1390 device_id < 100,
1391 device_id >= 100
1392)
1393ON COLUMNS (device_id, area)
1394INTO (
1395 device_id >= 0
1396);"#;
1397 let result =
1398 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
1399 .unwrap_err();
1400
1401 assert_eq!(
1402 result.output_msg(),
1403 "SQL statement is not supported, keyword: ON"
1404 );
1405 }
1406
1407 #[test]
1408 fn test_parse_alter_table_merge_partition_with_options() {
1409 let sql = r#"
1410ALTER TABLE alter_repartition_table MERGE PARTITION (
1411 device_id < 100 AND area < 'South',
1412 device_id < 100 AND area >= 'South'
1413) WITH (
1414 TIMEOUT = '5m',
1415 WAIT = false
1416);"#;
1417 let mut result =
1418 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
1419 .unwrap();
1420 assert_eq!(1, result.len());
1421
1422 let statement = result.remove(0);
1423 assert_matches!(statement, Statement::AlterTable { .. });
1424 if let Statement::AlterTable(alter_table) = statement {
1425 assert_matches!(
1426 alter_table.alter_operation(),
1427 AlterTableOperation::Repartition { .. }
1428 );
1429
1430 if let AlterTableOperation::Repartition { operation } = alter_table.alter_operation() {
1431 assert_eq!(operation.from_exprs.len(), 2);
1432 assert_eq!(
1433 operation.from_exprs[0].to_string(),
1434 "device_id < 100 AND area < 'South'"
1435 );
1436 assert_eq!(
1437 operation.from_exprs[1].to_string(),
1438 "device_id < 100 AND area >= 'South'"
1439 );
1440 assert_eq!(operation.into_exprs.len(), 1);
1441 }
1442
1443 let options = alter_table.options().to_str_map();
1445 assert_eq!(options.get("timeout").unwrap(), &"5m");
1446 assert_eq!(options.get("wait").unwrap(), &"false");
1447 assert_eq!(options.len(), 2);
1448 }
1449 }
1450
1451 #[test]
1452 fn test_parse_alter_table_repartition_multiple() {
1453 let sql = r#"
1454ALTER TABLE metrics REPARTITION
1455(
1456 a < 10,
1457 a >= 10
1458) INTO (
1459 a < 20
1460),
1461(
1462 b < 20
1463) INTO (
1464 b < 10,
1465 b >= 10,
1466);"#;
1467
1468 let result =
1469 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
1470 .unwrap_err();
1471 assert_eq!(
1472 result.output_msg(),
1473 "Invalid SQL syntax: sql parser error: Expected end of REPARTITION clause, found: ,"
1474 );
1475 }
1476
1477 #[test]
1478 fn test_parse_alter_drop_column() {
1479 let sql = "ALTER TABLE my_metric_1 DROP a";
1480 let result =
1481 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
1482 .unwrap_err();
1483 let err = result.output_msg();
1484 assert_eq!(
1485 err,
1486 "Invalid SQL syntax: sql parser error: Expected: COLUMN, found: a at Line: 1, Column: 30"
1487 );
1488
1489 let sql = "ALTER TABLE my_metric_1 DROP COLUMN a";
1490 let mut result =
1491 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
1492 .unwrap();
1493 assert_eq!(1, result.len());
1494
1495 let statement = result.remove(0);
1496 assert_matches!(statement, Statement::AlterTable { .. });
1497 match statement {
1498 Statement::AlterTable(alter_table) => {
1499 assert_eq!("my_metric_1", alter_table.table_name().0[0].to_string());
1500
1501 let alter_operation = alter_table.alter_operation();
1502 assert_matches!(alter_operation, AlterTableOperation::DropColumn { .. });
1503 match alter_operation {
1504 AlterTableOperation::DropColumn { name } => {
1505 assert_eq!("a", name.value);
1506 }
1507 _ => unreachable!(),
1508 }
1509 }
1510 _ => unreachable!(),
1511 }
1512 }
1513
1514 #[test]
1515 fn test_parse_alter_modify_column_type() {
1516 let sql_1 = "ALTER TABLE my_metric_1 MODIFY COLUMN a STRING";
1517 let result_1 = ParserContext::create_with_dialect(
1518 sql_1,
1519 &GreptimeDbDialect {},
1520 ParseOptions::default(),
1521 )
1522 .unwrap();
1523
1524 let sql_2 = "ALTER TABLE my_metric_1 MODIFY COLUMN a STRING";
1525 let mut result_2 = ParserContext::create_with_dialect(
1526 sql_2,
1527 &GreptimeDbDialect {},
1528 ParseOptions::default(),
1529 )
1530 .unwrap();
1531 assert_eq!(result_1, result_2);
1532 assert_eq!(1, result_2.len());
1533
1534 let statement = result_2.remove(0);
1535 assert_matches!(statement, Statement::AlterTable { .. });
1536 match statement {
1537 Statement::AlterTable(alter_table) => {
1538 assert_eq!("my_metric_1", alter_table.table_name().0[0].to_string());
1539
1540 let alter_operation = alter_table.alter_operation();
1541 assert_matches!(
1542 alter_operation,
1543 AlterTableOperation::ModifyColumnType { .. }
1544 );
1545 match alter_operation {
1546 AlterTableOperation::ModifyColumnType {
1547 column_name,
1548 target_type,
1549 json2_options,
1550 } => {
1551 assert_eq!("a", column_name.value);
1552 assert_eq!(DataType::String(None), *target_type);
1553 assert!(json2_options.is_none());
1554 }
1555 _ => unreachable!(),
1556 }
1557 }
1558 _ => unreachable!(),
1559 }
1560 }
1561
1562 #[test]
1563 fn test_parse_alter_json2() {
1564 let sql = r#"ALTER TABLE application_logs
1565MODIFY COLUMN attrs JSON2 (
1566 max_auto_expanded_paths = 2000,
1567 trace_id STRING,
1568 user.id STRING,
1569 user.name STRING,
1570 request_id STRING INVERTED INDEX
1571)"#;
1572 let mut statements =
1573 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
1574 .unwrap();
1575
1576 let Statement::AlterTable(alter_table) = statements.remove(0) else {
1577 unreachable!()
1578 };
1579 let AlterTableOperation::SetJsonSettings {
1580 column_name,
1581 json2_options: Some(options),
1582 } = alter_table.alter_operation()
1583 else {
1584 unreachable!()
1585 };
1586
1587 assert_eq!("attrs", column_name.value);
1588 assert_eq!(Some(2000), options.max_auto_expanded_paths);
1589 assert_eq!(4, options.type_hints.len());
1590 assert_eq!(vec!["user", "id"], options.type_hints[1].path);
1591 assert!(options.type_hints[3].inverted_index);
1592
1593 let formatted = alter_table.to_string();
1594 let reparsed = ParserContext::create_with_dialect(
1595 &formatted,
1596 &GreptimeDbDialect {},
1597 ParseOptions::default(),
1598 )
1599 .unwrap();
1600 assert_eq!(Statement::AlterTable(alter_table), reparsed[0]);
1601
1602 let mut empty = ParserContext::create_with_dialect(
1603 "ALTER TABLE application_logs MODIFY COLUMN attrs JSON2 ()",
1604 &GreptimeDbDialect {},
1605 ParseOptions::default(),
1606 )
1607 .unwrap();
1608 let Statement::AlterTable(empty) = empty.remove(0) else {
1609 unreachable!()
1610 };
1611 let AlterTableOperation::SetJsonSettings { json2_options, .. } = empty.alter_operation()
1612 else {
1613 unreachable!()
1614 };
1615 assert!(json2_options.is_none());
1616 }
1617
1618 #[test]
1619 fn test_parse_alter_change_column_alias_type() {
1620 let sql_1 = "ALTER TABLE my_metric_1 MODIFY COLUMN a MediumText";
1621 let mut result_1 = ParserContext::create_with_dialect(
1622 sql_1,
1623 &GreptimeDbDialect {},
1624 ParseOptions::default(),
1625 )
1626 .unwrap();
1627
1628 match result_1.remove(0) {
1629 Statement::AlterTable(alter_table) => {
1630 assert_eq!("my_metric_1", alter_table.table_name().0[0].to_string());
1631
1632 let alter_operation = alter_table.alter_operation();
1633 assert_matches!(
1634 alter_operation,
1635 AlterTableOperation::ModifyColumnType { .. }
1636 );
1637 match alter_operation {
1638 AlterTableOperation::ModifyColumnType {
1639 column_name,
1640 target_type,
1641 json2_options,
1642 } => {
1643 assert_eq!("a", column_name.value);
1644 assert_eq!(DataType::MediumText, *target_type);
1645 assert!(json2_options.is_none());
1646 }
1647 _ => unreachable!(),
1648 }
1649 }
1650 _ => unreachable!(),
1651 }
1652
1653 let sql_2 = "ALTER TABLE my_metric_1 MODIFY COLUMN a TIMESTAMP_US";
1654 let mut result_2 = ParserContext::create_with_dialect(
1655 sql_2,
1656 &GreptimeDbDialect {},
1657 ParseOptions::default(),
1658 )
1659 .unwrap();
1660
1661 match result_2.remove(0) {
1662 Statement::AlterTable(alter_table) => {
1663 assert_eq!("my_metric_1", alter_table.table_name().0[0].to_string());
1664
1665 let alter_operation = alter_table.alter_operation();
1666 assert_matches!(
1667 alter_operation,
1668 AlterTableOperation::ModifyColumnType { .. }
1669 );
1670 match alter_operation {
1671 AlterTableOperation::ModifyColumnType {
1672 column_name,
1673 target_type,
1674 json2_options,
1675 } => {
1676 assert_eq!("a", column_name.value);
1677 assert!(matches!(target_type, DataType::Timestamp(Some(6), _)));
1678 assert!(json2_options.is_none());
1679 }
1680 _ => unreachable!(),
1681 }
1682 }
1683 _ => unreachable!(),
1684 }
1685 }
1686
1687 #[test]
1688 fn test_parse_alter_rename_table() {
1689 let sql = "ALTER TABLE test_table table_t";
1690 let result =
1691 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
1692 .unwrap_err();
1693 let err = result.output_msg();
1694 assert_eq!(
1695 err,
1696 "Invalid SQL syntax: sql parser error: Expected ADD or DROP or MODIFY or RENAME or SET or UNSET or REPARTITION or SPLIT or MERGE or PARTITION after ALTER TABLE, found: table_t"
1697 );
1698
1699 let sql = "ALTER TABLE test_table RENAME table_t";
1700 let mut result =
1701 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
1702 .unwrap();
1703 assert_eq!(1, result.len());
1704
1705 let statement = result.remove(0);
1706 assert_matches!(statement, Statement::AlterTable { .. });
1707 match statement {
1708 Statement::AlterTable(alter_table) => {
1709 assert_eq!("test_table", alter_table.table_name().0[0].to_string());
1710
1711 let alter_operation = alter_table.alter_operation();
1712 assert_matches!(alter_operation, AlterTableOperation::RenameTable { .. });
1713 match alter_operation {
1714 AlterTableOperation::RenameTable { new_table_name } => {
1715 assert_eq!("table_t", new_table_name);
1716 }
1717 _ => unreachable!(),
1718 }
1719 }
1720 _ => unreachable!(),
1721 }
1722 }
1723
1724 fn check_parse_alter_table_set_options(sql: &str, expected: &[(&str, &str)]) {
1725 let result =
1726 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
1727 .unwrap();
1728 assert_eq!(1, result.len());
1729 let Statement::AlterTable(alter) = &result[0] else {
1730 unreachable!()
1731 };
1732 assert_eq!("test_table", alter.table_name.0[0].to_string());
1733 let AlterTableOperation::SetTableOptions { options } = &alter.alter_operation else {
1734 unreachable!()
1735 };
1736
1737 assert_eq!(sql, alter.to_string());
1738 let res = options
1739 .iter()
1740 .map(|o| (o.key.as_str(), o.value.as_str()))
1741 .collect::<Vec<_>>();
1742 assert_eq!(expected, &res);
1743 }
1744
1745 fn check_parse_alter_table_unset_options(sql: &str, expected: &[&str]) {
1746 let result =
1747 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
1748 .unwrap();
1749 assert_eq!(1, result.len());
1750 let Statement::AlterTable(alter) = &result[0] else {
1751 unreachable!()
1752 };
1753 assert_eq!("test_table", alter.table_name.0[0].to_string());
1754 let AlterTableOperation::UnsetTableOptions { keys } = &alter.alter_operation else {
1755 unreachable!()
1756 };
1757
1758 assert_eq!(sql, alter.to_string());
1759 assert_eq!(expected, keys);
1760 }
1761
1762 #[test]
1763 fn test_parse_alter_table_set_options() {
1764 check_parse_alter_table_set_options("ALTER TABLE test_table SET 'a'='A'", &[("a", "A")]);
1765 check_parse_alter_table_set_options(
1766 "ALTER TABLE test_table SET 'a'='A','b'='B'",
1767 &[("a", "A"), ("b", "B")],
1768 );
1769 check_parse_alter_table_set_options(
1770 "ALTER TABLE test_table SET 'a'='A','b'='B','c'='C'",
1771 &[("a", "A"), ("b", "B"), ("c", "C")],
1772 );
1773 check_parse_alter_table_set_options("ALTER TABLE test_table SET 'a'=NULL", &[("a", "")]);
1774
1775 ParserContext::create_with_dialect(
1776 "ALTER TABLE test_table SET a INTEGER",
1777 &GreptimeDbDialect {},
1778 ParseOptions::default(),
1779 )
1780 .unwrap_err();
1781 }
1782
1783 #[test]
1784 fn test_parse_alter_table_unset_options() {
1785 check_parse_alter_table_unset_options("ALTER TABLE test_table UNSET 'a'", &["a"]);
1786 check_parse_alter_table_unset_options("ALTER TABLE test_table UNSET 'a','b'", &["a", "b"]);
1787 ParserContext::create_with_dialect(
1788 "ALTER TABLE test_table UNSET a INTEGER",
1789 &GreptimeDbDialect {},
1790 ParseOptions::default(),
1791 )
1792 .unwrap_err();
1793 }
1794
1795 #[test]
1796 fn test_parse_alter_column_fulltext() {
1797 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)";
1798 let mut result =
1799 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
1800 .unwrap();
1801
1802 assert_eq!(1, result.len());
1803 let statement = result.remove(0);
1804 assert_matches!(statement, Statement::AlterTable { .. });
1805 match statement {
1806 Statement::AlterTable(alter_table) => {
1807 assert_eq!("test_table", alter_table.table_name().0[0].to_string());
1808
1809 let alter_operation = alter_table.alter_operation();
1810 match alter_operation {
1811 AlterTableOperation::SetIndex {
1812 options:
1813 SetIndexOperation::Fulltext {
1814 column_name,
1815 options,
1816 },
1817 } => {
1818 assert_eq!("a", column_name.value);
1819 assert_eq!(
1820 FulltextOptions::new_unchecked(
1821 true,
1822 FulltextAnalyzer::English,
1823 false,
1824 FulltextBackend::Bloom,
1825 1000,
1826 0.01,
1827 ),
1828 *options
1829 );
1830 }
1831 _ => unreachable!(),
1832 };
1833 }
1834 _ => unreachable!(),
1835 }
1836
1837 let sql = "ALTER TABLE test_table MODIFY COLUMN a UNSET FULLTEXT INDEX";
1838 let mut result =
1839 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
1840 .unwrap();
1841 assert_eq!(1, result.len());
1842 let statement = result.remove(0);
1843 assert_matches!(statement, Statement::AlterTable { .. });
1844 match statement {
1845 Statement::AlterTable(alter_table) => {
1846 assert_eq!("test_table", alter_table.table_name().0[0].to_string());
1847
1848 let alter_operation = alter_table.alter_operation();
1849 assert_eq!(
1850 alter_operation,
1851 &AlterTableOperation::UnsetIndex {
1852 options: UnsetIndexOperation::Fulltext {
1853 column_name: Ident::new("a"),
1854 }
1855 }
1856 );
1857 }
1858 _ => unreachable!(),
1859 }
1860
1861 let invalid_sql =
1862 "ALTER TABLE test_table MODIFY COLUMN a SET FULLTEXT INDEX WITH('abcd'='true')";
1863 let result = ParserContext::create_with_dialect(
1864 invalid_sql,
1865 &GreptimeDbDialect {},
1866 ParseOptions::default(),
1867 )
1868 .unwrap_err();
1869 let err = result.to_string();
1870 assert_eq!(
1871 err,
1872 "Invalid column option, column name: a, error: invalid FULLTEXT option: abcd"
1873 );
1874 }
1875
1876 #[test]
1877 fn test_parse_alter_column_inverted() {
1878 let sql = "ALTER TABLE test_table MODIFY COLUMN a SET INVERTED INDEX";
1879 let mut result =
1880 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
1881 .unwrap();
1882
1883 assert_eq!(1, result.len());
1884 let statement = result.remove(0);
1885 assert_matches!(statement, Statement::AlterTable { .. });
1886 match statement {
1887 Statement::AlterTable(alter_table) => {
1888 assert_eq!("test_table", alter_table.table_name().0[0].to_string());
1889
1890 let alter_operation = alter_table.alter_operation();
1891 match alter_operation {
1892 AlterTableOperation::SetIndex {
1893 options: SetIndexOperation::Inverted { column_name },
1894 } => assert_eq!("a", column_name.value),
1895 _ => unreachable!(),
1896 };
1897 }
1898 _ => unreachable!(),
1899 }
1900
1901 let sql = "ALTER TABLE test_table MODIFY COLUMN a UNSET INVERTED INDEX";
1902 let mut result =
1903 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
1904 .unwrap();
1905 assert_eq!(1, result.len());
1906 let statement = result.remove(0);
1907 assert_matches!(statement, Statement::AlterTable { .. });
1908 match statement {
1909 Statement::AlterTable(alter_table) => {
1910 assert_eq!("test_table", alter_table.table_name().0[0].to_string());
1911
1912 let alter_operation = alter_table.alter_operation();
1913 assert_eq!(
1914 alter_operation,
1915 &AlterTableOperation::UnsetIndex {
1916 options: UnsetIndexOperation::Inverted {
1917 column_name: Ident::new("a"),
1918 }
1919 }
1920 );
1921 }
1922 _ => unreachable!(),
1923 }
1924
1925 let invalid_sql = "ALTER TABLE test_table MODIFY COLUMN a SET INVERTED";
1926 ParserContext::create_with_dialect(
1927 invalid_sql,
1928 &GreptimeDbDialect {},
1929 ParseOptions::default(),
1930 )
1931 .unwrap_err();
1932 }
1933
1934 #[test]
1935 fn test_parse_alter_with_numeric_value() {
1936 for sql in [
1937 "ALTER TABLE test SET 'compaction.twcs.trigger_file_num'=8;",
1938 "ALTER TABLE test SET 'compaction.twcs.trigger_file_num'='8';",
1939 ] {
1940 let mut result = ParserContext::create_with_dialect(
1941 sql,
1942 &GreptimeDbDialect {},
1943 ParseOptions::default(),
1944 )
1945 .unwrap();
1946 assert_eq!(1, result.len());
1947
1948 let statement = result.remove(0);
1949 assert_matches!(statement, Statement::AlterTable { .. });
1950 match statement {
1951 Statement::AlterTable(alter_table) => {
1952 let alter_operation = alter_table.alter_operation();
1953 assert_matches!(alter_operation, AlterTableOperation::SetTableOptions { .. });
1954 match alter_operation {
1955 AlterTableOperation::SetTableOptions { options } => {
1956 assert_eq!(options.len(), 1);
1957 assert_eq!(options[0].key, "compaction.twcs.trigger_file_num");
1958 assert_eq!(options[0].value, "8");
1959 }
1960 _ => unreachable!(),
1961 }
1962 }
1963 _ => unreachable!(),
1964 }
1965 }
1966 }
1967
1968 #[test]
1969 fn test_parse_alter_drop_default() {
1970 let columns = vec![vec!["a"], vec!["a", "b", "c"]];
1971 for col in columns {
1972 let sql = col
1973 .iter()
1974 .map(|x| format!("MODIFY COLUMN {x} DROP DEFAULT"))
1975 .collect::<Vec<String>>()
1976 .join(",");
1977 let sql = format!("ALTER TABLE test_table {sql}");
1978 let mut result = ParserContext::create_with_dialect(
1979 &sql,
1980 &GreptimeDbDialect {},
1981 ParseOptions::default(),
1982 )
1983 .unwrap();
1984 assert_eq!(1, result.len());
1985 let statement = result.remove(0);
1986 assert_matches!(statement, Statement::AlterTable { .. });
1987 match statement {
1988 Statement::AlterTable(alter_table) => {
1989 assert_eq!(
1990 "test_table",
1991 alter_table.table_name().0[0].to_string_unquoted()
1992 );
1993 let alter_operation = alter_table.alter_operation();
1994 match alter_operation {
1995 AlterTableOperation::DropDefaults { columns } => {
1996 assert_eq!(col.len(), columns.len());
1997 for i in 0..columns.len() {
1998 assert_eq!(col[i], columns[i].0.value);
1999 }
2000 }
2001 _ => unreachable!(),
2002 }
2003 }
2004 _ => unreachable!(),
2005 }
2006 }
2007 }
2008
2009 #[test]
2010 fn test_parse_alter_set_default() {
2011 let columns = vec![vec!["a"], vec!["a", "b"], vec!["a", "b", "c"]];
2012 for col in columns {
2013 let sql = col
2014 .iter()
2015 .map(|x| format!("MODIFY COLUMN {x} SET DEFAULT 100"))
2016 .collect::<Vec<String>>()
2017 .join(",");
2018 let sql = format!("ALTER TABLE test_table {sql}");
2019 let mut result = ParserContext::create_with_dialect(
2020 &sql,
2021 &GreptimeDbDialect {},
2022 ParseOptions::default(),
2023 )
2024 .unwrap();
2025 assert_eq!(1, result.len());
2026 let statement = result.remove(0);
2027 assert_matches!(statement, Statement::AlterTable { .. });
2028 match statement {
2029 Statement::AlterTable(alter_table) => {
2030 assert_eq!("test_table", alter_table.table_name().to_string());
2031 let alter_operation = alter_table.alter_operation();
2032 match alter_operation {
2033 AlterTableOperation::SetDefaults { defaults } => {
2034 assert_eq!(col.len(), defaults.len());
2035 for i in 0..defaults.len() {
2036 assert_eq!(col[i], defaults[i].column_name.to_string());
2037 assert_eq!(
2038 "100".to_string(),
2039 defaults[i].default_constraint.to_string()
2040 );
2041 }
2042 }
2043 _ => unreachable!(),
2044 }
2045 }
2046 _ => unreachable!(),
2047 }
2048 }
2049 }
2050
2051 #[test]
2052 fn test_parse_alter_set_default_invalid() {
2053 let sql = "ALTER TABLE test_table MODIFY COLUMN a SET 100;";
2054 let result =
2055 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
2056 .unwrap_err();
2057 let err = result.output_msg();
2058 assert_eq!(
2059 err,
2060 "Invalid SQL syntax: sql parser error: Expected FULLTEXT OR INVERTED OR SKIPPING INDEX, found: 100"
2061 );
2062
2063 let sql = "ALTER TABLE test_table MODIFY COLUMN a SET DEFAULT 100, b SET DEFAULT 200";
2064 let result =
2065 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
2066 .unwrap_err();
2067 let err = result.output_msg();
2068 assert_eq!(
2069 err,
2070 "Invalid SQL syntax: sql parser error: Expected: MODIFY, found: b at Line: 1, Column: 57"
2071 );
2072
2073 let sql = "ALTER TABLE test_table MODIFY COLUMN a SET DEFAULT 100, MODIFY COLUMN b DROP DEFAULT 200";
2074 let result =
2075 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
2076 .unwrap_err();
2077 let err = result.output_msg();
2078 assert_eq!(
2079 err,
2080 "Invalid SQL syntax: sql parser error: Unexpected keyword, expect SET, got: `DROP`"
2081 );
2082 }
2083}