Shadow lambda arguments

In case of ambiguity, lambda functions should prefer its arguments to
other aliases or identifiers
This commit is contained in:
Raúl Marín 2021-08-05 18:52:00 +02:00
parent 4f0dbae0f9
commit 8b9778ebb6
4 changed files with 54 additions and 2 deletions

View File

@ -3,6 +3,7 @@
#include <Interpreters/QueryNormalizer.h>
#include <Interpreters/IdentifierSemantic.h>
#include <Interpreters/Context.h>
#include <Interpreters/RequiredSourceColumnsVisitor.h>
#include <Parsers/ASTFunction.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/ASTSelectQuery.h>
@ -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<ASTSelectQuery>())
{

View File

@ -39,7 +39,7 @@ public:
using SetOfASTs = std::set<const IAST *>;
using MapOfASTs = std::map<ASTPtr, ASTPtr>;
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_)

View File

@ -0,0 +1,3 @@
1000 [2,3,4]
1
1

View File

@ -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);