mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-09-29 13:10:48 +00:00
removeJoin: remove joined columns
This commit is contained in:
parent
25f3efde2b
commit
578ecc1645
@ -1,5 +1,7 @@
|
|||||||
#include <Interpreters/getHeaderForProcessingStage.h>
|
#include <Interpreters/getHeaderForProcessingStage.h>
|
||||||
#include <Interpreters/InterpreterSelectQuery.h>
|
#include <Interpreters/InterpreterSelectQuery.h>
|
||||||
|
#include <Interpreters/TreeRewriter.h>
|
||||||
|
#include <Interpreters/IdentifierSemantic.h>
|
||||||
#include <Storages/IStorage.h>
|
#include <Storages/IStorage.h>
|
||||||
#include <DataStreams/OneBlockInputStream.h>
|
#include <DataStreams/OneBlockInputStream.h>
|
||||||
#include <Parsers/ASTTablesInSelectQuery.h>
|
#include <Parsers/ASTTablesInSelectQuery.h>
|
||||||
@ -23,16 +25,58 @@ bool hasJoin(const ASTSelectQuery & select)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Rewrite original query removing joined tables from it
|
/// Rewrite original query removing joined tables from it
|
||||||
bool removeJoin(ASTSelectQuery & select)
|
bool removeJoin(ASTSelectQuery & select, TreeRewriterResult & rewriter_result, ContextPtr context)
|
||||||
{
|
{
|
||||||
if (hasJoin(select))
|
if (!hasJoin(select))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
select.tables()->children.resize(1);
|
||||||
|
|
||||||
|
/// Also remove GROUP BY cause ExpressionAnalyzer would check if it has all aggregate columns but joined columns would be missed.
|
||||||
|
select.setExpression(ASTSelectQuery::Expression::GROUP_BY, {});
|
||||||
|
rewriter_result.aggregates.clear();
|
||||||
|
|
||||||
|
/// Replace select list to remove joined columns
|
||||||
|
auto select_list = std::make_shared<ASTExpressionList>();
|
||||||
|
for (const auto & column : rewriter_result.required_source_columns)
|
||||||
|
select_list->children.emplace_back(std::make_shared<ASTIdentifier>(column.name));
|
||||||
|
|
||||||
|
select.setExpression(ASTSelectQuery::Expression::SELECT, select_list);
|
||||||
|
|
||||||
|
const DB::IdentifierMembershipCollector membership_collector{select, context};
|
||||||
|
|
||||||
|
/// Remove unknown identifiers from where, leave only ones from left table
|
||||||
|
auto replace_where = [&membership_collector](ASTSelectQuery & query, ASTSelectQuery::Expression expr)
|
||||||
{
|
{
|
||||||
/// The most simple temporary solution: leave only the first table in query.
|
auto where = query.getExpression(expr, false);
|
||||||
/// TODO: we also need to remove joined columns and related functions (taking in account aliases if any).
|
if (!where)
|
||||||
select.tables()->children.resize(1);
|
return;
|
||||||
return true;
|
|
||||||
}
|
const size_t left_table_pos = 0;
|
||||||
return false;
|
/// Test each argument of `and` function and select ones related to only left table
|
||||||
|
std::shared_ptr<ASTFunction> new_conj = makeASTFunction("and");
|
||||||
|
for (const auto & node : collectConjunctions(where))
|
||||||
|
{
|
||||||
|
if (membership_collector.getIdentsMembership(node) == left_table_pos)
|
||||||
|
new_conj->arguments->children.push_back(std::move(node));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_conj->arguments->children.empty())
|
||||||
|
/// No identifiers from left table
|
||||||
|
query.setExpression(expr, {});
|
||||||
|
else if (new_conj->arguments->children.size() == 1)
|
||||||
|
/// Only one expression, lift from `and`
|
||||||
|
query.setExpression(expr, std::move(new_conj->arguments->children[0]));
|
||||||
|
else
|
||||||
|
/// Set new expression
|
||||||
|
query.setExpression(expr, std::move(new_conj));
|
||||||
|
};
|
||||||
|
replace_where(select, ASTSelectQuery::Expression::WHERE);
|
||||||
|
replace_where(select, ASTSelectQuery::Expression::PREWHERE);
|
||||||
|
select.setExpression(ASTSelectQuery::Expression::HAVING, {});
|
||||||
|
select.setExpression(ASTSelectQuery::Expression::ORDER_BY, {});
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Block getHeaderForProcessingStage(
|
Block getHeaderForProcessingStage(
|
||||||
@ -72,7 +116,8 @@ Block getHeaderForProcessingStage(
|
|||||||
case QueryProcessingStage::MAX:
|
case QueryProcessingStage::MAX:
|
||||||
{
|
{
|
||||||
auto query = query_info.query->clone();
|
auto query = query_info.query->clone();
|
||||||
removeJoin(*query->as<ASTSelectQuery>());
|
TreeRewriterResult new_rewriter_result = *query_info.syntax_analyzer_result;
|
||||||
|
removeJoin(*query->as<ASTSelectQuery>(), new_rewriter_result, context);
|
||||||
|
|
||||||
auto stream = std::make_shared<OneBlockInputStream>(
|
auto stream = std::make_shared<OneBlockInputStream>(
|
||||||
metadata_snapshot->getSampleBlockForColumns(column_names, storage.getVirtuals(), storage.getStorageID()));
|
metadata_snapshot->getSampleBlockForColumns(column_names, storage.getVirtuals(), storage.getStorageID()));
|
||||||
|
@ -13,10 +13,11 @@ class IStorage;
|
|||||||
struct StorageInMemoryMetadata;
|
struct StorageInMemoryMetadata;
|
||||||
using StorageMetadataPtr = std::shared_ptr<const StorageInMemoryMetadata>;
|
using StorageMetadataPtr = std::shared_ptr<const StorageInMemoryMetadata>;
|
||||||
struct SelectQueryInfo;
|
struct SelectQueryInfo;
|
||||||
|
struct TreeRewriterResult;
|
||||||
class ASTSelectQuery;
|
class ASTSelectQuery;
|
||||||
|
|
||||||
bool hasJoin(const ASTSelectQuery & select);
|
bool hasJoin(const ASTSelectQuery & select);
|
||||||
bool removeJoin(ASTSelectQuery & select);
|
bool removeJoin(ASTSelectQuery & select, TreeRewriterResult & rewriter_result, ContextPtr context);
|
||||||
|
|
||||||
Block getHeaderForProcessingStage(
|
Block getHeaderForProcessingStage(
|
||||||
const IStorage & storage,
|
const IStorage & storage,
|
||||||
|
@ -46,54 +46,8 @@ namespace
|
|||||||
|
|
||||||
TreeRewriterResult modifySelect(ASTSelectQuery & select, const TreeRewriterResult & rewriter_result, ContextPtr context)
|
TreeRewriterResult modifySelect(ASTSelectQuery & select, const TreeRewriterResult & rewriter_result, ContextPtr context)
|
||||||
{
|
{
|
||||||
|
|
||||||
TreeRewriterResult new_rewriter_result = rewriter_result;
|
TreeRewriterResult new_rewriter_result = rewriter_result;
|
||||||
if (removeJoin(select))
|
removeJoin(select, new_rewriter_result, context);
|
||||||
{
|
|
||||||
/// Also remove GROUP BY cause ExpressionAnalyzer would check if it has all aggregate columns but joined columns would be missed.
|
|
||||||
select.setExpression(ASTSelectQuery::Expression::GROUP_BY, {});
|
|
||||||
new_rewriter_result.aggregates.clear();
|
|
||||||
|
|
||||||
/// Replace select list to remove joined columns
|
|
||||||
auto select_list = std::make_shared<ASTExpressionList>();
|
|
||||||
for (const auto & column : rewriter_result.required_source_columns)
|
|
||||||
select_list->children.emplace_back(std::make_shared<ASTIdentifier>(column.name));
|
|
||||||
|
|
||||||
select.setExpression(ASTSelectQuery::Expression::SELECT, select_list);
|
|
||||||
|
|
||||||
const DB::IdentifierMembershipCollector membership_collector{select, context};
|
|
||||||
|
|
||||||
/// Remove unknown identifiers from where, leave only ones from left table
|
|
||||||
auto replace_where = [&membership_collector](ASTSelectQuery & query, ASTSelectQuery::Expression expr)
|
|
||||||
{
|
|
||||||
auto where = query.getExpression(expr, false);
|
|
||||||
if (!where)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const size_t left_table_pos = 0;
|
|
||||||
/// Test each argument of `and` function and select ones related to only left table
|
|
||||||
std::shared_ptr<ASTFunction> new_conj = makeASTFunction("and");
|
|
||||||
for (const auto & node : collectConjunctions(where))
|
|
||||||
{
|
|
||||||
if (membership_collector.getIdentsMembership(node) == left_table_pos)
|
|
||||||
new_conj->arguments->children.push_back(std::move(node));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (new_conj->arguments->children.empty())
|
|
||||||
/// No identifiers from left table
|
|
||||||
query.setExpression(expr, {});
|
|
||||||
else if (new_conj->arguments->children.size() == 1)
|
|
||||||
/// Only one expression, lift from `and`
|
|
||||||
query.setExpression(expr, std::move(new_conj->arguments->children[0]));
|
|
||||||
else
|
|
||||||
/// Set new expression
|
|
||||||
query.setExpression(expr, std::move(new_conj));
|
|
||||||
};
|
|
||||||
replace_where(select,ASTSelectQuery::Expression::WHERE);
|
|
||||||
replace_where(select,ASTSelectQuery::Expression::PREWHERE);
|
|
||||||
select.setExpression(ASTSelectQuery::Expression::HAVING, {});
|
|
||||||
select.setExpression(ASTSelectQuery::Expression::ORDER_BY, {});
|
|
||||||
}
|
|
||||||
return new_rewriter_result;
|
return new_rewriter_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user