diff --git a/src/Core/Settings.h b/src/Core/Settings.h index 2986564b398..a5636814d21 100644 --- a/src/Core/Settings.h +++ b/src/Core/Settings.h @@ -240,6 +240,7 @@ class IColumn; M(Bool, metrics_perf_events_enabled, false, "If enabled, some of the perf events will be measured throughout queries' execution.", 0) \ M(String, metrics_perf_events_list, "", "Comma separated list of perf metrics that will be measured throughout queries' execution. Empty means all events. See PerfEventInfo in sources for the available events.", 0) \ M(Float, opentelemetry_start_trace_probability, 0., "Probability to start an OpenTelemetry trace for an incoming query.", 0) \ + M(Bool, prefer_column_name_to_alias, false, "Prefer using column names instead of aliases if possible.", 0) \ \ \ /** Limits during query execution are part of the settings. \ diff --git a/src/Interpreters/QueryNormalizer.cpp b/src/Interpreters/QueryNormalizer.cpp index 33d2e8d1ba1..0a2e6505558 100644 --- a/src/Interpreters/QueryNormalizer.cpp +++ b/src/Interpreters/QueryNormalizer.cpp @@ -72,6 +72,12 @@ void QueryNormalizer::visit(ASTIdentifier & node, ASTPtr & ast, Data & data) if (!IdentifierSemantic::getColumnName(node)) return; + if (data.settings.prefer_column_name_to_alias) + { + if (data.source_columns_set.find(node.name()) != data.source_columns_set.end()) + return; + } + /// If it is an alias, but not a parent alias (for constructs like "SELECT column + 1 AS column"). auto it_alias = data.aliases.find(node.name()); if (it_alias != data.aliases.end() && current_alias != node.name()) @@ -131,8 +137,20 @@ static bool needVisitChild(const ASTPtr & child) void QueryNormalizer::visit(ASTSelectQuery & select, const ASTPtr &, Data & data) { for (auto & child : select.children) - if (needVisitChild(child)) + { + if (child == select.groupBy() || child == select.orderBy() || child == select.having()) + { + bool old_setting = data.settings.prefer_column_name_to_alias; + data.settings.prefer_column_name_to_alias = false; visit(child, data); + data.settings.prefer_column_name_to_alias = old_setting; + } + else + { + if (needVisitChild(child)) + visit(child, data); + } + } /// If the WHERE clause or HAVING consists of a single alias, the reference must be replaced not only in children, /// but also in where_expression and having_expression. diff --git a/src/Interpreters/QueryNormalizer.h b/src/Interpreters/QueryNormalizer.h index e481f76ca8e..3dcccea1cfb 100644 --- a/src/Interpreters/QueryNormalizer.h +++ b/src/Interpreters/QueryNormalizer.h @@ -4,6 +4,7 @@ #include #include +#include namespace DB { @@ -21,12 +22,15 @@ class QueryNormalizer { const UInt64 max_ast_depth; const UInt64 max_expanded_ast_elements; + bool prefer_column_name_to_alias; template ExtractedSettings(const T & settings) - : max_ast_depth(settings.max_ast_depth), - max_expanded_ast_elements(settings.max_expanded_ast_elements) - {} + : max_ast_depth(settings.max_ast_depth) + , max_expanded_ast_elements(settings.max_expanded_ast_elements) + , prefer_column_name_to_alias(settings.prefer_column_name_to_alias) + { + } }; public: @@ -36,7 +40,8 @@ public: using MapOfASTs = std::map; const Aliases & aliases; - const ExtractedSettings settings; + const NameSet & source_columns_set; + ExtractedSettings settings; /// tmp data size_t level; @@ -44,8 +49,9 @@ public: SetOfASTs current_asts; /// vertices in the current call stack of this method std::string current_alias; /// the alias referencing to the ancestor of ast (the deepest ancestor with aliases) - Data(const Aliases & aliases_, ExtractedSettings && settings_) + Data(const Aliases & aliases_, const NameSet & source_columns_set_, ExtractedSettings && settings_) : aliases(aliases_) + , source_columns_set(source_columns_set_) , settings(settings_) , level(0) {} diff --git a/src/Interpreters/TreeRewriter.cpp b/src/Interpreters/TreeRewriter.cpp index 9318f87175a..e769cfe9acd 100644 --- a/src/Interpreters/TreeRewriter.cpp +++ b/src/Interpreters/TreeRewriter.cpp @@ -813,7 +813,14 @@ TreeRewriterResultPtr TreeRewriter::analyzeSelect( /// Optimizes logical expressions. LogicalExpressionsOptimizer(select_query, settings.optimize_min_equality_disjunction_chain_length.value).perform(); - normalize(query, result.aliases, settings); + NameSet all_source_columns_set = source_columns_set; + if (table_join) + { + for (const auto & [name, _] : table_join->columns_from_joined_table) + all_source_columns_set.insert(name); + } + + normalize(query, result.aliases, all_source_columns_set, settings); /// Remove unneeded columns according to 'required_result_columns'. /// Leave all selected columns in case of DISTINCT; columns that contain arrayJoin function inside. @@ -871,7 +878,7 @@ TreeRewriterResultPtr TreeRewriter::analyze( TreeRewriterResult result(source_columns, storage, metadata_snapshot, false); - normalize(query, result.aliases, settings); + normalize(query, result.aliases, result.source_columns_set, settings); /// Executing scalar subqueries. Column defaults could be a scalar subquery. executeScalarSubqueries(query, context, 0, result.scalars, false); @@ -896,7 +903,7 @@ TreeRewriterResultPtr TreeRewriter::analyze( return std::make_shared(result); } -void TreeRewriter::normalize(ASTPtr & query, Aliases & aliases, const Settings & settings) +void TreeRewriter::normalize(ASTPtr & query, Aliases & aliases, const NameSet & source_columns_set, const Settings & settings) { CustomizeCountDistinctVisitor::Data data_count_distinct{settings.count_distinct_implementation}; CustomizeCountDistinctVisitor(data_count_distinct).visit(query); @@ -945,7 +952,7 @@ void TreeRewriter::normalize(ASTPtr & query, Aliases & aliases, const Settings & FunctionNameNormalizer().visit(query.get()); /// Common subexpression elimination. Rewrite rules. - QueryNormalizer::Data normalizer_data(aliases, settings); + QueryNormalizer::Data normalizer_data(aliases, source_columns_set, settings); QueryNormalizer(normalizer_data).visit(query); } diff --git a/src/Interpreters/TreeRewriter.h b/src/Interpreters/TreeRewriter.h index 1cb5ff26525..4e3fe21bde9 100644 --- a/src/Interpreters/TreeRewriter.h +++ b/src/Interpreters/TreeRewriter.h @@ -119,7 +119,7 @@ public: private: const Context & context; - static void normalize(ASTPtr & query, Aliases & aliases, const Settings & settings); + static void normalize(ASTPtr & query, Aliases & aliases, const NameSet & source_columns_set, const Settings & settings); }; } diff --git a/src/Interpreters/tests/gtest_cycle_aliases.cpp b/src/Interpreters/tests/gtest_cycle_aliases.cpp index 56e23c6a497..c13e98cd69f 100644 --- a/src/Interpreters/tests/gtest_cycle_aliases.cpp +++ b/src/Interpreters/tests/gtest_cycle_aliases.cpp @@ -20,6 +20,6 @@ TEST(QueryNormalizer, SimpleCycleAlias) aliases["b"] = parseQuery(parser, "a as b", 0, 0)->children[0]; Settings settings; - QueryNormalizer::Data normalizer_data(aliases, settings); + QueryNormalizer::Data normalizer_data(aliases, {}, settings); EXPECT_THROW(QueryNormalizer(normalizer_data).visit(ast), Exception); } diff --git a/tests/queries/0_stateless/01764_prefer_column_name_to_alias.reference b/tests/queries/0_stateless/01764_prefer_column_name_to_alias.reference new file mode 100644 index 00000000000..6fde46c38a4 --- /dev/null +++ b/tests/queries/0_stateless/01764_prefer_column_name_to_alias.reference @@ -0,0 +1,3 @@ +4.5 9 +3 2 +3 3 diff --git a/tests/queries/0_stateless/01764_prefer_column_name_to_alias.sql b/tests/queries/0_stateless/01764_prefer_column_name_to_alias.sql new file mode 100644 index 00000000000..5524712c3c6 --- /dev/null +++ b/tests/queries/0_stateless/01764_prefer_column_name_to_alias.sql @@ -0,0 +1,8 @@ +SELECT avg(number) AS number, max(number) FROM numbers(10); -- { serverError 184 } +SELECT sum(x) AS x, max(x) FROM (SELECT 1 AS x UNION ALL SELECT 2 AS x) t; -- { serverError 184 } +select sum(C1) as C1, count(C1) as C2 from (select number as C1 from numbers(3)) as ITBL; -- { serverError 184 } + +set prefer_column_name_to_alias = 1; +SELECT avg(number) AS number, max(number) FROM numbers(10); +SELECT sum(x) AS x, max(x) FROM (SELECT 1 AS x UNION ALL SELECT 2 AS x) t settings prefer_column_name_to_alias = 1; +select sum(C1) as C1, count(C1) as C2 from (select number as C1 from numbers(3)) as ITBL settings prefer_column_name_to_alias = 1;