mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-10 09:32:06 +00:00
Support additional_result_filter
This commit is contained in:
parent
4cb1ffa2eb
commit
a60c315b3e
@ -33,8 +33,11 @@
|
|||||||
#include <QueryPipeline/QueryPipelineBuilder.h>
|
#include <QueryPipeline/QueryPipelineBuilder.h>
|
||||||
|
|
||||||
#include <Interpreters/Context.h>
|
#include <Interpreters/Context.h>
|
||||||
|
#include <Interpreters/StorageID.h>
|
||||||
|
|
||||||
|
#include <Storages/ColumnsDescription.h>
|
||||||
#include <Storages/SelectQueryInfo.h>
|
#include <Storages/SelectQueryInfo.h>
|
||||||
|
#include <Storages/StorageDummy.h>
|
||||||
#include <Storages/IStorage.h>
|
#include <Storages/IStorage.h>
|
||||||
|
|
||||||
#include <Analyzer/Utils.h>
|
#include <Analyzer/Utils.h>
|
||||||
@ -911,6 +914,46 @@ void addBuildSubqueriesForSetsStepIfNeeded(QueryPlan & query_plan,
|
|||||||
addCreatingSetsStep(query_plan, std::move(subqueries_for_sets), planner_context->getQueryContext());
|
addCreatingSetsStep(query_plan, std::move(subqueries_for_sets), planner_context->getQueryContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Support for `additional_result_filter` setting
|
||||||
|
void addAdditionalFilterStepIfNeeded(QueryPlan & query_plan,
|
||||||
|
const QueryNode & query_node,
|
||||||
|
const SelectQueryOptions & select_query_options,
|
||||||
|
PlannerContextPtr & planner_context
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (select_query_options.subquery_depth != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto & query_context = planner_context->getQueryContext();
|
||||||
|
const auto & settings = query_context->getSettingsRef();
|
||||||
|
|
||||||
|
auto additional_result_filter_ast = parseAdditionalResultFilter(settings);
|
||||||
|
if (!additional_result_filter_ast)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ColumnsDescription fake_column_descriptions;
|
||||||
|
NameSet fake_name_set;
|
||||||
|
for (const auto & column : query_node.getProjectionColumns())
|
||||||
|
{
|
||||||
|
fake_column_descriptions.add(ColumnDescription(column.name, column.type));
|
||||||
|
fake_name_set.emplace(column.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto storage = std::make_shared<StorageDummy>(StorageID{"dummy", "dummy"}, fake_column_descriptions);
|
||||||
|
auto fake_table_expression = std::make_shared<TableNode>(std::move(storage), query_context);
|
||||||
|
|
||||||
|
auto filter_info = buildFilterInfo(additional_result_filter_ast, fake_table_expression, planner_context, std::move(fake_name_set));
|
||||||
|
if (!filter_info.actions || !query_plan.isInitialized())
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto filter_step = std::make_unique<FilterStep>(query_plan.getCurrentDataStream(),
|
||||||
|
filter_info.actions,
|
||||||
|
filter_info.column_name,
|
||||||
|
filter_info.do_remove_column);
|
||||||
|
filter_step->setStepDescription("additional result filter");
|
||||||
|
query_plan.addStep(std::move(filter_step));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PlannerContextPtr buildPlannerContext(const QueryTreeNodePtr & query_tree_node,
|
PlannerContextPtr buildPlannerContext(const QueryTreeNodePtr & query_tree_node,
|
||||||
@ -1409,6 +1452,9 @@ void Planner::buildPlanForQueryNode()
|
|||||||
const auto & projection_analysis_result = expression_analysis_result.getProjection();
|
const auto & projection_analysis_result = expression_analysis_result.getProjection();
|
||||||
addExpressionStep(query_plan, projection_analysis_result.project_names_actions, "Project names", result_actions_to_execute);
|
addExpressionStep(query_plan, projection_analysis_result.project_names_actions, "Project names", result_actions_to_execute);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For additional_result_filter setting
|
||||||
|
addAdditionalFilterStepIfNeeded(query_plan, query_node, select_query_options, planner_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!select_query_options.only_analyze)
|
if (!select_query_options.only_analyze)
|
||||||
|
@ -387,46 +387,6 @@ void updatePrewhereOutputsIfNeeded(SelectQueryInfo & table_expression_query_info
|
|||||||
prewhere_outputs.insert(prewhere_outputs.end(), required_output_nodes.begin(), required_output_nodes.end());
|
prewhere_outputs.insert(prewhere_outputs.end(), required_output_nodes.begin(), required_output_nodes.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
FilterDAGInfo buildFilterInfo(ASTPtr filter_expression,
|
|
||||||
SelectQueryInfo & table_expression_query_info,
|
|
||||||
PlannerContextPtr & planner_context)
|
|
||||||
{
|
|
||||||
const auto & query_context = planner_context->getQueryContext();
|
|
||||||
|
|
||||||
auto filter_query_tree = buildQueryTree(filter_expression, query_context);
|
|
||||||
|
|
||||||
QueryAnalysisPass query_analysis_pass(table_expression_query_info.table_expression);
|
|
||||||
query_analysis_pass.run(filter_query_tree, query_context);
|
|
||||||
|
|
||||||
auto & table_expression_data = planner_context->getTableExpressionDataOrThrow(table_expression_query_info.table_expression);
|
|
||||||
const auto table_expression_names = table_expression_data.getColumnNames();
|
|
||||||
NameSet table_expression_required_names_without_filter(table_expression_names.begin(), table_expression_names.end());
|
|
||||||
|
|
||||||
collectSourceColumns(filter_query_tree, planner_context);
|
|
||||||
collectSets(filter_query_tree, *planner_context);
|
|
||||||
|
|
||||||
auto filter_actions_dag = std::make_shared<ActionsDAG>();
|
|
||||||
|
|
||||||
PlannerActionsVisitor actions_visitor(planner_context, false /*use_column_identifier_as_action_node_name*/);
|
|
||||||
auto expression_nodes = actions_visitor.visit(filter_actions_dag, filter_query_tree);
|
|
||||||
if (expression_nodes.size() != 1)
|
|
||||||
throw Exception(ErrorCodes::BAD_ARGUMENTS,
|
|
||||||
"Filter actions must return single output node. Actual {}",
|
|
||||||
expression_nodes.size());
|
|
||||||
|
|
||||||
auto & filter_actions_outputs = filter_actions_dag->getOutputs();
|
|
||||||
filter_actions_outputs = std::move(expression_nodes);
|
|
||||||
|
|
||||||
std::string filter_node_name = filter_actions_outputs[0]->result_name;
|
|
||||||
bool remove_filter_column = true;
|
|
||||||
|
|
||||||
for (const auto & filter_input_node : filter_actions_dag->getInputs())
|
|
||||||
if (table_expression_required_names_without_filter.contains(filter_input_node->result_name))
|
|
||||||
filter_actions_outputs.push_back(filter_input_node);
|
|
||||||
|
|
||||||
return {std::move(filter_actions_dag), std::move(filter_node_name), remove_filter_column};
|
|
||||||
}
|
|
||||||
|
|
||||||
FilterDAGInfo buildRowPolicyFilterIfNeeded(const StoragePtr & storage,
|
FilterDAGInfo buildRowPolicyFilterIfNeeded(const StoragePtr & storage,
|
||||||
SelectQueryInfo & table_expression_query_info,
|
SelectQueryInfo & table_expression_query_info,
|
||||||
PlannerContextPtr & planner_context)
|
PlannerContextPtr & planner_context)
|
||||||
@ -438,7 +398,7 @@ FilterDAGInfo buildRowPolicyFilterIfNeeded(const StoragePtr & storage,
|
|||||||
if (!row_policy_filter)
|
if (!row_policy_filter)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
return buildFilterInfo(row_policy_filter->expression, table_expression_query_info, planner_context);
|
return buildFilterInfo(row_policy_filter->expression, table_expression_query_info.table_expression, planner_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
FilterDAGInfo buildCustomKeyFilterIfNeeded(const StoragePtr & storage,
|
FilterDAGInfo buildCustomKeyFilterIfNeeded(const StoragePtr & storage,
|
||||||
@ -469,7 +429,7 @@ FilterDAGInfo buildCustomKeyFilterIfNeeded(const StoragePtr & storage,
|
|||||||
*storage,
|
*storage,
|
||||||
query_context);
|
query_context);
|
||||||
|
|
||||||
return buildFilterInfo(parallel_replicas_custom_filter_ast, table_expression_query_info, planner_context);
|
return buildFilterInfo(parallel_replicas_custom_filter_ast, table_expression_query_info.table_expression, planner_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Apply filters from additional_table_filters setting
|
/// Apply filters from additional_table_filters setting
|
||||||
@ -516,7 +476,7 @@ FilterDAGInfo buildAdditionalFiltersIfNeeded(const StoragePtr & storage,
|
|||||||
|
|
||||||
LOG_DEBUG(&Poco::Logger::get("buildAdditionalFiltersIfNeeded"), "Found additional filter: {}", additional_filter_ast->formatForErrorMessage());
|
LOG_DEBUG(&Poco::Logger::get("buildAdditionalFiltersIfNeeded"), "Found additional filter: {}", additional_filter_ast->formatForErrorMessage());
|
||||||
|
|
||||||
return buildFilterInfo(additional_filter_ast, table_expression_query_info, planner_context);
|
return buildFilterInfo(additional_filter_ast, table_expression_query_info.table_expression, planner_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
JoinTreeQueryPlan buildQueryPlanForTableExpression(QueryTreeNodePtr table_expression,
|
JoinTreeQueryPlan buildQueryPlanForTableExpression(QueryTreeNodePtr table_expression,
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
#include <Parsers/ASTSelectWithUnionQuery.h>
|
#include <Parsers/ASTSelectWithUnionQuery.h>
|
||||||
#include <Parsers/ASTSelectQuery.h>
|
#include <Parsers/ASTSelectQuery.h>
|
||||||
#include <Parsers/ASTSubquery.h>
|
#include <Parsers/ASTSubquery.h>
|
||||||
|
#include <Parsers/ExpressionListParsers.h>
|
||||||
|
#include <Parsers/parseQuery.h>
|
||||||
|
|
||||||
#include <DataTypes/DataTypesNumber.h>
|
#include <DataTypes/DataTypesNumber.h>
|
||||||
#include <DataTypes/DataTypeLowCardinality.h>
|
#include <DataTypes/DataTypeLowCardinality.h>
|
||||||
@ -28,8 +30,12 @@
|
|||||||
#include <Analyzer/TableFunctionNode.h>
|
#include <Analyzer/TableFunctionNode.h>
|
||||||
#include <Analyzer/ArrayJoinNode.h>
|
#include <Analyzer/ArrayJoinNode.h>
|
||||||
#include <Analyzer/JoinNode.h>
|
#include <Analyzer/JoinNode.h>
|
||||||
|
#include <Analyzer/QueryTreeBuilder.h>
|
||||||
|
#include <Analyzer/Passes/QueryAnalysisPass.h>
|
||||||
|
|
||||||
#include <Planner/PlannerActionsVisitor.h>
|
#include <Planner/PlannerActionsVisitor.h>
|
||||||
|
#include <Planner/CollectTableExpressionData.h>
|
||||||
|
#include <Planner/CollectSets.h>
|
||||||
|
|
||||||
namespace DB
|
namespace DB
|
||||||
{
|
{
|
||||||
@ -416,4 +422,61 @@ SelectQueryInfo buildSelectQueryInfo(const QueryTreeNodePtr & query_tree, const
|
|||||||
return select_query_info;
|
return select_query_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FilterDAGInfo buildFilterInfo(ASTPtr filter_expression,
|
||||||
|
const QueryTreeNodePtr & table_expression,
|
||||||
|
PlannerContextPtr & planner_context,
|
||||||
|
NameSet table_expression_required_names_without_filter)
|
||||||
|
{
|
||||||
|
const auto & query_context = planner_context->getQueryContext();
|
||||||
|
|
||||||
|
auto filter_query_tree = buildQueryTree(filter_expression, query_context);
|
||||||
|
|
||||||
|
QueryAnalysisPass query_analysis_pass(table_expression);
|
||||||
|
query_analysis_pass.run(filter_query_tree, query_context);
|
||||||
|
|
||||||
|
if (table_expression_required_names_without_filter.empty())
|
||||||
|
{
|
||||||
|
auto & table_expression_data = planner_context->getTableExpressionDataOrThrow(table_expression);
|
||||||
|
const auto & table_expression_names = table_expression_data.getColumnNames();
|
||||||
|
table_expression_required_names_without_filter.insert(table_expression_names.begin(), table_expression_names.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
collectSourceColumns(filter_query_tree, planner_context);
|
||||||
|
collectSets(filter_query_tree, *planner_context);
|
||||||
|
|
||||||
|
auto filter_actions_dag = std::make_shared<ActionsDAG>();
|
||||||
|
|
||||||
|
PlannerActionsVisitor actions_visitor(planner_context, false /*use_column_identifier_as_action_node_name*/);
|
||||||
|
auto expression_nodes = actions_visitor.visit(filter_actions_dag, filter_query_tree);
|
||||||
|
if (expression_nodes.size() != 1)
|
||||||
|
throw Exception(ErrorCodes::BAD_ARGUMENTS,
|
||||||
|
"Filter actions must return single output node. Actual {}",
|
||||||
|
expression_nodes.size());
|
||||||
|
|
||||||
|
auto & filter_actions_outputs = filter_actions_dag->getOutputs();
|
||||||
|
filter_actions_outputs = std::move(expression_nodes);
|
||||||
|
|
||||||
|
std::string filter_node_name = filter_actions_outputs[0]->result_name;
|
||||||
|
bool remove_filter_column = true;
|
||||||
|
|
||||||
|
for (const auto & filter_input_node : filter_actions_dag->getInputs())
|
||||||
|
if (table_expression_required_names_without_filter.contains(filter_input_node->result_name))
|
||||||
|
filter_actions_outputs.push_back(filter_input_node);
|
||||||
|
|
||||||
|
return {std::move(filter_actions_dag), std::move(filter_node_name), remove_filter_column};
|
||||||
|
}
|
||||||
|
|
||||||
|
ASTPtr parseAdditionalResultFilter(const Settings & settings)
|
||||||
|
{
|
||||||
|
const String & additional_result_filter = settings.additional_result_filter;
|
||||||
|
if (additional_result_filter.empty())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
ParserExpression parser;
|
||||||
|
auto additional_result_filter_ast = parseQuery(
|
||||||
|
parser, additional_result_filter.data(), additional_result_filter.data() + additional_result_filter.size(),
|
||||||
|
"additional result filter", settings.max_query_size, settings.max_parser_depth);
|
||||||
|
return additional_result_filter_ast;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -78,4 +78,12 @@ QueryTreeNodePtr buildSubqueryToReadColumnsFromTableExpression(const NamesAndTyp
|
|||||||
|
|
||||||
SelectQueryInfo buildSelectQueryInfo(const QueryTreeNodePtr & query_tree, const PlannerContextPtr & planner_context);
|
SelectQueryInfo buildSelectQueryInfo(const QueryTreeNodePtr & query_tree, const PlannerContextPtr & planner_context);
|
||||||
|
|
||||||
|
/// Build filter for specific table_expression
|
||||||
|
FilterDAGInfo buildFilterInfo(ASTPtr filter_expression,
|
||||||
|
const QueryTreeNodePtr & table_expression,
|
||||||
|
PlannerContextPtr & planner_context,
|
||||||
|
NameSet table_expression_required_names_without_filter = {});
|
||||||
|
|
||||||
|
ASTPtr parseAdditionalResultFilter(const Settings & settings);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user