From daa231c391a1eea69dc2f4da1ab03efcfda5e620 Mon Sep 17 00:00:00 2001 From: yariks5s Date: Tue, 9 Jan 2024 14:34:30 +0000 Subject: [PATCH 01/18] init --- src/Interpreters/JoinedTables.cpp | 15 +++++++++++++++ tests/queries/0_stateless/02933_paste_join.sql | 6 +++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/Interpreters/JoinedTables.cpp b/src/Interpreters/JoinedTables.cpp index c104af770f06..dc0ae09c46e3 100644 --- a/src/Interpreters/JoinedTables.cpp +++ b/src/Interpreters/JoinedTables.cpp @@ -1,3 +1,4 @@ +#include #include #include @@ -258,6 +259,20 @@ bool JoinedTables::resolveTables() } } } + else if (tables_with_columns.size() > 1) + { + Names column_names = {}; + for (const auto & t : tables_with_columns) + for (auto & name : t.columns.getNames()) + column_names.push_back(name); + + std::sort(column_names.begin(), column_names.end()); + for (size_t i = 0; i < column_names.size() - 1; i++) // Check if there is not any duplicates because it will lead to broken result + if (column_names[i] == column_names[i+1]) + throw Exception(ErrorCodes::BAD_ARGUMENTS, + "Name of columns and aliases should be unique for this query (you can add alias that will be different)" + "While processing '{}'", table_expressions[i]->formatForErrorMessage()); + } return !tables_with_columns.empty(); } diff --git a/tests/queries/0_stateless/02933_paste_join.sql b/tests/queries/0_stateless/02933_paste_join.sql index 1c346438d778..3f5ae6561490 100644 --- a/tests/queries/0_stateless/02933_paste_join.sql +++ b/tests/queries/0_stateless/02933_paste_join.sql @@ -1,6 +1,6 @@ select * from (SELECT number as a FROM numbers(10)) t1 PASTE JOIN (select number as a from numbers(10)) t2; select * from (SELECT number as a FROM numbers(10)) t1 PASTE JOIN (select number as a from numbers(10) order by a desc) t2; -create table if not exists test (num UInt64) engine=Memory; +create table if not exists test (number UInt64) engine=Memory; insert into test select number from numbers(6); insert into test select number from numbers(5); SELECT * FROM (SELECT 1) t1 PASTE JOIN (SELECT 2) SETTINGS joined_subquery_requires_alias=0; @@ -35,3 +35,7 @@ SET max_threads = 2; select * from (SELECT number as a FROM numbers(10)) t1 ANY PASTE JOIN (select number as a from numbers(10)) t2; -- { clientError SYNTAX_ERROR } select * from (SELECT number as a FROM numbers(10)) t1 ALL PASTE JOIN (select number as a from numbers(10)) t2; -- { clientError SYNTAX_ERROR } select * from (SELECT number as a FROM numbers_mt(10)) t1 PASTE JOIN (select number as a from numbers(10) ORDER BY a DESC) t2 SETTINGS max_block_size=3; -- { serverError BAD_ARGUMENTS } + + +INSERT INTO test SELECT * FROM numbers(10); +SELECT * FROM (SELECT number FROM test) AS t1 PASTE JOIN (SELECT number FROM numbers(10) ORDER BY number DESC ) AS t2 SETTINGS joined_subquery_requires_alias = 0; -- { serverError BAD_ARGUMENTS } From 7a1c1a3b6267a6720c1d3391bb2f048a76fec4e2 Mon Sep 17 00:00:00 2001 From: yariks5s Date: Wed, 10 Jan 2024 13:38:46 +0000 Subject: [PATCH 02/18] analyzer implementation --- src/Analyzer/Passes/QueryAnalysisPass.cpp | 26 +++++++++++++++++++ src/Interpreters/JoinedTables.cpp | 2 ++ src/Parsers/ExpressionElementParsers.cpp | 1 + .../queries/0_stateless/02933_paste_join.sql | 2 +- 4 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/Analyzer/Passes/QueryAnalysisPass.cpp b/src/Analyzer/Passes/QueryAnalysisPass.cpp index 4ad9581b5b6b..5c84948b4e15 100644 --- a/src/Analyzer/Passes/QueryAnalysisPass.cpp +++ b/src/Analyzer/Passes/QueryAnalysisPass.cpp @@ -1207,6 +1207,8 @@ class QueryAnalyzer static void validateJoinTableExpressionWithoutAlias(const QueryTreeNodePtr & join_node, const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope); + static void checkDuplicateTableNamesOrAlias(QueryTreeNodePtr & join_node, QueryTreeNodePtr & left_table_expr, QueryTreeNodePtr & right_table_expr); + static std::pair recursivelyCollectMaxOrdinaryExpressions(QueryTreeNodePtr & node, QueryTreeNodes & into); static void expandGroupByAll(QueryNode & query_tree_node_typed); @@ -6777,6 +6779,28 @@ void QueryAnalyzer::resolveArrayJoin(QueryTreeNodePtr & array_join_node, Identif } } +void QueryAnalyzer::checkDuplicateTableNamesOrAlias(QueryTreeNodePtr & join_node, QueryTreeNodePtr & left_table_expr, QueryTreeNodePtr & right_table_expr) +{ + Names column_names; + auto * left_node = left_table_expr->as(); + auto * right_node = right_table_expr->as(); + + for (const auto & name_and_type : left_node->getProjectionColumns()) + column_names.push_back(name_and_type.name); + for (const auto & name_and_type : right_node->getProjectionColumns()) + column_names.push_back(name_and_type.name); + + if (column_names.empty()) + return; + + std::sort(column_names.begin(), column_names.end()); + for (size_t i = 0; i < column_names.size() - 1; i++) // Check if there is not any duplicates because it will lead to broken result + if (column_names[i] == column_names[i+1]) + throw Exception(ErrorCodes::BAD_ARGUMENTS, + "Name of columns and aliases should be unique for this query (you can add alias that will be different)" + "While processing '{}'", join_node->formatASTForErrorMessage()); +} + /// Resolve join node in scope void QueryAnalyzer::resolveJoin(QueryTreeNodePtr & join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor) { @@ -6788,6 +6812,8 @@ void QueryAnalyzer::resolveJoin(QueryTreeNodePtr & join_node, IdentifierResolveS resolveQueryJoinTreeNode(join_node_typed.getRightTableExpression(), scope, expressions_visitor); validateJoinTableExpressionWithoutAlias(join_node, join_node_typed.getRightTableExpression(), scope); + checkDuplicateTableNamesOrAlias(join_node, join_node_typed.getLeftTableExpression(), join_node_typed.getRightTableExpression()); + if (join_node_typed.isOnJoinExpression()) { expressions_visitor.visit(join_node_typed.getJoinExpression()); diff --git a/src/Interpreters/JoinedTables.cpp b/src/Interpreters/JoinedTables.cpp index dc0ae09c46e3..bb0c8188b743 100644 --- a/src/Interpreters/JoinedTables.cpp +++ b/src/Interpreters/JoinedTables.cpp @@ -265,6 +265,8 @@ bool JoinedTables::resolveTables() for (const auto & t : tables_with_columns) for (auto & name : t.columns.getNames()) column_names.push_back(name); + if (column_names.empty()) + return false; std::sort(column_names.begin(), column_names.end()); for (size_t i = 0; i < column_names.size() - 1; i++) // Check if there is not any duplicates because it will lead to broken result diff --git a/src/Parsers/ExpressionElementParsers.cpp b/src/Parsers/ExpressionElementParsers.cpp index 594221fe0500..eeb76e3bb9ea 100644 --- a/src/Parsers/ExpressionElementParsers.cpp +++ b/src/Parsers/ExpressionElementParsers.cpp @@ -1451,6 +1451,7 @@ const char * ParserAlias::restricted_keywords[] = "ASOF", "BETWEEN", "CROSS", + "PASTE", "FINAL", "FORMAT", "FROM", diff --git a/tests/queries/0_stateless/02933_paste_join.sql b/tests/queries/0_stateless/02933_paste_join.sql index 3f5ae6561490..78b8b9484fcc 100644 --- a/tests/queries/0_stateless/02933_paste_join.sql +++ b/tests/queries/0_stateless/02933_paste_join.sql @@ -38,4 +38,4 @@ select * from (SELECT number as a FROM numbers_mt(10)) t1 PASTE JOIN (select num INSERT INTO test SELECT * FROM numbers(10); -SELECT * FROM (SELECT number FROM test) AS t1 PASTE JOIN (SELECT number FROM numbers(10) ORDER BY number DESC ) AS t2 SETTINGS joined_subquery_requires_alias = 0; -- { serverError BAD_ARGUMENTS } +SELECT * FROM (SELECT number FROM test) PASTE JOIN (SELECT number FROM numbers(10) ORDER BY number DESC ) SETTINGS joined_subquery_requires_alias = 0; -- { serverError BAD_ARGUMENTS } From 28eabae93316c984837fdf69be8a75764546b402 Mon Sep 17 00:00:00 2001 From: Yarik Briukhovetskyi <114298166+yariks5s@users.noreply.github.com> Date: Wed, 10 Jan 2024 14:53:01 +0100 Subject: [PATCH 03/18] style fix --- src/Interpreters/JoinedTables.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Interpreters/JoinedTables.cpp b/src/Interpreters/JoinedTables.cpp index bb0c8188b743..f84322418689 100644 --- a/src/Interpreters/JoinedTables.cpp +++ b/src/Interpreters/JoinedTables.cpp @@ -33,6 +33,7 @@ namespace ErrorCodes extern const int ALIAS_REQUIRED; extern const int AMBIGUOUS_COLUMN_NAME; extern const int LOGICAL_ERROR; + extern const int BAD_ARGUMENTS; } namespace From f656a6d79990551e31024e6fef0bf24db02b4578 Mon Sep 17 00:00:00 2001 From: yariks5s Date: Wed, 10 Jan 2024 15:16:53 +0000 Subject: [PATCH 04/18] errors fix --- src/Analyzer/Passes/QueryAnalysisPass.cpp | 7 ++++--- src/Interpreters/JoinedTables.cpp | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Analyzer/Passes/QueryAnalysisPass.cpp b/src/Analyzer/Passes/QueryAnalysisPass.cpp index 5c84948b4e15..20c72dbd068f 100644 --- a/src/Analyzer/Passes/QueryAnalysisPass.cpp +++ b/src/Analyzer/Passes/QueryAnalysisPass.cpp @@ -6791,13 +6791,13 @@ void QueryAnalyzer::checkDuplicateTableNamesOrAlias(QueryTreeNodePtr & join_node column_names.push_back(name_and_type.name); if (column_names.empty()) - return; + throw Exception(ErrorCodes::LOGICAL_ERROR, "Names of projection columns cannot be empty"); std::sort(column_names.begin(), column_names.end()); for (size_t i = 0; i < column_names.size() - 1; i++) // Check if there is not any duplicates because it will lead to broken result if (column_names[i] == column_names[i+1]) throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Name of columns and aliases should be unique for this query (you can add alias that will be different)" + "Name of columns and aliases should be unique for this query (you can add/change aliases so they will not be duplicated)" "While processing '{}'", join_node->formatASTForErrorMessage()); } @@ -6812,7 +6812,8 @@ void QueryAnalyzer::resolveJoin(QueryTreeNodePtr & join_node, IdentifierResolveS resolveQueryJoinTreeNode(join_node_typed.getRightTableExpression(), scope, expressions_visitor); validateJoinTableExpressionWithoutAlias(join_node, join_node_typed.getRightTableExpression(), scope); - checkDuplicateTableNamesOrAlias(join_node, join_node_typed.getLeftTableExpression(), join_node_typed.getRightTableExpression()); + if (!join_node_typed.getLeftTableExpression()->hasAlias() && !join_node_typed.getRightTableExpression()->hasAlias()) + checkDuplicateTableNamesOrAlias(join_node, join_node_typed.getLeftTableExpression(), join_node_typed.getRightTableExpression()); if (join_node_typed.isOnJoinExpression()) { diff --git a/src/Interpreters/JoinedTables.cpp b/src/Interpreters/JoinedTables.cpp index f84322418689..0ad98f151e76 100644 --- a/src/Interpreters/JoinedTables.cpp +++ b/src/Interpreters/JoinedTables.cpp @@ -24,6 +24,7 @@ #include #include #include +#include "Common/Exception.h" namespace DB { @@ -267,13 +268,13 @@ bool JoinedTables::resolveTables() for (auto & name : t.columns.getNames()) column_names.push_back(name); if (column_names.empty()) - return false; + throw Exception(ErrorCodes::LOGICAL_ERROR, "Names of joining columns cannot be empty"); std::sort(column_names.begin(), column_names.end()); for (size_t i = 0; i < column_names.size() - 1; i++) // Check if there is not any duplicates because it will lead to broken result if (column_names[i] == column_names[i+1]) throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Name of columns and aliases should be unique for this query (you can add alias that will be different)" + "Name of columns and aliases should be unique for this query (you can add/change aliases so they will not be duplicated)" "While processing '{}'", table_expressions[i]->formatForErrorMessage()); } From 92c6eba922bd1fb0bd2c447b67f71bf5d153210d Mon Sep 17 00:00:00 2001 From: yariks5s Date: Wed, 10 Jan 2024 18:18:50 +0000 Subject: [PATCH 05/18] avoiding only for paste join now --- src/Analyzer/Passes/QueryAnalysisPass.cpp | 12 ++++-- src/Interpreters/InterpreterSelectQuery.cpp | 4 +- src/Interpreters/JoinedTables.cpp | 42 +++++++++++++++++---- src/Interpreters/JoinedTables.h | 4 +- 4 files changed, 48 insertions(+), 14 deletions(-) diff --git a/src/Analyzer/Passes/QueryAnalysisPass.cpp b/src/Analyzer/Passes/QueryAnalysisPass.cpp index 20c72dbd068f..f94e4bbc65d5 100644 --- a/src/Analyzer/Passes/QueryAnalysisPass.cpp +++ b/src/Analyzer/Passes/QueryAnalysisPass.cpp @@ -1207,7 +1207,7 @@ class QueryAnalyzer static void validateJoinTableExpressionWithoutAlias(const QueryTreeNodePtr & join_node, const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope); - static void checkDuplicateTableNamesOrAlias(QueryTreeNodePtr & join_node, QueryTreeNodePtr & left_table_expr, QueryTreeNodePtr & right_table_expr); + static void checkDuplicateTableNamesOrAlias(QueryTreeNodePtr & join_node, QueryTreeNodePtr & left_table_expr, QueryTreeNodePtr & right_table_expr, IdentifierResolveScope & scope); static std::pair recursivelyCollectMaxOrdinaryExpressions(QueryTreeNodePtr & node, QueryTreeNodes & into); @@ -6779,8 +6779,14 @@ void QueryAnalyzer::resolveArrayJoin(QueryTreeNodePtr & array_join_node, Identif } } -void QueryAnalyzer::checkDuplicateTableNamesOrAlias(QueryTreeNodePtr & join_node, QueryTreeNodePtr & left_table_expr, QueryTreeNodePtr & right_table_expr) +void QueryAnalyzer::checkDuplicateTableNamesOrAlias(QueryTreeNodePtr & join_node, QueryTreeNodePtr & left_table_expr, QueryTreeNodePtr & right_table_expr, IdentifierResolveScope & scope) { + if (scope.context->getSettingsRef().joined_subquery_requires_alias) + return; + + if (join_node->as().getKind() != JoinKind::Paste) + return; + Names column_names; auto * left_node = left_table_expr->as(); auto * right_node = right_table_expr->as(); @@ -6813,7 +6819,7 @@ void QueryAnalyzer::resolveJoin(QueryTreeNodePtr & join_node, IdentifierResolveS validateJoinTableExpressionWithoutAlias(join_node, join_node_typed.getRightTableExpression(), scope); if (!join_node_typed.getLeftTableExpression()->hasAlias() && !join_node_typed.getRightTableExpression()->hasAlias()) - checkDuplicateTableNamesOrAlias(join_node, join_node_typed.getLeftTableExpression(), join_node_typed.getRightTableExpression()); + checkDuplicateTableNamesOrAlias(join_node, join_node_typed.getLeftTableExpression(), join_node_typed.getRightTableExpression(), scope); if (join_node_typed.isOnJoinExpression()) { diff --git a/src/Interpreters/InterpreterSelectQuery.cpp b/src/Interpreters/InterpreterSelectQuery.cpp index d1bc66f47f19..81f7f157060f 100644 --- a/src/Interpreters/InterpreterSelectQuery.cpp +++ b/src/Interpreters/InterpreterSelectQuery.cpp @@ -452,7 +452,7 @@ InterpreterSelectQuery::InterpreterSelectQuery( storage_snapshot = storage->getStorageSnapshotForQuery(metadata_snapshot, query_ptr, context); } - if (has_input || !joined_tables.resolveTables()) + if (has_input || !joined_tables.resolveTables(analysis_result)) joined_tables.makeFakeTable(storage, metadata_snapshot, source_header); if (context->getCurrentTransaction() && context->getSettingsRef().throw_on_unsupported_query_inside_transaction) @@ -513,7 +513,7 @@ InterpreterSelectQuery::InterpreterSelectQuery( rewriteMultipleJoins(query_ptr, joined_tables.tablesWithColumns(), context->getCurrentDatabase(), context->getSettingsRef()); joined_tables.reset(getSelectQuery()); - joined_tables.resolveTables(); + joined_tables.resolveTables(analysis_result); if (auto view_source = context->getViewSource()) { // If we are using a virtual block view to replace a table and that table is used diff --git a/src/Interpreters/JoinedTables.cpp b/src/Interpreters/JoinedTables.cpp index 0ad98f151e76..9623f8305709 100644 --- a/src/Interpreters/JoinedTables.cpp +++ b/src/Interpreters/JoinedTables.cpp @@ -25,6 +25,7 @@ #include #include #include "Common/Exception.h" +#include "Interpreters/ExpressionAnalyzer.h" namespace DB { @@ -238,7 +239,24 @@ StoragePtr JoinedTables::getLeftTableStorage() return DatabaseCatalog::instance().getTable(table_id, context); } -bool JoinedTables::resolveTables() +void JoinedTables::checkDuplicateNames() +{ + Names column_names = {}; + for (const auto & t : tables_with_columns) + for (auto & name : t.columns.getNames()) + column_names.push_back(name); + if (column_names.empty()) + throw Exception(ErrorCodes::LOGICAL_ERROR, "Names of joining columns cannot be empty"); + + std::sort(column_names.begin(), column_names.end()); + for (size_t i = 0; i < column_names.size() - 1; i++) // Check if there is not any duplicates because it will lead to broken result + if (column_names[i] == column_names[i+1]) + throw Exception(ErrorCodes::BAD_ARGUMENTS, + "Name of columns and aliases should be unique for this query (you can add/change aliases so they will not be duplicated)" + "While processing '{}'", table_expressions[i]->formatForErrorMessage()); +} + +bool JoinedTables::resolveTables(ExpressionAnalysisResult result) { const auto & settings = context->getSettingsRef(); bool include_alias_cols = include_all_columns || settings.asterisk_include_alias_columns; @@ -249,15 +267,23 @@ bool JoinedTables::resolveTables() if (settings.joined_subquery_requires_alias && tables_with_columns.size() > 1) { - for (size_t i = 0; i < tables_with_columns.size(); ++i) + if (result.hasJoin()) { - const auto & t = tables_with_columns[i]; - if (t.table.table.empty() && t.table.alias.empty()) + if (result.join->getTableJoin().kind() == JoinKind::Paste) + checkDuplicateNames(); + else { - throw Exception(ErrorCodes::ALIAS_REQUIRED, - "No alias for subquery or table function " - "in JOIN (set joined_subquery_requires_alias=0 to disable restriction). " - "While processing '{}'", table_expressions[i]->formatForErrorMessage()); + for (size_t i = 0; i < tables_with_columns.size(); ++i) + { + const auto & t = tables_with_columns[i]; + if (t.table.table.empty() && t.table.alias.empty()) + { + throw Exception(ErrorCodes::ALIAS_REQUIRED, + "No alias for subquery or table function " + "in JOIN (set joined_subquery_requires_alias=0 to disable restriction). " + "While processing '{}'", table_expressions[i]->formatForErrorMessage()); + } + } } } } diff --git a/src/Interpreters/JoinedTables.h b/src/Interpreters/JoinedTables.h index 771f5ae6ef0c..d1c1075b5c57 100644 --- a/src/Interpreters/JoinedTables.h +++ b/src/Interpreters/JoinedTables.h @@ -6,6 +6,7 @@ #include #include #include +#include "Interpreters/ExpressionAnalyzer.h" namespace DB { @@ -27,7 +28,8 @@ class JoinedTables void reset(const ASTSelectQuery & select_query); StoragePtr getLeftTableStorage(); - bool resolveTables(); + bool resolveTables(ExpressionAnalysisResult result); + void checkDuplicateNames(); /// Make fake tables_with_columns[0] in case we have predefined input in InterpreterSelectQuery void makeFakeTable(StoragePtr storage, const StorageMetadataPtr & metadata_snapshot, const Block & source_header); From df8b29b81feb120ff15cf1bbe9f7d4a708443ad8 Mon Sep 17 00:00:00 2001 From: yariks5s Date: Wed, 10 Jan 2024 18:49:37 +0000 Subject: [PATCH 06/18] remove redundant code --- src/Interpreters/JoinedTables.cpp | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/Interpreters/JoinedTables.cpp b/src/Interpreters/JoinedTables.cpp index 9623f8305709..fe203d69eb6c 100644 --- a/src/Interpreters/JoinedTables.cpp +++ b/src/Interpreters/JoinedTables.cpp @@ -287,22 +287,6 @@ bool JoinedTables::resolveTables(ExpressionAnalysisResult result) } } } - else if (tables_with_columns.size() > 1) - { - Names column_names = {}; - for (const auto & t : tables_with_columns) - for (auto & name : t.columns.getNames()) - column_names.push_back(name); - if (column_names.empty()) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Names of joining columns cannot be empty"); - - std::sort(column_names.begin(), column_names.end()); - for (size_t i = 0; i < column_names.size() - 1; i++) // Check if there is not any duplicates because it will lead to broken result - if (column_names[i] == column_names[i+1]) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Name of columns and aliases should be unique for this query (you can add/change aliases so they will not be duplicated)" - "While processing '{}'", table_expressions[i]->formatForErrorMessage()); - } return !tables_with_columns.empty(); } From 567e5d378eb684e8412e10a78cafc00219582755 Mon Sep 17 00:00:00 2001 From: yariks5s Date: Thu, 11 Jan 2024 15:43:17 +0000 Subject: [PATCH 07/18] fixes --- src/Analyzer/Passes/QueryAnalysisPass.cpp | 5 ++- src/Interpreters/InterpreterSelectQuery.cpp | 4 +- src/Interpreters/JoinedTables.cpp | 45 ++++--------------- src/Interpreters/JoinedTables.h | 4 +- .../0_stateless/02933_paste_join.reference | 6 +++ .../queries/0_stateless/02933_paste_join.sql | 4 +- 6 files changed, 23 insertions(+), 45 deletions(-) diff --git a/src/Analyzer/Passes/QueryAnalysisPass.cpp b/src/Analyzer/Passes/QueryAnalysisPass.cpp index f94e4bbc65d5..dec4eefae35a 100644 --- a/src/Analyzer/Passes/QueryAnalysisPass.cpp +++ b/src/Analyzer/Passes/QueryAnalysisPass.cpp @@ -2245,6 +2245,9 @@ void QueryAnalyzer::validateJoinTableExpressionWithoutAlias(const QueryTreeNodeP if (table_expression_has_alias) return; + if (join_node->as().getKind() == JoinKind::Paste) + return; + auto * query_node = table_expression_node->as(); auto * union_node = table_expression_node->as(); if ((query_node && !query_node->getCTEName().empty()) || (union_node && !union_node->getCTEName().empty())) @@ -6781,7 +6784,7 @@ void QueryAnalyzer::resolveArrayJoin(QueryTreeNodePtr & array_join_node, Identif void QueryAnalyzer::checkDuplicateTableNamesOrAlias(QueryTreeNodePtr & join_node, QueryTreeNodePtr & left_table_expr, QueryTreeNodePtr & right_table_expr, IdentifierResolveScope & scope) { - if (scope.context->getSettingsRef().joined_subquery_requires_alias) + if (!scope.context->getSettingsRef().joined_subquery_requires_alias) return; if (join_node->as().getKind() != JoinKind::Paste) diff --git a/src/Interpreters/InterpreterSelectQuery.cpp b/src/Interpreters/InterpreterSelectQuery.cpp index 81f7f157060f..d1bc66f47f19 100644 --- a/src/Interpreters/InterpreterSelectQuery.cpp +++ b/src/Interpreters/InterpreterSelectQuery.cpp @@ -452,7 +452,7 @@ InterpreterSelectQuery::InterpreterSelectQuery( storage_snapshot = storage->getStorageSnapshotForQuery(metadata_snapshot, query_ptr, context); } - if (has_input || !joined_tables.resolveTables(analysis_result)) + if (has_input || !joined_tables.resolveTables()) joined_tables.makeFakeTable(storage, metadata_snapshot, source_header); if (context->getCurrentTransaction() && context->getSettingsRef().throw_on_unsupported_query_inside_transaction) @@ -513,7 +513,7 @@ InterpreterSelectQuery::InterpreterSelectQuery( rewriteMultipleJoins(query_ptr, joined_tables.tablesWithColumns(), context->getCurrentDatabase(), context->getSettingsRef()); joined_tables.reset(getSelectQuery()); - joined_tables.resolveTables(analysis_result); + joined_tables.resolveTables(); if (auto view_source = context->getViewSource()) { // If we are using a virtual block view to replace a table and that table is used diff --git a/src/Interpreters/JoinedTables.cpp b/src/Interpreters/JoinedTables.cpp index fe203d69eb6c..c104af770f06 100644 --- a/src/Interpreters/JoinedTables.cpp +++ b/src/Interpreters/JoinedTables.cpp @@ -1,4 +1,3 @@ -#include #include #include @@ -24,8 +23,6 @@ #include #include #include -#include "Common/Exception.h" -#include "Interpreters/ExpressionAnalyzer.h" namespace DB { @@ -35,7 +32,6 @@ namespace ErrorCodes extern const int ALIAS_REQUIRED; extern const int AMBIGUOUS_COLUMN_NAME; extern const int LOGICAL_ERROR; - extern const int BAD_ARGUMENTS; } namespace @@ -239,24 +235,7 @@ StoragePtr JoinedTables::getLeftTableStorage() return DatabaseCatalog::instance().getTable(table_id, context); } -void JoinedTables::checkDuplicateNames() -{ - Names column_names = {}; - for (const auto & t : tables_with_columns) - for (auto & name : t.columns.getNames()) - column_names.push_back(name); - if (column_names.empty()) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Names of joining columns cannot be empty"); - - std::sort(column_names.begin(), column_names.end()); - for (size_t i = 0; i < column_names.size() - 1; i++) // Check if there is not any duplicates because it will lead to broken result - if (column_names[i] == column_names[i+1]) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Name of columns and aliases should be unique for this query (you can add/change aliases so they will not be duplicated)" - "While processing '{}'", table_expressions[i]->formatForErrorMessage()); -} - -bool JoinedTables::resolveTables(ExpressionAnalysisResult result) +bool JoinedTables::resolveTables() { const auto & settings = context->getSettingsRef(); bool include_alias_cols = include_all_columns || settings.asterisk_include_alias_columns; @@ -267,23 +246,15 @@ bool JoinedTables::resolveTables(ExpressionAnalysisResult result) if (settings.joined_subquery_requires_alias && tables_with_columns.size() > 1) { - if (result.hasJoin()) + for (size_t i = 0; i < tables_with_columns.size(); ++i) { - if (result.join->getTableJoin().kind() == JoinKind::Paste) - checkDuplicateNames(); - else + const auto & t = tables_with_columns[i]; + if (t.table.table.empty() && t.table.alias.empty()) { - for (size_t i = 0; i < tables_with_columns.size(); ++i) - { - const auto & t = tables_with_columns[i]; - if (t.table.table.empty() && t.table.alias.empty()) - { - throw Exception(ErrorCodes::ALIAS_REQUIRED, - "No alias for subquery or table function " - "in JOIN (set joined_subquery_requires_alias=0 to disable restriction). " - "While processing '{}'", table_expressions[i]->formatForErrorMessage()); - } - } + throw Exception(ErrorCodes::ALIAS_REQUIRED, + "No alias for subquery or table function " + "in JOIN (set joined_subquery_requires_alias=0 to disable restriction). " + "While processing '{}'", table_expressions[i]->formatForErrorMessage()); } } } diff --git a/src/Interpreters/JoinedTables.h b/src/Interpreters/JoinedTables.h index d1c1075b5c57..771f5ae6ef0c 100644 --- a/src/Interpreters/JoinedTables.h +++ b/src/Interpreters/JoinedTables.h @@ -6,7 +6,6 @@ #include #include #include -#include "Interpreters/ExpressionAnalyzer.h" namespace DB { @@ -28,8 +27,7 @@ class JoinedTables void reset(const ASTSelectQuery & select_query); StoragePtr getLeftTableStorage(); - bool resolveTables(ExpressionAnalysisResult result); - void checkDuplicateNames(); + bool resolveTables(); /// Make fake tables_with_columns[0] in case we have predefined input in InterpreterSelectQuery void makeFakeTable(StoragePtr storage, const StorageMetadataPtr & metadata_snapshot, const Block & source_header); diff --git a/tests/queries/0_stateless/02933_paste_join.reference b/tests/queries/0_stateless/02933_paste_join.reference index 5ff13917957c..18c2d5969f36 100644 --- a/tests/queries/0_stateless/02933_paste_join.reference +++ b/tests/queries/0_stateless/02933_paste_join.reference @@ -82,3 +82,9 @@ UInt64 7 2 8 1 9 0 +0 0 +1 1 +2 2 +3 3 +4 4 +5 5 diff --git a/tests/queries/0_stateless/02933_paste_join.sql b/tests/queries/0_stateless/02933_paste_join.sql index fac3f4b2fccb..94c88493cb2f 100644 --- a/tests/queries/0_stateless/02933_paste_join.sql +++ b/tests/queries/0_stateless/02933_paste_join.sql @@ -36,5 +36,5 @@ select * from (SELECT number as a FROM numbers_mt(10)) t1 PASTE JOIN (select num select * from (SELECT number as a FROM numbers(10)) t1 ANY PASTE JOIN (select number as a from numbers(10)) t2; -- { clientError SYNTAX_ERROR } select * from (SELECT number as a FROM numbers(10)) t1 ALL PASTE JOIN (select number as a from numbers(10)) t2; -- { clientError SYNTAX_ERROR } -INSERT INTO test SELECT * FROM numbers(10); -SELECT * FROM (SELECT number FROM test) PASTE JOIN (SELECT number FROM numbers(10) ORDER BY number DESC ) SETTINGS joined_subquery_requires_alias = 0; -- { serverError BAD_ARGUMENTS } +SELECT * FROM (SELECT number FROM test) PASTE JOIN (SELECT number FROM numbers(10) ORDER BY number DESC ) SETTINGS joined_subquery_requires_alias = 1, allow_experimental_analyzer = 1; -- { serverError BAD_ARGUMENTS } +SELECT * FROM (SELECT number FROM test) PASTE JOIN (SELECT number FROM numbers(6) ORDER BY number DESC ) SETTINGS joined_subquery_requires_alias = 0; From bfe76b1089cf5b22b3d1ff4de65de2af1b5d5fd4 Mon Sep 17 00:00:00 2001 From: yariks5s Date: Thu, 11 Jan 2024 22:48:54 +0000 Subject: [PATCH 08/18] fix flaky --- tests/queries/0_stateless/02933_paste_join.sql | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/queries/0_stateless/02933_paste_join.sql b/tests/queries/0_stateless/02933_paste_join.sql index 94c88493cb2f..77544bc2629d 100644 --- a/tests/queries/0_stateless/02933_paste_join.sql +++ b/tests/queries/0_stateless/02933_paste_join.sql @@ -37,4 +37,6 @@ select * from (SELECT number as a FROM numbers(10)) t1 ANY PASTE JOIN (select nu select * from (SELECT number as a FROM numbers(10)) t1 ALL PASTE JOIN (select number as a from numbers(10)) t2; -- { clientError SYNTAX_ERROR } SELECT * FROM (SELECT number FROM test) PASTE JOIN (SELECT number FROM numbers(10) ORDER BY number DESC ) SETTINGS joined_subquery_requires_alias = 1, allow_experimental_analyzer = 1; -- { serverError BAD_ARGUMENTS } +TRUNCATE TABLE test; +INSERT INTO test SELECT number from numbers(6); SELECT * FROM (SELECT number FROM test) PASTE JOIN (SELECT number FROM numbers(6) ORDER BY number DESC ) SETTINGS joined_subquery_requires_alias = 0; From 157c596fd101896e3f6ed6e986e1b0305e4213ca Mon Sep 17 00:00:00 2001 From: yariks5s Date: Fri, 12 Jan 2024 12:16:34 +0000 Subject: [PATCH 09/18] stateless --- tests/queries/0_stateless/02933_paste_join.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/queries/0_stateless/02933_paste_join.sql b/tests/queries/0_stateless/02933_paste_join.sql index 77544bc2629d..5eff72f7caf6 100644 --- a/tests/queries/0_stateless/02933_paste_join.sql +++ b/tests/queries/0_stateless/02933_paste_join.sql @@ -39,4 +39,4 @@ select * from (SELECT number as a FROM numbers(10)) t1 ALL PASTE JOIN (select nu SELECT * FROM (SELECT number FROM test) PASTE JOIN (SELECT number FROM numbers(10) ORDER BY number DESC ) SETTINGS joined_subquery_requires_alias = 1, allow_experimental_analyzer = 1; -- { serverError BAD_ARGUMENTS } TRUNCATE TABLE test; INSERT INTO test SELECT number from numbers(6); -SELECT * FROM (SELECT number FROM test) PASTE JOIN (SELECT number FROM numbers(6) ORDER BY number DESC ) SETTINGS joined_subquery_requires_alias = 0; +SELECT * FROM (SELECT number FROM test) PASTE JOIN (SELECT number FROM numbers(6) ORDER BY number) SETTINGS joined_subquery_requires_alias = 0; From eea8d2ab22a7d3f17dbf5a954aa62ec982a3c4f9 Mon Sep 17 00:00:00 2001 From: yariks5s Date: Mon, 15 Jan 2024 14:13:37 +0000 Subject: [PATCH 10/18] enhanced tests --- .../0_stateless/02933_paste_join.reference | 18 ++++++++++++++++++ tests/queries/0_stateless/02933_paste_join.sql | 4 ++++ 2 files changed, 22 insertions(+) diff --git a/tests/queries/0_stateless/02933_paste_join.reference b/tests/queries/0_stateless/02933_paste_join.reference index 18c2d5969f36..2bfee53b776b 100644 --- a/tests/queries/0_stateless/02933_paste_join.reference +++ b/tests/queries/0_stateless/02933_paste_join.reference @@ -88,3 +88,21 @@ UInt64 3 3 4 4 5 5 +0 0 +1 1 +2 2 +3 3 +4 4 +5 5 +0 0 +1 1 +2 2 +3 3 +4 4 +5 5 +0 0 +1 1 +2 2 +3 3 +4 4 +5 5 diff --git a/tests/queries/0_stateless/02933_paste_join.sql b/tests/queries/0_stateless/02933_paste_join.sql index 5eff72f7caf6..7726ffcff047 100644 --- a/tests/queries/0_stateless/02933_paste_join.sql +++ b/tests/queries/0_stateless/02933_paste_join.sql @@ -40,3 +40,7 @@ SELECT * FROM (SELECT number FROM test) PASTE JOIN (SELECT number FROM numbers(1 TRUNCATE TABLE test; INSERT INTO test SELECT number from numbers(6); SELECT * FROM (SELECT number FROM test) PASTE JOIN (SELECT number FROM numbers(6) ORDER BY number) SETTINGS joined_subquery_requires_alias = 0; +SELECT * FROM (SELECT number FROM test PASTE JOIN (Select number FROM numbers(7))) PASTE JOIN (SELECT number FROM numbers(6) PASTE JOIN (SELECT number FROM test)) SETTINGS joined_subquery_requires_alias = 0; +SELECT * FROM (SELECT number FROM test PASTE JOIN (Select number FROM numbers(7))) PASTE JOIN (SELECT number FROM numbers(6) CROSS JOIN (SELECT number FROM test)) SETTINGS joined_subquery_requires_alias = 0; +SELECT * FROM (SELECT number FROM test PASTE JOIN (SELECT number FROM test PASTE JOIN (Select number FROM numbers(7)))) PASTE JOIN (SELECT number FROM numbers(6) CROSS JOIN (SELECT number FROM test)) SETTINGS joined_subquery_requires_alias = 0; + From b4f078e5ccdfa3cee696a7013e0803fa4fe16924 Mon Sep 17 00:00:00 2001 From: yariks5s Date: Mon, 15 Jan 2024 16:49:42 +0000 Subject: [PATCH 11/18] fix bug with several joins --- src/Analyzer/Passes/QueryAnalysisPass.cpp | 42 ++++++++++--------- .../0_stateless/02933_paste_join.reference | 1 + .../queries/0_stateless/02933_paste_join.sql | 2 +- 3 files changed, 24 insertions(+), 21 deletions(-) diff --git a/src/Analyzer/Passes/QueryAnalysisPass.cpp b/src/Analyzer/Passes/QueryAnalysisPass.cpp index dec4eefae35a..6f4f4224a3cd 100644 --- a/src/Analyzer/Passes/QueryAnalysisPass.cpp +++ b/src/Analyzer/Passes/QueryAnalysisPass.cpp @@ -1207,7 +1207,7 @@ class QueryAnalyzer static void validateJoinTableExpressionWithoutAlias(const QueryTreeNodePtr & join_node, const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope); - static void checkDuplicateTableNamesOrAlias(QueryTreeNodePtr & join_node, QueryTreeNodePtr & left_table_expr, QueryTreeNodePtr & right_table_expr, IdentifierResolveScope & scope); + static void checkDuplicateTableNamesOrAlias(QueryTreeNodePtr & join_node, QueryTreeNodePtr & left_table_expr, QueryTreeNodePtr & right_table_expr, IdentifierResolveScope & scope, Names & column_names); static std::pair recursivelyCollectMaxOrdinaryExpressions(QueryTreeNodePtr & node, QueryTreeNodes & into); @@ -1382,11 +1382,11 @@ class QueryAnalyzer void resolveTableFunction(QueryTreeNodePtr & table_function_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor, bool nested_table_function); - void resolveArrayJoin(QueryTreeNodePtr & array_join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor); + void resolveArrayJoin(QueryTreeNodePtr & array_join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor, Names & column_names); - void resolveJoin(QueryTreeNodePtr & join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor); + void resolveJoin(QueryTreeNodePtr & join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor, Names & column_names); - void resolveQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor); + void resolveQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor, Names & column_names); void resolveQuery(const QueryTreeNodePtr & query_node, IdentifierResolveScope & scope); @@ -6655,10 +6655,10 @@ void QueryAnalyzer::resolveTableFunction(QueryTreeNodePtr & table_function_node, } /// Resolve array join node in scope -void QueryAnalyzer::resolveArrayJoin(QueryTreeNodePtr & array_join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor) +void QueryAnalyzer::resolveArrayJoin(QueryTreeNodePtr & array_join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor, Names & column_names) { auto & array_join_node_typed = array_join_node->as(); - resolveQueryJoinTreeNode(array_join_node_typed.getTableExpression(), scope, expressions_visitor); + resolveQueryJoinTreeNode(array_join_node_typed.getTableExpression(), scope, expressions_visitor, column_names); std::unordered_set array_join_column_names; @@ -6782,7 +6782,7 @@ void QueryAnalyzer::resolveArrayJoin(QueryTreeNodePtr & array_join_node, Identif } } -void QueryAnalyzer::checkDuplicateTableNamesOrAlias(QueryTreeNodePtr & join_node, QueryTreeNodePtr & left_table_expr, QueryTreeNodePtr & right_table_expr, IdentifierResolveScope & scope) +void QueryAnalyzer::checkDuplicateTableNamesOrAlias(QueryTreeNodePtr & join_node, QueryTreeNodePtr & left_table_expr, QueryTreeNodePtr & right_table_expr, IdentifierResolveScope & scope, Names & column_names) { if (!scope.context->getSettingsRef().joined_subquery_requires_alias) return; @@ -6790,14 +6790,15 @@ void QueryAnalyzer::checkDuplicateTableNamesOrAlias(QueryTreeNodePtr & join_node if (join_node->as().getKind() != JoinKind::Paste) return; - Names column_names; auto * left_node = left_table_expr->as(); auto * right_node = right_table_expr->as(); - for (const auto & name_and_type : left_node->getProjectionColumns()) - column_names.push_back(name_and_type.name); - for (const auto & name_and_type : right_node->getProjectionColumns()) - column_names.push_back(name_and_type.name); + if (left_node) + for (const auto & name_and_type : left_node->getProjectionColumns()) + column_names.push_back(name_and_type.name); + if (right_node) + for (const auto & name_and_type : right_node->getProjectionColumns()) + column_names.push_back(name_and_type.name); if (column_names.empty()) throw Exception(ErrorCodes::LOGICAL_ERROR, "Names of projection columns cannot be empty"); @@ -6811,18 +6812,18 @@ void QueryAnalyzer::checkDuplicateTableNamesOrAlias(QueryTreeNodePtr & join_node } /// Resolve join node in scope -void QueryAnalyzer::resolveJoin(QueryTreeNodePtr & join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor) +void QueryAnalyzer::resolveJoin(QueryTreeNodePtr & join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor, Names & column_names) { auto & join_node_typed = join_node->as(); - resolveQueryJoinTreeNode(join_node_typed.getLeftTableExpression(), scope, expressions_visitor); + resolveQueryJoinTreeNode(join_node_typed.getLeftTableExpression(), scope, expressions_visitor, column_names); validateJoinTableExpressionWithoutAlias(join_node, join_node_typed.getLeftTableExpression(), scope); - resolveQueryJoinTreeNode(join_node_typed.getRightTableExpression(), scope, expressions_visitor); + resolveQueryJoinTreeNode(join_node_typed.getRightTableExpression(), scope, expressions_visitor, column_names); validateJoinTableExpressionWithoutAlias(join_node, join_node_typed.getRightTableExpression(), scope); if (!join_node_typed.getLeftTableExpression()->hasAlias() && !join_node_typed.getRightTableExpression()->hasAlias()) - checkDuplicateTableNamesOrAlias(join_node, join_node_typed.getLeftTableExpression(), join_node_typed.getRightTableExpression(), scope); + checkDuplicateTableNamesOrAlias(join_node, join_node_typed.getLeftTableExpression(), join_node_typed.getRightTableExpression(), scope, column_names); if (join_node_typed.isOnJoinExpression()) { @@ -6910,7 +6911,7 @@ void QueryAnalyzer::resolveJoin(QueryTreeNodePtr & join_node, IdentifierResolveS * * Query join tree must be initialized before calling this function. */ -void QueryAnalyzer::resolveQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor) +void QueryAnalyzer::resolveQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor, Names & column_names) { auto from_node_type = join_tree_node->getNodeType(); @@ -6934,12 +6935,12 @@ void QueryAnalyzer::resolveQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, } case QueryTreeNodeType::ARRAY_JOIN: { - resolveArrayJoin(join_tree_node, scope, expressions_visitor); + resolveArrayJoin(join_tree_node, scope, expressions_visitor, column_names); break; } case QueryTreeNodeType::JOIN: { - resolveJoin(join_tree_node, scope, expressions_visitor); + resolveJoin(join_tree_node, scope, expressions_visitor, column_names); break; } case QueryTreeNodeType::IDENTIFIER: @@ -7166,7 +7167,8 @@ void QueryAnalyzer::resolveQuery(const QueryTreeNodePtr & query_node, Identifier initializeQueryJoinTreeNode(query_node_typed.getJoinTree(), scope); scope.alias_name_to_table_expression_node.clear(); - resolveQueryJoinTreeNode(query_node_typed.getJoinTree(), scope, visitor); + Names column_names; + resolveQueryJoinTreeNode(query_node_typed.getJoinTree(), scope, visitor, column_names); } if (!scope.group_by_use_nulls) diff --git a/tests/queries/0_stateless/02933_paste_join.reference b/tests/queries/0_stateless/02933_paste_join.reference index 2bfee53b776b..4d9183130f55 100644 --- a/tests/queries/0_stateless/02933_paste_join.reference +++ b/tests/queries/0_stateless/02933_paste_join.reference @@ -106,3 +106,4 @@ UInt64 3 3 4 4 5 5 +1 1 1 diff --git a/tests/queries/0_stateless/02933_paste_join.sql b/tests/queries/0_stateless/02933_paste_join.sql index 7726ffcff047..a2e87c625e11 100644 --- a/tests/queries/0_stateless/02933_paste_join.sql +++ b/tests/queries/0_stateless/02933_paste_join.sql @@ -43,4 +43,4 @@ SELECT * FROM (SELECT number FROM test) PASTE JOIN (SELECT number FROM numbers(6 SELECT * FROM (SELECT number FROM test PASTE JOIN (Select number FROM numbers(7))) PASTE JOIN (SELECT number FROM numbers(6) PASTE JOIN (SELECT number FROM test)) SETTINGS joined_subquery_requires_alias = 0; SELECT * FROM (SELECT number FROM test PASTE JOIN (Select number FROM numbers(7))) PASTE JOIN (SELECT number FROM numbers(6) CROSS JOIN (SELECT number FROM test)) SETTINGS joined_subquery_requires_alias = 0; SELECT * FROM (SELECT number FROM test PASTE JOIN (SELECT number FROM test PASTE JOIN (Select number FROM numbers(7)))) PASTE JOIN (SELECT number FROM numbers(6) CROSS JOIN (SELECT number FROM test)) SETTINGS joined_subquery_requires_alias = 0; - +SELECT * FROM (SELECT 1 AS a) PASTE JOIN (SELECT 1 AS b) PASTE JOIN (SELECT 1 AS c) SETTINGS allow_experimental_analyzer = 1; From 66f71008b3e60aab7a4d81c2c0524214b80bf367 Mon Sep 17 00:00:00 2001 From: yariks5s Date: Tue, 16 Jan 2024 15:36:43 +0000 Subject: [PATCH 12/18] revert and fix --- src/Analyzer/Passes/QueryAnalysisPass.cpp | 39 ++++++++++--------- .../0_stateless/02933_paste_join.reference | 2 +- .../queries/0_stateless/02933_paste_join.sql | 4 +- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/Analyzer/Passes/QueryAnalysisPass.cpp b/src/Analyzer/Passes/QueryAnalysisPass.cpp index 6f4f4224a3cd..f0275df3afd1 100644 --- a/src/Analyzer/Passes/QueryAnalysisPass.cpp +++ b/src/Analyzer/Passes/QueryAnalysisPass.cpp @@ -1207,7 +1207,7 @@ class QueryAnalyzer static void validateJoinTableExpressionWithoutAlias(const QueryTreeNodePtr & join_node, const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope); - static void checkDuplicateTableNamesOrAlias(QueryTreeNodePtr & join_node, QueryTreeNodePtr & left_table_expr, QueryTreeNodePtr & right_table_expr, IdentifierResolveScope & scope, Names & column_names); + static void checkDuplicateTableNamesOrAlias(const QueryTreeNodePtr & join_node, QueryTreeNodePtr & left_table_expr, QueryTreeNodePtr & right_table_expr, IdentifierResolveScope & scope); static std::pair recursivelyCollectMaxOrdinaryExpressions(QueryTreeNodePtr & node, QueryTreeNodes & into); @@ -1382,11 +1382,11 @@ class QueryAnalyzer void resolveTableFunction(QueryTreeNodePtr & table_function_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor, bool nested_table_function); - void resolveArrayJoin(QueryTreeNodePtr & array_join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor, Names & column_names); + void resolveArrayJoin(QueryTreeNodePtr & array_join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor); - void resolveJoin(QueryTreeNodePtr & join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor, Names & column_names); + void resolveJoin(QueryTreeNodePtr & join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor); - void resolveQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor, Names & column_names); + void resolveQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor); void resolveQuery(const QueryTreeNodePtr & query_node, IdentifierResolveScope & scope); @@ -2254,9 +2254,12 @@ void QueryAnalyzer::validateJoinTableExpressionWithoutAlias(const QueryTreeNodeP return; auto table_expression_node_type = table_expression_node->getNodeType(); - if (table_expression_node_type == QueryTreeNodeType::TABLE_FUNCTION || + auto * join_typed = join_node->as(); + if (table_expression_node_type == QueryTreeNodeType::QUERY && join_typed->getKind() == JoinKind::Paste) + checkDuplicateTableNamesOrAlias(join_node, join_typed->getLeftTableExpression(), join_typed->getRightTableExpression(), scope); + else if ((table_expression_node_type == QueryTreeNodeType::TABLE_FUNCTION || table_expression_node_type == QueryTreeNodeType::QUERY || - table_expression_node_type == QueryTreeNodeType::UNION) + table_expression_node_type == QueryTreeNodeType::UNION) && join_typed->getKind() != JoinKind::Paste) throw Exception(ErrorCodes::ALIAS_REQUIRED, "JOIN {} no alias for subquery or table function {}. " "In scope {} (set joined_subquery_requires_alias = 0 to disable restriction)", @@ -6655,10 +6658,10 @@ void QueryAnalyzer::resolveTableFunction(QueryTreeNodePtr & table_function_node, } /// Resolve array join node in scope -void QueryAnalyzer::resolveArrayJoin(QueryTreeNodePtr & array_join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor, Names & column_names) +void QueryAnalyzer::resolveArrayJoin(QueryTreeNodePtr & array_join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor) { auto & array_join_node_typed = array_join_node->as(); - resolveQueryJoinTreeNode(array_join_node_typed.getTableExpression(), scope, expressions_visitor, column_names); + resolveQueryJoinTreeNode(array_join_node_typed.getTableExpression(), scope, expressions_visitor); std::unordered_set array_join_column_names; @@ -6782,8 +6785,9 @@ void QueryAnalyzer::resolveArrayJoin(QueryTreeNodePtr & array_join_node, Identif } } -void QueryAnalyzer::checkDuplicateTableNamesOrAlias(QueryTreeNodePtr & join_node, QueryTreeNodePtr & left_table_expr, QueryTreeNodePtr & right_table_expr, IdentifierResolveScope & scope, Names & column_names) +void QueryAnalyzer::checkDuplicateTableNamesOrAlias(const QueryTreeNodePtr & join_node, QueryTreeNodePtr & left_table_expr, QueryTreeNodePtr & right_table_expr, IdentifierResolveScope & scope) { + Names column_names; if (!scope.context->getSettingsRef().joined_subquery_requires_alias) return; @@ -6812,19 +6816,16 @@ void QueryAnalyzer::checkDuplicateTableNamesOrAlias(QueryTreeNodePtr & join_node } /// Resolve join node in scope -void QueryAnalyzer::resolveJoin(QueryTreeNodePtr & join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor, Names & column_names) +void QueryAnalyzer::resolveJoin(QueryTreeNodePtr & join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor) { auto & join_node_typed = join_node->as(); - resolveQueryJoinTreeNode(join_node_typed.getLeftTableExpression(), scope, expressions_visitor, column_names); + resolveQueryJoinTreeNode(join_node_typed.getLeftTableExpression(), scope, expressions_visitor); validateJoinTableExpressionWithoutAlias(join_node, join_node_typed.getLeftTableExpression(), scope); - resolveQueryJoinTreeNode(join_node_typed.getRightTableExpression(), scope, expressions_visitor, column_names); + resolveQueryJoinTreeNode(join_node_typed.getRightTableExpression(), scope, expressions_visitor); validateJoinTableExpressionWithoutAlias(join_node, join_node_typed.getRightTableExpression(), scope); - if (!join_node_typed.getLeftTableExpression()->hasAlias() && !join_node_typed.getRightTableExpression()->hasAlias()) - checkDuplicateTableNamesOrAlias(join_node, join_node_typed.getLeftTableExpression(), join_node_typed.getRightTableExpression(), scope, column_names); - if (join_node_typed.isOnJoinExpression()) { expressions_visitor.visit(join_node_typed.getJoinExpression()); @@ -6911,7 +6912,7 @@ void QueryAnalyzer::resolveJoin(QueryTreeNodePtr & join_node, IdentifierResolveS * * Query join tree must be initialized before calling this function. */ -void QueryAnalyzer::resolveQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor, Names & column_names) +void QueryAnalyzer::resolveQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor) { auto from_node_type = join_tree_node->getNodeType(); @@ -6935,12 +6936,12 @@ void QueryAnalyzer::resolveQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, } case QueryTreeNodeType::ARRAY_JOIN: { - resolveArrayJoin(join_tree_node, scope, expressions_visitor, column_names); + resolveArrayJoin(join_tree_node, scope, expressions_visitor); break; } case QueryTreeNodeType::JOIN: { - resolveJoin(join_tree_node, scope, expressions_visitor, column_names); + resolveJoin(join_tree_node, scope, expressions_visitor); break; } case QueryTreeNodeType::IDENTIFIER: @@ -7168,7 +7169,7 @@ void QueryAnalyzer::resolveQuery(const QueryTreeNodePtr & query_node, Identifier scope.alias_name_to_table_expression_node.clear(); Names column_names; - resolveQueryJoinTreeNode(query_node_typed.getJoinTree(), scope, visitor, column_names); + resolveQueryJoinTreeNode(query_node_typed.getJoinTree(), scope, visitor); } if (!scope.group_by_use_nulls) diff --git a/tests/queries/0_stateless/02933_paste_join.reference b/tests/queries/0_stateless/02933_paste_join.reference index 4d9183130f55..74a87ef0be3e 100644 --- a/tests/queries/0_stateless/02933_paste_join.reference +++ b/tests/queries/0_stateless/02933_paste_join.reference @@ -106,4 +106,4 @@ UInt64 3 3 4 4 5 5 -1 1 1 +1 2 3 diff --git a/tests/queries/0_stateless/02933_paste_join.sql b/tests/queries/0_stateless/02933_paste_join.sql index a2e87c625e11..9007b4d853ef 100644 --- a/tests/queries/0_stateless/02933_paste_join.sql +++ b/tests/queries/0_stateless/02933_paste_join.sql @@ -36,11 +36,11 @@ select * from (SELECT number as a FROM numbers_mt(10)) t1 PASTE JOIN (select num select * from (SELECT number as a FROM numbers(10)) t1 ANY PASTE JOIN (select number as a from numbers(10)) t2; -- { clientError SYNTAX_ERROR } select * from (SELECT number as a FROM numbers(10)) t1 ALL PASTE JOIN (select number as a from numbers(10)) t2; -- { clientError SYNTAX_ERROR } -SELECT * FROM (SELECT number FROM test) PASTE JOIN (SELECT number FROM numbers(10) ORDER BY number DESC ) SETTINGS joined_subquery_requires_alias = 1, allow_experimental_analyzer = 1; -- { serverError BAD_ARGUMENTS } TRUNCATE TABLE test; INSERT INTO test SELECT number from numbers(6); SELECT * FROM (SELECT number FROM test) PASTE JOIN (SELECT number FROM numbers(6) ORDER BY number) SETTINGS joined_subquery_requires_alias = 0; SELECT * FROM (SELECT number FROM test PASTE JOIN (Select number FROM numbers(7))) PASTE JOIN (SELECT number FROM numbers(6) PASTE JOIN (SELECT number FROM test)) SETTINGS joined_subquery_requires_alias = 0; SELECT * FROM (SELECT number FROM test PASTE JOIN (Select number FROM numbers(7))) PASTE JOIN (SELECT number FROM numbers(6) CROSS JOIN (SELECT number FROM test)) SETTINGS joined_subquery_requires_alias = 0; SELECT * FROM (SELECT number FROM test PASTE JOIN (SELECT number FROM test PASTE JOIN (Select number FROM numbers(7)))) PASTE JOIN (SELECT number FROM numbers(6) CROSS JOIN (SELECT number FROM test)) SETTINGS joined_subquery_requires_alias = 0; -SELECT * FROM (SELECT 1 AS a) PASTE JOIN (SELECT 1 AS b) PASTE JOIN (SELECT 1 AS c) SETTINGS allow_experimental_analyzer = 1; +SELECT * FROM (SELECT 1 AS a) PASTE JOIN (SELECT 2 AS b) PASTE JOIN (SELECT 3 AS c) SETTINGS allow_experimental_analyzer = 1; +SELECT * FROM (SELECT 1 AS a) PASTE JOIN (SELECT 2 AS b) PASTE JOIN (SELECT 3 AS a) SETTINGS allow_experimental_analyzer = 1; -- { serverError AMBIGUOUS_COLUMN_NAME } From 243c37b888d14d5c2469fdf3fe38ecfdfd6bdb24 Mon Sep 17 00:00:00 2001 From: yariks5s Date: Wed, 17 Jan 2024 12:20:01 +0000 Subject: [PATCH 13/18] test --- tests/queries/0_stateless/02933_paste_join.reference | 6 ------ tests/queries/0_stateless/02933_paste_join.sql | 3 +-- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/tests/queries/0_stateless/02933_paste_join.reference b/tests/queries/0_stateless/02933_paste_join.reference index 74a87ef0be3e..0b285913cd00 100644 --- a/tests/queries/0_stateless/02933_paste_join.reference +++ b/tests/queries/0_stateless/02933_paste_join.reference @@ -100,10 +100,4 @@ UInt64 3 3 4 4 5 5 -0 0 -1 1 -2 2 -3 3 -4 4 -5 5 1 2 3 diff --git a/tests/queries/0_stateless/02933_paste_join.sql b/tests/queries/0_stateless/02933_paste_join.sql index 9007b4d853ef..dc458417e7f4 100644 --- a/tests/queries/0_stateless/02933_paste_join.sql +++ b/tests/queries/0_stateless/02933_paste_join.sql @@ -40,7 +40,6 @@ TRUNCATE TABLE test; INSERT INTO test SELECT number from numbers(6); SELECT * FROM (SELECT number FROM test) PASTE JOIN (SELECT number FROM numbers(6) ORDER BY number) SETTINGS joined_subquery_requires_alias = 0; SELECT * FROM (SELECT number FROM test PASTE JOIN (Select number FROM numbers(7))) PASTE JOIN (SELECT number FROM numbers(6) PASTE JOIN (SELECT number FROM test)) SETTINGS joined_subquery_requires_alias = 0; -SELECT * FROM (SELECT number FROM test PASTE JOIN (Select number FROM numbers(7))) PASTE JOIN (SELECT number FROM numbers(6) CROSS JOIN (SELECT number FROM test)) SETTINGS joined_subquery_requires_alias = 0; -SELECT * FROM (SELECT number FROM test PASTE JOIN (SELECT number FROM test PASTE JOIN (Select number FROM numbers(7)))) PASTE JOIN (SELECT number FROM numbers(6) CROSS JOIN (SELECT number FROM test)) SETTINGS joined_subquery_requires_alias = 0; +SELECT * FROM (SELECT number FROM test PASTE JOIN (SELECT number FROM test PASTE JOIN (Select number FROM numbers(7)))) PASTE JOIN (SELECT number FROM numbers(6) PASTE JOIN (SELECT number FROM test)) SETTINGS joined_subquery_requires_alias = 0; SELECT * FROM (SELECT 1 AS a) PASTE JOIN (SELECT 2 AS b) PASTE JOIN (SELECT 3 AS c) SETTINGS allow_experimental_analyzer = 1; SELECT * FROM (SELECT 1 AS a) PASTE JOIN (SELECT 2 AS b) PASTE JOIN (SELECT 3 AS a) SETTINGS allow_experimental_analyzer = 1; -- { serverError AMBIGUOUS_COLUMN_NAME } From f05733e7b8ef6b4935957dad7d02d5701aee371a Mon Sep 17 00:00:00 2001 From: Yarik Briukhovetskyi <114298166+yariks5s@users.noreply.github.com> Date: Wed, 17 Jan 2024 15:28:02 +0100 Subject: [PATCH 14/18] Update QueryAnalysisPass.cpp --- src/Analyzer/Passes/QueryAnalysisPass.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Analyzer/Passes/QueryAnalysisPass.cpp b/src/Analyzer/Passes/QueryAnalysisPass.cpp index f0275df3afd1..d1573a2f25b9 100644 --- a/src/Analyzer/Passes/QueryAnalysisPass.cpp +++ b/src/Analyzer/Passes/QueryAnalysisPass.cpp @@ -2245,9 +2245,6 @@ void QueryAnalyzer::validateJoinTableExpressionWithoutAlias(const QueryTreeNodeP if (table_expression_has_alias) return; - if (join_node->as().getKind() == JoinKind::Paste) - return; - auto * query_node = table_expression_node->as(); auto * union_node = table_expression_node->as(); if ((query_node && !query_node->getCTEName().empty()) || (union_node && !union_node->getCTEName().empty())) @@ -2256,7 +2253,10 @@ void QueryAnalyzer::validateJoinTableExpressionWithoutAlias(const QueryTreeNodeP auto table_expression_node_type = table_expression_node->getNodeType(); auto * join_typed = join_node->as(); if (table_expression_node_type == QueryTreeNodeType::QUERY && join_typed->getKind() == JoinKind::Paste) + { checkDuplicateTableNamesOrAlias(join_node, join_typed->getLeftTableExpression(), join_typed->getRightTableExpression(), scope); + return; + } else if ((table_expression_node_type == QueryTreeNodeType::TABLE_FUNCTION || table_expression_node_type == QueryTreeNodeType::QUERY || table_expression_node_type == QueryTreeNodeType::UNION) && join_typed->getKind() != JoinKind::Paste) From 38914ef70c3f3bac5d5f745e255999d2763cf18d Mon Sep 17 00:00:00 2001 From: Yarik Briukhovetskyi <114298166+yariks5s@users.noreply.github.com> Date: Wed, 17 Jan 2024 15:48:26 +0100 Subject: [PATCH 15/18] Update QueryAnalysisPass.cpp --- src/Analyzer/Passes/QueryAnalysisPass.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Analyzer/Passes/QueryAnalysisPass.cpp b/src/Analyzer/Passes/QueryAnalysisPass.cpp index d1573a2f25b9..752c0dd4f6b7 100644 --- a/src/Analyzer/Passes/QueryAnalysisPass.cpp +++ b/src/Analyzer/Passes/QueryAnalysisPass.cpp @@ -2257,9 +2257,9 @@ void QueryAnalyzer::validateJoinTableExpressionWithoutAlias(const QueryTreeNodeP checkDuplicateTableNamesOrAlias(join_node, join_typed->getLeftTableExpression(), join_typed->getRightTableExpression(), scope); return; } - else if ((table_expression_node_type == QueryTreeNodeType::TABLE_FUNCTION || + else if (table_expression_node_type == QueryTreeNodeType::TABLE_FUNCTION || table_expression_node_type == QueryTreeNodeType::QUERY || - table_expression_node_type == QueryTreeNodeType::UNION) && join_typed->getKind() != JoinKind::Paste) + table_expression_node_type == QueryTreeNodeType::UNION) throw Exception(ErrorCodes::ALIAS_REQUIRED, "JOIN {} no alias for subquery or table function {}. " "In scope {} (set joined_subquery_requires_alias = 0 to disable restriction)", From 6ad6d6a12134237ab7dce9a81e05255d6a26e6b7 Mon Sep 17 00:00:00 2001 From: yariks5s Date: Thu, 18 Jan 2024 15:41:25 +0000 Subject: [PATCH 16/18] fix due to review --- src/Analyzer/Passes/QueryAnalysisPass.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Analyzer/Passes/QueryAnalysisPass.cpp b/src/Analyzer/Passes/QueryAnalysisPass.cpp index 752c0dd4f6b7..23b19bc4f722 100644 --- a/src/Analyzer/Passes/QueryAnalysisPass.cpp +++ b/src/Analyzer/Passes/QueryAnalysisPass.cpp @@ -6808,7 +6808,7 @@ void QueryAnalyzer::checkDuplicateTableNamesOrAlias(const QueryTreeNodePtr & joi throw Exception(ErrorCodes::LOGICAL_ERROR, "Names of projection columns cannot be empty"); std::sort(column_names.begin(), column_names.end()); - for (size_t i = 0; i < column_names.size() - 1; i++) // Check if there is not any duplicates because it will lead to broken result + for (size_t i = 0; i < column_names.size() - 1; i++) // Check if there is no any duplicates because it will lead to broken result if (column_names[i] == column_names[i+1]) throw Exception(ErrorCodes::BAD_ARGUMENTS, "Name of columns and aliases should be unique for this query (you can add/change aliases so they will not be duplicated)" @@ -7168,7 +7168,6 @@ void QueryAnalyzer::resolveQuery(const QueryTreeNodePtr & query_node, Identifier initializeQueryJoinTreeNode(query_node_typed.getJoinTree(), scope); scope.alias_name_to_table_expression_node.clear(); - Names column_names; resolveQueryJoinTreeNode(query_node_typed.getJoinTree(), scope, visitor); } From 76b43a6aba4634ad4b74adb5bf5fd2c3aecfc7be Mon Sep 17 00:00:00 2001 From: yariks5s Date: Fri, 19 Jan 2024 18:13:05 +0000 Subject: [PATCH 17/18] small changes(revert) --- src/Analyzer/Passes/QueryAnalysisPass.cpp | 20 +++++++++++-------- .../0_stateless/02933_paste_join.reference | 4 ++++ .../queries/0_stateless/02933_paste_join.sql | 10 ++++++++++ 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/Analyzer/Passes/QueryAnalysisPass.cpp b/src/Analyzer/Passes/QueryAnalysisPass.cpp index 23b19bc4f722..000040bb172e 100644 --- a/src/Analyzer/Passes/QueryAnalysisPass.cpp +++ b/src/Analyzer/Passes/QueryAnalysisPass.cpp @@ -2245,19 +2245,17 @@ void QueryAnalyzer::validateJoinTableExpressionWithoutAlias(const QueryTreeNodeP if (table_expression_has_alias) return; + if (join_node->as().getKind() == JoinKind::Paste) + return; + auto * query_node = table_expression_node->as(); auto * union_node = table_expression_node->as(); if ((query_node && !query_node->getCTEName().empty()) || (union_node && !union_node->getCTEName().empty())) return; auto table_expression_node_type = table_expression_node->getNodeType(); - auto * join_typed = join_node->as(); - if (table_expression_node_type == QueryTreeNodeType::QUERY && join_typed->getKind() == JoinKind::Paste) - { - checkDuplicateTableNamesOrAlias(join_node, join_typed->getLeftTableExpression(), join_typed->getRightTableExpression(), scope); - return; - } - else if (table_expression_node_type == QueryTreeNodeType::TABLE_FUNCTION || + + if (table_expression_node_type == QueryTreeNodeType::TABLE_FUNCTION || table_expression_node_type == QueryTreeNodeType::QUERY || table_expression_node_type == QueryTreeNodeType::UNION) throw Exception(ErrorCodes::ALIAS_REQUIRED, @@ -6797,6 +6795,9 @@ void QueryAnalyzer::checkDuplicateTableNamesOrAlias(const QueryTreeNodePtr & joi auto * left_node = left_table_expr->as(); auto * right_node = right_table_expr->as(); + if (!left_node && !right_node) + return; + if (left_node) for (const auto & name_and_type : left_node->getProjectionColumns()) column_names.push_back(name_and_type.name); @@ -6811,7 +6812,7 @@ void QueryAnalyzer::checkDuplicateTableNamesOrAlias(const QueryTreeNodePtr & joi for (size_t i = 0; i < column_names.size() - 1; i++) // Check if there is no any duplicates because it will lead to broken result if (column_names[i] == column_names[i+1]) throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Name of columns and aliases should be unique for this query (you can add/change aliases so they will not be duplicated)" + "Name of columns and aliases should be unique for this query (you can add/change aliases to avoid duplication)" "While processing '{}'", join_node->formatASTForErrorMessage()); } @@ -6826,6 +6827,9 @@ void QueryAnalyzer::resolveJoin(QueryTreeNodePtr & join_node, IdentifierResolveS resolveQueryJoinTreeNode(join_node_typed.getRightTableExpression(), scope, expressions_visitor); validateJoinTableExpressionWithoutAlias(join_node, join_node_typed.getRightTableExpression(), scope); + if (!join_node_typed.getLeftTableExpression()->hasAlias() && !join_node_typed.getRightTableExpression()->hasAlias()) + checkDuplicateTableNamesOrAlias(join_node, join_node_typed.getLeftTableExpression(), join_node_typed.getRightTableExpression(), scope); + if (join_node_typed.isOnJoinExpression()) { expressions_visitor.visit(join_node_typed.getJoinExpression()); diff --git a/tests/queries/0_stateless/02933_paste_join.reference b/tests/queries/0_stateless/02933_paste_join.reference index 0b285913cd00..81a8ac22da41 100644 --- a/tests/queries/0_stateless/02933_paste_join.reference +++ b/tests/queries/0_stateless/02933_paste_join.reference @@ -101,3 +101,7 @@ UInt64 4 4 5 5 1 2 3 +0 0 +1 1 +0 +1 diff --git a/tests/queries/0_stateless/02933_paste_join.sql b/tests/queries/0_stateless/02933_paste_join.sql index dc458417e7f4..604078d1c3a9 100644 --- a/tests/queries/0_stateless/02933_paste_join.sql +++ b/tests/queries/0_stateless/02933_paste_join.sql @@ -43,3 +43,13 @@ SELECT * FROM (SELECT number FROM test PASTE JOIN (Select number FROM numbers(7) SELECT * FROM (SELECT number FROM test PASTE JOIN (SELECT number FROM test PASTE JOIN (Select number FROM numbers(7)))) PASTE JOIN (SELECT number FROM numbers(6) PASTE JOIN (SELECT number FROM test)) SETTINGS joined_subquery_requires_alias = 0; SELECT * FROM (SELECT 1 AS a) PASTE JOIN (SELECT 2 AS b) PASTE JOIN (SELECT 3 AS c) SETTINGS allow_experimental_analyzer = 1; SELECT * FROM (SELECT 1 AS a) PASTE JOIN (SELECT 2 AS b) PASTE JOIN (SELECT 3 AS a) SETTINGS allow_experimental_analyzer = 1; -- { serverError AMBIGUOUS_COLUMN_NAME } + +SET allow_experimental_analyzer = 1; +CREATE TABLE test1 (a Int32) engine=MergeTree order by a; +INSERT INTO test1 SELECT * FROM numbers(2); +CREATE TABLE test2 (a Int32) engine=MergeTree order by a; +INSERT INTO test2 SELECT * FROM numbers(2); +SELECT * FROM test1 PASTE JOIN (SELECT * FROM test2); +SELECT a `test2.a` FROM test1 PASTE JOIN test2; +SELECT * FROM test1 `test2.a` PASTE JOIN test2 `test2.a`; -- { serverError MULTIPLE_EXPRESSIONS_FOR_ALIAS } +SELECT * FROM test1 PASTE JOIN (SELECT number AS a FROM numbers(2) ORDER BY number DESC); -- { serverError AMBIGUOUS_COLUMN_NAME } From e28fd94e1c35c75043108582ca920e8a0e4a56a4 Mon Sep 17 00:00:00 2001 From: Yarik Briukhovetskyi <114298166+yariks5s@users.noreply.github.com> Date: Fri, 19 Jan 2024 20:19:34 +0100 Subject: [PATCH 18/18] fix style --- src/Analyzer/Passes/QueryAnalysisPass.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Analyzer/Passes/QueryAnalysisPass.cpp b/src/Analyzer/Passes/QueryAnalysisPass.cpp index 000040bb172e..fbab9b56db24 100644 --- a/src/Analyzer/Passes/QueryAnalysisPass.cpp +++ b/src/Analyzer/Passes/QueryAnalysisPass.cpp @@ -2254,7 +2254,7 @@ void QueryAnalyzer::validateJoinTableExpressionWithoutAlias(const QueryTreeNodeP return; auto table_expression_node_type = table_expression_node->getNodeType(); - + if (table_expression_node_type == QueryTreeNodeType::TABLE_FUNCTION || table_expression_node_type == QueryTreeNodeType::QUERY || table_expression_node_type == QueryTreeNodeType::UNION)