2018-12-26 14:43:25 +00:00
|
|
|
#include <Interpreters/RequiredSourceColumnsVisitor.h>
|
|
|
|
#include <Common/typeid_cast.h>
|
|
|
|
#include <Core/Names.h>
|
|
|
|
#include <Parsers/IAST.h>
|
|
|
|
#include <Parsers/ASTIdentifier.h>
|
|
|
|
#include <Parsers/ASTFunction.h>
|
|
|
|
#include <Parsers/ASTSelectQuery.h>
|
|
|
|
#include <Parsers/ASTSubquery.h>
|
|
|
|
#include <Parsers/ASTTablesInSelectQuery.h>
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
|
|
|
extern const int TYPE_MISMATCH;
|
|
|
|
extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
|
|
|
|
}
|
|
|
|
|
2020-06-16 16:32:32 +00:00
|
|
|
std::vector<String> RequiredSourceColumnsMatcher::extractNamesFromLambda(const ASTFunction & node)
|
2018-12-26 14:43:25 +00:00
|
|
|
{
|
|
|
|
if (node.arguments->children.size() != 2)
|
|
|
|
throw Exception("lambda requires two arguments", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
|
|
|
|
2019-03-11 13:22:51 +00:00
|
|
|
const auto * lambda_args_tuple = node.arguments->children[0]->as<ASTFunction>();
|
2018-12-26 14:43:25 +00:00
|
|
|
|
|
|
|
if (!lambda_args_tuple || lambda_args_tuple->name != "tuple")
|
|
|
|
throw Exception("First argument of lambda must be a tuple", ErrorCodes::TYPE_MISMATCH);
|
|
|
|
|
|
|
|
std::vector<String> names;
|
|
|
|
for (auto & child : lambda_args_tuple->arguments->children)
|
|
|
|
{
|
2019-03-11 13:22:51 +00:00
|
|
|
const auto * identifier = child->as<ASTIdentifier>();
|
2018-12-26 14:43:25 +00:00
|
|
|
if (!identifier)
|
|
|
|
throw Exception("lambda argument declarations must be identifiers", ErrorCodes::TYPE_MISMATCH);
|
|
|
|
|
2020-10-24 18:46:10 +00:00
|
|
|
names.push_back(identifier->name());
|
2018-12-26 14:43:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return names;
|
|
|
|
}
|
|
|
|
|
2019-08-09 14:50:04 +00:00
|
|
|
bool RequiredSourceColumnsMatcher::needChildVisit(const ASTPtr & node, const ASTPtr & child)
|
2018-12-26 14:43:25 +00:00
|
|
|
{
|
2019-03-11 13:22:51 +00:00
|
|
|
if (child->as<ASTSelectQuery>())
|
2018-12-26 14:43:25 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
/// Processed. Do not need children.
|
2019-03-11 13:22:51 +00:00
|
|
|
if (node->as<ASTTableExpression>() || node->as<ASTArrayJoin>() || node->as<ASTSelectQuery>())
|
2018-12-26 14:43:25 +00:00
|
|
|
return false;
|
|
|
|
|
2019-03-11 13:22:51 +00:00
|
|
|
if (const auto * f = node->as<ASTFunction>())
|
2018-12-26 14:43:25 +00:00
|
|
|
{
|
2021-02-28 07:25:56 +00:00
|
|
|
/// "indexHint" is a special function for index analysis.
|
|
|
|
/// Everything that is inside it is not calculated. See KeyCondition
|
2018-12-26 14:43:25 +00:00
|
|
|
/// "lambda" visit children itself.
|
2021-02-28 07:25:56 +00:00
|
|
|
if (f->name == "indexHint" || f->name == "lambda")
|
2018-12-26 14:43:25 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-08-09 14:50:04 +00:00
|
|
|
void RequiredSourceColumnsMatcher::visit(const ASTPtr & ast, Data & data)
|
2018-12-26 14:43:25 +00:00
|
|
|
{
|
|
|
|
/// results are columns
|
|
|
|
|
2019-03-11 13:22:51 +00:00
|
|
|
if (auto * t = ast->as<ASTIdentifier>())
|
2018-12-26 14:43:25 +00:00
|
|
|
{
|
|
|
|
visit(*t, ast, data);
|
2019-02-22 13:33:56 +00:00
|
|
|
return;
|
2018-12-26 14:43:25 +00:00
|
|
|
}
|
2019-03-11 13:22:51 +00:00
|
|
|
if (auto * t = ast->as<ASTFunction>())
|
2018-12-26 14:43:25 +00:00
|
|
|
{
|
|
|
|
data.addColumnAliasIfAny(*ast);
|
|
|
|
visit(*t, ast, data);
|
2019-02-22 13:33:56 +00:00
|
|
|
return;
|
2018-12-26 14:43:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// results are tables
|
|
|
|
|
2019-03-11 13:22:51 +00:00
|
|
|
if (auto * t = ast->as<ASTTablesInSelectQueryElement>())
|
2018-12-26 14:43:25 +00:00
|
|
|
{
|
|
|
|
visit(*t, ast, data);
|
2019-02-22 13:33:56 +00:00
|
|
|
return;
|
2018-12-26 14:43:25 +00:00
|
|
|
}
|
|
|
|
|
2019-03-11 13:22:51 +00:00
|
|
|
if (auto * t = ast->as<ASTTableExpression>())
|
2018-12-26 14:43:25 +00:00
|
|
|
{
|
|
|
|
visit(*t, ast, data);
|
2019-02-22 13:33:56 +00:00
|
|
|
return;
|
2018-12-26 14:43:25 +00:00
|
|
|
}
|
2020-04-12 03:20:15 +00:00
|
|
|
|
2019-03-11 13:22:51 +00:00
|
|
|
if (auto * t = ast->as<ASTSelectQuery>())
|
2018-12-26 14:43:25 +00:00
|
|
|
{
|
2019-02-22 13:33:56 +00:00
|
|
|
visit(*t, ast, data);
|
|
|
|
return;
|
2018-12-26 14:43:25 +00:00
|
|
|
}
|
2020-04-12 03:20:15 +00:00
|
|
|
|
2019-03-11 13:22:51 +00:00
|
|
|
if (ast->as<ASTSubquery>())
|
2018-12-26 14:43:25 +00:00
|
|
|
{
|
2019-02-22 13:33:56 +00:00
|
|
|
return;
|
2018-12-26 14:43:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// other
|
|
|
|
|
2019-03-11 13:22:51 +00:00
|
|
|
if (auto * t = ast->as<ASTArrayJoin>())
|
2018-12-26 14:43:25 +00:00
|
|
|
{
|
|
|
|
data.has_array_join = true;
|
2019-02-22 13:33:56 +00:00
|
|
|
visit(*t, ast, data);
|
|
|
|
return;
|
2018-12-26 14:43:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-09 14:50:04 +00:00
|
|
|
void RequiredSourceColumnsMatcher::visit(const ASTSelectQuery & select, const ASTPtr &, Data & data)
|
2018-12-26 14:43:25 +00:00
|
|
|
{
|
|
|
|
/// special case for top-level SELECT items: they are publics
|
2019-04-09 14:22:35 +00:00
|
|
|
for (auto & node : select.select()->children)
|
2018-12-26 14:43:25 +00:00
|
|
|
{
|
2019-03-11 13:22:51 +00:00
|
|
|
if (const auto * identifier = node->as<ASTIdentifier>())
|
2019-02-15 15:34:30 +00:00
|
|
|
data.addColumnIdentifier(*identifier);
|
2018-12-26 14:43:25 +00:00
|
|
|
else
|
2019-02-15 15:34:30 +00:00
|
|
|
data.addColumnAliasIfAny(*node);
|
2018-12-26 14:43:25 +00:00
|
|
|
}
|
|
|
|
|
2021-08-10 15:21:23 +00:00
|
|
|
if (auto & with = select.with())
|
|
|
|
{
|
|
|
|
for (auto & node : with->children)
|
|
|
|
{
|
|
|
|
if (const auto * identifier = node->as<ASTIdentifier>())
|
|
|
|
data.addColumnIdentifier(*identifier);
|
|
|
|
else
|
|
|
|
data.addColumnAliasIfAny(*node);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-26 14:43:25 +00:00
|
|
|
std::vector<ASTPtr *> out;
|
2020-04-22 06:01:33 +00:00
|
|
|
for (const auto & node : select.children)
|
2021-01-19 15:27:16 +00:00
|
|
|
{
|
|
|
|
// We should not go into WITH statement because all needed aliases are already expanded to
|
|
|
|
// the right place after normalization. And it might contain unused unknown columns.
|
|
|
|
if (node != select.select() && node != select.with())
|
2019-04-09 14:22:35 +00:00
|
|
|
Visitor(data).visit(node);
|
2021-01-19 15:27:16 +00:00
|
|
|
}
|
2018-12-26 14:43:25 +00:00
|
|
|
|
|
|
|
/// revisit select_expression_list (with children) when all the aliases are set
|
2019-08-09 14:50:04 +00:00
|
|
|
Visitor(data).visit(select.select());
|
2018-12-26 14:43:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void RequiredSourceColumnsMatcher::visit(const ASTIdentifier & node, const ASTPtr &, Data & data)
|
|
|
|
{
|
2020-10-24 18:46:10 +00:00
|
|
|
// FIXME(ilezhankin): shouldn't ever encounter
|
|
|
|
if (node.name().empty())
|
2018-12-26 14:43:25 +00:00
|
|
|
throw Exception("Expected not empty name", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
|
|
|
|
2020-10-24 18:46:10 +00:00
|
|
|
if (!data.private_aliases.count(node.name()))
|
2018-12-26 14:43:25 +00:00
|
|
|
data.addColumnIdentifier(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
void RequiredSourceColumnsMatcher::visit(const ASTFunction & node, const ASTPtr &, Data & data)
|
|
|
|
{
|
|
|
|
/// Do not add formal parameters of the lambda expression
|
|
|
|
if (node.name == "lambda")
|
|
|
|
{
|
|
|
|
Names local_aliases;
|
|
|
|
for (const auto & name : extractNamesFromLambda(node))
|
|
|
|
if (data.private_aliases.insert(name).second)
|
|
|
|
local_aliases.push_back(name);
|
|
|
|
|
|
|
|
/// visit child with masked local aliases
|
2019-01-21 19:56:11 +00:00
|
|
|
RequiredSourceColumnsVisitor(data).visit(node.arguments->children[1]);
|
2018-12-26 14:43:25 +00:00
|
|
|
|
|
|
|
for (const auto & name : local_aliases)
|
|
|
|
data.private_aliases.erase(name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-09 14:50:04 +00:00
|
|
|
void RequiredSourceColumnsMatcher::visit(const ASTTablesInSelectQueryElement & node, const ASTPtr &, Data & data)
|
2018-12-26 14:43:25 +00:00
|
|
|
{
|
2020-04-22 06:01:33 +00:00
|
|
|
for (const auto & child : node.children)
|
2020-04-15 10:07:16 +00:00
|
|
|
if (child->as<ASTTableJoin>())
|
|
|
|
data.has_table_join = true;
|
2018-12-26 14:43:25 +00:00
|
|
|
}
|
|
|
|
|
2019-02-22 17:08:10 +00:00
|
|
|
/// ASTIdentifiers here are tables. Do not visit them as generic ones.
|
2020-04-14 14:43:09 +00:00
|
|
|
void RequiredSourceColumnsMatcher::visit(const ASTTableExpression &, const ASTPtr &, Data &)
|
2018-12-26 14:43:25 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-02-22 13:33:56 +00:00
|
|
|
void RequiredSourceColumnsMatcher::visit(const ASTArrayJoin & node, const ASTPtr &, Data & data)
|
2018-12-26 14:43:25 +00:00
|
|
|
{
|
|
|
|
ASTPtr expression_list = node.expression_list;
|
|
|
|
if (!expression_list || expression_list->children.empty())
|
|
|
|
throw Exception("Expected not empty expression_list", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
|
|
|
|
|
|
|
std::vector<ASTPtr *> out;
|
|
|
|
|
|
|
|
/// Tech debt. Ignore ARRAY JOIN top-level identifiers and aliases. There's its own logic for them.
|
|
|
|
for (auto & expr : expression_list->children)
|
|
|
|
{
|
|
|
|
data.addArrayJoinAliasIfAny(*expr);
|
|
|
|
|
2019-03-11 13:22:51 +00:00
|
|
|
if (const auto * identifier = expr->as<ASTIdentifier>())
|
2018-12-26 14:43:25 +00:00
|
|
|
{
|
|
|
|
data.addArrayJoinIdentifier(*identifier);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
out.push_back(&expr);
|
|
|
|
}
|
|
|
|
|
2019-02-22 13:33:56 +00:00
|
|
|
for (ASTPtr * add_node : out)
|
|
|
|
Visitor(data).visit(*add_node);
|
2018-12-26 14:43:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|