diff --git a/src/Interpreters/QueryNormalizer.cpp b/src/Interpreters/QueryNormalizer.cpp index aae714198b5..ea61ade2b49 100644 --- a/src/Interpreters/QueryNormalizer.cpp +++ b/src/Interpreters/QueryNormalizer.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -170,6 +171,24 @@ void QueryNormalizer::visitChildren(IAST * node, Data & data) /// Don't go into query argument. return; } + + /// For lambda functions we need to avoid replacing lambda parameters with external aliases, for example, + /// Select 1 as x, arrayMap(x -> x + 2, [1, 2, 3]) + /// shouldn't be replaced with Select 1 as x, arrayMap(x -> **(1 as x)** + 2, [1, 2, 3]) + Aliases extracted_aliases; + if (func_node->name == "lambda") + { + Names lambda_aliases = RequiredSourceColumnsMatcher::extractNamesFromLambda(*func_node); + for (const auto & name : lambda_aliases) + { + auto it = data.aliases.find(name); + if (it != data.aliases.end()) + { + extracted_aliases.insert(data.aliases.extract(it)); + } + } + } + /// We skip the first argument. We also assume that the lambda function can not have parameters. size_t first_pos = 0; if (func_node->name == "lambda") @@ -192,6 +211,11 @@ void QueryNormalizer::visitChildren(IAST * node, Data & data) { visitChildren(func_node->window_definition.get(), data); } + + for (auto & it : extracted_aliases) + { + data.aliases.insert(it); + } } else if (!node->as()) { diff --git a/src/Interpreters/QueryNormalizer.h b/src/Interpreters/QueryNormalizer.h index 7fc0f4bdf82..eebcff62cde 100644 --- a/src/Interpreters/QueryNormalizer.h +++ b/src/Interpreters/QueryNormalizer.h @@ -39,7 +39,7 @@ public: using SetOfASTs = std::set; using MapOfASTs = std::map; - const Aliases & aliases; + Aliases & aliases; const NameSet & source_columns_set; ExtractedSettings settings; @@ -53,7 +53,7 @@ public: /// It's Ok to have "c + 1 AS c" in queries, but not in table definition const bool allow_self_aliases; /// for constructs like "SELECT column + 1 AS column" - Data(const Aliases & aliases_, const NameSet & source_columns_set_, bool ignore_alias_, ExtractedSettings && settings_, bool allow_self_aliases_) + Data(Aliases & aliases_, const NameSet & source_columns_set_, bool ignore_alias_, ExtractedSettings && settings_, bool allow_self_aliases_) : aliases(aliases_) , source_columns_set(source_columns_set_) , settings(settings_) diff --git a/tests/queries/0_stateless/01960_lambda_precedence.reference b/tests/queries/0_stateless/01960_lambda_precedence.reference new file mode 100644 index 00000000000..552cf82b9ba --- /dev/null +++ b/tests/queries/0_stateless/01960_lambda_precedence.reference @@ -0,0 +1,3 @@ +1000 [2,3,4] +1 +1 diff --git a/tests/queries/0_stateless/01960_lambda_precedence.sql b/tests/queries/0_stateless/01960_lambda_precedence.sql new file mode 100644 index 00000000000..858ca7f5dd0 --- /dev/null +++ b/tests/queries/0_stateless/01960_lambda_precedence.sql @@ -0,0 +1,25 @@ +SELECT + 1000 AS a, + arrayMap(a -> (a + 1), [1, 2, 3]); + + +-- https://github.com/ClickHouse/ClickHouse/issues/5046 +SELECT sum(c1) AS v +FROM + ( + SELECT + 1 AS c1, + ['v'] AS c2 + ) +WHERE arrayExists(v -> (v = 'v'), c2); + + +SELECT sum(c1) AS v +FROM + ( + SELECT + 1 AS c1, + ['v'] AS c2, + ['d'] AS d + ) +WHERE arrayExists(i -> (d = ['d']), c2);