mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-09-22 09:40:49 +00:00
Merge pull request #3202 from zhang2014/fix/ISSUES-3145
ISSUES-3145 support qualified asterisk
This commit is contained in:
commit
6374094f0c
@ -281,26 +281,36 @@ ExpressionAnalyzer::ExpressionAnalyzer(
|
||||
analyzeAggregation();
|
||||
}
|
||||
|
||||
static std::vector<ASTTableExpression> getTableExpressions(const ASTPtr & query)
|
||||
{
|
||||
ASTSelectQuery * select_query = typeid_cast<ASTSelectQuery *>(query.get());
|
||||
|
||||
std::vector<ASTTableExpression> tables_expression;
|
||||
|
||||
if (select_query && select_query->tables)
|
||||
{
|
||||
for (const auto & element : select_query->tables->children)
|
||||
{
|
||||
ASTTablesInSelectQueryElement & select_element = static_cast<ASTTablesInSelectQueryElement &>(*element);
|
||||
|
||||
if (select_element.table_expression)
|
||||
tables_expression.emplace_back(static_cast<ASTTableExpression &>(*select_element.table_expression));
|
||||
}
|
||||
}
|
||||
|
||||
return tables_expression;
|
||||
}
|
||||
|
||||
void ExpressionAnalyzer::translateQualifiedNames()
|
||||
{
|
||||
if (!select_query || !select_query->tables || select_query->tables->children.empty())
|
||||
return;
|
||||
|
||||
auto & element = static_cast<ASTTablesInSelectQueryElement &>(*select_query->tables->children[0]);
|
||||
std::vector<DatabaseAndTableWithAlias> tables;
|
||||
std::vector<ASTTableExpression> tables_expression = getTableExpressions(query);
|
||||
|
||||
if (!element.table_expression) /// This is ARRAY JOIN without a table at the left side.
|
||||
return;
|
||||
|
||||
auto & table_expression = static_cast<ASTTableExpression &>(*element.table_expression);
|
||||
auto * join = select_query->join();
|
||||
|
||||
std::vector<DatabaseAndTableWithAlias> tables = {getTableNameWithAliasFromTableExpression(table_expression, context)};
|
||||
|
||||
if (join)
|
||||
{
|
||||
const auto & join_table_expression = static_cast<const ASTTableExpression &>(*join->table_expression);
|
||||
tables.emplace_back(getTableNameWithAliasFromTableExpression(join_table_expression, context));
|
||||
}
|
||||
for (const auto & table_expression : tables_expression)
|
||||
tables.emplace_back(getTableNameWithAliasFromTableExpression(table_expression, context));
|
||||
|
||||
translateQualifiedNamesImpl(query, tables);
|
||||
}
|
||||
@ -358,10 +368,11 @@ void ExpressionAnalyzer::translateQualifiedNamesImpl(ASTPtr & ast, const std::ve
|
||||
&& ((!table_names.table.empty() && ident->name == table_names.table)
|
||||
|| (!table_names.alias.empty() && ident->name == table_names.alias))))
|
||||
{
|
||||
/// Replace to plain asterisk.
|
||||
ast = std::make_shared<ASTAsterisk>();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw Exception("Unknown qualified identifier: " + ident->getAliasOrColumnName(), ErrorCodes::UNKNOWN_IDENTIFIER);
|
||||
}
|
||||
else if (auto * join = typeid_cast<ASTTableJoin *>(ast.get()))
|
||||
{
|
||||
@ -862,6 +873,31 @@ static NamesAndTypesList::iterator findColumn(const String & name, NamesAndTypes
|
||||
[&](const NamesAndTypesList::value_type & val) { return val.name == name; });
|
||||
}
|
||||
|
||||
static NamesAndTypesList getNamesAndTypeListFromTableExpression(const ASTTableExpression & table_expression, const Context & context)
|
||||
{
|
||||
NamesAndTypesList names_and_type_list;
|
||||
if (table_expression.subquery)
|
||||
{
|
||||
const auto & subquery = table_expression.subquery->children.at(0);
|
||||
names_and_type_list = InterpreterSelectWithUnionQuery::getSampleBlock(subquery, context).getNamesAndTypesList();
|
||||
}
|
||||
else if (table_expression.table_function)
|
||||
{
|
||||
const auto table_function = table_expression.table_function;
|
||||
auto query_context = const_cast<Context *>(&context.getQueryContext());
|
||||
const auto & function_storage = query_context->executeTableFunction(table_function);
|
||||
names_and_type_list = function_storage->getSampleBlockNonMaterialized().getNamesAndTypesList();
|
||||
}
|
||||
else if (table_expression.database_and_table_name)
|
||||
{
|
||||
const auto & identifier = static_cast<const ASTIdentifier &>(*table_expression.database_and_table_name);
|
||||
auto database_table = getDatabaseAndTableNameFromIdentifier(identifier);
|
||||
const auto & table = context.getTable(database_table.first, database_table.second);
|
||||
names_and_type_list = table->getSampleBlockNonMaterialized().getNamesAndTypesList();
|
||||
}
|
||||
|
||||
return names_and_type_list;
|
||||
}
|
||||
|
||||
void ExpressionAnalyzer::normalizeTree()
|
||||
{
|
||||
@ -879,7 +915,20 @@ void ExpressionAnalyzer::normalizeTree()
|
||||
if (all_columns_name.empty())
|
||||
throw Exception("Logical error: an asterisk cannot be replaced with empty columns.", ErrorCodes::LOGICAL_ERROR);
|
||||
|
||||
QueryNormalizer(query, aliases, settings, all_columns_name).perform();
|
||||
TableNamesAndColumnsName table_names_nad_columns_name;
|
||||
if (select_query && select_query->tables && !select_query->tables->children.empty())
|
||||
{
|
||||
std::vector<ASTTableExpression> tables_expression = getTableExpressions(query);
|
||||
|
||||
for (const auto & table_expression : tables_expression)
|
||||
{
|
||||
const auto table_name = getTableNameWithAliasFromTableExpression(table_expression, context);
|
||||
NamesAndTypesList names_and_types = getNamesAndTypeListFromTableExpression(table_expression, context);
|
||||
table_names_nad_columns_name.emplace_back(std::pair(table_name, names_and_types.getNames()));
|
||||
}
|
||||
}
|
||||
|
||||
QueryNormalizer(query, aliases, settings, all_columns_name, table_names_nad_columns_name).perform();
|
||||
}
|
||||
|
||||
|
||||
@ -2274,30 +2323,9 @@ NamesAndTypesList ExpressionAnalyzer::AnalyzedJoin::getColumnsFromJoinedTable(co
|
||||
{
|
||||
if (const ASTTablesInSelectQueryElement * node = select_query_with_join->join())
|
||||
{
|
||||
Block nested_result_sample;
|
||||
const auto & table_expression = static_cast<const ASTTableExpression &>(*node->table_expression);
|
||||
|
||||
if (table_expression.subquery)
|
||||
{
|
||||
const auto & subquery = table_expression.subquery->children.at(0);
|
||||
nested_result_sample = InterpreterSelectWithUnionQuery::getSampleBlock(subquery, context);
|
||||
}
|
||||
else if (table_expression.table_function)
|
||||
{
|
||||
const auto table_function = table_expression.table_function;
|
||||
auto query_context = const_cast<Context *>(&context.getQueryContext());
|
||||
const auto & join_storage = query_context->executeTableFunction(table_function);
|
||||
nested_result_sample = join_storage->getSampleBlockNonMaterialized();
|
||||
}
|
||||
else if (table_expression.database_and_table_name)
|
||||
{
|
||||
const auto & identifier = static_cast<const ASTIdentifier &>(*table_expression.database_and_table_name);
|
||||
auto database_table = getDatabaseAndTableNameFromIdentifier(identifier);
|
||||
const auto & table = context.getTable(database_table.first, database_table.second);
|
||||
nested_result_sample = table->getSampleBlockNonMaterialized();
|
||||
}
|
||||
|
||||
columns_from_joined_table = nested_result_sample.getNamesAndTypesList();
|
||||
columns_from_joined_table = getNamesAndTypeListFromTableExpression(table_expression, context);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -303,7 +303,7 @@ ASTs PredicateExpressionsOptimizer::getSelectQueryProjectionColumns(ASTPtr & ast
|
||||
/// first should normalize query tree.
|
||||
std::unordered_map<String, ASTPtr> aliases;
|
||||
getQueryAliases(ast, aliases, 0);
|
||||
QueryNormalizer(ast, aliases, settings, {}).perform();
|
||||
QueryNormalizer(ast, aliases, settings, {}, {}).perform();
|
||||
|
||||
ASTs projection_columns;
|
||||
auto select_query = static_cast<ASTSelectQuery *>(ast.get());
|
||||
|
@ -8,6 +8,8 @@
|
||||
#include <Common/StringUtils/StringUtils.h>
|
||||
#include <Common/typeid_cast.h>
|
||||
#include <Poco/String.h>
|
||||
#include <Parsers/ASTQualifiedAsterisk.h>
|
||||
#include <iostream>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
@ -29,9 +31,11 @@ bool functionIsInOrGlobalInOperator(const String & name)
|
||||
|
||||
}
|
||||
|
||||
QueryNormalizer::QueryNormalizer(
|
||||
ASTPtr & query, const QueryNormalizer::Aliases & aliases, const Settings & settings, const Names & all_columns_name)
|
||||
: query(query), aliases(aliases), settings(settings), all_columns_name(all_columns_name)
|
||||
QueryNormalizer::QueryNormalizer(ASTPtr & query, const QueryNormalizer::Aliases & aliases,
|
||||
const Settings & settings, const Names & all_columns_name,
|
||||
const TableNamesAndColumnsName & table_names_and_columns_name)
|
||||
: query(query), aliases(aliases), settings(settings), all_columns_name(all_columns_name),
|
||||
table_names_and_columns_name(table_names_and_columns_name)
|
||||
{
|
||||
}
|
||||
|
||||
@ -143,7 +147,7 @@ void QueryNormalizer::performImpl(ASTPtr & ast, MapOfASTs & finished_asts, SetOf
|
||||
}
|
||||
else if (ASTExpressionList * expr_list = typeid_cast<ASTExpressionList *>(ast.get()))
|
||||
{
|
||||
/// Replace * with a list of columns.
|
||||
/// Replace *, alias.*, database.table.* with a list of columns.
|
||||
ASTs & asts = expr_list->children;
|
||||
for (int i = static_cast<int>(asts.size()) - 1; i >= 0; --i)
|
||||
{
|
||||
@ -154,6 +158,31 @@ void QueryNormalizer::performImpl(ASTPtr & ast, MapOfASTs & finished_asts, SetOf
|
||||
for (size_t idx = 0; idx < all_columns_name.size(); idx++)
|
||||
asts.insert(asts.begin() + idx + i, std::make_shared<ASTIdentifier>(all_columns_name[idx]));
|
||||
}
|
||||
else if (typeid_cast<ASTQualifiedAsterisk *>(asts[i].get()) && !table_names_and_columns_name.empty())
|
||||
{
|
||||
ASTQualifiedAsterisk * qualified_asterisk = static_cast<ASTQualifiedAsterisk *>(asts[i].get());
|
||||
ASTIdentifier * identifier = typeid_cast<ASTIdentifier *>(qualified_asterisk->children[0].get());
|
||||
size_t num_components = identifier->children.size();
|
||||
|
||||
for (const auto table_name_and_columns_name : table_names_and_columns_name)
|
||||
{
|
||||
const auto table_name = table_name_and_columns_name.first;
|
||||
const auto table_all_columns_name = table_name_and_columns_name.second;
|
||||
|
||||
if ((num_components == 2
|
||||
&& !table_name.database.empty()
|
||||
&& static_cast<const ASTIdentifier &>(*identifier->children[0]).name == table_name.database
|
||||
&& static_cast<const ASTIdentifier &>(*identifier->children[1]).name == table_name.table)
|
||||
|| (num_components == 0
|
||||
&& ((!table_name.table.empty() && identifier->name == table_name.table)
|
||||
|| (!table_name.alias.empty() && identifier->name == table_name.alias))))
|
||||
{
|
||||
asts.erase(asts.begin() + i);
|
||||
for (size_t idx = 0; idx < table_all_columns_name.size(); idx++)
|
||||
asts.insert(asts.begin() + idx + i, std::make_shared<ASTIdentifier>(table_all_columns_name[idx]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ASTTablesInSelectQueryElement * tables_elem = typeid_cast<ASTTablesInSelectQueryElement *>(ast.get()))
|
||||
|
@ -1,17 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include <Parsers/IAST.h>
|
||||
#include "Settings.h"
|
||||
#include <Interpreters/Settings.h>
|
||||
#include <Interpreters/evaluateQualified.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
using TableNameAndColumnsName = std::pair<DatabaseAndTableWithAlias, Names>;
|
||||
using TableNamesAndColumnsName = std::vector<TableNameAndColumnsName>;
|
||||
|
||||
class QueryNormalizer
|
||||
{
|
||||
public:
|
||||
using Aliases = std::unordered_map<String, ASTPtr>;
|
||||
|
||||
QueryNormalizer(ASTPtr & query, const Aliases & aliases, const Settings & settings, const Names & all_columns_name);
|
||||
QueryNormalizer(ASTPtr & query, const Aliases & aliases, const Settings & settings, const Names & all_columns_name,
|
||||
const TableNamesAndColumnsName & table_names_and_columns_name);
|
||||
|
||||
void perform();
|
||||
|
||||
@ -23,8 +28,9 @@ private:
|
||||
const Aliases & aliases;
|
||||
const Settings & settings;
|
||||
const Names & all_columns_name;
|
||||
const std::vector<std::pair<DatabaseAndTableWithAlias, Names>> & table_names_and_columns_name;
|
||||
|
||||
void performImpl(ASTPtr &ast, MapOfASTs &finished_asts, SetOfASTs ¤t_asts, std::string current_alias, size_t level);
|
||||
void performImpl(ASTPtr & ast, MapOfASTs & finished_asts, SetOfASTs & current_asts, std::string current_alias, size_t level);
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
1 2
|
||||
1 2 3 1 4 5
|
||||
1 2 1 3 1 2 1 3
|
||||
1 2 1 3 1 2 1 3 3
|
||||
1 2 1 3 1 3
|
||||
1 2 1 3 1 3 3
|
||||
|
Loading…
Reference in New Issue
Block a user