ISSUES-4006 support parse MySQL create query

This commit is contained in:
zhang2014 2020-04-29 02:36:43 +08:00
parent 5f80db7569
commit c53a48fe01
42 changed files with 2868 additions and 44 deletions

View File

@ -144,6 +144,7 @@ add_object_library(clickhouse_compression Compression)
add_object_library(clickhouse_datastreams DataStreams)
add_object_library(clickhouse_datatypes DataTypes)
add_object_library(clickhouse_databases Databases)
add_object_library(clickhouse_databases_mysql Databases/MySQL)
add_object_library(clickhouse_disks Disks)
add_object_library(clickhouse_interpreters Interpreters)
add_object_library(clickhouse_interpreters_clusterproxy Interpreters/ClusterProxy)

View File

@ -1,16 +1,17 @@
#include <Databases/DatabaseFactory.h>
#include <Databases/DatabaseAtomic.h>
#include <Databases/DatabaseDictionary.h>
#include <Databases/DatabaseFactory.h>
#include <Databases/DatabaseLazy.h>
#include <Databases/DatabaseMemory.h>
#include <Databases/DatabaseOrdinary.h>
#include <Databases/MySQL/createMySQLDatabase.h>
#include <Parsers/ASTLiteral.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/formatAST.h>
#include <Parsers/ASTCreateQuery.h>
#include <Parsers/ASTFunction.h>
#include <Common/parseAddress.h>
#include "DatabaseFactory.h"
#include <Poco/File.h>
#include <Poco/Path.h>
@ -18,12 +19,6 @@
# include "config_core.h"
#endif
#if USE_MYSQL
# include <Databases/DatabaseMySQL.h>
# include <Interpreters/evaluateConstantExpression.h>
#endif
namespace DB
{
@ -94,42 +89,8 @@ DatabasePtr DatabaseFactory::getImpl(const ASTCreateQuery & create, const String
return std::make_shared<DatabaseDictionary>(database_name, context);
#if USE_MYSQL
else if (engine_name == "MySQL")
{
const ASTFunction * engine = engine_define->engine;
if (!engine->arguments || engine->arguments->children.size() != 4)
throw Exception("MySQL Database require mysql_hostname, mysql_database_name, mysql_username, mysql_password arguments.",
ErrorCodes::BAD_ARGUMENTS);
ASTs & arguments = engine->arguments->children;
arguments[1] = evaluateConstantExpressionOrIdentifierAsLiteral(arguments[1], context);
const auto & host_name_and_port = safeGetLiteralValue<String>(arguments[0], "MySQL");
const auto & database_name_in_mysql = safeGetLiteralValue<String>(arguments[1], "MySQL");
const auto & mysql_user_name = safeGetLiteralValue<String>(arguments[2], "MySQL");
const auto & mysql_user_password = safeGetLiteralValue<String>(arguments[3], "MySQL");
try
{
const auto & [remote_host_name, remote_port] = parseAddress(host_name_and_port, 3306);
auto mysql_pool = mysqlxx::Pool(database_name_in_mysql, remote_host_name, mysql_user_name, mysql_user_password, remote_port);
auto mysql_database = std::make_shared<DatabaseMySQL>(
context, database_name, metadata_path, engine_define, database_name_in_mysql, std::move(mysql_pool));
mysql_database->empty(); /// test database is works fine.
return mysql_database;
}
catch (...)
{
const auto & exception_message = getCurrentExceptionMessage(true);
throw Exception("Cannot create MySQL database, because " + exception_message, ErrorCodes::CANNOT_CREATE_DATABASE);
}
}
return createMySQLDatabase(database_name, metadata_path, engine_define, context);
#endif
else if (engine_name == "Lazy")

View File

@ -0,0 +1,97 @@
//#include <Databases/MySQL/DatabaseMaterializeMySQL.h>
//
//#include <Common/quoteString.h>
//#include <Interpreters/Context.h>
//#include <DataTypes/DataTypeString.h>
//#include <DataTypes/DataTypesNumber.h>
//#include <Formats/MySQLBlockInputStream.h>
//#include <Databases/MySQL/MasterStatusInfo.h>
//#include <IO/Operators.h>
//
//namespace DB
//{
//
//static MasterStatusInfo fetchMasterStatus(const mysqlxx::PoolWithFailover::Entry & connection)
//{
// Block header
// {
// {std::make_shared<DataTypeString>(), "File"},
// {std::make_shared<DataTypeUInt64>(), "Position"},
// {std::make_shared<DataTypeString>(), "Binlog_Do_DB"},
// {std::make_shared<DataTypeString>(), "Binlog_Ignore_DB"},
// {std::make_shared<DataTypeString>(), "Executed_Gtid_Set"},
// };
//
// MySQLBlockInputStream input(connection, "SHOW MASTER STATUS;", header, DEFAULT_BLOCK_SIZE);
// Block master_status = input.read();
//
// if (!master_status || master_status.rows() != 1)
// throw Exception("Unable to get master status from MySQL.", ErrorCodes::LOGICAL_ERROR);
//
// return MasterStatusInfo
// {
// (*master_status.getByPosition(0).column)[0].safeGet<String>(),
// (*master_status.getByPosition(1).column)[0].safeGet<UInt64>(),
// (*master_status.getByPosition(2).column)[0].safeGet<String>(),
// (*master_status.getByPosition(3).column)[0].safeGet<String>(),
// (*master_status.getByPosition(4).column)[0].safeGet<String>()
// };
//}
//
//static std::vector<String> fetchTablesInDB(const mysqlxx::PoolWithFailover::Entry & connection, const std::string & database)
//{
// Block header{{std::make_shared<DataTypeString>(), "table_name"}};
// String query = "SELECT TABLE_NAME AS table_name FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = " + quoteString(database);
//
// std::vector<String> tables_in_db;
// MySQLBlockInputStream input(connection, query, header, DEFAULT_BLOCK_SIZE);
//
// while (Block block = input.read())
// {
// tables_in_db.reserve(tables_in_db.size() + block.rows());
// for (size_t index = 0; index < block.rows(); ++index)
// tables_in_db.emplace_back((*block.getByPosition(0).column)[index].safeGet<String>());
// }
//
// return tables_in_db;
//}
//
//DatabaseMaterializeMySQL::DatabaseMaterializeMySQL(
// const Context & context, const String & database_name_, const String & metadata_path_,
// const ASTStorage * database_engine_define_, const String & mysql_database_name_, mysqlxx::Pool && pool_)
// : IDatabase(database_name_)
// , global_context(context.getGlobalContext()), metadata_path(metadata_path_)
// , database_engine_define(database_engine_define_->clone()), mysql_database_name(mysql_database_name_), pool(std::move(pool_))
//{
// try
// {
// mysqlxx::PoolWithFailover::Entry connection = pool.get();
//
// connection->query("FLUSH TABLES;").execute();
// connection->query("FLUSH TABLES WITH READ LOCK;").execute();
//
// MasterStatusInfo master_status = fetchMasterStatus(connection);
// connection->query("SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;").execute();
// connection->query("START TRANSACTION /*!40100 WITH CONSISTENT SNAPSHOT */;").execute();
//
// std::vector<String> tables_in_db = fetchTablesInDB(connection, mysql_database_name);
// connection->query("UNLOCK TABLES;");
//
// for (const auto & dumping_table_name : tables_in_db)
// {
// /// TODO: 查询表结构, 根据不同的模式创建对应的表(暂时只支持多version即可)
//// connection->query("SHOW CREATE TABLE " + doubleQuoteString())
// MySQLBlockInputStream input(
// "SELECT * FROM " + backQuoteIfNeed(mysql_database_name) + "." + backQuoteIfNeed(dumping_table_name));
// /// TODO: 查询所有数据写入对应表中(全量dump)
// /// TODO: 启动slave, 监听事件
// }
// }
// catch (...)
// {
// throw;
// }
//}
//
//
//}

View File

@ -0,0 +1,30 @@
//#pragma once
//
//#include <DataTypes/DataTypeString.h>
//#include <DataTypes/DataTypesNumber.h>
//#include <Databases/IDatabase.h>
//#include <Parsers/ASTCreateQuery.h>
//#include <mysqlxx/Pool.h>
//
//namespace DB
//{
//
//class DatabaseMaterializeMySQL : public IDatabase
//{
//public:
// DatabaseMaterializeMySQL(
// const Context & context, const String & database_name_, const String & metadata_path_,
// const ASTStorage * database_engine_define_, const String & mysql_database_name_, mysqlxx::Pool && pool_);
//
// String getEngineName() const override { return "MySQL"; }
//
//private:
// const Context & global_context;
// String metadata_path;
// ASTPtr database_engine_define;
// String mysql_database_name;
//
// mutable mysqlxx::Pool pool;
//};
//
//}

View File

@ -9,7 +9,7 @@
# include <DataTypes/DataTypeString.h>
# include <DataTypes/DataTypesNumber.h>
# include <DataTypes/convertMySQLDataType.h>
# include <Databases/DatabaseMySQL.h>
# include <Databases/MySQL/DatabaseMySQL.h>
# include <Formats/MySQLBlockInputStream.h>
# include <IO/Operators.h>
# include <Parsers/ASTCreateQuery.h>
@ -70,6 +70,7 @@ DatabaseMySQL::DatabaseMySQL(
, database_name_in_mysql(database_name_in_mysql_)
, mysql_pool(std::move(pool))
{
empty(); /// test database is works fine.
}
bool DatabaseMySQL::empty() const

View File

@ -0,0 +1,6 @@
#include <Databases/MySQL/MasterStatusInfo.h>
namespace DB
{
}

View File

@ -0,0 +1,27 @@
#pragma once
#include <Core/Types.h>
#include <mysqlxx/Connection.h>
namespace DB
{
struct MasterStatusInfo
{
String binlog_file;
UInt64 binlog_position;
String binlog_do_db;
String binlog_ignore_db;
String executed_gtid_set;
MasterStatusInfo(
String binlog_file_, UInt64 binlog_position_, String binlog_do_db_, String binlog_ignore_db_, String executed_gtid_set_);
};
std::shared_ptr<MasterStatusInfo> fetchMasterStatusInfo(mysqlxx::Connection * connection);
}

View File

@ -0,0 +1,84 @@
#include <Databases/MySQL/createMySQLDatabase.h>
#if USE_MYSQL
#include <Core/Types.h>
#include <Common/parseAddress.h>
#include <Common/SettingsChanges.h>
#include <Databases/MySQL/DatabaseMySQL.h>
#include <Databases/MySQL/DatabaseMaterializeMySQL.h>
#include <mysqlxx/Pool.h>
#include <Parsers/ASTFunction.h>
#include <Interpreters/evaluateConstantExpression.h>
namespace DB
{
namespace ErrorCodes
{
extern const int BAD_ARGUMENTS;
extern const int CANNOT_CREATE_DATABASE;
}
static inline String safeGetLiteralValue(const ASTPtr & ast)
{
if (!ast || !ast->as<ASTLiteral>())
throw Exception("Database engine MySQL requested literal argument.", ErrorCodes::BAD_ARGUMENTS);
return ast->as<ASTLiteral>()->value.safeGet<String>();
}
/*static inline bool materializeMySQLDatabase(const ASTSetQuery * settings)
{
if (!settings || settings->changes.empty())
return false;
for (const auto & change : settings->changes)
{
if (change.name == "materialize_data")
{
if (change.value.getType() == Field::Types::String)
return change.value.safeGet<String>() == "true"; ///TODO: ignore case
}
}
return false;
}*/
DatabasePtr createMySQLDatabase(const String & database_name, const String & metadata_path, const ASTStorage * define, Context & context)
{
const ASTFunction * engine = define->engine;
if (!engine->arguments || engine->arguments->children.size() != 4)
throw Exception( "MySQL Database require mysql_hostname, mysql_database_name, mysql_username, mysql_password arguments.",
ErrorCodes::BAD_ARGUMENTS);
ASTs & arguments = engine->arguments->children;
arguments[1] = evaluateConstantExpressionOrIdentifierAsLiteral(arguments[1], context);
const auto & host_name_and_port = safeGetLiteralValue(arguments[0]);
const auto & mysql_database_name = safeGetLiteralValue(arguments[1]);
const auto & mysql_user_name = safeGetLiteralValue(arguments[2]);
const auto & mysql_user_password = safeGetLiteralValue(arguments[3]);
try
{
const auto & [remote_host_name, remote_port] = parseAddress(host_name_and_port, 3306);
auto mysql_pool = mysqlxx::Pool(mysql_database_name, remote_host_name, mysql_user_name, mysql_user_password, remote_port);
/*if (materializeMySQLDatabase(define->settings))
return std::make_shared<DatabaseMaterializeMySQL>(
context, database_name, metadata_path, define, mysql_database_name, std::move(mysql_pool));*/
return std::make_shared<DatabaseMySQL>(context, database_name, metadata_path, define, mysql_database_name, std::move(mysql_pool));
}
catch (...)
{
const auto & exception_message = getCurrentExceptionMessage(true);
throw Exception("Cannot create MySQL database, because " + exception_message, ErrorCodes::CANNOT_CREATE_DATABASE);
}
}
}
#endif

View File

@ -0,0 +1,19 @@
#pragma once
#if !defined(ARCADIA_BUILD)
# include "config_core.h"
#endif
#if USE_MYSQL
#include <Databases/IDatabase.h>
#include <Parsers/ASTCreateQuery.h>
namespace DB
{
DatabasePtr createMySQLDatabase(const String & database_name, const String & metadata_path, const ASTStorage * define, Context & context);
}
#endif

View File

@ -1,5 +1,6 @@
include(${ClickHouse_SOURCE_DIR}/cmake/dbms_glob_sources.cmake)
add_headers_and_sources(clickhouse_parsers .)
add_headers_and_sources(clickhouse_parsers ./MySQL)
add_library(clickhouse_parsers ${clickhouse_parsers_headers} ${clickhouse_parsers_sources})
target_link_libraries(clickhouse_parsers PUBLIC clickhouse_common_io)

View File

@ -0,0 +1,95 @@
#include <Parsers/CommonParsers.h>
#include <Parsers/ExpressionListParsers.h>
#include <Parsers/MySQL/ASTCreateDefines.h>
#include <Parsers/MySQL/ASTDeclareIndex.h>
#include <Parsers/MySQL/ASTDeclareColumn.h>
#include <Parsers/MySQL/ASTDeclareConstraint.h>
namespace DB
{
namespace MySQLParser
{
class ParserCreateDefine : public IParserBase
{
protected:
const char * getName() const override { return "table property (column, index, constraint)"; }
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override
{
MySQLParser::ParserDeclareIndex p_declare_index;
MySQLParser::ParserDeclareColumn p_declare_column;
MySQLParser::ParserDeclareConstraint p_declare_constraint;
if (likely(!p_declare_index.parse(pos, node, expected)))
{
if (likely(!p_declare_constraint.parse(pos, node, expected)))
{
if (!p_declare_column.parse(pos, node, expected))
return false;
}
}
return true;
}
};
ASTPtr ASTCreateDefines::clone() const
{
auto res = std::make_shared<ASTCreateDefines>(*this);
res->children.clear();
if (columns)
res->set(res->columns, columns->clone());
if (indices)
res->set(res->indices, indices->clone());
if (constraints)
res->set(res->constraints, constraints->clone());
return res;
}
bool ParserCreateDefines::parseImpl(IParser::Pos & pos, ASTPtr & node, Expected & expected)
{
ASTPtr create_defines;
ParserList create_defines_parser(std::make_unique<ParserCreateDefine>(), std::make_unique<ParserToken>(TokenType::Comma), false);
if (!create_defines_parser.parse(pos, create_defines, expected))
return false;
ASTPtr columns = std::make_shared<ASTExpressionList>();
ASTPtr indices = std::make_shared<ASTExpressionList>();
ASTPtr constraints = std::make_shared<ASTExpressionList>();
for (const auto & create_define : create_defines->children)
{
if (create_define->as<ASTDeclareColumn>())
columns->children.push_back(create_define);
else if (create_define->as<ASTDeclareIndex>())
indices->children.push_back(create_define);
else if (create_define->as<ASTDeclareConstraint>())
constraints->children.push_back(create_define);
else
return false;
}
auto res = std::make_shared<ASTCreateDefines>();
if (!columns->children.empty())
res->set(res->columns, columns);
if (!indices->children.empty())
res->set(res->indices, indices);
if (!constraints->children.empty())
res->set(res->constraints, constraints);
node = res;
return true;
}
}
}

View File

@ -0,0 +1,37 @@
#pragma once
#include <Parsers/IAST.h>
#include <Parsers/IParserBase.h>
#include <Parsers/ASTExpressionList.h>
namespace DB
{
namespace MySQLParser
{
class ASTCreateDefines : public IAST
{
public:
ASTExpressionList * columns = nullptr;
ASTExpressionList * indices = nullptr;
ASTExpressionList * constraints = nullptr;
ASTPtr clone() const override;
String getID(char) const override { return "Create definitions"; }
};
class ParserCreateDefines : public IParserBase
{
protected:
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
const char * getName() const override { return "table property list (column, index, constraint)"; }
};
}
}

View File

@ -0,0 +1,128 @@
#include <Parsers/MySQL/ASTCreateQuery.h>
#include <Interpreters/StorageID.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/CommonParsers.h>
#include <Parsers/ExpressionElementParsers.h>
#include <Parsers/ExpressionListParsers.h>
#include <Parsers/MySQL/ASTCreateDefines.h>
#include <Parsers/MySQL/ASTDeclarePartitionOptions.h>
#include <Parsers/MySQL/ASTDeclareTableOptions.h>
namespace DB
{
namespace MySQLParser
{
ASTPtr ASTCreateQuery::clone() const
{
auto res = std::make_shared<ASTCreateQuery>(*this);
res->children.clear();
if (columns_list)
{
res->columns_list = columns_list->clone();
res->children.emplace_back(res->columns_list);
}
if (table_options)
{
res->table_options = table_options->clone();
res->children.emplace_back(res->table_options);
}
if (partition_options)
{
res->partition_options = partition_options->clone();
res->children.emplace_back(res->partition_options);
}
return res;
}
bool ParserCreateQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
{
ASTPtr table;
ASTPtr like_table;
ASTPtr columns_list;
ASTPtr table_options;
ASTPtr partition_options;
bool is_temporary = false;
bool if_not_exists = false;
if (!ParserKeyword("CREATE").ignore(pos, expected))
return false;
if (ParserKeyword("TEMPORARY").ignore(pos, expected))
is_temporary = true;
if (!ParserKeyword("TABLE").ignore(pos, expected))
return false;
if (ParserKeyword("IF NOT EXISTS").ignore(pos, expected))
if_not_exists = true;
if (!ParserCompoundIdentifier(true).parse(pos, table, expected))
return false;
if (ParserKeyword("LIKE").ignore(pos, expected))
{
if (!ParserCompoundIdentifier(true).parse(pos, like_table, expected))
return false;
}
if (ParserToken(TokenType::OpeningRoundBracket).ignore(pos, expected))
{
if (ParserKeyword("LIKE").ignore(pos, expected))
{
if (!ParserCompoundIdentifier(true).parse(pos, like_table, expected))
return false;
if (!ParserToken(TokenType::ClosingRoundBracket).ignore(pos, expected))
return false;
}
else
{
if (!ParserCreateDefines().parse(pos, columns_list, expected))
return false;
if (!ParserToken(TokenType::ClosingRoundBracket).ignore(pos, expected))
return false;
ParserDeclareTableOptions().parse(pos, table_options, expected);
ParserDeclarePartitionOptions().parse(pos, partition_options, expected);
}
}
auto create_query = std::make_shared<ASTCreateQuery>();
create_query->temporary = is_temporary;
create_query->if_not_exists = if_not_exists;
StorageID table_id = getTableIdentifier(table);
create_query->table = table_id.table_name;
create_query->database = table_id.database_name;
create_query->like_table = like_table;
create_query->columns_list = columns_list;
create_query->table_options = table_options;
create_query->partition_options = partition_options;
if (create_query->like_table)
create_query->children.emplace_back(create_query->like_table);
if (create_query->columns_list)
create_query->children.emplace_back(create_query->columns_list);
if (create_query->table_options)
create_query->children.emplace_back(create_query->table_options);
if (create_query->partition_options)
create_query->children.emplace_back(create_query->partition_options);
node = create_query;
return true;
}
}
}

View File

@ -0,0 +1,40 @@
#pragma once
#include <Parsers/IAST.h>
#include <Parsers/IParserBase.h>
namespace DB
{
namespace MySQLParser
{
class ASTCreateQuery : public IAST
{
public:
bool temporary{false};
bool if_not_exists{false};
String table;
String database;
ASTPtr like_table;
ASTPtr columns_list;
ASTPtr table_options;
ASTPtr partition_options;
ASTPtr clone() const override;
String getID(char) const override { return "create query"; }
};
class ParserCreateQuery : public IParserBase
{
protected:
const char * getName() const override { return "create query"; }
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
};
}
}

View File

@ -0,0 +1,98 @@
#include <Parsers/MySQL/ASTDeclareColumn.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/ExpressionListParsers.h>
#include <Parsers/ExpressionElementParsers.h>
#include <Parsers/MySQL/ASTDeclareOption.h>
#include <Parsers/MySQL/ASTDeclareReference.h>
#include <Parsers/MySQL/ASTDeclareConstraint.h>
namespace DB
{
namespace MySQLParser
{
ASTPtr ASTDeclareColumn::clone() const
{
auto res = std::make_shared<ASTDeclareColumn>(*this);
res->children.clear();
if (data_type)
{
res->data_type = data_type->clone();
res->children.emplace_back(res->data_type);
}
if (column_options)
{
res->column_options = column_options->clone();
res->children.emplace_back(res->column_options);
}
return res;
}
bool ParserDeclareColumn::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
{
ASTPtr column_name;
ASTPtr column_data_type;
ASTPtr column_options;
ParserExpression p_expression;
ParserIdentifier p_identifier;
if (!p_identifier.parse(pos, column_name, expected))
return false;
if (!p_expression.parse(pos, column_data_type, expected))
return false;
if (!parseColumnDeclareOptions(pos, column_options, expected))
return false;
auto declare_column = std::make_shared<ASTDeclareColumn>();
declare_column->name = column_name->as<ASTIdentifier>()->name;
declare_column->data_type = column_data_type;
declare_column->column_options = column_options;
if (declare_column->data_type)
declare_column->children.emplace_back(declare_column->data_type);
if (declare_column->column_options)
declare_column->children.emplace_back(declare_column->column_options);
node = declare_column;
return true;
}
bool ParserDeclareColumn::parseColumnDeclareOptions(IParser::Pos & pos, ASTPtr & node, Expected & expected)
{
ParserDeclareOption p_non_generate_options{
{
OptionDescribe("NULL", "is_null", std::make_unique<ParserAlwaysTrue>()),
OptionDescribe("NOT NULL", "is_null", std::make_unique<ParserAlwaysFalse>()),
OptionDescribe("DEFAULT", "default", std::make_unique<ParserExpression>()),
OptionDescribe("AUTO_INCREMENT", "auto_increment", std::make_unique<ParserAlwaysTrue>()),
OptionDescribe("UNIQUE", "unique_key", std::make_unique<ParserAlwaysTrue>()),
OptionDescribe("UNIQUE KEY", "unique_key", std::make_unique<ParserAlwaysTrue>()),
OptionDescribe("KEY", "primary_key", std::make_unique<ParserAlwaysTrue>()),
OptionDescribe("PRIMARY KEY", "primary_key", std::make_unique<ParserAlwaysTrue>()),
OptionDescribe("COMMENT", "comment", std::make_unique<ParserStringLiteral>()),
OptionDescribe("COLLATE", "collate", std::make_unique<ParserCharsetName>()),
OptionDescribe("COLUMN_FORMAT", "column_format", std::make_unique<ParserIdentifier>()),
OptionDescribe("STORAGE", "storage", std::make_unique<ParserIdentifier>()),
OptionDescribe("AS", "generated", std::make_unique<ParserExpression>()),
OptionDescribe("GENERATED ALWAYS AS", "generated", std::make_unique<ParserExpression>()),
OptionDescribe("STORED", "is_stored", std::make_unique<ParserAlwaysTrue>()),
OptionDescribe("VIRTUAL", "is_stored", std::make_unique<ParserAlwaysFalse>()),
OptionDescribe("", "reference", std::make_unique<ParserDeclareReference>()),
OptionDescribe("", "constraint", std::make_unique<ParserDeclareConstraint>()),
}
};
return p_non_generate_options.parse(pos, node, expected);
}
}
}

View File

@ -0,0 +1,37 @@
#pragma once
#include <Parsers/IAST.h>
#include <Parsers/IParserBase.h>
namespace DB
{
namespace MySQLParser
{
class ASTDeclareColumn : public IAST
{
public:
String name;
ASTPtr data_type;
ASTPtr column_options;
ASTPtr clone() const override;
String getID(char /*delimiter*/) const override { return "Column definition"; }
};
class ParserDeclareColumn : public IParserBase
{
protected:
const char * getName() const override { return "index declaration"; }
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
bool parseColumnDeclareOptions(Pos & pos, ASTPtr & node, Expected & expected);
};
}
}

View File

@ -0,0 +1,74 @@
#include <Parsers/MySQL/ASTDeclareConstraint.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/CommonParsers.h>
#include <Parsers/ExpressionElementParsers.h>
#include <Parsers/ExpressionListParsers.h>
namespace DB
{
namespace MySQLParser
{
ASTPtr ASTDeclareConstraint::clone() const
{
auto res = std::make_shared<ASTDeclareConstraint>(*this);
res->children.clear();
if (check_expression)
{
res->check_expression = check_expression->clone();
res->children.emplace_back(res->check_expression);
}
return res;
}
bool ParserDeclareConstraint::parseImpl(IParser::Pos & pos, ASTPtr & node, Expected & expected)
{
bool enforced = true;
ASTPtr constraint_symbol;
ASTPtr index_check_expression;
ParserExpression p_expression;
if (ParserKeyword("CONSTRAINT").ignore(pos, expected))
{
if (!ParserKeyword("CHECK").checkWithoutMoving(pos, expected))
ParserIdentifier().parse(pos, constraint_symbol, expected);
}
if (!ParserKeyword("CHECK").ignore(pos, expected))
return false;
if (!p_expression.parse(pos, index_check_expression, expected))
return false;
if (ParserKeyword("NOT").ignore(pos, expected))
{
if (!ParserKeyword("ENFORCED").ignore(pos, expected))
return false;
enforced = false;
}
else
{
enforced = true;
ParserKeyword("ENFORCED").ignore(pos, expected);
}
auto declare_constraint = std::make_shared<ASTDeclareConstraint>();
declare_constraint->enforced = enforced;
declare_constraint->check_expression = index_check_expression;
if (constraint_symbol)
declare_constraint->constraint_name = constraint_symbol->as<ASTIdentifier>()->name;
node = declare_constraint;
return true;
}
}
}

View File

@ -0,0 +1,35 @@
#pragma once
#include <Parsers/IAST.h>
#include <Parsers/IParserBase.h>
namespace DB
{
namespace MySQLParser
{
class ASTDeclareConstraint : public IAST
{
public:
bool enforced{true};
String constraint_name;
ASTPtr check_expression;
ASTPtr clone() const override;
String getID(char /*delimiter*/) const override { return "constraint declaration"; }
};
class ParserDeclareConstraint : public IParserBase
{
protected:
const char * getName() const override { return "constraint declaration"; }
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
};
}
}

View File

@ -0,0 +1,235 @@
#include <Parsers/ASTIdentifier.h>
#include <Parsers/CommonParsers.h>
#include <Parsers/ExpressionListParsers.h>
#include <Parsers/ExpressionElementParsers.h>
#include <Parsers/MySQL/ASTDeclareIndex.h>
#include <Parsers/MySQL/ASTDeclareOption.h>
#include <Parsers/MySQL/ASTDeclareReference.h>
namespace DB
{
namespace MySQLParser
{
struct ParserIndexColumn : public IParserBase
{
protected:
const char * getName() const override { return "index column"; }
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override
{
ParserExpression p_expression;
if (!p_expression.parse(pos, node, expected))
return false;
ParserKeyword("ASC").ignore(pos, expected);
ParserKeyword("DESC").ignore(pos, expected);
return true;
}
};
ASTPtr ASTDeclareIndex::clone() const
{
auto res = std::make_shared<ASTDeclareIndex>(*this);
res->children.clear();
if (index_columns)
{
res->index_columns = index_columns->clone();
res->children.emplace_back(res->index_columns);
}
if (index_options)
{
res->index_options = index_options->clone();
res->children.emplace_back(res->index_options);
}
if (reference_definition)
{
res->reference_definition = reference_definition->clone();
res->children.emplace_back(res->reference_definition);
}
return res;
}
bool ParserDeclareIndex::parseImpl(IParser::Pos & pos, ASTPtr & node, Expected & expected)
{
String index_name;
String index_type;
ASTPtr index_columns;
ASTPtr index_options;
ASTPtr declare_reference;
ParserIndexColumn p_expression;
ParserDeclareOption p_index_options{
{
OptionDescribe("KEY_BLOCK_SIZE", "key_block_size", std::make_unique<ParserLiteral>()),
OptionDescribe("USING", "index_type", std::make_unique<ParserIdentifier>()),
OptionDescribe("WITH PARSER", "index_parser", std::make_unique<ParserIdentifier>()),
OptionDescribe("COMMENT", "comment", std::make_unique<ParserStringLiteral>()),
OptionDescribe("VISIBLE", "visible", std::make_unique<ParserAlwaysTrue>()),
OptionDescribe("INVISIBLE", "visible", std::make_unique<ParserAlwaysFalse>()),
}
};
if (!parseDeclareOrdinaryIndex(pos, index_name, index_type, expected))
{
if (!parseDeclareConstraintIndex(pos, index_name, index_type, expected))
return false;
}
ParserToken s_opening_round(TokenType::OpeningRoundBracket);
ParserToken s_closing_round(TokenType::ClosingRoundBracket);
if (!s_opening_round.ignore(pos, expected))
return false;
ParserList p_index_columns(std::make_unique<ParserIndexColumn>(), std::make_unique<ParserToken>(TokenType::Comma));
if (!p_index_columns.parse(pos, index_columns, expected))
return false;
if (!s_closing_round.ignore(pos, expected))
return false;
if (index_type != "FOREIGN")
p_index_options.parse(pos, index_options, expected);
else
{
if (!ParserDeclareReference().parse(pos, declare_reference, expected))
return false;
}
auto declare_index = std::make_shared<ASTDeclareIndex>();
declare_index->index_name = index_name;
declare_index->index_type = index_type;
declare_index->index_columns = index_columns;
declare_index->index_options = index_options;
declare_index->reference_definition = declare_reference;
if (declare_index->index_columns)
declare_index->children.emplace_back(declare_index->index_columns);
if (declare_index->index_options)
declare_index->children.emplace_back(declare_index->index_options);
if (declare_index->reference_definition)
declare_index->children.emplace_back(declare_index->reference_definition);
node = declare_index;
return true;
}
bool ParserDeclareIndex::parseDeclareOrdinaryIndex(IParser::Pos & pos, String & index_name, String & index_type, Expected & expected)
{
ASTPtr temp_node;
ParserKeyword k_key("KEY");
ParserKeyword k_index("INDEX");
ParserExpression p_expression;
ParserIdentifier p_identifier;
if (ParserKeyword("SPATIAL").ignore(pos, expected))
{
if (!k_key.ignore(pos, expected))
k_index.ignore(pos, expected);
index_type = "SPATIAL";
if (p_identifier.parse(pos, temp_node, expected))
index_name = temp_node->as<ASTIdentifier>()->name;
}
else if (ParserKeyword("FULLTEXT").ignore(pos, expected))
{
if (!k_key.ignore(pos, expected))
k_index.ignore(pos, expected);
index_type = "FULLTEXT";
if (p_identifier.parse(pos, temp_node, expected))
index_name = temp_node->as<ASTIdentifier>()->name;
}
else
{
if (!k_key.ignore(pos, expected))
{
if (!k_index.ignore(pos, expected))
return false;
}
index_type = "BTREE"; /// default index type
if (p_identifier.parse(pos, temp_node, expected))
index_name = temp_node->as<ASTIdentifier>()->name;
if (ParserKeyword("USING").ignore(pos, expected))
{
if (!p_identifier.parse(pos, temp_node, expected))
return false;
index_type = temp_node->as<ASTIdentifier>()->name;
}
}
return true;
}
bool ParserDeclareIndex::parseDeclareConstraintIndex(IParser::Pos & pos, String & index_name, String & index_type, Expected & expected)
{
ASTPtr temp_node;
ParserIdentifier p_identifier;
if (ParserKeyword("CONSTRAINT").ignore(pos, expected))
{
if (!ParserKeyword("PRIMARY").checkWithoutMoving(pos, expected) && !ParserKeyword("UNIQUE").checkWithoutMoving(pos, expected)
&& !ParserKeyword("FOREIGN").checkWithoutMoving(pos, expected))
{
if (!p_identifier.parse(pos, temp_node, expected))
return false;
index_name = temp_node->as<ASTIdentifier>()->name;
}
}
if (ParserKeyword("UNIQUE").ignore(pos, expected))
{
if (!ParserKeyword("KEY").ignore(pos, expected))
ParserKeyword("INDEX").ignore(pos, expected);
if (p_identifier.parse(pos, temp_node, expected))
index_name = temp_node->as<ASTIdentifier>()->name; /// reset index_name
index_type = "UNIQUE_BTREE"; /// default btree index_type
if (ParserKeyword("USING").ignore(pos, expected))
{
if (!p_identifier.parse(pos, temp_node, expected))
return false;
index_type = temp_node->as<ASTIdentifier>()->name;
}
}
else if (ParserKeyword("PRIMARY KEY").ignore(pos, expected))
{
index_type = "PRIMARY_KEY_BTREE"; /// default btree index_type
if (ParserKeyword("USING").ignore(pos, expected))
{
if (!p_identifier.parse(pos, temp_node, expected))
return false;
index_type = temp_node->as<ASTIdentifier>()->name;
}
}
else if (ParserKeyword("FOREIGN KEY").ignore(pos, expected))
{
index_type = "FOREIGN";
if (p_identifier.parse(pos, temp_node, expected))
index_name = temp_node->as<ASTIdentifier>()->name; /// reset index_name
}
return true;
}
}
}

View File

@ -0,0 +1,43 @@
#pragma once
#include <Core/Field.h>
#include <Parsers/IAST.h>
#include <Parsers/IParserBase.h>
namespace DB
{
namespace MySQLParser
{
class ASTDeclareIndex: public IAST
{
public:
String index_name;
String index_type;
ASTPtr index_columns;
ASTPtr index_options;
ASTPtr reference_definition;
ASTPtr clone() const override;
String getID(char /*delimiter*/) const override { return "index declaration"; }
};
class ParserDeclareIndex : public IParserBase
{
protected:
const char * getName() const override { return "index declaration"; }
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
bool parseDeclareOrdinaryIndex(Pos & pos, String & index_name, String & index_type, Expected & expected);
bool parseDeclareConstraintIndex(Pos & pos, String & index_name, String & index_type, Expected & expected);
};
}
}

View File

@ -0,0 +1,142 @@
#include <Parsers/MySQL/ASTDeclareOption.h>
#include <IO/ReadBufferFromMemory.h>
#include <IO/ReadHelpers.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/ASTLiteral.h>
namespace DB
{
namespace MySQLParser
{
bool ParserDeclareOption::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
{
std::unordered_map<String, ASTPtr> changes;
std::unordered_map<String, std::shared_ptr<IParser>> usage_parsers_cached;
usage_parsers_cached.reserve(options_collection.size());
const auto & get_parser_from_cache = [&](const char * usage_name)
{
auto iterator = usage_parsers_cached.find(usage_name);
if (iterator == usage_parsers_cached.end())
iterator = usage_parsers_cached.insert(std::make_pair(usage_name, std::make_shared<ParserKeyword>(usage_name))).first;
return iterator->second;
};
while (true)
{
ASTPtr value;
bool found{false};
for (const auto & option_describe : options_collection)
{
if (strlen(option_describe.usage_name) == 0)
{
if (option_describe.value_parser->parse(pos, value, expected))
{
found = true;
changes.insert(std::make_pair(option_describe.option_name, value));
}
}
else if (get_parser_from_cache(option_describe.usage_name)->ignore(pos, expected))
{
ParserToken{TokenType::Equals}.ignore(pos, expected);
if (!option_describe.value_parser->parse(pos, value, expected))
return false;
/*const auto & changes_iterator = changes.find(option_describe.option_name);
if (changes_iterator != changes.end())
throw Exception("Duplicate options declare", ErrorCodes::)*/
found = true;
changes.insert(std::make_pair(option_describe.option_name, value));
}
}
if (!found)
break;
ParserToken{TokenType::Comma}.ignore(pos, expected);
}
if (!changes.empty())
{
auto options_declare = std::make_shared<ASTDeclareOptions>();
options_declare->changes = changes;
node = options_declare;
}
return true;
}
ASTPtr ASTDeclareOptions::clone() const
{
auto res = std::make_shared<ASTDeclareOptions>(*this);
res->children.clear();
res->changes.clear();
for (const auto & [name, value] : this->changes)
res->changes.insert(std::make_pair(name, value->clone()));
return res;
}
bool ParserAlwaysTrue::parseImpl(IParser::Pos & /*pos*/, ASTPtr & node, Expected & /*expected*/)
{
node = std::make_shared<ASTLiteral>(Field(UInt64(1)));
return true;
}
bool ParserAlwaysFalse::parseImpl(IParser::Pos & /*pos*/, ASTPtr & node, Expected & /*expected*/)
{
node = std::make_shared<ASTLiteral>(Field(UInt64(0)));
return true;
}
bool ParserCharsetName::parseImpl(IParser::Pos & pos, ASTPtr & node, Expected &)
{
/// Identifier in backquotes or in double quotes
if (pos->type == TokenType::QuotedIdentifier)
{
ReadBufferFromMemory buf(pos->begin, pos->size());
String s;
if (*pos->begin == '`')
readBackQuotedStringWithSQLStyle(s, buf);
else
readDoubleQuotedStringWithSQLStyle(s, buf);
if (s.empty()) /// Identifiers "empty string" are not allowed.
return false;
node = std::make_shared<ASTIdentifier>(s);
++pos;
return true;
}
else if (pos->type == TokenType::BareWord)
{
const char * begin = pos->begin;
while (true)
{
if (isWhitespaceASCII(*pos->end))
break;
else
{
++pos;
}
}
node = std::make_shared<ASTIdentifier>(String(begin, pos->end));
++pos;
return true;
}
return false;
}
}
}

View File

@ -0,0 +1,76 @@
#pragma once
#include <Parsers/IAST.h>
#include <Parsers/IParserBase.h>
#include <Parsers/CommonParsers.h>
namespace DB
{
namespace MySQLParser
{
struct OptionDescribe
{
const char * usage_name;
String option_name;
std::shared_ptr<IParser> value_parser;
OptionDescribe(const char * usage_name_, const String & option_name_, const std::shared_ptr<IParser> & value_parser_)
:usage_name(usage_name_), option_name(option_name_), value_parser(value_parser_)
{
}
};
class ASTDeclareOptions : public IAST
{
public:
std::unordered_map<String, ASTPtr> changes;
ASTPtr clone() const override;
String getID(char /*delimiter*/) const override { return "options declaration"; }
};
class ParserAlwaysTrue : public IParserBase
{
public:
const char * getName() const override { return "always true"; }
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
};
class ParserAlwaysFalse : public IParserBase
{
public:
const char * getName() const override { return "always false"; }
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
};
/// Copy and paste from ParserIdentifier,
/// the difference is that multiple tokens are glued if there is no whitespace ASCII between them
struct ParserCharsetName : public IParserBase
{
protected:
const char * getName() const override { return "charset name"; }
bool parseImpl(Pos & pos, ASTPtr & node, Expected &) override;
};
class ParserDeclareOption : public IParserBase
{
protected:
std::vector<OptionDescribe> options_collection;
const char * getName() const override { return "option declaration"; }
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
public:
ParserDeclareOption(const std::vector<OptionDescribe> & options_collection_) : options_collection(options_collection_) {}
};
}
}

View File

@ -0,0 +1,127 @@
#include <Parsers/MySQL/ASTDeclarePartition.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/ExpressionElementParsers.h>
#include <Parsers/ExpressionListParsers.h>
#include <Parsers/MySQL/ASTDeclareOption.h>
#include <Parsers/MySQL/ASTDeclareSubPartition.h>
namespace DB
{
namespace MySQLParser
{
ASTPtr ASTDeclarePartition::clone() const
{
auto res = std::make_shared<ASTDeclarePartition>(*this);
res->children.clear();
if (options)
{
res->options = options->clone();
res->children.emplace_back(res->options);
}
if (less_than)
{
res->less_than = less_than->clone();
res->children.emplace_back(res->less_than);
}
if (in_expression)
{
res->in_expression = in_expression->clone();
res->children.emplace_back(res->in_expression);
}
if (subpartitions)
{
res->subpartitions = subpartitions->clone();
res->children.emplace_back(res->subpartitions);
}
return res;
}
bool ParserDeclarePartition::parseImpl(IParser::Pos & pos, ASTPtr & node, Expected & expected)
{
if (!ParserKeyword{"PARTITION"}.ignore(pos, expected))
return false;
ASTPtr options;
ASTPtr less_than;
ASTPtr in_expression;
ASTPtr partition_name;
ParserExpression p_expression;
ParserIdentifier p_identifier;
if (!p_identifier.parse(pos, partition_name, expected))
return false;
ParserKeyword p_values("VALUES");
if (p_values.ignore(pos, expected))
{
if (ParserKeyword{"IN"}.ignore(pos, expected))
{
if (!p_expression.parse(pos, in_expression, expected))
return false;
}
else if (ParserKeyword{"LESS THAN"}.ignore(pos, expected))
{
if (!p_expression.parse(pos, less_than, expected))
return false;
}
}
if (!ParserDeclareOption{
{
OptionDescribe("ENGINE", "engine", std::make_shared<ParserIdentifier>()),
OptionDescribe("STORAGE ENGINE", "engine", std::make_shared<ParserIdentifier>()),
OptionDescribe("COMMENT", "comment", std::make_shared<ParserStringLiteral>()),
OptionDescribe("DATA DIRECTORY", "data_directory", std::make_shared<ParserStringLiteral>()),
OptionDescribe("INDEX DIRECTORY", "index_directory", std::make_shared<ParserStringLiteral>()),
OptionDescribe("MAX_ROWS", "max_rows", std::make_shared<ParserLiteral>()),
OptionDescribe("MIN_ROWS", "min_rows", std::make_shared<ParserLiteral>()),
OptionDescribe("TABLESPACE", "tablespace", std::make_shared<ParserIdentifier>()),
}
}.parse(pos, options, expected))
return false;
ASTPtr subpartitions;
if (ParserToken(TokenType::OpeningRoundBracket).ignore(pos, expected))
{
if (!DB::ParserList(std::make_unique<ParserDeclareSubPartition>(), std::make_unique<ParserToken>(TokenType::Comma))
.parse(pos, subpartitions, expected))
return false;
if (!ParserToken(TokenType::ClosingRoundBracket).ignore(pos, expected))
return false;
}
auto partition_declare = std::make_shared<ASTDeclarePartition>();
partition_declare->options = options;
partition_declare->less_than = less_than;
partition_declare->in_expression = in_expression;
partition_declare->subpartitions = subpartitions;
partition_declare->partition_name = partition_name->as<ASTIdentifier>()->name;
if (partition_declare->options)
partition_declare->children.emplace_back(partition_declare->options);
if (partition_declare->less_than)
partition_declare->children.emplace_back(partition_declare->less_than);
if (partition_declare->in_expression)
partition_declare->children.emplace_back(partition_declare->in_expression);
if (partition_declare->subpartitions)
partition_declare->children.emplace_back(partition_declare->subpartitions);
node = partition_declare;
return true;
}
}
}

View File

@ -0,0 +1,35 @@
#pragma once
#include <Parsers/IAST.h>
#include <Parsers/IParserBase.h>
namespace DB
{
namespace MySQLParser
{
class ASTDeclarePartition : public IAST
{
public:
String partition_name;
ASTPtr less_than;
ASTPtr in_expression;
ASTPtr options;
ASTPtr subpartitions;
ASTPtr clone() const override;
String getID(char /*delimiter*/) const override { return "partition declaration"; }
};
class ParserDeclarePartition : public IParserBase
{
protected:
const char * getName() const override { return "partition declaration"; }
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
};
}
}

View File

@ -0,0 +1,184 @@
#include <Parsers/MySQL/ASTDeclarePartitionOptions.h>
#include <Parsers/ASTLiteral.h>
#include <Parsers/CommonParsers.h>
#include <Parsers/ExpressionListParsers.h>
#include <Parsers/ExpressionElementParsers.h>
#include <Parsers/MySQL/ASTDeclarePartition.h>
namespace DB
{
namespace MySQLParser
{
ASTPtr ASTDeclarePartitionOptions::clone() const
{
auto res = std::make_shared<ASTDeclarePartitionOptions>(*this);
res->children.clear();
if (partition_numbers)
{
res->partition_numbers = partition_numbers->clone();
res->children.emplace_back(res->partition_numbers);
}
if (partition_expression)
{
res->partition_expression = partition_expression->clone();
res->children.emplace_back(res->partition_expression);
}
if (subpartition_numbers)
{
res->subpartition_numbers = subpartition_numbers->clone();
res->children.emplace_back(res->subpartition_numbers);
}
if (subpartition_expression)
{
res->subpartition_expression = subpartition_expression->clone();
res->children.emplace_back(res->subpartition_expression);
}
return res;
}
bool ParserDeclarePartitionOptions::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
{
String partition_type;
ASTPtr partition_numbers;
ASTPtr partition_expression;
String subpartition_type;
ASTPtr subpartition_numbers;
ASTPtr subpartition_expression;
ASTPtr declare_partitions;
if (!ParserKeyword("PARTITION BY").ignore(pos, expected))
return false;
if (!parsePartitionExpression(pos, partition_type, partition_expression, expected))
return false;
if (ParserKeyword("PARTITIONS").ignore(pos, expected))
{
ParserLiteral p_literal;
if (!p_literal.parse(pos, partition_numbers, expected))
return false;
}
if (ParserKeyword("SUBPARTITION BY").ignore(pos, expected))
{
if (!parsePartitionExpression(pos, subpartition_type, subpartition_expression, expected, true))
return false;
if (ParserKeyword("SUBPARTITIONS").ignore(pos, expected))
{
ParserLiteral p_literal;
if (!p_literal.parse(pos, subpartition_numbers, expected))
return false;
}
}
if (ParserToken(TokenType::OpeningRoundBracket).ignore(pos, expected))
{
if (!ParserList(std::make_unique<ParserDeclarePartition>(), std::make_unique<ParserToken>(TokenType::Comma))
.parse(pos, declare_partitions, expected))
return false;
if (!ParserToken(TokenType::ClosingRoundBracket).ignore(pos, expected))
return false;
}
auto declare_partition_options = std::make_shared<ASTDeclarePartitionOptions>();
declare_partition_options->partition_type = partition_type;
declare_partition_options->partition_numbers = partition_numbers;
declare_partition_options->partition_expression = partition_expression;
declare_partition_options->subpartition_type = subpartition_type;
declare_partition_options->subpartition_numbers = subpartition_numbers;
declare_partition_options->subpartition_expression = subpartition_expression;
declare_partition_options->declare_partitions = declare_partitions;
if (declare_partition_options->partition_numbers)
declare_partition_options->children.emplace_back(declare_partition_options->partition_numbers);
if (declare_partition_options->partition_expression)
declare_partition_options->children.emplace_back(declare_partition_options->partition_expression);
if (declare_partition_options->subpartition_numbers)
declare_partition_options->children.emplace_back(declare_partition_options->subpartition_numbers);
if (declare_partition_options->subpartition_expression)
declare_partition_options->children.emplace_back(declare_partition_options->subpartition_expression);
if (declare_partition_options->declare_partitions)
declare_partition_options->children.emplace_back(declare_partition_options->declare_partitions);
node = declare_partition_options;
return true;
}
bool ParserDeclarePartitionOptions::parsePartitionExpression(Pos & pos, std::string & type, ASTPtr & node, Expected & expected, bool subpartition)
{
ASTPtr expression;
ParserExpression p_expression;
if (!subpartition && ParserKeyword("LIST").ignore(pos, expected))
{
type = "list";
ParserKeyword("COLUMNS").ignore(pos, expected);
if (!p_expression.parse(pos, expression, expected))
return false;
}
else if (!subpartition && ParserKeyword("RANGE").ignore(pos, expected))
{
type = "range";
ParserKeyword("COLUMNS").ignore(pos, expected);
if (!p_expression.parse(pos, expression, expected))
return false;
}
else
{
if (ParserKeyword("LINEAR").ignore(pos, expected))
type = "linear_";
if (ParserKeyword("KEY").ignore(pos, expected))
{
type += "key";
if (ParserKeyword("ALGORITHM").ignore(pos, expected))
{
if (!ParserToken(TokenType::Equals).ignore(pos, expected))
return false;
ASTPtr algorithm;
ParserLiteral p_literal;
if (!p_literal.parse(pos, algorithm, expected) || !algorithm->as<ASTLiteral>())
return false;
UInt64 algorithm_type = algorithm->as<ASTLiteral>()->value.safeGet<UInt64>();
if (algorithm_type != 1 && algorithm_type != 2)
return false;
type += "_" + toString(algorithm_type);
}
if (!p_expression.parse(pos, expression, expected))
return false;
}
else if (ParserKeyword("HASH").ignore(pos, expected))
{
type += "hash";
if (!p_expression.parse(pos, expression, expected))
return false;
}
else
return false;
}
node = expression;
return true;
}
}
}

View File

@ -0,0 +1,40 @@
#pragma once
#include <Parsers/IAST.h>
#include <Parsers/IParserBase.h>
namespace DB
{
namespace MySQLParser
{
class ASTDeclarePartitionOptions : public IAST
{
public:
String partition_type;
ASTPtr partition_numbers;
ASTPtr partition_expression;
String subpartition_type;
ASTPtr subpartition_numbers;
ASTPtr subpartition_expression;
ASTPtr declare_partitions;
ASTPtr clone() const override;
String getID(char /*delimiter*/) const override { return "partition options declaration"; }
};
class ParserDeclarePartitionOptions : public IParserBase
{
protected:
const char * getName() const override { return "partition options declaration"; }
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
bool parsePartitionExpression(Pos & pos, std::string & type, ASTPtr & node, Expected & expected, bool subpartition = false);
};
}
}

View File

@ -0,0 +1,105 @@
#include <Parsers/MySQL/ASTDeclareReference.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/CommonParsers.h>
#include <Parsers/ExpressionListParsers.h>
#include <Parsers/ExpressionElementParsers.h>
namespace DB
{
namespace MySQLParser
{
bool parseReferenceOption(IParser::Pos & pos, ASTDeclareReference::ReferenceOption & option, Expected & expected)
{
if (ParserKeyword("RESTRICT").ignore(pos, expected))
option = ASTDeclareReference::RESTRICT;
else if (ParserKeyword("CASCADE").ignore(pos, expected))
option = ASTDeclareReference::CASCADE;
else if (ParserKeyword("SET NULL").ignore(pos, expected))
option = ASTDeclareReference::SET_NULL;
else if (ParserKeyword("NO ACTION").ignore(pos, expected))
option = ASTDeclareReference::NO_ACTION;
else if (ParserKeyword("SET DEFAULT").ignore(pos, expected))
option = ASTDeclareReference::SET_DEFAULT;
else
return false;
return true;
}
ASTPtr ASTDeclareReference::clone() const
{
auto res = std::make_shared<ASTDeclareReference>(*this);
res->children.clear();
if (reference_expression)
{
res->reference_expression = reference_expression->clone();
res->children.emplace_back(res->reference_expression);
}
return res;
}
bool ParserDeclareReference::parseImpl(IParser::Pos & pos, ASTPtr & node, Expected & expected)
{
ASTPtr table_name;
ASTPtr expression;
ParserExpression p_expression;
ParserIdentifier p_identifier;
ASTDeclareReference::MatchKind match_kind = ASTDeclareReference::MATCH_FULL;
ASTDeclareReference::ReferenceOption delete_option = ASTDeclareReference::RESTRICT;
ASTDeclareReference::ReferenceOption update_option = ASTDeclareReference::RESTRICT;
if (!ParserKeyword("REFERENCES").ignore(pos, expected))
return false;
if (!p_identifier.parse(pos, table_name, expected))
return false;
if (!p_expression.parse(pos, expression, expected))
return false;
if (ParserKeyword("MATCH").ignore(pos, expected))
{
if (ParserKeyword("FULL").ignore(pos, expected))
match_kind = ASTDeclareReference::MATCH_FULL;
else if (ParserKeyword("SIMPLE").ignore(pos, expected))
match_kind = ASTDeclareReference::MATCH_SIMPLE;
else if (ParserKeyword("PARTIAL").ignore(pos, expected))
match_kind = ASTDeclareReference::MATCH_PARTIAL;
else
return false;
}
while (true)
{
if (ParserKeyword("ON DELETE").ignore(pos, expected))
{
if (!parseReferenceOption(pos, delete_option, expected))
return false;
}
else if (ParserKeyword("ON UPDATE").ignore(pos, expected))
{
if (!parseReferenceOption(pos, update_option, expected))
return false;
}
else
break;
}
auto declare_reference = std::make_shared<ASTDeclareReference>();
declare_reference->kind = match_kind;
declare_reference->on_delete_option = delete_option;
declare_reference->on_update_option = update_option;
declare_reference->reference_expression = expression;
declare_reference->reference_table_name = table_name->as<ASTIdentifier>()->name;
node = declare_reference;
return true;
}
}
}

View File

@ -0,0 +1,52 @@
#pragma once
#include <Parsers/IAST.h>
#include <Parsers/IParserBase.h>
namespace DB
{
namespace MySQLParser
{
class ASTDeclareReference : public IAST
{
public:
enum MatchKind
{
MATCH_FULL,
MATCH_PARTIAL,
MATCH_SIMPLE
};
enum ReferenceOption
{
RESTRICT,
CASCADE,
SET_NULL,
NO_ACTION,
SET_DEFAULT
};
MatchKind kind;
String reference_table_name;
ASTPtr reference_expression;
ReferenceOption on_delete_option;
ReferenceOption on_update_option;
ASTPtr clone() const override;
String getID(char /*delimiter*/) const override { return "subpartition declaration"; }
};
class ParserDeclareReference : public IParserBase
{
protected:
const char * getName() const override { return "reference declaration"; }
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
};
}
}

View File

@ -0,0 +1,66 @@
#include <Parsers/MySQL/ASTDeclareSubPartition.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/CommonParsers.h>
#include <Parsers/MySQL/ASTDeclareOption.h>
#include <Parsers/ExpressionElementParsers.h>
namespace DB
{
namespace MySQLParser
{
bool ParserDeclareSubPartition::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
{
if (!ParserKeyword{"SUBPARTITION"}.ignore(pos, expected))
return false;
ASTPtr options;
ASTPtr logical_name;
ParserIdentifier p_identifier;
if (!p_identifier.parse(pos, logical_name, expected))
return false;
if (!ParserDeclareOption{
{
OptionDescribe("ENGINE", "engine", std::make_shared<ParserIdentifier>()),
OptionDescribe("STORAGE ENGINE", "engine", std::make_shared<ParserIdentifier>()),
OptionDescribe("COMMENT", "comment", std::make_shared<ParserStringLiteral>()),
OptionDescribe("DATA DIRECTORY", "data_directory", std::make_shared<ParserStringLiteral>()),
OptionDescribe("INDEX DIRECTORY", "index_directory", std::make_shared<ParserStringLiteral>()),
OptionDescribe("MAX_ROWS", "max_rows", std::make_shared<ParserLiteral>()),
OptionDescribe("MIN_ROWS", "min_rows", std::make_shared<ParserLiteral>()),
OptionDescribe("TABLESPACE", "tablespace", std::make_shared<ParserIdentifier>()),
}
}.parse(pos, options, expected))
return false;
auto subpartition_declare = std::make_shared<ASTDeclareSubPartition>();
subpartition_declare->options = options;
subpartition_declare->logical_name = logical_name->as<ASTIdentifier>()->name;
if (subpartition_declare->options)
subpartition_declare->children.emplace_back(subpartition_declare->options);
node = subpartition_declare;
return true;
}
ASTPtr ASTDeclareSubPartition::clone() const
{
auto res = std::make_shared<ASTDeclareSubPartition>(*this);
res->children.clear();
if (options)
{
res->options = options->clone();
res->children.emplace_back(res->options);
}
return res;
}
}
}

View File

@ -0,0 +1,33 @@
#pragma once
#include <Parsers/IAST.h>
#include <Parsers/IParserBase.h>
namespace DB
{
namespace MySQLParser
{
class ASTDeclareSubPartition : public IAST
{
public:
ASTPtr options;
String logical_name;
ASTPtr clone() const override;
String getID(char /*delimiter*/) const override { return "subpartition declaration"; }
};
class ParserDeclareSubPartition : public IParserBase
{
protected:
const char * getName() const override { return "subpartition declaration"; }
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
};
}
}

View File

@ -0,0 +1,102 @@
#include <Parsers/MySQL/ASTDeclareTableOptions.h>
#include <IO/ReadBufferFromMemory.h>
#include <IO/ReadHelpers.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/ASTLiteral.h>
#include <Parsers/ExpressionElementParsers.h>
#include <Parsers/ExpressionListParsers.h>
#include <Parsers/MySQL/ASTDeclareOption.h>
namespace DB
{
namespace MySQLParser
{
template <bool allow_default = false>
struct ParserBoolOption : public IParserBase
{
protected:
const char * getName() const override { return "bool option with default"; }
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override
{
if constexpr(allow_default)
{
if (ParserKeyword("DEFAULT").ignore(pos, expected))
{
node = std::make_shared<ASTIdentifier>("DEFAULT");
return true;
}
}
ParserLiteral p_literal;
if (!p_literal.parse(pos, node, expected) || !node->as<ASTLiteral>())
return false;
return !(node->as<ASTLiteral>()->value.safeGet<UInt64>() != 0 && node->as<ASTLiteral>()->value.safeGet<UInt64>() != 1);
}
};
struct ParserTablespaceName : public IParserBase
{
protected:
const char * getName() const override { return "table space name"; }
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override
{
ParserIdentifier p_identifier;
if (!p_identifier.parse(pos, node, expected))
return false;
if (ParserKeyword("STORAGE").ignore(pos, expected))
{
if (!ParserKeyword("DISK").ignore(pos, expected))
{
if (!ParserKeyword("MEMORY").ignore(pos, expected))
return false;
}
}
return true;
}
};
bool ParserDeclareTableOptions::parseImpl(IParser::Pos & pos, ASTPtr & node, Expected & expected)
{
return ParserDeclareOption{
{
OptionDescribe("AUTO_INCREMENT", "auto_increment", std::make_shared<ParserLiteral>()),
OptionDescribe("AVG_ROW_LENGTH", "avg_row_length", std::make_shared<ParserLiteral>()),
OptionDescribe("CHARACTER SET", "character_set", std::make_shared<ParserCharsetName>()),
OptionDescribe("DEFAULT CHARACTER SET", "character_set", std::make_shared<ParserIdentifier>()),
OptionDescribe("CHECKSUM", "checksum", std::make_shared<ParserBoolOption<false>>()),
OptionDescribe("COLLATE", "collate", std::make_shared<ParserCharsetName>()),
OptionDescribe("DEFAULT COLLATE", "collate", std::make_shared<ParserIdentifier>()),
OptionDescribe("COMMENT", "comment", std::make_shared<ParserStringLiteral>()),
OptionDescribe("COMPRESSION", "compression", std::make_shared<ParserStringLiteral>()),
OptionDescribe("CONNECTION", "connection", std::make_shared<ParserStringLiteral>()),
OptionDescribe("DATA DIRECTORY", "data_directory", std::make_shared<ParserStringLiteral>()),
OptionDescribe("INDEX DIRECTORY", "index_directory", std::make_shared<ParserStringLiteral>()),
OptionDescribe("DELAY_KEY_WRITE", "delay_key_write", std::make_shared<ParserBoolOption<false>>()),
OptionDescribe("ENCRYPTION", "encryption", std::make_shared<ParserStringLiteral>()),
OptionDescribe("ENGINE", "engine", std::make_shared<ParserIdentifier>()),
OptionDescribe("INSERT_METHOD", "insert_method", std::make_shared<ParserIdentifier>()),
OptionDescribe("KEY_BLOCK_SIZE", "key_block_size", std::make_shared<ParserLiteral>()),
OptionDescribe("MAX_ROWS", "max_rows", std::make_shared<ParserLiteral>()),
OptionDescribe("MIN_ROWS", "min_rows", std::make_shared<ParserLiteral>()),
OptionDescribe("PACK_KEYS", "pack_keys", std::make_shared<ParserBoolOption<true>>()),
OptionDescribe("PASSWORD", "password", std::make_shared<ParserStringLiteral>()),
OptionDescribe("ROW_FORMAT", "row_format", std::make_shared<ParserIdentifier>()),
OptionDescribe("STATS_AUTO_RECALC", "stats_auto_recalc", std::make_shared<ParserBoolOption<true>>()),
OptionDescribe("STATS_PERSISTENT", "stats_persistent", std::make_shared<ParserBoolOption<true>>()),
OptionDescribe("STATS_SAMPLE_PAGES", "stats_sample_pages", std::make_shared<ParserLiteral>()),
OptionDescribe("TABLESPACE", "tablespace", std::make_shared<ParserTablespaceName>()),
OptionDescribe("UNION", "union", std::make_shared<ParserExpression>()),
}
}.parse(pos, node, expected);
}
}
}

View File

@ -0,0 +1,21 @@
#pragma once
#include <Parsers/IParserBase.h>
namespace DB
{
namespace MySQLParser
{
class ParserDeclareTableOptions : public IParserBase
{
protected:
const char * getName() const override { return "table options declaration"; }
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
};
}
}

View File

@ -0,0 +1,60 @@
#include <gtest/gtest.h>
#include <Parsers/parseQuery.h>
#include <Parsers/ASTLiteral.h>
#include <Parsers/ASTFunction.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/MySQL/ASTDeclareColumn.h>
#include <Parsers/MySQL/ASTDeclareOption.h>
#include <Parsers/MySQL/ASTDeclareReference.h>
#include <Parsers/MySQL/ASTDeclareConstraint.h>
using namespace DB;
using namespace DB::MySQLParser;
TEST(ParserColumn, AllNonGeneratedColumnOption)
{
ParserDeclareColumn p_column;
String input = "col_01 VARCHAR(100) NOT NULL DEFAULT NULL AUTO_INCREMENT UNIQUE KEY PRIMARY KEY COMMENT 'column comment' COLLATE utf-8 "
"COLUMN_FORMAT FIXED STORAGE MEMORY REFERENCES tbl_name (col_01) CHECK 1";
ASTPtr ast = parseQuery(p_column, input.data(), input.data() + input.size(), "", 0, 0);
EXPECT_EQ(ast->as<ASTDeclareColumn>()->name, "col_01");
EXPECT_EQ(ast->as<ASTDeclareColumn>()->data_type->as<ASTFunction>()->name, "VARCHAR");
EXPECT_EQ(ast->as<ASTDeclareColumn>()->data_type->as<ASTFunction>()->arguments->children[0]->as<ASTLiteral>()->value.safeGet<UInt64>(), 100);
ASTDeclareOptions * declare_options = ast->as<ASTDeclareColumn>()->column_options->as<ASTDeclareOptions>();
EXPECT_EQ(declare_options->changes["is_null"]->as<ASTLiteral>()->value.safeGet<UInt64>(), 0);
EXPECT_TRUE(declare_options->changes["default"]->as<ASTLiteral>()->value.isNull());
EXPECT_EQ(declare_options->changes["auto_increment"]->as<ASTLiteral>()->value.safeGet<UInt64>(), 1);
EXPECT_EQ(declare_options->changes["unique_key"]->as<ASTLiteral>()->value.safeGet<UInt64>(), 1);
EXPECT_EQ(declare_options->changes["primary_key"]->as<ASTLiteral>()->value.safeGet<UInt64>(), 1);
EXPECT_EQ(declare_options->changes["comment"]->as<ASTLiteral>()->value.safeGet<DB::String>(), "column comment");
EXPECT_EQ(declare_options->changes["collate"]->as<ASTIdentifier>()->name, "utf-8");
EXPECT_EQ(declare_options->changes["column_format"]->as<ASTIdentifier>()->name, "FIXED");
EXPECT_EQ(declare_options->changes["storage"]->as<ASTIdentifier>()->name, "MEMORY");
EXPECT_TRUE(declare_options->changes["reference"]->as<ASTDeclareReference>());
EXPECT_TRUE(declare_options->changes["constraint"]->as<ASTDeclareConstraint>());
}
TEST(ParserColumn, AllGeneratedColumnOption)
{
ParserDeclareColumn p_column;
String input = "col_01 VARCHAR(100) NULL UNIQUE KEY PRIMARY KEY COMMENT 'column comment' COLLATE utf-8 "
"REFERENCES tbl_name (col_01) CHECK 1 GENERATED ALWAYS AS (1) STORED";
ASTPtr ast = parseQuery(p_column, input.data(), input.data() + input.size(), "", 0, 0);
EXPECT_EQ(ast->as<ASTDeclareColumn>()->name, "col_01");
EXPECT_EQ(ast->as<ASTDeclareColumn>()->data_type->as<ASTFunction>()->name, "VARCHAR");
EXPECT_EQ(ast->as<ASTDeclareColumn>()->data_type->as<ASTFunction>()->arguments->children[0]->as<ASTLiteral>()->value.safeGet<UInt64>(), 100);
ASTDeclareOptions * declare_options = ast->as<ASTDeclareColumn>()->column_options->as<ASTDeclareOptions>();
EXPECT_EQ(declare_options->changes["is_null"]->as<ASTLiteral>()->value.safeGet<UInt64>(), 1);
EXPECT_EQ(declare_options->changes["unique_key"]->as<ASTLiteral>()->value.safeGet<UInt64>(), 1);
EXPECT_EQ(declare_options->changes["primary_key"]->as<ASTLiteral>()->value.safeGet<UInt64>(), 1);
EXPECT_EQ(declare_options->changes["comment"]->as<ASTLiteral>()->value.safeGet<DB::String>(), "column comment");
EXPECT_EQ(declare_options->changes["collate"]->as<ASTIdentifier>()->name, "utf-8");
EXPECT_EQ(declare_options->changes["generated"]->as<ASTLiteral>()->value.safeGet<UInt64>(), 1);
EXPECT_EQ(declare_options->changes["is_stored"]->as<ASTLiteral>()->value.safeGet<UInt64>(), 1);
EXPECT_TRUE(declare_options->changes["reference"]->as<ASTDeclareReference>());
EXPECT_TRUE(declare_options->changes["constraint"]->as<ASTDeclareConstraint>());
}

View File

@ -0,0 +1,57 @@
#include <gtest/gtest.h>
#include <Parsers/parseQuery.h>
#include <Parsers/ASTLiteral.h>
#include <Parsers/ASTFunction.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/MySQL/ASTDeclareConstraint.h>
using namespace DB;
using namespace DB::MySQLParser;
TEST(ParserConstraint, CheckConstraint)
{
/// [CONSTRAINT [symbol]] CHECK (expr) [[NOT] ENFORCED]
ParserDeclareConstraint p_constraint;
String constraint_01 = "CONSTRAINT symbol_name CHECK col_01 = 1";
ASTPtr ast_constraint_01 = parseQuery(p_constraint, constraint_01.data(), constraint_01.data() + constraint_01.size(), "", 0, 0);
EXPECT_EQ(ast_constraint_01->as<ASTDeclareConstraint>()->constraint_name, "symbol_name");
auto check_expression_01 = ast_constraint_01->as<ASTDeclareConstraint>()->check_expression->as<ASTFunction>();
EXPECT_EQ(check_expression_01->name, "equals");
EXPECT_EQ(check_expression_01->arguments->children[0]->as<ASTIdentifier>()->name, "col_01");
EXPECT_EQ(check_expression_01->arguments->children[1]->as<ASTLiteral>()->value.safeGet<UInt64>(), 1);
String constraint_02 = "CONSTRAINT CHECK col_01 = 1";
ASTPtr ast_constraint_02 = parseQuery(p_constraint, constraint_02.data(), constraint_02.data() + constraint_02.size(), "", 0, 0);
EXPECT_EQ(ast_constraint_02->as<ASTDeclareConstraint>()->constraint_name, "");
auto check_expression_02 = ast_constraint_02->as<ASTDeclareConstraint>()->check_expression->as<ASTFunction>();
EXPECT_EQ(check_expression_02->name, "equals");
EXPECT_EQ(check_expression_02->arguments->children[0]->as<ASTIdentifier>()->name, "col_01");
EXPECT_EQ(check_expression_02->arguments->children[1]->as<ASTLiteral>()->value.safeGet<UInt64>(), 1);
String constraint_03 = "CHECK col_01 = 1";
ASTPtr ast_constraint_03 = parseQuery(p_constraint, constraint_03.data(), constraint_03.data() + constraint_03.size(), "", 0, 0);
EXPECT_EQ(ast_constraint_03->as<ASTDeclareConstraint>()->constraint_name, "");
auto check_expression_03 = ast_constraint_03->as<ASTDeclareConstraint>()->check_expression->as<ASTFunction>();
EXPECT_EQ(check_expression_03->name, "equals");
EXPECT_EQ(check_expression_03->arguments->children[0]->as<ASTIdentifier>()->name, "col_01");
EXPECT_EQ(check_expression_03->arguments->children[1]->as<ASTLiteral>()->value.safeGet<UInt64>(), 1);
String constraint_04 = "CONSTRAINT CHECK col_01 = 1 ENFORCED";
ASTPtr ast_constraint_04 = parseQuery(p_constraint, constraint_04.data(), constraint_04.data() + constraint_04.size(), "", 0, 0);
EXPECT_TRUE(ast_constraint_04->as<ASTDeclareConstraint>()->enforced);
EXPECT_EQ(ast_constraint_04->as<ASTDeclareConstraint>()->constraint_name, "");
auto check_expression_04 = ast_constraint_04->as<ASTDeclareConstraint>()->check_expression->as<ASTFunction>();
EXPECT_EQ(check_expression_04->name, "equals");
EXPECT_EQ(check_expression_04->arguments->children[0]->as<ASTIdentifier>()->name, "col_01");
EXPECT_EQ(check_expression_04->arguments->children[1]->as<ASTLiteral>()->value.safeGet<UInt64>(), 1);
String constraint_05 = "CONSTRAINT CHECK col_01 = 1 NOT ENFORCED";
ASTPtr ast_constraint_05 = parseQuery(p_constraint, constraint_05.data(), constraint_05.data() + constraint_05.size(), "", 0, 0);
EXPECT_FALSE(ast_constraint_05->as<ASTDeclareConstraint>()->enforced);
EXPECT_EQ(ast_constraint_05->as<ASTDeclareConstraint>()->constraint_name, "");
auto check_expression_05 = ast_constraint_05->as<ASTDeclareConstraint>()->check_expression->as<ASTFunction>();
EXPECT_EQ(check_expression_05->name, "equals");
EXPECT_EQ(check_expression_05->arguments->children[0]->as<ASTIdentifier>()->name, "col_01");
EXPECT_EQ(check_expression_05->arguments->children[1]->as<ASTLiteral>()->value.safeGet<UInt64>(), 1);
}

View File

@ -0,0 +1,33 @@
#include <gtest/gtest.h>
#include <Parsers/parseQuery.h>
#include <Parsers/ASTFunction.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/MySQL/ASTCreateQuery.h>
#include <Parsers/MySQL/ASTDeclareOption.h>
#include <Parsers/MySQL/ASTDeclarePartitionOptions.h>
#include <Parsers/MySQL/ASTCreateDefines.h>
using namespace DB;
using namespace DB::MySQLParser;
TEST(CreateTableParser, LikeCreate)
{
ParserCreateQuery p_create_query;
String like_create_01 = "CREATE TABLE IF NOT EXISTS table_name LIKE table_name_01";
parseQuery(p_create_query, like_create_01.data(), like_create_01.data() + like_create_01.size(), "", 0, 0);
String like_create_02 = "CREATE TABLE IF NOT EXISTS table_name (LIKE table_name_01)";
parseQuery(p_create_query, like_create_02.data(), like_create_02.data() + like_create_02.size(), "", 0, 0);
}
TEST(CreateTableParser, SimpleCreate)
{
ParserCreateQuery p_create_query;
String input = "CREATE TABLE IF NOT EXISTS table_name(col_01 VARCHAR(100), INDEX (col_01), CHECK 1) ENGINE INNODB PARTITION BY HASH(col_01)";
ASTPtr ast = parseQuery(p_create_query, input.data(), input.data() + input.size(), "", 0, 0);
EXPECT_TRUE(ast->as<ASTCreateQuery>()->if_not_exists);
EXPECT_EQ(ast->as<ASTCreateQuery>()->columns_list->as<ASTCreateDefines>()->columns->children.size(), 1);
EXPECT_EQ(ast->as<ASTCreateQuery>()->columns_list->as<ASTCreateDefines>()->indices->children.size(), 1);
EXPECT_EQ(ast->as<ASTCreateQuery>()->columns_list->as<ASTCreateDefines>()->constraints->children.size(), 1);
EXPECT_EQ(ast->as<ASTCreateQuery>()->table_options->as<ASTDeclareOptions>()->changes["engine"]->as<ASTIdentifier>()->name, "INNODB");
EXPECT_TRUE(ast->as<ASTCreateQuery>()->partition_options->as<ASTDeclarePartitionOptions>());
}

View File

@ -0,0 +1,125 @@
#include <gtest/gtest.h>
#include <Parsers/parseQuery.h>
#include <Parsers/ASTLiteral.h>
#include <Parsers/ASTFunction.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/MySQL/ASTDeclareIndex.h>
#include <Parsers/MySQL/ASTDeclareOption.h>
using namespace DB;
using namespace DB::MySQLParser;
TEST(ParserIndex, AllIndexOptions)
{
String input = "INDEX (col_01, col_02(100), col_03 DESC) KEY_BLOCK_SIZE 3 USING HASH WITH PARSER parser_name COMMENT 'index comment' VISIBLE";
ParserDeclareIndex p_index;
ASTPtr ast = parseQuery(p_index, input.data(), input.data() + input.size(), "", 0, 0);
ASTDeclareIndex * declare_index = ast->as<ASTDeclareIndex>();
EXPECT_EQ(declare_index->index_columns->children[0]->as<ASTIdentifier>()->name, "col_01");
EXPECT_EQ(declare_index->index_columns->children[1]->as<ASTFunction>()->name, "col_02");
EXPECT_EQ(declare_index->index_columns->children[1]->as<ASTFunction>()->arguments->children[0]->as<ASTLiteral>()->value.safeGet<UInt64>(), 100);
EXPECT_EQ(declare_index->index_columns->children[2]->as<ASTIdentifier>()->name, "col_03");
ASTDeclareOptions * declare_options = declare_index->index_options->as<ASTDeclareOptions>();
EXPECT_EQ(declare_options->changes["key_block_size"]->as<ASTLiteral>()->value.safeGet<UInt64>(), 3);
EXPECT_EQ(declare_options->changes["index_type"]->as<ASTIdentifier>()->name, "HASH");
EXPECT_EQ(declare_options->changes["comment"]->as<ASTLiteral>()->value.safeGet<String>(), "index comment");
EXPECT_EQ(declare_options->changes["visible"]->as<ASTLiteral>()->value.safeGet<UInt64>(), 1);
}
TEST(ParserIndex, OptionalIndexOptions)
{
String input = "INDEX (col_01, col_02(100), col_03 DESC) USING HASH INVISIBLE KEY_BLOCK_SIZE 3";
ParserDeclareIndex p_index;
ASTPtr ast = parseQuery(p_index, input.data(), input.data() + input.size(), "", 0, 0);
ASTDeclareIndex * declare_index = ast->as<ASTDeclareIndex>();
EXPECT_EQ(declare_index->index_columns->children[0]->as<ASTIdentifier>()->name, "col_01");
EXPECT_EQ(declare_index->index_columns->children[1]->as<ASTFunction>()->name, "col_02");
EXPECT_EQ(declare_index->index_columns->children[1]->as<ASTFunction>()->arguments->children[0]->as<ASTLiteral>()->value.safeGet<UInt64>(), 100);
EXPECT_EQ(declare_index->index_columns->children[2]->as<ASTIdentifier>()->name, "col_03");
ASTDeclareOptions * declare_options = declare_index->index_options->as<ASTDeclareOptions>();
EXPECT_EQ(declare_options->changes["index_type"]->as<ASTIdentifier>()->name, "HASH");
EXPECT_EQ(declare_options->changes["visible"]->as<ASTLiteral>()->value.safeGet<UInt64>(), 0);
EXPECT_EQ(declare_options->changes["key_block_size"]->as<ASTLiteral>()->value.safeGet<UInt64>(), 3);
}
TEST(ParserIndex, OrdinaryIndex)
{
ParserDeclareIndex p_index;
String non_unique_index_01 = "KEY index_name USING HASH (col_01) INVISIBLE";
parseQuery(p_index, non_unique_index_01.data(), non_unique_index_01.data() + non_unique_index_01.size(), "", 0, 0);
String non_unique_index_02 = "INDEX index_name USING HASH (col_01) INVISIBLE";
parseQuery(p_index, non_unique_index_02.data(), non_unique_index_02.data() + non_unique_index_02.size(), "", 0, 0);
String fulltext_index_01 = "FULLTEXT index_name (col_01) INVISIBLE";
parseQuery(p_index, fulltext_index_01.data(), fulltext_index_01.data() + fulltext_index_01.size(), "", 0, 0);
String fulltext_index_02 = "FULLTEXT INDEX index_name (col_01) INVISIBLE";
parseQuery(p_index, fulltext_index_02.data(), fulltext_index_02.data() + fulltext_index_02.size(), "", 0, 0);
String fulltext_index_03 = "FULLTEXT KEY index_name (col_01) INVISIBLE";
parseQuery(p_index, fulltext_index_03.data(), fulltext_index_03.data() + fulltext_index_03.size(), "", 0, 0);
String spatial_index_01 = "SPATIAL index_name (col_01) INVISIBLE";
parseQuery(p_index, spatial_index_01.data(), spatial_index_01.data() + spatial_index_01.size(), "", 0, 0);
String spatial_index_02 = "SPATIAL INDEX index_name (col_01) INVISIBLE";
parseQuery(p_index, spatial_index_02.data(), spatial_index_02.data() + spatial_index_02.size(), "", 0, 0);
String spatial_index_03 = "SPATIAL KEY index_name (col_01) INVISIBLE";
parseQuery(p_index, spatial_index_03.data(), spatial_index_03.data() + spatial_index_03.size(), "", 0, 0);
}
TEST(ParserIndex, ConstraintIndex)
{
ParserDeclareIndex p_index;
String primary_key_01 = "PRIMARY KEY (col_01) INVISIBLE";
parseQuery(p_index, primary_key_01.data(), primary_key_01.data() + primary_key_01.size(), "", 0, 0);
String primary_key_02 = "PRIMARY KEY USING BTREE (col_01) INVISIBLE";
parseQuery(p_index, primary_key_02.data(), primary_key_02.data() + primary_key_02.size(), "", 0, 0);
String primary_key_03 = "CONSTRAINT PRIMARY KEY USING BTREE (col_01) INVISIBLE";
parseQuery(p_index, primary_key_03.data(), primary_key_03.data() + primary_key_03.size(), "", 0, 0);
String primary_key_04 = "CONSTRAINT index_name PRIMARY KEY USING BTREE (col_01) INVISIBLE";
parseQuery(p_index, primary_key_04.data(), primary_key_04.data() + primary_key_04.size(), "", 0, 0);
String unique_key_01 = "UNIQUE (col_01) INVISIBLE";
parseQuery(p_index, unique_key_01.data(), unique_key_01.data() + unique_key_01.size(), "", 0, 0);
String unique_key_02 = "UNIQUE INDEX (col_01) INVISIBLE";
parseQuery(p_index, unique_key_02.data(), unique_key_02.data() + unique_key_02.size(), "", 0, 0);
String unique_key_03 = "UNIQUE KEY (col_01) INVISIBLE";
parseQuery(p_index, unique_key_03.data(), unique_key_03.data() + unique_key_03.size(), "", 0, 0);
String unique_key_04 = "UNIQUE KEY index_name (col_01) INVISIBLE";
parseQuery(p_index, unique_key_04.data(), unique_key_04.data() + unique_key_04.size(), "", 0, 0);
String unique_key_05 = "UNIQUE KEY index_name USING HASH (col_01) INVISIBLE";
parseQuery(p_index, unique_key_05.data(), unique_key_05.data() + unique_key_05.size(), "", 0, 0);
String unique_key_06 = "CONSTRAINT UNIQUE KEY index_name USING HASH (col_01) INVISIBLE";
parseQuery(p_index, unique_key_06.data(), unique_key_06.data() + unique_key_06.size(), "", 0, 0);
String unique_key_07 = "CONSTRAINT index_name UNIQUE KEY index_name_1 USING HASH (col_01) INVISIBLE";
parseQuery(p_index, unique_key_07.data(), unique_key_07.data() + unique_key_07.size(), "", 0, 0);
String foreign_key_01 = "FOREIGN KEY (col_01) REFERENCES tbl_name (col_01)";
parseQuery(p_index, foreign_key_01.data(), foreign_key_01.data() + foreign_key_01.size(), "", 0, 0);
String foreign_key_02 = "FOREIGN KEY index_name (col_01) REFERENCES tbl_name (col_01)";
parseQuery(p_index, foreign_key_02.data(), foreign_key_02.data() + foreign_key_02.size(), "", 0, 0);
String foreign_key_03 = "CONSTRAINT FOREIGN KEY index_name (col_01) REFERENCES tbl_name (col_01)";
parseQuery(p_index, foreign_key_03.data(), foreign_key_03.data() + foreign_key_03.size(), "", 0, 0);
String foreign_key_04 = "CONSTRAINT index_name FOREIGN KEY index_name_01 (col_01) REFERENCES tbl_name (col_01)";
parseQuery(p_index, foreign_key_04.data(), foreign_key_04.data() + foreign_key_04.size(), "", 0, 0);
}

View File

@ -0,0 +1,167 @@
#include <gtest/gtest.h>
#include <Parsers/parseQuery.h>
#include <Parsers/ASTLiteral.h>
#include <Parsers/ASTFunction.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/MySQL/ASTDeclarePartition.h>
#include <Parsers/MySQL/ASTDeclarePartitionOptions.h>
using namespace DB;
using namespace DB::MySQLParser;
TEST(ParserPartitionOptions, HashPatitionOptions)
{
String hash_partition = "PARTITION BY HASH(col_01)";
ParserDeclarePartitionOptions p_partition_options;
ASTPtr ast_01 = parseQuery(p_partition_options, hash_partition.data(), hash_partition.data() + hash_partition.size(), "", 0, 0);
ASTDeclarePartitionOptions * declare_partition_options_01 = ast_01->as<ASTDeclarePartitionOptions>();
EXPECT_EQ(declare_partition_options_01->partition_type, "hash");
EXPECT_EQ(declare_partition_options_01->partition_expression->as<ASTIdentifier>()->name, "col_01");
String linear_hash_partition = "PARTITION BY LINEAR HASH(col_01)";
ASTPtr ast_02 = parseQuery(p_partition_options, linear_hash_partition.data(), linear_hash_partition.data() + linear_hash_partition.size(), "", 0, 0);
ASTDeclarePartitionOptions * declare_partition_options_02 = ast_02->as<ASTDeclarePartitionOptions>();
EXPECT_EQ(declare_partition_options_02->partition_type, "linear_hash");
EXPECT_EQ(declare_partition_options_02->partition_expression->as<ASTIdentifier>()->name, "col_01");
}
TEST(ParserPartitionOptions, KeyPatitionOptions)
{
String key_partition = "PARTITION BY KEY(col_01)";
ParserDeclarePartitionOptions p_partition_options;
ASTPtr ast_01 = parseQuery(p_partition_options, key_partition.data(), key_partition.data() + key_partition.size(), "", 0, 0);
ASTDeclarePartitionOptions * declare_partition_options_01 = ast_01->as<ASTDeclarePartitionOptions>();
EXPECT_EQ(declare_partition_options_01->partition_type, "key");
EXPECT_EQ(declare_partition_options_01->partition_expression->as<ASTIdentifier>()->name, "col_01");
String linear_key_partition = "PARTITION BY LINEAR KEY(col_01, col_02)";
ASTPtr ast_02 = parseQuery(p_partition_options, linear_key_partition.data(), linear_key_partition.data() + linear_key_partition.size(), "", 0, 0);
ASTDeclarePartitionOptions * declare_partition_options_02 = ast_02->as<ASTDeclarePartitionOptions>();
EXPECT_EQ(declare_partition_options_02->partition_type, "linear_key");
ASTPtr columns_list = declare_partition_options_02->partition_expression->as<ASTFunction>()->arguments;
EXPECT_EQ(columns_list->children[0]->as<ASTIdentifier>()->name, "col_01");
EXPECT_EQ(columns_list->children[1]->as<ASTIdentifier>()->name, "col_02");
String key_partition_with_algorithm = "PARTITION BY KEY ALGORITHM=1 (col_01)";
ASTPtr ast_03 = parseQuery(p_partition_options, key_partition_with_algorithm.data(), key_partition_with_algorithm.data() + key_partition_with_algorithm.size(), "", 0, 0);
ASTDeclarePartitionOptions * declare_partition_options_03 = ast_03->as<ASTDeclarePartitionOptions>();
EXPECT_EQ(declare_partition_options_03->partition_type, "key_1");
EXPECT_EQ(declare_partition_options_03->partition_expression->as<ASTIdentifier>()->name, "col_01");
}
TEST(ParserPartitionOptions, RangePatitionOptions)
{
String range_partition = "PARTITION BY RANGE(col_01)";
ParserDeclarePartitionOptions p_partition_options;
ASTPtr ast_01 = parseQuery(p_partition_options, range_partition.data(), range_partition.data() + range_partition.size(), "", 0, 0);
ASTDeclarePartitionOptions * declare_partition_options_01 = ast_01->as<ASTDeclarePartitionOptions>();
EXPECT_EQ(declare_partition_options_01->partition_type, "range");
EXPECT_EQ(declare_partition_options_01->partition_expression->as<ASTIdentifier>()->name, "col_01");
String range_columns_partition = "PARTITION BY RANGE COLUMNS(col_01, col_02)";
ASTPtr ast_02 = parseQuery(p_partition_options, range_columns_partition.data(), range_columns_partition.data() + range_columns_partition.size(), "", 0, 0);
ASTDeclarePartitionOptions * declare_partition_options_02 = ast_02->as<ASTDeclarePartitionOptions>();
EXPECT_EQ(declare_partition_options_02->partition_type, "range");
ASTPtr columns_list = declare_partition_options_02->partition_expression->as<ASTFunction>()->arguments;
EXPECT_EQ(columns_list->children[0]->as<ASTIdentifier>()->name, "col_01");
EXPECT_EQ(columns_list->children[1]->as<ASTIdentifier>()->name, "col_02");
}
TEST(ParserPartitionOptions, ListPatitionOptions)
{
String range_partition = "PARTITION BY LIST(col_01)";
ParserDeclarePartitionOptions p_partition_options;
ASTPtr ast_01 = parseQuery(p_partition_options, range_partition.data(), range_partition.data() + range_partition.size(), "", 0, 0);
ASTDeclarePartitionOptions * declare_partition_options_01 = ast_01->as<ASTDeclarePartitionOptions>();
EXPECT_EQ(declare_partition_options_01->partition_type, "list");
EXPECT_EQ(declare_partition_options_01->partition_expression->as<ASTIdentifier>()->name, "col_01");
String range_columns_partition = "PARTITION BY LIST COLUMNS(col_01, col_02)";
ASTPtr ast_02 = parseQuery(p_partition_options, range_columns_partition.data(), range_columns_partition.data() + range_columns_partition.size(), "", 0, 0);
ASTDeclarePartitionOptions * declare_partition_options_02 = ast_02->as<ASTDeclarePartitionOptions>();
EXPECT_EQ(declare_partition_options_02->partition_type, "list");
ASTPtr columns_list = declare_partition_options_02->partition_expression->as<ASTFunction>()->arguments;
EXPECT_EQ(columns_list->children[0]->as<ASTIdentifier>()->name, "col_01");
EXPECT_EQ(columns_list->children[1]->as<ASTIdentifier>()->name, "col_02");
}
TEST(ParserPartitionOptions, PatitionNumberOptions)
{
String numbers_partition = "PARTITION BY KEY(col_01) PARTITIONS 2";
ParserDeclarePartitionOptions p_partition_options;
ASTPtr ast = parseQuery(p_partition_options, numbers_partition.data(), numbers_partition.data() + numbers_partition.size(), "", 0, 0);
ASTDeclarePartitionOptions * declare_partition_options = ast->as<ASTDeclarePartitionOptions>();
EXPECT_EQ(declare_partition_options->partition_type, "key");
EXPECT_EQ(declare_partition_options->partition_expression->as<ASTIdentifier>()->name, "col_01");
EXPECT_EQ(declare_partition_options->partition_numbers->as<ASTLiteral>()->value.safeGet<UInt64>(), 2);
}
TEST(ParserPartitionOptions, PatitionWithSubpartitionOptions)
{
String partition_with_subpartition = "PARTITION BY KEY(col_01) PARTITIONS 3 SUBPARTITION BY HASH(col_02) SUBPARTITIONS 4";
ParserDeclarePartitionOptions p_partition_options;
ASTPtr ast = parseQuery(p_partition_options, partition_with_subpartition.data(), partition_with_subpartition.data() + partition_with_subpartition.size(), "", 0, 0);
ASTDeclarePartitionOptions * declare_partition_options = ast->as<ASTDeclarePartitionOptions>();
EXPECT_EQ(declare_partition_options->partition_type, "key");
EXPECT_EQ(declare_partition_options->partition_expression->as<ASTIdentifier>()->name, "col_01");
EXPECT_EQ(declare_partition_options->partition_numbers->as<ASTLiteral>()->value.safeGet<UInt64>(), 3);
EXPECT_EQ(declare_partition_options->subpartition_type, "hash");
EXPECT_EQ(declare_partition_options->subpartition_expression->as<ASTIdentifier>()->name, "col_02");
EXPECT_EQ(declare_partition_options->subpartition_numbers->as<ASTLiteral>()->value.safeGet<UInt64>(), 4);
}
TEST(ParserPartitionOptions, PatitionOptionsWithDeclarePartition)
{
String partition_options_with_declare = "PARTITION BY KEY(col_01) PARTITIONS 3 SUBPARTITION BY HASH(col_02) SUBPARTITIONS 4 (PARTITION partition_name)";
ParserDeclarePartitionOptions p_partition_options;
ASTPtr ast = parseQuery(p_partition_options,
partition_options_with_declare.data(),
partition_options_with_declare.data() + partition_options_with_declare.size(), "", 0, 0);
ASTDeclarePartitionOptions * declare_partition_options = ast->as<ASTDeclarePartitionOptions>();
EXPECT_EQ(declare_partition_options->partition_type, "key");
EXPECT_EQ(declare_partition_options->partition_expression->as<ASTIdentifier>()->name, "col_01");
EXPECT_EQ(declare_partition_options->partition_numbers->as<ASTLiteral>()->value.safeGet<UInt64>(), 3);
EXPECT_EQ(declare_partition_options->subpartition_type, "hash");
EXPECT_EQ(declare_partition_options->subpartition_expression->as<ASTIdentifier>()->name, "col_02");
EXPECT_EQ(declare_partition_options->subpartition_numbers->as<ASTLiteral>()->value.safeGet<UInt64>(), 4);
EXPECT_TRUE(declare_partition_options->declare_partitions->as<ASTExpressionList>()->children[0]->as<ASTDeclarePartition>());
}
TEST(ParserPartitionOptions, PatitionOptionsWithDeclarePartitions)
{
String partition_options_with_declare = "PARTITION BY KEY(col_01) PARTITIONS 3 SUBPARTITION BY HASH(col_02) SUBPARTITIONS 4 (PARTITION partition_01, PARTITION partition_02)";
ParserDeclarePartitionOptions p_partition_options;
ASTPtr ast = parseQuery(p_partition_options,
partition_options_with_declare.data(),
partition_options_with_declare.data() + partition_options_with_declare.size(), "", 0, 0);
ASTDeclarePartitionOptions * declare_partition_options = ast->as<ASTDeclarePartitionOptions>();
EXPECT_EQ(declare_partition_options->partition_type, "key");
EXPECT_EQ(declare_partition_options->partition_expression->as<ASTIdentifier>()->name, "col_01");
EXPECT_EQ(declare_partition_options->partition_numbers->as<ASTLiteral>()->value.safeGet<UInt64>(), 3);
EXPECT_EQ(declare_partition_options->subpartition_type, "hash");
EXPECT_EQ(declare_partition_options->subpartition_expression->as<ASTIdentifier>()->name, "col_02");
EXPECT_EQ(declare_partition_options->subpartition_numbers->as<ASTLiteral>()->value.safeGet<UInt64>(), 4);
EXPECT_TRUE(declare_partition_options->declare_partitions->as<ASTExpressionList>()->children[0]->as<ASTDeclarePartition>());
EXPECT_TRUE(declare_partition_options->declare_partitions->as<ASTExpressionList>()->children[1]->as<ASTDeclarePartition>());
}

View File

@ -0,0 +1,149 @@
#include <gtest/gtest.h>
#include <Parsers/parseQuery.h>
#include <Parsers/ASTLiteral.h>
#include <Parsers/ASTFunction.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/MySQL/ASTDeclareOption.h>
#include <Parsers/MySQL/ASTDeclarePartition.h>
#include <Parsers/MySQL/ASTDeclareSubPartition.h>
using namespace DB;
using namespace DB::MySQLParser;
TEST(ParserPartition, AllPatitionOptions)
{
String input = "PARTITION partition_name ENGINE = engine_name COMMENT 'partition comment'"
" INDEX DIRECTORY 'index_directory' DATA DIRECTORY 'data_directory' max_rows 1000 MIN_ROWs 0"
" TABLESPACE table_space_name";
ParserDeclarePartition p_partition;
ASTPtr ast = parseQuery(p_partition, input.data(), input.data() + input.size(), "", 0, 0);
ASTDeclarePartition * declare_partition = ast->as<ASTDeclarePartition>();
EXPECT_EQ(declare_partition->partition_name, "partition_name");
ASTDeclareOptions * declare_options = declare_partition->options->as<ASTDeclareOptions>();
EXPECT_EQ(declare_options->changes["engine"]->as<ASTIdentifier>()->name, "engine_name");
EXPECT_EQ(declare_options->changes["comment"]->as<ASTLiteral>()->value.safeGet<String>(), "partition comment");
EXPECT_EQ(declare_options->changes["data_directory"]->as<ASTLiteral>()->value.safeGet<String>(), "data_directory");
EXPECT_EQ(declare_options->changes["index_directory"]->as<ASTLiteral>()->value.safeGet<String>(), "index_directory");
EXPECT_EQ(declare_options->changes["min_rows"]->as<ASTLiteral>()->value.safeGet<UInt64>(), 0);
EXPECT_EQ(declare_options->changes["max_rows"]->as<ASTLiteral>()->value.safeGet<UInt64>(), 1000);
EXPECT_EQ(declare_options->changes["tablespace"]->as<ASTIdentifier>()->name, "table_space_name");
}
TEST(ParserPartition, OptionalPatitionOptions)
{
String input = "PARTITION partition_name STORAGE engine = engine_name max_rows 1000 min_rows 0 tablespace table_space_name";
ParserDeclarePartition p_partition;
ASTPtr ast = parseQuery(p_partition, input.data(), input.data() + input.size(), "", 0, 0);
ASTDeclarePartition * declare_partition = ast->as<ASTDeclarePartition>();
EXPECT_EQ(declare_partition->partition_name, "partition_name");
ASTDeclareOptions * declare_options = declare_partition->options->as<ASTDeclareOptions>();
EXPECT_EQ(declare_options->changes["engine"]->as<ASTIdentifier>()->name, "engine_name");
EXPECT_EQ(declare_options->changes["min_rows"]->as<ASTLiteral>()->value.safeGet<UInt64>(), 0);
EXPECT_EQ(declare_options->changes["max_rows"]->as<ASTLiteral>()->value.safeGet<UInt64>(), 1000);
EXPECT_EQ(declare_options->changes["tablespace"]->as<ASTIdentifier>()->name, "table_space_name");
}
TEST(ParserPartition, PatitionOptionsWithLessThan)
{
ParserDeclarePartition p_partition;
String partition_01 = "PARTITION partition_01 VALUES LESS THAN (1991) STORAGE engine = engine_name";
ASTPtr ast_partition_01 = parseQuery(p_partition, partition_01.data(), partition_01.data() + partition_01.size(), "", 0, 0);
ASTDeclarePartition * declare_partition_01 = ast_partition_01->as<ASTDeclarePartition>();
EXPECT_EQ(declare_partition_01->partition_name, "partition_01");
EXPECT_EQ(declare_partition_01->less_than->as<ASTLiteral>()->value.safeGet<UInt64>(), 1991);
ASTDeclareOptions * declare_options_01 = declare_partition_01->options->as<ASTDeclareOptions>();
EXPECT_EQ(declare_options_01->changes["engine"]->as<ASTIdentifier>()->name, "engine_name");
String partition_02 = "PARTITION partition_02 VALUES LESS THAN MAXVALUE STORAGE engine = engine_name";
ASTPtr ast_partition_02 = parseQuery(p_partition, partition_02.data(), partition_02.data() + partition_02.size(), "", 0, 0);
ASTDeclarePartition * declare_partition_02 = ast_partition_02->as<ASTDeclarePartition>();
EXPECT_EQ(declare_partition_02->partition_name, "partition_02");
EXPECT_EQ(declare_partition_02->less_than->as<ASTIdentifier>()->name, "MAXVALUE");
ASTDeclareOptions * declare_options_02 = declare_partition_02->options->as<ASTDeclareOptions>();
EXPECT_EQ(declare_options_02->changes["engine"]->as<ASTIdentifier>()->name, "engine_name");
String partition_03 = "PARTITION partition_03 VALUES LESS THAN (50, MAXVALUE) STORAGE engine = engine_name";
ASTPtr ast_partition_03 = parseQuery(p_partition, partition_03.data(), partition_03.data() + partition_03.size(), "", 0, 0);
ASTDeclarePartition * declare_partition_03 = ast_partition_03->as<ASTDeclarePartition>();
EXPECT_EQ(declare_partition_03->partition_name, "partition_03");
ASTPtr declare_partition_03_argument = declare_partition_03->less_than->as<ASTFunction>()->arguments;
EXPECT_EQ(declare_partition_03_argument->children[0]->as<ASTLiteral>()->value.safeGet<UInt64>(), 50);
EXPECT_EQ(declare_partition_03_argument->children[1]->as<ASTIdentifier>()->name, "MAXVALUE");
ASTDeclareOptions * declare_options_03 = declare_partition_03->options->as<ASTDeclareOptions>();
EXPECT_EQ(declare_options_03->changes["engine"]->as<ASTIdentifier>()->name, "engine_name");
String partition_04 = "PARTITION partition_04 VALUES LESS THAN (MAXVALUE, MAXVALUE) STORAGE engine = engine_name";
ASTPtr ast_partition_04 = parseQuery(p_partition, partition_04.data(), partition_04.data() + partition_04.size(), "", 0, 0);
ASTDeclarePartition * declare_partition_04 = ast_partition_04->as<ASTDeclarePartition>();
EXPECT_EQ(declare_partition_04->partition_name, "partition_04");
ASTPtr declare_partition_04_argument = declare_partition_04->less_than->as<ASTFunction>()->arguments;
EXPECT_EQ(declare_partition_04_argument->children[0]->as<ASTIdentifier>()->name, "MAXVALUE");
EXPECT_EQ(declare_partition_04_argument->children[1]->as<ASTIdentifier>()->name, "MAXVALUE");
ASTDeclareOptions * declare_options_04 = declare_partition_04->options->as<ASTDeclareOptions>();
EXPECT_EQ(declare_options_04->changes["engine"]->as<ASTIdentifier>()->name, "engine_name");
}
TEST(ParserPartition, PatitionOptionsWithInExpression)
{
ParserDeclarePartition p_partition;
String partition_01 = "PARTITION partition_01 VALUES IN (NULL, 1991, MAXVALUE) STORAGE engine = engine_name";
ASTPtr ast_partition_01 = parseQuery(p_partition, partition_01.data(), partition_01.data() + partition_01.size(), "", 0, 0);
ASTDeclarePartition * declare_partition_01 = ast_partition_01->as<ASTDeclarePartition>();
EXPECT_EQ(declare_partition_01->partition_name, "partition_01");
ASTPtr declare_partition_01_argument = declare_partition_01->in_expression->as<ASTFunction>()->arguments;
EXPECT_TRUE(declare_partition_01_argument->children[0]->as<ASTLiteral>()->value.isNull());
EXPECT_EQ(declare_partition_01_argument->children[1]->as<ASTLiteral>()->value.safeGet<UInt64>(), 1991);
EXPECT_EQ(declare_partition_01_argument->children[2]->as<ASTIdentifier>()->name, "MAXVALUE");
ASTDeclareOptions * declare_options_01 = declare_partition_01->options->as<ASTDeclareOptions>();
EXPECT_EQ(declare_options_01->changes["engine"]->as<ASTIdentifier>()->name, "engine_name");
String partition_02 = "PARTITION partition_02 VALUES IN ((NULL, 1991), (1991, NULL), (MAXVALUE, MAXVALUE)) STORAGE engine = engine_name";
ASTPtr ast_partition_02 = parseQuery(p_partition, partition_02.data(), partition_02.data() + partition_02.size(), "", 0, 0);
ASTDeclarePartition * declare_partition_02 = ast_partition_02->as<ASTDeclarePartition>();
EXPECT_EQ(declare_partition_02->partition_name, "partition_02");
ASTPtr declare_partition_02_argument = declare_partition_02->in_expression->as<ASTFunction>()->arguments;
ASTPtr argument_01 = declare_partition_02_argument->children[0];
EXPECT_TRUE(argument_01->as<ASTLiteral>()->value.safeGet<Tuple>()[0].isNull());
EXPECT_EQ(argument_01->as<ASTLiteral>()->value.safeGet<Tuple>()[1].safeGet<UInt64>(), 1991);
ASTPtr argument_02 = declare_partition_02_argument->children[1];
EXPECT_EQ(argument_02->as<ASTLiteral>()->value.safeGet<Tuple>()[0].safeGet<UInt64>(), 1991);
EXPECT_TRUE(argument_02->as<ASTLiteral>()->value.safeGet<Tuple>()[1].isNull());
ASTPtr argument_03 = declare_partition_02_argument->children[2]->as<ASTFunction>()->arguments;
EXPECT_EQ(argument_03->as<ASTExpressionList>()->children[0]->as<ASTIdentifier>()->name, "MAXVALUE");
EXPECT_EQ(argument_03->as<ASTExpressionList>()->children[1]->as<ASTIdentifier>()->name, "MAXVALUE");
ASTDeclareOptions * declare_options_02 = declare_partition_02->options->as<ASTDeclareOptions>();
EXPECT_EQ(declare_options_02->changes["engine"]->as<ASTIdentifier>()->name, "engine_name");
}
TEST(ParserPartition, PatitionOptionsWithSubpartitions)
{
ParserDeclarePartition p_partition;
String partition_01 = "PARTITION partition_01 VALUES IN (NULL, 1991, MAXVALUE) STORAGE engine = engine_name (SUBPARTITION s_p01)";
ASTPtr ast_partition_01 = parseQuery(p_partition, partition_01.data(), partition_01.data() + partition_01.size(), "", 0, 0);
ASTDeclarePartition * declare_partition_01 = ast_partition_01->as<ASTDeclarePartition>();
EXPECT_EQ(declare_partition_01->partition_name, "partition_01");
EXPECT_TRUE(declare_partition_01->subpartitions->as<ASTExpressionList>()->children[0]->as<ASTDeclareSubPartition>());
String partition_02 = "PARTITION partition_02 VALUES IN (NULL, 1991, MAXVALUE) STORAGE engine = engine_name (SUBPARTITION s_p01, SUBPARTITION s_p02)";
ASTPtr ast_partition_02 = parseQuery(p_partition, partition_02.data(), partition_02.data() + partition_02.size(), "", 0, 0);
ASTDeclarePartition * declare_partition_02 = ast_partition_02->as<ASTDeclarePartition>();
EXPECT_EQ(declare_partition_02->partition_name, "partition_02");
EXPECT_TRUE(declare_partition_02->subpartitions->as<ASTExpressionList>()->children[0]->as<ASTDeclareSubPartition>());
EXPECT_TRUE(declare_partition_02->subpartitions->as<ASTExpressionList>()->children[1]->as<ASTDeclareSubPartition>());
}

View File

@ -0,0 +1,92 @@
#include <gtest/gtest.h>
#include <Parsers/parseQuery.h>
#include <Parsers/ASTFunction.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/MySQL/ASTDeclareReference.h>
using namespace DB;
using namespace DB::MySQLParser;
TEST(ParserReference, SimpleReference)
{
ParserDeclareReference p_reference;
String reference_01 = "REFERENCES table_name (ref_col_01)";
ASTPtr ast_reference_01 = parseQuery(p_reference, reference_01.data(), reference_01.data() + reference_01.size(), "", 0, 0);
EXPECT_EQ(ast_reference_01->as<ASTDeclareReference>()->reference_table_name, "table_name");
EXPECT_EQ(ast_reference_01->as<ASTDeclareReference>()->reference_expression->as<ASTIdentifier>()->name, "ref_col_01");
String reference_02 = "REFERENCES table_name (ref_col_01, ref_col_02)";
ASTPtr ast_reference_02 = parseQuery(p_reference, reference_02.data(), reference_02.data() + reference_02.size(), "", 0, 0);
EXPECT_EQ(ast_reference_02->as<ASTDeclareReference>()->reference_table_name, "table_name");
ASTPtr arguments = ast_reference_02->as<ASTDeclareReference>()->reference_expression->as<ASTFunction>()->arguments;
EXPECT_EQ(arguments->children[0]->as<ASTIdentifier>()->name, "ref_col_01");
EXPECT_EQ(arguments->children[1]->as<ASTIdentifier>()->name, "ref_col_02");
}
TEST(ParserReference, ReferenceDifferenceKind)
{
ParserDeclareReference p_reference;
String reference_01 = "REFERENCES table_name (ref_col_01) MATCH FULL";
ASTPtr ast_reference_01 = parseQuery(p_reference, reference_01.data(), reference_01.data() + reference_01.size(), "", 0, 0);
EXPECT_EQ(ast_reference_01->as<ASTDeclareReference>()->reference_table_name, "table_name");
EXPECT_EQ(ast_reference_01->as<ASTDeclareReference>()->reference_expression->as<ASTIdentifier>()->name, "ref_col_01");
EXPECT_EQ(ast_reference_01->as<ASTDeclareReference>()->kind, ASTDeclareReference::MATCH_FULL);
String reference_02 = "REFERENCES table_name (ref_col_01) MATCH PARTIAL";
ASTPtr ast_reference_02 = parseQuery(p_reference, reference_02.data(), reference_02.data() + reference_02.size(), "", 0, 0);
EXPECT_EQ(ast_reference_02->as<ASTDeclareReference>()->reference_table_name, "table_name");
EXPECT_EQ(ast_reference_02->as<ASTDeclareReference>()->reference_expression->as<ASTIdentifier>()->name, "ref_col_01");
EXPECT_EQ(ast_reference_02->as<ASTDeclareReference>()->kind, ASTDeclareReference::MATCH_PARTIAL);
String reference_03 = "REFERENCES table_name (ref_col_01) MATCH SIMPLE";
ASTPtr ast_reference_03 = parseQuery(p_reference, reference_03.data(), reference_03.data() + reference_03.size(), "", 0, 0);
EXPECT_EQ(ast_reference_03->as<ASTDeclareReference>()->reference_table_name, "table_name");
EXPECT_EQ(ast_reference_03->as<ASTDeclareReference>()->reference_expression->as<ASTIdentifier>()->name, "ref_col_01");
EXPECT_EQ(ast_reference_03->as<ASTDeclareReference>()->kind, ASTDeclareReference::MATCH_SIMPLE);
}
TEST(ParserReference, ReferenceDifferenceOption)
{
ParserDeclareReference p_reference;
String reference_01 = "REFERENCES table_name (ref_col_01) MATCH FULL ON DELETE RESTRICT ON UPDATE RESTRICT";
ASTPtr ast_reference_01 = parseQuery(p_reference, reference_01.data(), reference_01.data() + reference_01.size(), "", 0, 0);
EXPECT_EQ(ast_reference_01->as<ASTDeclareReference>()->reference_table_name, "table_name");
EXPECT_EQ(ast_reference_01->as<ASTDeclareReference>()->reference_expression->as<ASTIdentifier>()->name, "ref_col_01");
EXPECT_EQ(ast_reference_01->as<ASTDeclareReference>()->kind, ASTDeclareReference::MATCH_FULL);
EXPECT_EQ(ast_reference_01->as<ASTDeclareReference>()->on_delete_option, ASTDeclareReference::RESTRICT);
EXPECT_EQ(ast_reference_01->as<ASTDeclareReference>()->on_update_option, ASTDeclareReference::RESTRICT);
String reference_02 = "REFERENCES table_name (ref_col_01) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE";
ASTPtr ast_reference_02 = parseQuery(p_reference, reference_02.data(), reference_02.data() + reference_02.size(), "", 0, 0);
EXPECT_EQ(ast_reference_02->as<ASTDeclareReference>()->reference_table_name, "table_name");
EXPECT_EQ(ast_reference_02->as<ASTDeclareReference>()->reference_expression->as<ASTIdentifier>()->name, "ref_col_01");
EXPECT_EQ(ast_reference_02->as<ASTDeclareReference>()->kind, ASTDeclareReference::MATCH_FULL);
EXPECT_EQ(ast_reference_02->as<ASTDeclareReference>()->on_delete_option, ASTDeclareReference::CASCADE);
EXPECT_EQ(ast_reference_02->as<ASTDeclareReference>()->on_update_option, ASTDeclareReference::CASCADE);
String reference_03 = "REFERENCES table_name (ref_col_01) MATCH FULL ON DELETE SET NULL ON UPDATE SET NULL";
ASTPtr ast_reference_03 = parseQuery(p_reference, reference_03.data(), reference_03.data() + reference_03.size(), "", 0, 0);
EXPECT_EQ(ast_reference_03->as<ASTDeclareReference>()->reference_table_name, "table_name");
EXPECT_EQ(ast_reference_03->as<ASTDeclareReference>()->reference_expression->as<ASTIdentifier>()->name, "ref_col_01");
EXPECT_EQ(ast_reference_03->as<ASTDeclareReference>()->kind, ASTDeclareReference::MATCH_FULL);
EXPECT_EQ(ast_reference_03->as<ASTDeclareReference>()->on_delete_option, ASTDeclareReference::SET_NULL);
EXPECT_EQ(ast_reference_03->as<ASTDeclareReference>()->on_update_option, ASTDeclareReference::SET_NULL);
String reference_04 = "REFERENCES table_name (ref_col_01) MATCH FULL ON UPDATE NO ACTION ON DELETE NO ACTION";
ASTPtr ast_reference_04 = parseQuery(p_reference, reference_04.data(), reference_04.data() + reference_04.size(), "", 0, 0);
EXPECT_EQ(ast_reference_04->as<ASTDeclareReference>()->reference_table_name, "table_name");
EXPECT_EQ(ast_reference_04->as<ASTDeclareReference>()->reference_expression->as<ASTIdentifier>()->name, "ref_col_01");
EXPECT_EQ(ast_reference_04->as<ASTDeclareReference>()->kind, ASTDeclareReference::MATCH_FULL);
EXPECT_EQ(ast_reference_04->as<ASTDeclareReference>()->on_delete_option, ASTDeclareReference::NO_ACTION);
EXPECT_EQ(ast_reference_04->as<ASTDeclareReference>()->on_update_option, ASTDeclareReference::NO_ACTION);
String reference_05 = "REFERENCES table_name (ref_col_01) MATCH FULL ON UPDATE SET DEFAULT ON DELETE SET DEFAULT";
ASTPtr ast_reference_05 = parseQuery(p_reference, reference_05.data(), reference_05.data() + reference_05.size(), "", 0, 0);
EXPECT_EQ(ast_reference_05->as<ASTDeclareReference>()->reference_table_name, "table_name");
EXPECT_EQ(ast_reference_05->as<ASTDeclareReference>()->reference_expression->as<ASTIdentifier>()->name, "ref_col_01");
EXPECT_EQ(ast_reference_05->as<ASTDeclareReference>()->kind, ASTDeclareReference::MATCH_FULL);
EXPECT_EQ(ast_reference_05->as<ASTDeclareReference>()->on_delete_option, ASTDeclareReference::SET_DEFAULT);
EXPECT_EQ(ast_reference_05->as<ASTDeclareReference>()->on_update_option, ASTDeclareReference::SET_DEFAULT);
}

View File

@ -0,0 +1,45 @@
#include <gtest/gtest.h>
#include <Parsers/parseQuery.h>
#include <Parsers/ASTLiteral.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/MySQL/ASTDeclareOption.h>
#include <Parsers/MySQL/ASTDeclareSubPartition.h>
using namespace DB;
using namespace DB::MySQLParser;
TEST(ParserSubpartition, AllSubpatitionOptions)
{
String input = "SUBPARTITION subpartition_name ENGINE = engine_name COMMENT 'subpartition comment'"
" DATA DIRECTORY 'data_directory' INDEX DIRECTORY 'index_directory' max_rows 1000 MIN_ROWs 0"
" TABLESPACE table_space_name";
MySQLParser::ParserDeclareSubPartition p_subpartition;
ASTPtr ast = parseQuery(p_subpartition, input.data(), input.data() + input.size(), "", 0, 0);
ASTDeclareSubPartition * declare_subpartition = ast->as<ASTDeclareSubPartition>();
EXPECT_EQ(declare_subpartition->logical_name, "subpartition_name");
ASTDeclareOptions * declare_options = declare_subpartition->options->as<ASTDeclareOptions>();
EXPECT_EQ(declare_options->changes["engine"]->as<ASTIdentifier>()->name, "engine_name");
EXPECT_EQ(declare_options->changes["comment"]->as<ASTLiteral>()->value.safeGet<String>(), "subpartition comment");
EXPECT_EQ(declare_options->changes["data_directory"]->as<ASTLiteral>()->value.safeGet<String>(), "data_directory");
EXPECT_EQ(declare_options->changes["index_directory"]->as<ASTLiteral>()->value.safeGet<String>(), "index_directory");
EXPECT_EQ(declare_options->changes["min_rows"]->as<ASTLiteral>()->value.safeGet<UInt64>(), 0);
EXPECT_EQ(declare_options->changes["max_rows"]->as<ASTLiteral>()->value.safeGet<UInt64>(), 1000);
EXPECT_EQ(declare_options->changes["tablespace"]->as<ASTIdentifier>()->name, "table_space_name");
}
TEST(ParserSubpartition, OptionalSubpatitionOptions)
{
String input = "SUBPARTITION subpartition_name STORAGE engine = engine_name max_rows 1000 min_rows 0 tablespace table_space_name";
MySQLParser::ParserDeclareSubPartition p_subpartition;
ASTPtr ast = parseQuery(p_subpartition, input.data(), input.data() + input.size(), "", 0, 0);
ASTDeclareSubPartition * declare_subpartition = ast->as<ASTDeclareSubPartition>();
EXPECT_EQ(declare_subpartition->logical_name, "subpartition_name");
ASTDeclareOptions * declare_options = declare_subpartition->options->as<ASTDeclareOptions>();
EXPECT_EQ(declare_options->changes["engine"]->as<ASTIdentifier>()->name, "engine_name");
EXPECT_EQ(declare_options->changes["min_rows"]->as<ASTLiteral>()->value.safeGet<UInt64>(), 0);
EXPECT_EQ(declare_options->changes["max_rows"]->as<ASTLiteral>()->value.safeGet<UInt64>(), 1000);
EXPECT_EQ(declare_options->changes["tablespace"]->as<ASTIdentifier>()->name, "table_space_name");
}

View File

@ -0,0 +1,64 @@
#include <gtest/gtest.h>
#include <Parsers/parseQuery.h>
#include <Parsers/ASTLiteral.h>
#include <Parsers/ASTFunction.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/MySQL/ASTDeclareOption.h>
#include <Parsers/MySQL/ASTDeclareTableOptions.h>
using namespace DB;
using namespace DB::MySQLParser;
TEST(ParserTableOptions, AllSubpatitionOptions)
{
String input = "AUTO_INCREMENt = 1 AVG_ROW_LENGTh 3 CHARACTER SET utf-8 CHECKSUM 1 COLLATE utf8_bin"
" COMMENT 'table option comment' COMPRESSION 'LZ4' CONNECTION 'connect_string' DATA DIRECTORY 'data_directory'"
" INDEX DIRECTORY 'index_directory' DELAY_KEY_WRITE 0 ENCRYPTION 'Y' ENGINE INNODB INSERT_METHOD NO KEY_BLOCK_SIZE 3"
" MAX_ROWS 1000 MIN_ROWS 0 PACK_KEYS DEFAULT PASSWORD 'password' ROW_FORMAT DYNAMIC STATS_AUTO_RECALC DEFAULT "
" STATS_PERSISTENT DEFAULT STATS_SAMPLE_PAGES 3 TABLESPACE tablespace_name STORAGE MEMORY UNION (table_01, table_02)";
ParserDeclareTableOptions p_table_options;
ASTPtr ast = parseQuery(p_table_options, input.data(), input.data() + input.size(), "", 0, 0);
ASTDeclareOptions * declare_options = ast->as<ASTDeclareOptions>();
EXPECT_EQ(declare_options->changes["auto_increment"]->as<ASTLiteral>()->value.safeGet<UInt64>(), 1);
EXPECT_EQ(declare_options->changes["avg_row_length"]->as<ASTLiteral>()->value.safeGet<UInt64>(), 3);
EXPECT_EQ(declare_options->changes["character_set"]->as<ASTIdentifier>()->name, "utf-8");
EXPECT_EQ(declare_options->changes["checksum"]->as<ASTLiteral>()->value.safeGet<UInt64>(), 1);
EXPECT_EQ(declare_options->changes["collate"]->as<ASTIdentifier>()->name, "utf8_bin");
EXPECT_EQ(declare_options->changes["comment"]->as<ASTLiteral>()->value.safeGet<String>(), "table option comment");
EXPECT_EQ(declare_options->changes["compression"]->as<ASTLiteral>()->value.safeGet<String>(), "LZ4");
EXPECT_EQ(declare_options->changes["connection"]->as<ASTLiteral>()->value.safeGet<String>(), "connect_string");
EXPECT_EQ(declare_options->changes["data_directory"]->as<ASTLiteral>()->value.safeGet<String>(), "data_directory");
EXPECT_EQ(declare_options->changes["index_directory"]->as<ASTLiteral>()->value.safeGet<String>(), "index_directory");
EXPECT_EQ(declare_options->changes["delay_key_write"]->as<ASTLiteral>()->value.safeGet<UInt64>(), 0);
EXPECT_EQ(declare_options->changes["encryption"]->as<ASTLiteral>()->value.safeGet<String>(), "Y");
EXPECT_EQ(declare_options->changes["engine"]->as<ASTIdentifier>()->name, "INNODB");
EXPECT_EQ(declare_options->changes["insert_method"]->as<ASTIdentifier>()->name, "NO");
EXPECT_EQ(declare_options->changes["key_block_size"]->as<ASTLiteral>()->value.safeGet<UInt64>(), 3);
EXPECT_EQ(declare_options->changes["max_rows"]->as<ASTLiteral>()->value.safeGet<UInt64>(), 1000);
EXPECT_EQ(declare_options->changes["min_rows"]->as<ASTLiteral>()->value.safeGet<UInt64>(), 0);
EXPECT_EQ(declare_options->changes["pack_keys"]->as<ASTIdentifier>()->name, "DEFAULT");
EXPECT_EQ(declare_options->changes["password"]->as<ASTLiteral>()->value.safeGet<String>(), "password");
EXPECT_EQ(declare_options->changes["row_format"]->as<ASTIdentifier>()->name, "DYNAMIC");
EXPECT_EQ(declare_options->changes["stats_auto_recalc"]->as<ASTIdentifier>()->name, "DEFAULT");
EXPECT_EQ(declare_options->changes["stats_persistent"]->as<ASTIdentifier>()->name, "DEFAULT");
EXPECT_EQ(declare_options->changes["stats_sample_pages"]->as<ASTLiteral>()->value.safeGet<UInt64>(), 3);
EXPECT_EQ(declare_options->changes["tablespace"]->as<ASTIdentifier>()->name, "tablespace_name");
ASTPtr arguments = declare_options->changes["union"]->as<ASTFunction>()->arguments;
EXPECT_EQ(arguments->children[0]->as<ASTIdentifier>()->name, "table_01");
EXPECT_EQ(arguments->children[1]->as<ASTIdentifier>()->name, "table_02");
}
TEST(ParserTableOptions, OptionalTableOptions)
{
String input = "STATS_AUTO_RECALC DEFAULT AUTO_INCREMENt = 1 ";
ParserDeclareTableOptions p_table_options;
ASTPtr ast = parseQuery(p_table_options, input.data(), input.data() + input.size(), "", 0, 0);
ASTDeclareOptions * declare_options = ast->as<ASTDeclareOptions>();
EXPECT_EQ(declare_options->changes["auto_increment"]->as<ASTLiteral>()->value.safeGet<UInt64>(), 1);
EXPECT_EQ(declare_options->changes["stats_auto_recalc"]->as<ASTIdentifier>()->name, "DEFAULT");
}