Merge pull request #25795 from sand6255/MySQL-column-comments-support

MySQL Engine column comments support
This commit is contained in:
Kseniia Sumarokova 2021-06-30 20:18:47 +03:00 committed by GitHub
commit 360f772762
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 52 additions and 23 deletions

View File

@ -232,7 +232,7 @@ void DatabaseMySQL::fetchLatestTablesStructureIntoCache(
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)
{
@ -296,7 +296,7 @@ std::map<String, UInt64> DatabaseMySQL::fetchTablesWithModificationTime(ContextP
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
{
const auto & settings = local_context->getSettingsRef();

View File

@ -8,6 +8,7 @@
#include <Core/MultiEnum.h>
#include <Core/NamesAndTypes.h>
#include <Common/ThreadPool.h>
#include <Storages/ColumnsDescription.h>
#include <Databases/DatabasesCommon.h>
#include <Databases/MySQL/ConnectionMySQLSettings.h>
#include <Parsers/ASTCreateQuery.h>
@ -111,7 +112,7 @@ private:
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;

View File

@ -40,14 +40,14 @@ String toQueryStringWithQuote(const std::vector<String> & quote_list)
namespace DB
{
std::map<String, NamesAndTypesList> fetchTablesColumnsList(
std::map<String, ColumnsDescription> fetchTablesColumnsList(
mysqlxx::PoolWithFailover & pool,
const String & database_name,
const std::vector<String> & tables_name,
const Settings & settings,
MultiEnum<MySQLDataTypesSupport> type_support)
{
std::map<String, NamesAndTypesList> tables_and_columns;
std::map<String, ColumnsDescription> tables_and_columns;
if (tables_name.empty())
return tables_and_columns;
@ -62,6 +62,7 @@ std::map<String, NamesAndTypesList> fetchTablesColumnsList(
{ std::make_shared<DataTypeUInt64>(), "length" },
{ std::make_shared<DataTypeUInt64>(), "precision" },
{ std::make_shared<DataTypeUInt64>(), "scale" },
{ std::make_shared<DataTypeString>(), "column_comment" },
};
WriteBufferFromOwnString query;
@ -72,8 +73,9 @@ std::map<String, NamesAndTypesList> fetchTablesColumnsList(
" IS_NULLABLE = 'YES' AS is_nullable,"
" COLUMN_TYPE LIKE '%unsigned' AS is_unsigned,"
" CHARACTER_MAXIMUM_LENGTH AS length,"
" NUMERIC_PRECISION as numeric_precision,"
" IF(ISNULL(NUMERIC_SCALE), DATETIME_PRECISION, NUMERIC_SCALE) AS scale" // we know DATETIME_PRECISION as a scale in CH
" NUMERIC_PRECISION AS numeric_precision,"
" 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"
" WHERE ";
@ -94,21 +96,26 @@ std::map<String, NamesAndTypesList> fetchTablesColumnsList(
const auto & char_max_length_col = *block.getByPosition(5).column;
const auto & precision_col = *block.getByPosition(6).column;
const auto & scale_col = *block.getByPosition(7).column;
const auto & column_comment_col = *block.getByPosition(8).column;
size_t rows = block.rows();
for (size_t i = 0; i < rows; ++i)
{
String table_name = table_name_col[i].safeGet<String>();
tables_and_columns[table_name].emplace_back(
column_name_col[i].safeGet<String>(),
convertMySQLDataType(
type_support,
column_type_col[i].safeGet<String>(),
settings.external_table_functions_use_nulls && is_nullable_col[i].safeGet<UInt64>(),
is_unsigned_col[i].safeGet<UInt64>(),
char_max_length_col[i].safeGet<UInt64>(),
precision_col[i].safeGet<UInt64>(),
scale_col[i].safeGet<UInt64>()));
ColumnDescription column_description(
column_name_col[i].safeGet<String>(),
convertMySQLDataType(
type_support,
column_type_col[i].safeGet<String>(),
settings.external_table_functions_use_nulls && is_nullable_col[i].safeGet<UInt64>(),
is_unsigned_col[i].safeGet<UInt64>(),
char_max_length_col[i].safeGet<UInt64>(),
precision_col[i].safeGet<UInt64>(),
scale_col[i].safeGet<UInt64>())
);
column_description.comment = column_comment_col[i].safeGet<String>();
tables_and_columns[table_name].add(column_description);
}
}
return tables_and_columns;

View File

@ -7,8 +7,8 @@
#include <common/types.h>
#include <Core/MultiEnum.h>
#include <Core/NamesAndTypes.h>
#include <Core/SettingsEnums.h>
#include <Storages/ColumnsDescription.h>
#include <map>
#include <vector>
@ -17,7 +17,7 @@
namespace DB
{
std::map<String, NamesAndTypesList> fetchTablesColumnsList(
std::map<String, ColumnsDescription> fetchTablesColumnsList(
mysqlxx::PoolWithFailover & pool,
const String & database_name,
const std::vector<String> & tables_name,

View File

@ -141,7 +141,6 @@ static ColumnsDescription createColumnsDescription(const NamesAndTypesList & col
throw Exception("Columns of different size provided.", ErrorCodes::LOGICAL_ERROR);
ColumnsDescription columns_description;
ColumnDescription column_description;
for (
auto [column_name_and_type, declare_column_ast] = std::tuple{columns_name_and_type.begin(), columns_definition->children.begin()};
@ -157,10 +156,10 @@ static ColumnsDescription createColumnsDescription(const NamesAndTypesList & col
if (options->changes.count("comment"))
comment = options->changes.at("comment")->as<ASTLiteral>()->value.safeGet<String>();
column_description.name = column_name_and_type->name;
column_description.type = column_name_and_type->type;
ColumnDescription column_description(column_name_and_type->name, column_name_and_type->type);
if (!comment.empty())
column_description.comment = std::move(comment);
columns_description.add(column_description);
}

View File

@ -87,7 +87,7 @@ ColumnsDescription TableFunctionMySQL::getActualTableStructure(ContextPtr contex
throw Exception("MySQL table " + (remote_database_name.empty() ? "" : (backQuote(remote_database_name) + "."))
+ backQuote(remote_table_name) + " doesn't exist.", ErrorCodes::UNKNOWN_TABLE);
return ColumnsDescription{columns->second};
return columns->second;
}
StoragePtr TableFunctionMySQL::executeImpl(

View File

@ -167,6 +167,28 @@ def test_bad_arguments_for_mysql_database_engine(started_cluster):
assert 'Database engine MySQL requested literal argument.' in str(exception.value)
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`')
time.sleep(
3) # Because the unit of MySQL modification time is seconds, modifications made in the same second cannot be obtained
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'")
clickhouse_node.query("DROP DATABASE test_database")
mysql_node.query("DROP DATABASE test_database")
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: