sql/parsers/
alter_parser.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#[cfg(feature = "enterprise")]
16pub mod trigger;
17
18use std::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                    // consume the current token.
263                    self.parser.next_token();
264                    self.parse_alter_column_unset_index(column_name)
265                } else if w.keyword == Keyword::SET {
266                    // consume the current token.
267                    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                    // consume the current token.
280                    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
497/// Parses a string literal and an optional string literal value.
498fn 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
545/// Parses a comma separated list of string literals.
546fn 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}