ClickHouse
150 строк · 6.2 Кб
1#include <Planner/PlannerContext.h>
2
3#include <Analyzer/TableNode.h>
4#include <Analyzer/ColumnNode.h>
5#include <Analyzer/ConstantNode.h>
6#include <Interpreters/Context.h>
7
8namespace DB
9{
10
11namespace ErrorCodes
12{
13extern const int LOGICAL_ERROR;
14}
15
16const ColumnIdentifier & GlobalPlannerContext::createColumnIdentifier(const QueryTreeNodePtr & column_node)
17{
18const auto & column_node_typed = column_node->as<ColumnNode &>();
19auto column_source_node = column_node_typed.getColumnSource();
20
21return createColumnIdentifier(column_node_typed.getColumn(), column_source_node);
22}
23
24const ColumnIdentifier & GlobalPlannerContext::createColumnIdentifier(const NameAndTypePair & column, const QueryTreeNodePtr & column_source_node)
25{
26std::string column_identifier;
27
28const auto & source_alias = column_source_node->getAlias();
29if (!source_alias.empty())
30column_identifier = source_alias + "." + column.name;
31else
32column_identifier = column.name;
33
34auto [it, inserted] = column_identifiers.emplace(column_identifier);
35if (!inserted)
36throw Exception(ErrorCodes::LOGICAL_ERROR, "Column identifier {} is already registered", column_identifier);
37
38assert(inserted);
39
40return *it;
41}
42
43bool GlobalPlannerContext::hasColumnIdentifier(const ColumnIdentifier & column_identifier)
44{
45return column_identifiers.contains(column_identifier);
46}
47
48PlannerContext::PlannerContext(ContextMutablePtr query_context_, GlobalPlannerContextPtr global_planner_context_, const SelectQueryOptions & select_query_options_)
49: query_context(std::move(query_context_))
50, global_planner_context(std::move(global_planner_context_))
51, is_ast_level_optimization_allowed(!(query_context->getClientInfo().query_kind == ClientInfo::QueryKind::SECONDARY_QUERY || select_query_options_.ignore_ast_optimizations))
52{}
53
54PlannerContext::PlannerContext(ContextMutablePtr query_context_, PlannerContextPtr planner_context_)
55: query_context(std::move(query_context_))
56, global_planner_context(planner_context_->global_planner_context)
57, is_ast_level_optimization_allowed(planner_context_->is_ast_level_optimization_allowed)
58{}
59
60TableExpressionData & PlannerContext::getOrCreateTableExpressionData(const QueryTreeNodePtr & table_expression_node)
61{
62auto [it, _] = table_expression_node_to_data.emplace(table_expression_node, TableExpressionData());
63return it->second;
64}
65
66const TableExpressionData & PlannerContext::getTableExpressionDataOrThrow(const QueryTreeNodePtr & table_expression_node) const
67{
68auto table_expression_data_it = table_expression_node_to_data.find(table_expression_node);
69if (table_expression_data_it == table_expression_node_to_data.end())
70throw Exception(ErrorCodes::LOGICAL_ERROR,
71"Table expression {} is not registered in planner context",
72table_expression_node->formatASTForErrorMessage());
73
74return table_expression_data_it->second;
75}
76
77TableExpressionData & PlannerContext::getTableExpressionDataOrThrow(const QueryTreeNodePtr & table_expression_node)
78{
79auto table_expression_data_it = table_expression_node_to_data.find(table_expression_node);
80if (table_expression_data_it == table_expression_node_to_data.end())
81throw Exception(ErrorCodes::LOGICAL_ERROR,
82"Table expression {} is not registered in planner context",
83table_expression_node->formatASTForErrorMessage());
84
85return table_expression_data_it->second;
86}
87
88const TableExpressionData * PlannerContext::getTableExpressionDataOrNull(const QueryTreeNodePtr & table_expression_node) const
89{
90auto table_expression_data_it = table_expression_node_to_data.find(table_expression_node);
91if (table_expression_data_it == table_expression_node_to_data.end())
92return nullptr;
93
94return &table_expression_data_it->second;
95}
96
97TableExpressionData * PlannerContext::getTableExpressionDataOrNull(const QueryTreeNodePtr & table_expression_node)
98{
99auto table_expression_data_it = table_expression_node_to_data.find(table_expression_node);
100if (table_expression_data_it == table_expression_node_to_data.end())
101return nullptr;
102
103return &table_expression_data_it->second;
104}
105
106const ColumnIdentifier & PlannerContext::getColumnNodeIdentifierOrThrow(const QueryTreeNodePtr & column_node) const
107{
108auto & column_node_typed = column_node->as<ColumnNode &>();
109const auto & column_name = column_node_typed.getColumnName();
110auto column_source = column_node_typed.getColumnSource();
111const auto & table_expression_data = getTableExpressionDataOrThrow(column_source);
112return table_expression_data.getColumnIdentifierOrThrow(column_name);
113}
114
115const ColumnIdentifier * PlannerContext::getColumnNodeIdentifierOrNull(const QueryTreeNodePtr & column_node) const
116{
117auto & column_node_typed = column_node->as<ColumnNode &>();
118const auto & column_name = column_node_typed.getColumnName();
119auto column_source = column_node_typed.getColumnSourceOrNull();
120if (!column_source)
121return nullptr;
122
123const auto * table_expression_data = getTableExpressionDataOrNull(column_source);
124if (!table_expression_data)
125return nullptr;
126
127return table_expression_data->getColumnIdentifierOrNull(column_name);
128}
129
130PlannerContext::SetKey PlannerContext::createSetKey(const DataTypePtr & left_operand_type, const QueryTreeNodePtr & set_source_node)
131{
132const auto set_source_hash = set_source_node->getTreeHash();
133if (set_source_node->as<ConstantNode>())
134{
135/* We need to hash the type of the left operand because we can build different sets for different types.
136* (It's done for performance reasons. It's cheaper to convert a small set of values from literal to the type of the left operand.)
137*
138* For example in expression `(a :: Decimal(9, 1) IN (1.0, 2.5)) AND (b :: Decimal(9, 0) IN (1, 2.5))`
139* we need to build two different sets:
140* - `{1, 2.5} :: Set(Decimal(9, 1))` for a
141* - `{1} :: Set(Decimal(9, 0))` for b (2.5 omitted because bercause it's not representable as Decimal(9, 0)).
142*/
143return "__set_" + left_operand_type->getName() + '_' + toString(set_source_hash);
144}
145
146/// For other cases we will cast left operand to the type of the set source, so no difference in types.
147return "__set_" + toString(set_source_hash);
148}
149
150}
151