mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-22 07:31:57 +00:00
Implemented MySQL column comments support
This commit is contained in:
parent
71603a7d13
commit
c2c78929cb
@ -232,7 +232,7 @@ void DatabaseMySQL::fetchLatestTablesStructureIntoCache(
|
|||||||
wait_update_tables_name.emplace_back(table_modification_time.first);
|
wait_update_tables_name.emplace_back(table_modification_time.first);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<String, NamesAndTypesList> tables_and_columns = fetchTablesColumnsList(wait_update_tables_name, local_context);
|
std::map<String, ColumnsDescription> tables_and_columns = fetchTablesColumnsList(wait_update_tables_name, local_context);
|
||||||
|
|
||||||
for (const auto & table_and_columns : tables_and_columns)
|
for (const auto & table_and_columns : tables_and_columns)
|
||||||
{
|
{
|
||||||
@ -296,7 +296,7 @@ std::map<String, UInt64> DatabaseMySQL::fetchTablesWithModificationTime(ContextP
|
|||||||
return tables_with_modification_time;
|
return tables_with_modification_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<String, NamesAndTypesList>
|
std::map<String, ColumnsDescription>
|
||||||
DatabaseMySQL::fetchTablesColumnsList(const std::vector<String> & tables_name, ContextPtr local_context) const
|
DatabaseMySQL::fetchTablesColumnsList(const std::vector<String> & tables_name, ContextPtr local_context) const
|
||||||
{
|
{
|
||||||
const auto & settings = local_context->getSettingsRef();
|
const auto & settings = local_context->getSettingsRef();
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include <Core/MultiEnum.h>
|
#include <Core/MultiEnum.h>
|
||||||
#include <Core/NamesAndTypes.h>
|
#include <Core/NamesAndTypes.h>
|
||||||
#include <Common/ThreadPool.h>
|
#include <Common/ThreadPool.h>
|
||||||
|
#include <Storages/ColumnsDescription.h>
|
||||||
#include <Databases/DatabasesCommon.h>
|
#include <Databases/DatabasesCommon.h>
|
||||||
#include <Databases/MySQL/ConnectionMySQLSettings.h>
|
#include <Databases/MySQL/ConnectionMySQLSettings.h>
|
||||||
#include <Parsers/ASTCreateQuery.h>
|
#include <Parsers/ASTCreateQuery.h>
|
||||||
@ -111,7 +112,7 @@ private:
|
|||||||
|
|
||||||
std::map<String, UInt64> fetchTablesWithModificationTime(ContextPtr local_context) const;
|
std::map<String, UInt64> fetchTablesWithModificationTime(ContextPtr local_context) const;
|
||||||
|
|
||||||
std::map<String, NamesAndTypesList> fetchTablesColumnsList(const std::vector<String> & tables_name, ContextPtr context) const;
|
std::map<String, ColumnsDescription> fetchTablesColumnsList(const std::vector<String> & tables_name, ContextPtr context) const;
|
||||||
|
|
||||||
void destroyLocalCacheExtraTables(const std::map<String, UInt64> & tables_with_modification_time) const;
|
void destroyLocalCacheExtraTables(const std::map<String, UInt64> & tables_with_modification_time) const;
|
||||||
|
|
||||||
|
@ -40,14 +40,14 @@ String toQueryStringWithQuote(const std::vector<String> & quote_list)
|
|||||||
namespace DB
|
namespace DB
|
||||||
{
|
{
|
||||||
|
|
||||||
std::map<String, NamesAndTypesList> fetchTablesColumnsList(
|
std::map<String, ColumnsDescription> fetchTablesColumnsList(
|
||||||
mysqlxx::PoolWithFailover & pool,
|
mysqlxx::PoolWithFailover & pool,
|
||||||
const String & database_name,
|
const String & database_name,
|
||||||
const std::vector<String> & tables_name,
|
const std::vector<String> & tables_name,
|
||||||
const Settings & settings,
|
const Settings & settings,
|
||||||
MultiEnum<MySQLDataTypesSupport> type_support)
|
MultiEnum<MySQLDataTypesSupport> type_support)
|
||||||
{
|
{
|
||||||
std::map<String, NamesAndTypesList> tables_and_columns;
|
std::map<String, ColumnsDescription> tables_and_columns;
|
||||||
|
|
||||||
if (tables_name.empty())
|
if (tables_name.empty())
|
||||||
return tables_and_columns;
|
return tables_and_columns;
|
||||||
@ -62,6 +62,7 @@ std::map<String, NamesAndTypesList> fetchTablesColumnsList(
|
|||||||
{ std::make_shared<DataTypeUInt64>(), "length" },
|
{ std::make_shared<DataTypeUInt64>(), "length" },
|
||||||
{ std::make_shared<DataTypeUInt64>(), "precision" },
|
{ std::make_shared<DataTypeUInt64>(), "precision" },
|
||||||
{ std::make_shared<DataTypeUInt64>(), "scale" },
|
{ std::make_shared<DataTypeUInt64>(), "scale" },
|
||||||
|
{ std::make_shared<DataTypeString>(), "column_comment" },
|
||||||
};
|
};
|
||||||
|
|
||||||
WriteBufferFromOwnString query;
|
WriteBufferFromOwnString query;
|
||||||
@ -72,8 +73,9 @@ std::map<String, NamesAndTypesList> fetchTablesColumnsList(
|
|||||||
" IS_NULLABLE = 'YES' AS is_nullable,"
|
" IS_NULLABLE = 'YES' AS is_nullable,"
|
||||||
" COLUMN_TYPE LIKE '%unsigned' AS is_unsigned,"
|
" COLUMN_TYPE LIKE '%unsigned' AS is_unsigned,"
|
||||||
" CHARACTER_MAXIMUM_LENGTH AS length,"
|
" CHARACTER_MAXIMUM_LENGTH AS length,"
|
||||||
" NUMERIC_PRECISION as numeric_precision,"
|
" NUMERIC_PRECISION AS numeric_precision,"
|
||||||
" IF(ISNULL(NUMERIC_SCALE), DATETIME_PRECISION, NUMERIC_SCALE) AS scale" // we know DATETIME_PRECISION as a scale in CH
|
" IF(ISNULL(NUMERIC_SCALE), DATETIME_PRECISION, NUMERIC_SCALE) AS scale," // we know DATETIME_PRECISION as a scale in CH
|
||||||
|
" COLUMN_COMMENT AS column_comment"
|
||||||
" FROM INFORMATION_SCHEMA.COLUMNS"
|
" FROM INFORMATION_SCHEMA.COLUMNS"
|
||||||
" WHERE ";
|
" WHERE ";
|
||||||
|
|
||||||
@ -94,21 +96,24 @@ std::map<String, NamesAndTypesList> fetchTablesColumnsList(
|
|||||||
const auto & char_max_length_col = *block.getByPosition(5).column;
|
const auto & char_max_length_col = *block.getByPosition(5).column;
|
||||||
const auto & precision_col = *block.getByPosition(6).column;
|
const auto & precision_col = *block.getByPosition(6).column;
|
||||||
const auto & scale_col = *block.getByPosition(7).column;
|
const auto & scale_col = *block.getByPosition(7).column;
|
||||||
|
const auto & column_comment_col = *block.getByPosition(8).column;
|
||||||
|
|
||||||
size_t rows = block.rows();
|
size_t rows = block.rows();
|
||||||
for (size_t i = 0; i < rows; ++i)
|
for (size_t i = 0; i < rows; ++i)
|
||||||
{
|
{
|
||||||
String table_name = table_name_col[i].safeGet<String>();
|
String table_name = table_name_col[i].safeGet<String>();
|
||||||
tables_and_columns[table_name].emplace_back(
|
tables_and_columns[table_name].add(
|
||||||
column_name_col[i].safeGet<String>(),
|
ColumnDescription(
|
||||||
convertMySQLDataType(
|
column_name_col[i].safeGet<String>(),
|
||||||
type_support,
|
convertMySQLDataType(
|
||||||
column_type_col[i].safeGet<String>(),
|
type_support,
|
||||||
settings.external_table_functions_use_nulls && is_nullable_col[i].safeGet<UInt64>(),
|
column_type_col[i].safeGet<String>(),
|
||||||
is_unsigned_col[i].safeGet<UInt64>(),
|
settings.external_table_functions_use_nulls && is_nullable_col[i].safeGet<UInt64>(),
|
||||||
char_max_length_col[i].safeGet<UInt64>(),
|
is_unsigned_col[i].safeGet<UInt64>(),
|
||||||
precision_col[i].safeGet<UInt64>(),
|
char_max_length_col[i].safeGet<UInt64>(),
|
||||||
scale_col[i].safeGet<UInt64>()));
|
precision_col[i].safeGet<UInt64>(),
|
||||||
|
scale_col[i].safeGet<UInt64>()),
|
||||||
|
column_comment_col[i].safeGet<String>()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return tables_and_columns;
|
return tables_and_columns;
|
||||||
|
@ -7,8 +7,8 @@
|
|||||||
|
|
||||||
#include <common/types.h>
|
#include <common/types.h>
|
||||||
#include <Core/MultiEnum.h>
|
#include <Core/MultiEnum.h>
|
||||||
#include <Core/NamesAndTypes.h>
|
|
||||||
#include <Core/SettingsEnums.h>
|
#include <Core/SettingsEnums.h>
|
||||||
|
#include <Storages/ColumnsDescription.h>
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -17,7 +17,7 @@
|
|||||||
namespace DB
|
namespace DB
|
||||||
{
|
{
|
||||||
|
|
||||||
std::map<String, NamesAndTypesList> fetchTablesColumnsList(
|
std::map<String, ColumnsDescription> fetchTablesColumnsList(
|
||||||
mysqlxx::PoolWithFailover & pool,
|
mysqlxx::PoolWithFailover & pool,
|
||||||
const String & database_name,
|
const String & database_name,
|
||||||
const std::vector<String> & tables_name,
|
const std::vector<String> & tables_name,
|
||||||
|
@ -123,7 +123,6 @@ static ColumnsDescription createColumnsDescription(const NamesAndTypesList & col
|
|||||||
throw Exception("Columns of different size provided.", ErrorCodes::LOGICAL_ERROR);
|
throw Exception("Columns of different size provided.", ErrorCodes::LOGICAL_ERROR);
|
||||||
|
|
||||||
ColumnsDescription columns_description;
|
ColumnsDescription columns_description;
|
||||||
ColumnDescription column_description;
|
|
||||||
|
|
||||||
for (
|
for (
|
||||||
auto [column_name_and_type, declare_column_ast] = std::tuple{columns_name_and_type.begin(), columns_definition->children.begin()};
|
auto [column_name_and_type, declare_column_ast] = std::tuple{columns_name_and_type.begin(), columns_definition->children.begin()};
|
||||||
@ -139,11 +138,7 @@ static ColumnsDescription createColumnsDescription(const NamesAndTypesList & col
|
|||||||
if (options->changes.count("comment"))
|
if (options->changes.count("comment"))
|
||||||
comment = options->changes.at("comment")->as<ASTLiteral>()->value.safeGet<String>();
|
comment = options->changes.at("comment")->as<ASTLiteral>()->value.safeGet<String>();
|
||||||
|
|
||||||
column_description.name = column_name_and_type->name;
|
columns_description.add(ColumnDescription(column_name_and_type->name, column_name_and_type->type, comment));
|
||||||
column_description.type = column_name_and_type->type;
|
|
||||||
if (!comment.empty())
|
|
||||||
column_description.comment = std::move(comment);
|
|
||||||
columns_description.add(column_description);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return columns_description;
|
return columns_description;
|
||||||
|
@ -43,8 +43,8 @@ namespace ErrorCodes
|
|||||||
extern const int LOGICAL_ERROR;
|
extern const int LOGICAL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnDescription::ColumnDescription(String name_, DataTypePtr type_)
|
ColumnDescription::ColumnDescription(String name_, DataTypePtr type_, String comment_)
|
||||||
: name(std::move(name_)), type(std::move(type_))
|
: name(std::move(name_)), type(std::move(type_)), comment(std::move(comment_))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ struct ColumnDescription
|
|||||||
ColumnDescription() = default;
|
ColumnDescription() = default;
|
||||||
ColumnDescription(ColumnDescription &&) = default;
|
ColumnDescription(ColumnDescription &&) = default;
|
||||||
ColumnDescription(const ColumnDescription &) = default;
|
ColumnDescription(const ColumnDescription &) = default;
|
||||||
ColumnDescription(String name_, DataTypePtr type_);
|
ColumnDescription(String name_, DataTypePtr type_, String comment_ = "");
|
||||||
|
|
||||||
bool operator==(const ColumnDescription & other) const;
|
bool operator==(const ColumnDescription & other) const;
|
||||||
bool operator!=(const ColumnDescription & other) const { return !(*this == other); }
|
bool operator!=(const ColumnDescription & other) const { return !(*this == other); }
|
||||||
|
@ -87,7 +87,7 @@ ColumnsDescription TableFunctionMySQL::getActualTableStructure(ContextPtr contex
|
|||||||
throw Exception("MySQL table " + (remote_database_name.empty() ? "" : (backQuote(remote_database_name) + "."))
|
throw Exception("MySQL table " + (remote_database_name.empty() ? "" : (backQuote(remote_database_name) + "."))
|
||||||
+ backQuote(remote_table_name) + " doesn't exist.", ErrorCodes::UNKNOWN_TABLE);
|
+ backQuote(remote_table_name) + " doesn't exist.", ErrorCodes::UNKNOWN_TABLE);
|
||||||
|
|
||||||
return ColumnsDescription{columns->second};
|
return columns->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
StoragePtr TableFunctionMySQL::executeImpl(
|
StoragePtr TableFunctionMySQL::executeImpl(
|
||||||
|
@ -167,6 +167,25 @@ def test_bad_arguments_for_mysql_database_engine(started_cluster):
|
|||||||
assert 'Database engine MySQL requested literal argument.' in str(exception.value)
|
assert 'Database engine MySQL requested literal argument.' in str(exception.value)
|
||||||
mysql_node.query("DROP DATABASE test_bad_arguments")
|
mysql_node.query("DROP DATABASE test_bad_arguments")
|
||||||
|
|
||||||
|
def test_column_comments_for_mysql_database_engine(started_cluster):
|
||||||
|
with contextlib.closing(MySQLNodeInstance('root', 'clickhouse', started_cluster.mysql_ip, started_cluster.mysql_port)) as mysql_node:
|
||||||
|
mysql_node.query("DROP DATABASE IF EXISTS test_database")
|
||||||
|
mysql_node.query("CREATE DATABASE test_database DEFAULT CHARACTER SET 'utf8'")
|
||||||
|
|
||||||
|
clickhouse_node.query(
|
||||||
|
"CREATE DATABASE test_database ENGINE = MySQL('mysql57:3306', 'test_database', 'root', 'clickhouse')")
|
||||||
|
assert 'test_database' in clickhouse_node.query('SHOW DATABASES')
|
||||||
|
|
||||||
|
mysql_node.query(
|
||||||
|
"CREATE TABLE `test_database`.`test_table` ( `id` int(11) NOT NULL, PRIMARY KEY (`id`), `test` int COMMENT 'test comment') ENGINE=InnoDB;")
|
||||||
|
assert 'test comment' in clickhouse_node.query('DESCRIBE TABLE `test_database`.`test_table`')
|
||||||
|
|
||||||
|
mysql_node.query("ALTER TABLE `test_database`.`test_table` ADD COLUMN `add_column` int(11) COMMENT 'add_column comment'")
|
||||||
|
assert 'add_column comment' in clickhouse_node.query(
|
||||||
|
"SELECT comment FROM system.columns WHERE table = 'test_table' AND database = 'test_database'")
|
||||||
|
|
||||||
|
mysql_node.query("DROP DATABASE test_database")
|
||||||
|
|
||||||
|
|
||||||
def test_data_types_support_level_for_mysql_database_engine(started_cluster):
|
def test_data_types_support_level_for_mysql_database_engine(started_cluster):
|
||||||
with contextlib.closing(MySQLNodeInstance('root', 'clickhouse', started_cluster.mysql_ip, started_cluster.mysql_port)) as mysql_node:
|
with contextlib.closing(MySQLNodeInstance('root', 'clickhouse', started_cluster.mysql_ip, started_cluster.mysql_port)) as mysql_node:
|
||||||
|
Loading…
Reference in New Issue
Block a user