diff --git a/dbms/src/Interpreters/TranslateQualifiedNamesVisitor.cpp b/dbms/src/Interpreters/TranslateQualifiedNamesVisitor.cpp index 1b063bc4625..34b59d4f993 100644 --- a/dbms/src/Interpreters/TranslateQualifiedNamesVisitor.cpp +++ b/dbms/src/Interpreters/TranslateQualifiedNamesVisitor.cpp @@ -267,4 +267,14 @@ void TranslateQualifiedNamesMatcher::extractJoinUsingColumns(const ASTPtr ast, D } } +void RestoreQualifiedNamesData::visit(ASTIdentifier & identifier, ASTPtr & ast) +{ + if (IdentifierSemantic::getColumnName(identifier) && + IdentifierSemantic::getMembership(identifier)) + { + ast = identifier.clone(); + ast->as()->restoreCompoundName(); + } +} + } diff --git a/dbms/src/Interpreters/TranslateQualifiedNamesVisitor.h b/dbms/src/Interpreters/TranslateQualifiedNamesVisitor.h index 346c39b3344..413651ea843 100644 --- a/dbms/src/Interpreters/TranslateQualifiedNamesVisitor.h +++ b/dbms/src/Interpreters/TranslateQualifiedNamesVisitor.h @@ -66,4 +66,15 @@ private: /// It finds columns and translate their names to the normal form. Expand asterisks and qualified asterisks with column names. using TranslateQualifiedNamesVisitor = TranslateQualifiedNamesMatcher::Visitor; +/// Restore ASTIdentifiers to long form +struct RestoreQualifiedNamesData +{ + using TypeToVisit = ASTIdentifier; + + void visit(ASTIdentifier & identifier, ASTPtr & ast); +}; + +using RestoreQualifiedNamesMatcher = OneTypeMatcher; +using RestoreQualifiedNamesVisitor = InDepthNodeVisitor; + } diff --git a/dbms/src/Parsers/ASTIdentifier.cpp b/dbms/src/Parsers/ASTIdentifier.cpp index 6b0329409a3..fe806ce795a 100644 --- a/dbms/src/Parsers/ASTIdentifier.cpp +++ b/dbms/src/Parsers/ASTIdentifier.cpp @@ -43,6 +43,15 @@ void ASTIdentifier::setShortName(const String & new_name) semantic->special = special; } +void ASTIdentifier::restoreCompoundName() +{ + if (name_parts.empty()) + return; + name = name_parts[0]; + for (size_t i = 1; i < name_parts.size(); ++i) + name += '.' + name_parts[i]; +} + void ASTIdentifier::formatImplWithoutAlias(const FormatSettings & settings, FormatState &, FormatStateStacked) const { auto format_element = [&](const String & elem_name) diff --git a/dbms/src/Parsers/ASTIdentifier.h b/dbms/src/Parsers/ASTIdentifier.h index 434f84eb77e..01f7766f1ef 100644 --- a/dbms/src/Parsers/ASTIdentifier.h +++ b/dbms/src/Parsers/ASTIdentifier.h @@ -38,6 +38,7 @@ public: bool isShort() const { return name_parts.empty() || name == name_parts.back(); } void setShortName(const String & new_name); + void restoreCompoundName(); const String & shortName() const { diff --git a/dbms/src/Storages/StorageDistributed.cpp b/dbms/src/Storages/StorageDistributed.cpp index 27ceb1f45db..7b810484d1c 100644 --- a/dbms/src/Storages/StorageDistributed.cpp +++ b/dbms/src/Storages/StorageDistributed.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -78,10 +79,20 @@ namespace ASTPtr rewriteSelectQuery(const ASTPtr & query, const std::string & database, const std::string & table, ASTPtr table_function_ptr = nullptr) { auto modified_query_ast = query->clone(); + + ASTSelectQuery & select_query = modified_query_ast->as(); + + /// restore long column names in JOIN ON expressions + if (auto tables = select_query.tables()) + { + RestoreQualifiedNamesVisitor::Data data; + RestoreQualifiedNamesVisitor(data).visit(tables); + } + if (table_function_ptr) - modified_query_ast->as().addTableFunction(table_function_ptr); + select_query.addTableFunction(table_function_ptr); else - modified_query_ast->as().replaceDatabaseAndTable(database, table); + select_query.replaceDatabaseAndTable(database, table); return modified_query_ast; } diff --git a/dbms/tests/queries/0_stateless/00974_distributed_join_on.reference b/dbms/tests/queries/0_stateless/00974_distributed_join_on.reference new file mode 100644 index 00000000000..b4628801267 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00974_distributed_join_on.reference @@ -0,0 +1,8 @@ +1 +1 +1 +1 +1 +1 +42 42 +42 42 diff --git a/dbms/tests/queries/0_stateless/00974_distributed_join_on.sql b/dbms/tests/queries/0_stateless/00974_distributed_join_on.sql new file mode 100644 index 00000000000..355d9f81e82 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00974_distributed_join_on.sql @@ -0,0 +1,34 @@ +DROP TABLE IF EXISTS source_table1; +DROP TABLE IF EXISTS source_table2; +DROP TABLE IF EXISTS distributed_table1; +DROP TABLE IF EXISTS distributed_table2; + +CREATE TABLE source_table1 (a Int64, b String) ENGINE = Memory; +CREATE TABLE source_table2 (c Int64, d String) ENGINE = Memory; + +INSERT INTO source_table1 VALUES (42, 'qwe'); +INSERT INTO source_table2 VALUES (42, 'qwe'); + +CREATE TABLE distributed_table1 AS source_table1 +ENGINE = Distributed('test_shard_localhost', currentDatabase(), source_table1); + +CREATE TABLE distributed_table2 AS source_table2 +ENGINE = Distributed('test_shard_localhost', currentDatabase(), source_table2); + +SET prefer_localhost_replica = 1; +SELECT 1 FROM distributed_table1 AS t1 GLOBAL JOIN distributed_table2 AS t2 ON t1.a = t2.c LIMIT 1; +SELECT 1 FROM distributed_table1 AS t1 GLOBAL JOIN distributed_table2 AS t2 ON t2.c = t1.a LIMIT 1; +SELECT 1 FROM distributed_table1 AS t1 GLOBAL JOIN distributed_table1 AS t2 ON t1.a = t2.a LIMIT 1; + +SET prefer_localhost_replica = 0; +SELECT 1 FROM distributed_table1 AS t1 GLOBAL JOIN distributed_table2 AS t2 ON t1.a = t2.c LIMIT 1; +SELECT 1 FROM distributed_table1 AS t1 GLOBAL JOIN distributed_table2 AS t2 ON t2.c = t1.a LIMIT 1; +SELECT 1 FROM distributed_table1 AS t1 GLOBAL JOIN distributed_table1 AS t2 ON t1.a = t2.a LIMIT 1; + +SELECT t1.a as t1_a, t2.a as t2_a FROM source_table1 AS t1 JOIN source_table1 AS t2 ON t1_a = t2_a LIMIT 1; +SELECT t1.a as t1_a, t2.a as t2_a FROM distributed_table1 AS t1 GLOBAL JOIN distributed_table1 AS t2 ON t1_a = t2_a LIMIT 1; + +DROP TABLE source_table1; +DROP TABLE source_table2; +DROP TABLE distributed_table1; +DROP TABLE distributed_table2;