diff --git a/src/Parsers/MySQL/ASTAlterCommand.cpp b/src/Parsers/MySQL/ASTAlterCommand.cpp index 7219b3de1d1..8fa734c9997 100644 --- a/src/Parsers/MySQL/ASTAlterCommand.cpp +++ b/src/Parsers/MySQL/ASTAlterCommand.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include namespace DB @@ -13,12 +14,37 @@ namespace DB namespace MySQLParser { +ASTPtr ASTAlterCommand::clone() const +{ + auto res = std::make_shared(*this); + res->children.clear(); + + if (index_decl) + res->set(res->index_decl, index_decl->clone()); + + if (default_expression) + res->set(res->default_expression, default_expression->clone()); + + if (additional_columns) + res->set(res->additional_columns, additional_columns->clone()); + + if (order_by_columns) + res->set(res->order_by_columns, additional_columns->clone()); + + if (properties) + res->set(res->properties, properties->clone()); + + return res; +} + bool ParserAlterCommand::parseImpl(IParser::Pos & pos, ASTPtr & node, Expected & expected) { ParserKeyword k_add("ADD"); ParserKeyword k_drop("DROP"); ParserKeyword k_alter("ALTER"); ParserKeyword k_rename("RENAME"); + ParserKeyword k_modify("MODIFY"); + ParserKeyword k_change("CHANGE"); if (k_add.ignore(pos, expected)) return parseAddCommand(pos, node, expected); @@ -28,13 +54,12 @@ bool ParserAlterCommand::parseImpl(IParser::Pos & pos, ASTPtr & node, Expected & return parseAlterCommand(pos, node, expected); else if (k_rename.ignore(pos, expected)) return parseRenameCommand(pos, node, expected); + else if (k_modify.ignore(pos, expected)) + return parseModifyCommand(pos, node, expected); + else if (k_change.ignore(pos, expected)) + return parseModifyCommand(pos, node, expected, true); else return parseOtherCommand(pos, node, expected); - - // | MODIFY [COLUMN] col_name column_definition [FIRST | AFTER col_name] - // | CHANGE [COLUMN] old_col_name new_col_name column_definition [FIRST | AFTER col_name] - - } bool ParserAlterCommand::parseAddCommand(IParser::Pos & pos, ASTPtr & node, Expected & expected) @@ -273,45 +298,89 @@ bool ParserAlterCommand::parseRenameCommand(IParser::Pos & pos, ASTPtr & node, E bool ParserAlterCommand::parseOtherCommand(IParser::Pos & pos, ASTPtr & node, Expected & expected) { - // | CONVERT TO CHARACTER SET charset_name [COLLATE collation_name] - // | [DEFAULT] CHARACTER SET [=] charset_name [COLLATE [=] collation_name] - // | LOCK [=] {DEFAULT | NONE | SHARED | EXCLUSIVE} - // | ORDER BY col_name [, col_name] ... + auto alter_command = std::make_shared(); - if (ParserKeyword("FORCE").ignore(pos, expected)) + if (ParserKeyword("ORDER BY").ignore(pos, expected)) { - /// FORCE - } - else if (ParserKeyword("ALGORITHM").ignore(pos, expected)) - { - /// ALGORITHM [=] {DEFAULT | INSTANT | INPLACE | COPY} - } - else if (ParserKeyword("WITH").ignore(pos, expected) || ParserKeyword("WITHOUT").ignore(pos, expected)) - { - /// {WITHOUT | WITH} VALIDATION - } - else if (ParserKeyword("IMPORT").ignore(pos, expected) || ParserKeyword("DISCARD").ignore(pos, expected)) - { - /// {DISCARD | IMPORT} TABLESPACE - } - else if (ParserKeyword("ENABLE").ignore(pos, expected) || ParserKeyword("DISABLE").ignore(pos, expected)) - { - /// {DISABLE | ENABLE} KEYS + /// ORDER BY col_name [, col_name] ... + ASTPtr columns; + ParserList columns_p(std::make_unique(), std::make_unique(TokenType::Comma)); + + if (!columns_p.parse(pos, columns, expected)) + return false; + + alter_command->type = ASTAlterCommand::ORDER_BY; + alter_command->set(alter_command->order_by_columns, columns); } else { - ASTPtr table_options; + ParserDeclareOption options_p{ + { + OptionDescribe("FORCE", "force", std::make_shared()), + OptionDescribe("ALGORITHM", "algorithm", std::make_shared()), + OptionDescribe("WITH VALIDATION", "validation", std::make_shared()), + OptionDescribe("WITHOUT VALIDATION", "validation", std::make_shared()), + OptionDescribe("IMPORT TABLESPACE", "import_tablespace", std::make_shared()), + OptionDescribe("DISCARD TABLESPACE", "import_tablespace", std::make_shared()), + OptionDescribe("ENABLE KEYS", "enable_keys", std::make_shared()), + OptionDescribe("DISABLE KEYS", "enable_keys", std::make_shared()), + /// TODO: with collate + OptionDescribe("CONVERT TO CHARACTER SET", "charset", std::make_shared()), + OptionDescribe("CHARACTER SET", "charset", std::make_shared()), + OptionDescribe("DEFAULT CHARACTER SET", "charset", std::make_shared()), + OptionDescribe("LOCK", "lock", std::make_shared()) + } + }; + + ASTPtr properties_options; ParserDeclareTableOptions table_options_p; - if (!table_options_p.parse(pos, table_options, expected)) + if (!options_p.parse(pos, properties_options, expected) && !table_options_p.parse(pos, properties_options, expected)) return false; - /// set. + alter_command->type = ASTAlterCommand::MODIFY_PROPERTIES; + alter_command->set(alter_command->properties, properties_options); } - return false; -} - + node = alter_command; + return true; +} + +bool ParserAlterCommand::parseModifyCommand(IParser::Pos & pos, ASTPtr & node, Expected & expected, bool exists_old_column_name) +{ + ASTPtr old_column_name; + auto alter_command = std::make_shared(); + + ParserKeyword("COLUMN").ignore(pos, expected); + if (exists_old_column_name && !ParserIdentifier().parse(pos, old_column_name, expected)) + return false; + + ASTPtr additional_column; + if (!ParserDeclareColumn().parse(pos, additional_column, expected)) + return false; + + if (ParserKeyword("FIRST").ignore(pos, expected)) + alter_command->first = true; + else if (ParserKeyword("AFTER").ignore(pos, expected)) + { + ASTPtr after_column; + ParserIdentifier identifier_p; + if (!identifier_p.parse(pos, after_column, expected)) + return false; + + alter_command->column_name = getIdentifierName(after_column); + } + + node = alter_command; + alter_command->type = ASTAlterCommand::MODIFY_COLUMN; + alter_command->set(alter_command->additional_columns, std::make_shared()); + alter_command->additional_columns->children.emplace_back(additional_column); + + if (exists_old_column_name) + alter_command->old_name = getIdentifierName(old_column_name); + + return true; +} } } diff --git a/src/Parsers/MySQL/ASTAlterCommand.h b/src/Parsers/MySQL/ASTAlterCommand.h index 8cfe77ba81c..2e7fea705b1 100644 --- a/src/Parsers/MySQL/ASTAlterCommand.h +++ b/src/Parsers/MySQL/ASTAlterCommand.h @@ -31,9 +31,9 @@ public: MODIFY_CHECK, MODIFY_COLUMN, - MODIFY_TABLE_OPTIONS, MODIFY_INDEX_VISIBLE, MODIFY_COLUMN_DEFAULT, + MODIFY_PROPERTIES, ORDER_BY, @@ -50,6 +50,8 @@ public: /// For ADD COLUMN ASTExpressionList * additional_columns; + /// For ORDER BY + ASTExpressionList * order_by_columns; bool first = false; bool index_visible = false; @@ -60,6 +62,12 @@ public: String index_name; String column_name; String constraint_name; + + IAST * properties; + + ASTPtr clone() const override; + + String getID(char delim) const override { return "AlterCommand" + (delim + std::to_string(static_cast(type))); } }; class ParserAlterCommand : public IParserBase @@ -77,6 +85,8 @@ protected: bool parseRenameCommand(Pos & pos, ASTPtr & node, Expected & expected); + bool parseModifyCommand(Pos & pos, ASTPtr & node, Expected & expected, bool exists_old_column_name = false); + bool parseOtherCommand(Pos & pos, ASTPtr & node, Expected & expected); }; diff --git a/src/Parsers/MySQL/ASTAlterQuery.cpp b/src/Parsers/MySQL/ASTAlterQuery.cpp index f97163130be..da2dc178373 100644 --- a/src/Parsers/MySQL/ASTAlterQuery.cpp +++ b/src/Parsers/MySQL/ASTAlterQuery.cpp @@ -1,11 +1,12 @@ #include #include +#include #include #include #include #include -#include +#include namespace DB { @@ -27,7 +28,7 @@ ASTPtr ASTAlterQuery::clone() const return res; } -void ASTAlterQuery::formatImpl(const IAST::FormatSettings & settings, IAST::FormatState & state, IAST::FormatStateStacked frame) const +/*void ASTAlterQuery::formatImpl(const IAST::FormatSettings & settings, IAST::FormatState & state, IAST::FormatStateStacked frame) const { frame.need_parens = false; @@ -50,7 +51,7 @@ void ASTAlterQuery::formatImpl(const IAST::FormatSettings & settings, IAST::Form frame_nested.need_parens = false; ++frame_nested.indent; // static_cast(command_list)->formatImpl(settings, state, frame_nested); -} +}*/ bool ParserAlterQuery::parseImpl(IParser::Pos & pos, ASTPtr & node, Expected & expected) { diff --git a/src/Parsers/MySQL/ASTAlterQuery.h b/src/Parsers/MySQL/ASTAlterQuery.h index a973be85b56..37f5687a456 100644 --- a/src/Parsers/MySQL/ASTAlterQuery.h +++ b/src/Parsers/MySQL/ASTAlterQuery.h @@ -22,8 +22,8 @@ public: String getID(char delim) const override { return "AlterQuery" + (delim + database) + delim + table; } -protected: - void formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override; +/*protected: + void formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override;*/ }; class ParserAlterQuery : public IParserBase diff --git a/src/Parsers/MySQL/ASTDeclareColumn.cpp b/src/Parsers/MySQL/ASTDeclareColumn.cpp index b4c49b7fe0e..66f49aed565 100644 --- a/src/Parsers/MySQL/ASTDeclareColumn.cpp +++ b/src/Parsers/MySQL/ASTDeclareColumn.cpp @@ -49,8 +49,7 @@ bool ParserDeclareColumn::parseImpl(Pos & pos, ASTPtr & node, Expected & expecte if (!ParserDataType().parse(pos, column_data_type, expected)) return false; - if (!parseColumnDeclareOptions(pos, column_options, expected)) - return false; + parseColumnDeclareOptions(pos, column_options, expected); auto declare_column = std::make_shared(); declare_column->name = getIdentifierName(column_name); @@ -68,7 +67,7 @@ bool ParserDeclareColumn::parseImpl(Pos & pos, ASTPtr & node, Expected & expecte } bool ParserDeclareColumn::parseColumnDeclareOptions(IParser::Pos & pos, ASTPtr & node, Expected & expected) { - ParserDeclareOption p_non_generate_options{ + ParserDeclareOptions p_non_generate_options{ { OptionDescribe("ZEROFILL", "zero_fill", std::make_unique()), OptionDescribe("NULL", "is_null", std::make_unique()), diff --git a/src/Parsers/MySQL/ASTDeclareIndex.cpp b/src/Parsers/MySQL/ASTDeclareIndex.cpp index ebb269e1361..f6a1cf92857 100644 --- a/src/Parsers/MySQL/ASTDeclareIndex.cpp +++ b/src/Parsers/MySQL/ASTDeclareIndex.cpp @@ -66,7 +66,7 @@ bool ParserDeclareIndex::parseImpl(IParser::Pos & pos, ASTPtr & node, Expected & ASTPtr declare_reference; ParserIndexColumn p_expression; - ParserDeclareOption p_index_options{ + ParserDeclareOptions p_index_options{ { OptionDescribe("KEY_BLOCK_SIZE", "key_block_size", std::make_unique()), OptionDescribe("USING", "index_type", std::make_unique()), diff --git a/src/Parsers/MySQL/ASTDeclareOption.cpp b/src/Parsers/MySQL/ASTDeclareOption.cpp index 188190e0a4f..6fc84d7afec 100644 --- a/src/Parsers/MySQL/ASTDeclareOption.cpp +++ b/src/Parsers/MySQL/ASTDeclareOption.cpp @@ -11,7 +11,8 @@ namespace DB namespace MySQLParser { -bool ParserDeclareOption::parseImpl(Pos & pos, ASTPtr & node, Expected & expected) +template +bool ParserDeclareOptionImpl::parseImpl(Pos & pos, ASTPtr & node, Expected & expected) { std::unordered_map changes; std::unordered_map> usage_parsers_cached; @@ -26,7 +27,7 @@ bool ParserDeclareOption::parseImpl(Pos & pos, ASTPtr & node, Expected & expecte return iterator->second; }; - while (true) + do { ASTPtr value; bool found{false}; @@ -57,9 +58,7 @@ bool ParserDeclareOption::parseImpl(Pos & pos, ASTPtr & node, Expected & expecte if (!found) break; - -// ParserToken{TokenType::Comma}.ignore(pos, expected); - } + } while (recursive); if (!changes.empty()) { @@ -69,7 +68,7 @@ bool ParserDeclareOption::parseImpl(Pos & pos, ASTPtr & node, Expected & expecte node = options_declare; } - return true; + return !changes.empty(); } ASTPtr ASTDeclareOptions::clone() const @@ -135,6 +134,10 @@ bool ParserCharsetName::parseImpl(IParser::Pos & pos, ASTPtr & node, Expected &) return false; } + +template class ParserDeclareOptionImpl; +template class ParserDeclareOptionImpl; + } } diff --git a/src/Parsers/MySQL/ASTDeclareOption.h b/src/Parsers/MySQL/ASTDeclareOption.h index fa6c25bd914..db4a40a8515 100644 --- a/src/Parsers/MySQL/ASTDeclareOption.h +++ b/src/Parsers/MySQL/ASTDeclareOption.h @@ -58,18 +58,24 @@ protected: bool parseImpl(Pos & pos, ASTPtr & node, Expected &) override; }; -class ParserDeclareOption : public IParserBase +template +class ParserDeclareOptionImpl : public IParserBase { protected: + bool recursive = recursive_; + std::vector options_collection; const char * getName() const override { return "option declaration"; } bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override; public: - ParserDeclareOption(const std::vector & options_collection_) : options_collection(options_collection_) {} + ParserDeclareOptionImpl(const std::vector & options_collection_) : options_collection(options_collection_) {} }; +using ParserDeclareOption = ParserDeclareOptionImpl; +using ParserDeclareOptions = ParserDeclareOptionImpl; + } diff --git a/src/Parsers/MySQL/ASTDeclarePartition.cpp b/src/Parsers/MySQL/ASTDeclarePartition.cpp index 68a56109e64..289fbe5eba4 100644 --- a/src/Parsers/MySQL/ASTDeclarePartition.cpp +++ b/src/Parsers/MySQL/ASTDeclarePartition.cpp @@ -75,7 +75,7 @@ bool ParserDeclarePartition::parseImpl(IParser::Pos & pos, ASTPtr & node, Expect } } - if (!ParserDeclareOption{ + if (!ParserDeclareOptions{ { OptionDescribe("ENGINE", "engine", std::make_shared()), OptionDescribe("STORAGE ENGINE", "engine", std::make_shared()), diff --git a/src/Parsers/MySQL/ASTDeclareSubPartition.cpp b/src/Parsers/MySQL/ASTDeclareSubPartition.cpp index 25c04779656..050f41697dd 100644 --- a/src/Parsers/MySQL/ASTDeclareSubPartition.cpp +++ b/src/Parsers/MySQL/ASTDeclareSubPartition.cpp @@ -23,7 +23,7 @@ bool ParserDeclareSubPartition::parseImpl(Pos & pos, ASTPtr & node, Expected & e if (!p_identifier.parse(pos, logical_name, expected)) return false; - if (!ParserDeclareOption{ + if (!ParserDeclareOptions{ { OptionDescribe("ENGINE", "engine", std::make_shared()), OptionDescribe("STORAGE ENGINE", "engine", std::make_shared()), diff --git a/src/Parsers/MySQL/ASTDeclareTableOptions.cpp b/src/Parsers/MySQL/ASTDeclareTableOptions.cpp index 6d318a20f23..5ed3dad1ae9 100644 --- a/src/Parsers/MySQL/ASTDeclareTableOptions.cpp +++ b/src/Parsers/MySQL/ASTDeclareTableOptions.cpp @@ -45,6 +45,7 @@ protected: bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override { ParserIdentifier p_identifier; + if (!p_identifier.parse(pos, node, expected)) return false; @@ -63,7 +64,7 @@ protected: bool ParserDeclareTableOptions::parseImpl(IParser::Pos & pos, ASTPtr & node, Expected & expected) { - return ParserDeclareOption{ + return ParserDeclareOptions{ { OptionDescribe("AUTO_INCREMENT", "auto_increment", std::make_shared()), OptionDescribe("AVG_ROW_LENGTH", "avg_row_length", std::make_shared()), diff --git a/src/Parsers/MySQL/tests/gtest_alter_command_parser.cpp b/src/Parsers/MySQL/tests/gtest_alter_command_parser.cpp new file mode 100644 index 00000000000..81aed23372b --- /dev/null +++ b/src/Parsers/MySQL/tests/gtest_alter_command_parser.cpp @@ -0,0 +1,258 @@ +#include +#include +#include +#include +#include +#include +#include + +using namespace DB; +using namespace DB::MySQLParser; + +ASTPtr tryParserQuery(IParser & parser, const String & query) +{ + return parseQuery(parser, query.data(), query.data() + query.size(), "", 0, 0); +} + +TEST(ParserAlterCommand, AddAlterCommand) +{ + ParserAlterCommand alter_p; + + ASTPtr ast = tryParserQuery(alter_p, "ADD column_name INT"); + EXPECT_EQ(ast->as()->type, ASTAlterCommand::ADD_COLUMN); + EXPECT_EQ(ast->as()->additional_columns->children.size(), 1); + EXPECT_EQ(ast->as()->additional_columns->children[0]->as()->name, "column_name"); + + ast = tryParserQuery(alter_p, "ADD COLUMN column_name INT"); + EXPECT_EQ(ast->as()->type, ASTAlterCommand::ADD_COLUMN); + EXPECT_EQ(ast->as()->additional_columns->children.size(), 1); + EXPECT_EQ(ast->as()->additional_columns->children[0]->as()->name, "column_name"); + + ast = tryParserQuery(alter_p, "ADD (column_name INT)"); + EXPECT_EQ(ast->as()->type, ASTAlterCommand::ADD_COLUMN); + EXPECT_EQ(ast->as()->additional_columns->children.size(), 1); + EXPECT_EQ(ast->as()->additional_columns->children[0]->as()->name, "column_name"); + + ast = tryParserQuery(alter_p, "ADD COLUMN (column_name INT, column_name_1 INT)"); + EXPECT_EQ(ast->as()->type, ASTAlterCommand::ADD_COLUMN); + EXPECT_EQ(ast->as()->additional_columns->children.size(), 2); + EXPECT_EQ(ast->as()->additional_columns->children[0]->as()->name, "column_name"); + EXPECT_EQ(ast->as()->additional_columns->children[1]->as()->name, "column_name_1"); + + ast = tryParserQuery(alter_p, "ADD INDEX (col_01, col_02(100), col_03 DESC) KEY_BLOCK_SIZE 3"); + EXPECT_EQ(ast->as()->type, ASTAlterCommand::ADD_INDEX); + EXPECT_EQ(ast->as()->index_decl->index_columns->children.size(), 3); + EXPECT_EQ(getIdentifierName(ast->as()->index_decl->index_columns->children[0]), "col_01"); + EXPECT_EQ(ast->as()->index_decl->index_columns->children[1]->as()->name, "col_02"); + EXPECT_EQ(getIdentifierName(ast->as()->index_decl->index_columns->children[2]), "col_03"); +} + +TEST(ParserAlterCommand, DropAlterCommand) +{ + ParserAlterCommand alter_p; + + ASTPtr ast = tryParserQuery(alter_p, "DROP CHECK constraint_name"); + EXPECT_EQ(ast->as()->type, ASTAlterCommand::DROP_CHECK); + EXPECT_EQ(ast->as()->constraint_name, "constraint_name"); + + ast = tryParserQuery(alter_p, "DROP CONSTRAINT constraint_name"); + EXPECT_EQ(ast->as()->type, ASTAlterCommand::DROP_CHECK); + EXPECT_EQ(ast->as()->constraint_name, "constraint_name"); + + ast = tryParserQuery(alter_p, "DROP KEY index_name"); + EXPECT_EQ(ast->as()->type, ASTAlterCommand::DROP_INDEX); + EXPECT_EQ(ast->as()->index_type, "KEY"); + EXPECT_EQ(ast->as()->index_name, "index_name"); + + ast = tryParserQuery(alter_p, "DROP INDEX index_name"); + EXPECT_EQ(ast->as()->type, ASTAlterCommand::DROP_INDEX); + EXPECT_EQ(ast->as()->index_type, "KEY"); + EXPECT_EQ(ast->as()->index_name, "index_name"); + + ast = tryParserQuery(alter_p, "DROP PRIMARY KEY"); + EXPECT_EQ(ast->as()->type, ASTAlterCommand::DROP_INDEX); + EXPECT_EQ(ast->as()->index_type, "PRIMARY_KEY"); + + ast = tryParserQuery(alter_p, "DROP FOREIGN KEY fk_symbol"); + EXPECT_EQ(ast->as()->type, ASTAlterCommand::DROP_INDEX); + EXPECT_EQ(ast->as()->index_name, "fk_symbol"); + EXPECT_EQ(ast->as()->index_type, "FOREIGN"); + + ast = tryParserQuery(alter_p, "DROP column_name"); + EXPECT_EQ(ast->as()->type, ASTAlterCommand::DROP_COLUMN); + EXPECT_EQ(ast->as()->column_name, "column_name"); + + ast = tryParserQuery(alter_p, "DROP COLUMN column_name"); + EXPECT_EQ(ast->as()->type, ASTAlterCommand::DROP_COLUMN); + EXPECT_EQ(ast->as()->column_name, "column_name"); +} + +TEST(ParserAlterCommand, AlterAlterCommand) +{ + ParserAlterCommand alter_p; + + ASTPtr ast = tryParserQuery(alter_p, "ALTER CHECK constraint_name NOT ENFORCED"); + EXPECT_EQ(ast->as()->type, ASTAlterCommand::MODIFY_CHECK); + EXPECT_TRUE(ast->as()->not_check_enforced); + EXPECT_EQ(ast->as()->constraint_name, "constraint_name"); + + ast = tryParserQuery(alter_p, "ALTER CHECK constraint_name ENFORCED"); + EXPECT_EQ(ast->as()->type, ASTAlterCommand::MODIFY_CHECK); + EXPECT_FALSE(ast->as()->not_check_enforced); + EXPECT_EQ(ast->as()->constraint_name, "constraint_name"); + + ast = tryParserQuery(alter_p, "ALTER CONSTRAINT constraint_name NOT ENFORCED"); + EXPECT_EQ(ast->as()->type, ASTAlterCommand::MODIFY_CHECK); + EXPECT_TRUE(ast->as()->not_check_enforced); + EXPECT_EQ(ast->as()->constraint_name, "constraint_name"); + + ast = tryParserQuery(alter_p, "ALTER CONSTRAINT constraint_name ENFORCED"); + EXPECT_EQ(ast->as()->type, ASTAlterCommand::MODIFY_CHECK); + EXPECT_FALSE(ast->as()->not_check_enforced); + EXPECT_EQ(ast->as()->constraint_name, "constraint_name"); + + ast = tryParserQuery(alter_p, "ALTER INDEX index_name VISIBLE"); + EXPECT_EQ(ast->as()->type, ASTAlterCommand::MODIFY_INDEX_VISIBLE); + EXPECT_TRUE(ast->as()->index_visible); + EXPECT_EQ(ast->as()->index_name, "index_name"); + + ast = tryParserQuery(alter_p, "ALTER INDEX index_name INVISIBLE"); + EXPECT_EQ(ast->as()->type, ASTAlterCommand::MODIFY_INDEX_VISIBLE); + EXPECT_FALSE(ast->as()->index_visible); + EXPECT_EQ(ast->as()->index_name, "index_name"); + + ast = tryParserQuery(alter_p, "ALTER column_name SET DEFAULT other_column"); + EXPECT_EQ(ast->as()->type, ASTAlterCommand::MODIFY_COLUMN_DEFAULT); + EXPECT_EQ(ast->as()->column_name, "column_name"); + EXPECT_EQ(getIdentifierName(ast->as()->default_expression), "other_column"); + + ast = tryParserQuery(alter_p, "ALTER column_name DROP DEFAULT"); + EXPECT_EQ(ast->as()->type, ASTAlterCommand::DROP_COLUMN_DEFAULT); + EXPECT_EQ(ast->as()->column_name, "column_name"); + + ast = tryParserQuery(alter_p, "ALTER COLUMN column_name SET DEFAULT other_column"); + EXPECT_EQ(ast->as()->type, ASTAlterCommand::MODIFY_COLUMN_DEFAULT); + EXPECT_EQ(ast->as()->column_name, "column_name"); + EXPECT_EQ(getIdentifierName(ast->as()->default_expression), "other_column"); + + ast = tryParserQuery(alter_p, "ALTER COLUMN column_name DROP DEFAULT"); + EXPECT_EQ(ast->as()->type, ASTAlterCommand::DROP_COLUMN_DEFAULT); + EXPECT_EQ(ast->as()->column_name, "column_name"); +} + +TEST(ParserAlterCommand, RenameAlterCommand) +{ + ParserAlterCommand alter_p; + + ASTPtr ast = tryParserQuery(alter_p, "RENAME COLUMN old_column_name TO new_column_name"); + EXPECT_EQ(ast->as()->type, ASTAlterCommand::RENAME_COLUMN); + EXPECT_EQ(ast->as()->old_name, "old_column_name"); + EXPECT_EQ(ast->as()->column_name, "new_column_name"); + + ast = tryParserQuery(alter_p, "RENAME KEY old_index_name TO new_index_name"); + EXPECT_EQ(ast->as()->type, ASTAlterCommand::RENAME_INDEX); + EXPECT_EQ(ast->as()->old_name, "old_index_name"); + EXPECT_EQ(ast->as()->index_name, "new_index_name"); + + ast = tryParserQuery(alter_p, "RENAME INDEX old_index_name TO new_index_name"); + EXPECT_EQ(ast->as()->type, ASTAlterCommand::RENAME_INDEX); + EXPECT_EQ(ast->as()->old_name, "old_index_name"); + EXPECT_EQ(ast->as()->index_name, "new_index_name"); + + ast = tryParserQuery(alter_p, "RENAME TO new_table_name"); + EXPECT_EQ(ast->as()->type, ASTAlterCommand::RENAME_FOREIGN); + EXPECT_EQ(ast->as()->index_name, "new_table_name"); +} + +TEST(ParserAlterCommand, ModifyAlterCommand) +{ + ParserAlterCommand alter_p; + + ASTPtr ast = tryParserQuery(alter_p, "MODIFY column_name INT"); + EXPECT_EQ(ast->as()->type, ASTAlterCommand::MODIFY_COLUMN); + EXPECT_EQ(ast->as()->column_name, ""); + EXPECT_EQ(ast->as()->old_name, ""); + EXPECT_FALSE(ast->as()->first); + EXPECT_EQ(ast->as()->additional_columns->children.size(), 1); + EXPECT_EQ(ast->as()->additional_columns->children[0]->as()->name, "column_name"); + + ast = tryParserQuery(alter_p, "MODIFY column_name INT FIRST"); + EXPECT_EQ(ast->as()->type, ASTAlterCommand::MODIFY_COLUMN); + EXPECT_EQ(ast->as()->column_name, ""); + EXPECT_EQ(ast->as()->old_name, ""); + EXPECT_TRUE(ast->as()->first); + EXPECT_EQ(ast->as()->additional_columns->children.size(), 1); + EXPECT_EQ(ast->as()->additional_columns->children[0]->as()->name, "column_name"); + + ast = tryParserQuery(alter_p, "MODIFY column_name INT AFTER other_column_name"); + EXPECT_EQ(ast->as()->type, ASTAlterCommand::MODIFY_COLUMN); + EXPECT_EQ(ast->as()->old_name, ""); + EXPECT_FALSE(ast->as()->first); + EXPECT_EQ(ast->as()->column_name, "other_column_name"); + EXPECT_EQ(ast->as()->additional_columns->children.size(), 1); + EXPECT_EQ(ast->as()->additional_columns->children[0]->as()->name, "column_name"); + + ast = tryParserQuery(alter_p, "MODIFY COLUMN column_name INT AFTER other_column_name"); + EXPECT_EQ(ast->as()->type, ASTAlterCommand::MODIFY_COLUMN); + EXPECT_EQ(ast->as()->old_name, ""); + EXPECT_FALSE(ast->as()->first); + EXPECT_EQ(ast->as()->column_name, "other_column_name"); + EXPECT_EQ(ast->as()->additional_columns->children.size(), 1); + EXPECT_EQ(ast->as()->additional_columns->children[0]->as()->name, "column_name"); +} + +TEST(ParserAlterCommand, ChangeAlterCommand) +{ + ParserAlterCommand alter_p; + + ASTPtr ast = tryParserQuery(alter_p, "CHANGE old_column_name new_column_name INT"); + EXPECT_EQ(ast->as()->type, ASTAlterCommand::MODIFY_COLUMN); + EXPECT_FALSE(ast->as()->first); + EXPECT_EQ(ast->as()->column_name, ""); + EXPECT_EQ(ast->as()->old_name, "old_column_name"); + EXPECT_EQ(ast->as()->additional_columns->children.size(), 1); + EXPECT_EQ(ast->as()->additional_columns->children[0]->as()->name, "new_column_name"); + + ast = tryParserQuery(alter_p, "CHANGE old_column_name new_column_name INT FIRST"); + EXPECT_EQ(ast->as()->type, ASTAlterCommand::MODIFY_COLUMN); + EXPECT_TRUE(ast->as()->first); + EXPECT_EQ(ast->as()->column_name, ""); + EXPECT_EQ(ast->as()->old_name, "old_column_name"); + EXPECT_EQ(ast->as()->additional_columns->children.size(), 1); + EXPECT_EQ(ast->as()->additional_columns->children[0]->as()->name, "new_column_name"); + + ast = tryParserQuery(alter_p, "CHANGE old_column_name new_column_name INT AFTER other_column_name"); + EXPECT_EQ(ast->as()->type, ASTAlterCommand::MODIFY_COLUMN); + EXPECT_FALSE(ast->as()->first); + EXPECT_EQ(ast->as()->column_name, "other_column_name"); + EXPECT_EQ(ast->as()->old_name, "old_column_name"); + EXPECT_EQ(ast->as()->additional_columns->children.size(), 1); + EXPECT_EQ(ast->as()->additional_columns->children[0]->as()->name, "new_column_name"); + + ast = tryParserQuery(alter_p, "CHANGE COLUMN old_column_name new_column_name INT AFTER other_column_name"); + EXPECT_EQ(ast->as()->type, ASTAlterCommand::MODIFY_COLUMN); + EXPECT_FALSE(ast->as()->first); + EXPECT_EQ(ast->as()->column_name, "other_column_name"); + EXPECT_EQ(ast->as()->old_name, "old_column_name"); + EXPECT_EQ(ast->as()->additional_columns->children.size(), 1); + EXPECT_EQ(ast->as()->additional_columns->children[0]->as()->name, "new_column_name"); +} + +TEST(ParserAlterCommand, AlterOptionsCommand) +{ + ParserAlterCommand alter_p; + + ASTPtr ast = tryParserQuery(alter_p, "ALGORITHM DEFAULT"); + EXPECT_EQ(ast->as()->type, ASTAlterCommand::MODIFY_PROPERTIES); + EXPECT_EQ(ast->as()->properties->as()->changes.size(), 1); + EXPECT_EQ(getIdentifierName(ast->as()->properties->as()->changes["algorithm"]), "DEFAULT"); + + ast = tryParserQuery(alter_p, "AUTO_INCREMENT 1 CHECKSUM 1"); + EXPECT_EQ(ast->as()->type, ASTAlterCommand::MODIFY_PROPERTIES); + EXPECT_EQ(ast->as()->properties->as()->changes.size(), 2); + EXPECT_EQ(ast->as()->properties->as()->changes["checksum"]->as()->value.safeGet(), 1); + EXPECT_EQ(ast->as()->properties->as()->changes["auto_increment"]->as()->value.safeGet(), 1); + + EXPECT_THROW(tryParserQuery(alter_p, "ALGORITHM DEFAULT AUTO_INCREMENT 1"), Exception); +} +