diff --git a/src/Core/QualifiedTableName.h b/src/Core/QualifiedTableName.h index c1cb9b27d15..cd72dc2809d 100644 --- a/src/Core/QualifiedTableName.h +++ b/src/Core/QualifiedTableName.h @@ -40,6 +40,20 @@ struct QualifiedTableName return hash_state.get64(); } + std::vector getParts() const { + if (database.empty()) + return {table}; + else + return {database, table}; + } + + std::string getFullName() const { + if (database.empty()) + return table; + else + return database + '.' + table; + } + /// NOTE: It's different from compound identifier parsing and does not support escaping and dots in name. /// Usually it's better to use ParserIdentifier instead, /// but we parse DDL dictionary name (and similar things) this way for historical reasons. diff --git a/src/Interpreters/AddDefaultDatabaseVisitor.h b/src/Interpreters/AddDefaultDatabaseVisitor.h index f4b09d5a761..98d33db3021 100644 --- a/src/Interpreters/AddDefaultDatabaseVisitor.h +++ b/src/Interpreters/AddDefaultDatabaseVisitor.h @@ -143,21 +143,12 @@ private: { if (auto * identifier = child->children[i]->as()) { + /// Identifier already qualified if (identifier->compound()) continue; - auto storage_id = context->getExternalDictionariesLoader().getStorageID(identifier->name(), context); - - if (!storage_id.database_name.empty()) - { - std::vector name_parts = {storage_id.database_name, storage_id.table_name}; - child->children[i] = std::make_shared(std::move(name_parts)); - } - else - { - std::vector name_parts = {storage_id.table_name}; - child->children[i] = std::make_shared(std::move(name_parts)); - } + auto qualified_dictionary_name = context->getExternalDictionariesLoader().qualifyDictionaryNameWithDatabase(identifier->name(), context); + child->children[i] = std::make_shared(qualified_dictionary_name.getParts()); } else if (auto * literal = child->children[i]->as()) { @@ -167,7 +158,8 @@ private: continue; auto dictionary_name = literal_value.get(); - literal_value = context->getExternalDictionariesLoader().getStorageID(dictionary_name, context).getFullTableName(); + auto qualified_dictionary_name = context->getExternalDictionariesLoader().qualifyDictionaryNameWithDatabase(dictionary_name, context); + literal_value = qualified_dictionary_name.getFullName(); } } else if (is_operator_in && i == 1) diff --git a/src/Interpreters/ExternalDictionariesLoader.cpp b/src/Interpreters/ExternalDictionariesLoader.cpp index c49b037ef96..c09ab8b78e5 100644 --- a/src/Interpreters/ExternalDictionariesLoader.cpp +++ b/src/Interpreters/ExternalDictionariesLoader.cpp @@ -87,19 +87,26 @@ DictionaryStructure ExternalDictionariesLoader::getDictionaryStructure(const std return ExternalDictionariesLoader::getDictionaryStructure(*load_result.config); } -StorageID ExternalDictionariesLoader::getStorageID(const std::string & dictionary_name, ContextPtr context) const +QualifiedTableName ExternalDictionariesLoader::qualifyDictionaryNameWithDatabase(const std::string & dictionary_name, ContextPtr query_context) const { - if (has(dictionary_name)) - return StorageID("", dictionary_name); - auto qualified_name = QualifiedTableName::tryParseFromString(dictionary_name); if (!qualified_name) - return StorageID("", dictionary_name); + { + QualifiedTableName qualified_dictionary_name; + qualified_dictionary_name.table = dictionary_name; + return qualified_dictionary_name; + } + + if (qualified_name->database.empty() && has(dictionary_name)) + { + /// This is xml dictionary + return *qualified_name; + } if (qualified_name->database.empty()) - return StorageID(context->getCurrentDatabase(), dictionary_name); + qualified_name->database = query_context->getCurrentDatabase(); - return StorageID("", dictionary_name); + return *qualified_name; } std::string ExternalDictionariesLoader::resolveDictionaryName(const std::string & dictionary_name, const std::string & current_database_name) const diff --git a/src/Interpreters/ExternalDictionariesLoader.h b/src/Interpreters/ExternalDictionariesLoader.h index fea2c363f9a..421154a6d4f 100644 --- a/src/Interpreters/ExternalDictionariesLoader.h +++ b/src/Interpreters/ExternalDictionariesLoader.h @@ -27,7 +27,7 @@ public: void reloadDictionary(const std::string & dictionary_name, ContextPtr context) const; - StorageID getStorageID(const std::string & dictionary_name, ContextPtr context) const; + QualifiedTableName qualifyDictionaryNameWithDatabase(const std::string & dictionary_name, ContextPtr context) const; DictionaryStructure getDictionaryStructure(const std::string & dictionary_name, ContextPtr context) const; diff --git a/src/Interpreters/InterpreterCreateQuery.cpp b/src/Interpreters/InterpreterCreateQuery.cpp index e1b2f9097d6..6d38c55bd62 100644 --- a/src/Interpreters/InterpreterCreateQuery.cpp +++ b/src/Interpreters/InterpreterCreateQuery.cpp @@ -924,7 +924,6 @@ BlockIO InterpreterCreateQuery::createTable(ASTCreateQuery & create) visitor.visit(*create.select); } - if (create.columns_list) { AddDefaultDatabaseVisitor visitor(getContext(), current_database); diff --git a/tests/queries/0_stateless/02097_default_dict_get_add_database.reference b/tests/queries/0_stateless/02097_default_dict_get_add_database.reference new file mode 100644 index 00000000000..9b0ac07a68a --- /dev/null +++ b/tests/queries/0_stateless/02097_default_dict_get_add_database.reference @@ -0,0 +1 @@ +CREATE TABLE `02097_db`.test_table_default (`data_1` UInt64 DEFAULT dictGetUInt64(\'02097_db.test_dictionary\', \'data_column_1\', toUInt64(0)), `data_2` UInt8 DEFAULT dictGet(`02097_db`.test_dictionary, \'data_column_2\', toUInt64(0))) ENGINE = TinyLog diff --git a/tests/queries/0_stateless/02097_default_dict_get_add_database.sql b/tests/queries/0_stateless/02097_default_dict_get_add_database.sql new file mode 100755 index 00000000000..d3e4bb6752d --- /dev/null +++ b/tests/queries/0_stateless/02097_default_dict_get_add_database.sql @@ -0,0 +1,43 @@ +-- Tags: no-parallel + +DROP DATABASE IF EXISTS 02097_db; +CREATE DATABASE 02097_db; + +USE 02097_db; + +DROP TABLE IF EXISTS test_table; +CREATE TABLE test_table +( + key_column UInt64, + data_column_1 UInt64, + data_column_2 UInt8 +) +ENGINE = MergeTree +ORDER BY key_column; + +DROP DICTIONARY IF EXISTS test_dictionary; +CREATE DICTIONARY test_dictionary +( + key_column UInt64 DEFAULT 0, + data_column_1 UInt64 DEFAULT 1, + data_column_2 UInt8 DEFAULT 1 +) +PRIMARY KEY key_column +LAYOUT(DIRECT()) +SOURCE(CLICKHOUSE(TABLE 'test_table')); + +DROP TABLE IF EXISTS test_table_default; +CREATE TABLE test_table_default +( + data_1 DEFAULT dictGetUInt64('test_dictionary', 'data_column_1', toUInt64(0)), + data_2 DEFAULT dictGet(test_dictionary, 'data_column_2', toUInt64(0)) +) +ENGINE=TinyLog; + +SELECT create_table_query FROM system.tables WHERE name = 'test_table_default' AND database = '02097_db'; + +DROP DICTIONARY test_dictionary; +DROP TABLE test_table; +DROP TABLE test_table_default; + +DROP DATABASE 02097_db;