1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
|
#include <Planner/PlannerWindowFunctions.h>
#include <Analyzer/ConstantNode.h>
#include <Analyzer/FunctionNode.h>
#include <Analyzer/WindowNode.h>
#include <Interpreters/Context.h>
#include <Planner/PlannerSorting.h>
#include <Planner/PlannerActionsVisitor.h>
namespace DB
{
namespace ErrorCodes
{
extern const int NOT_IMPLEMENTED;
}
namespace
{
WindowDescription extractWindowDescriptionFromWindowNode(const QueryTreeNodePtr & node, const PlannerContext & planner_context)
{
auto & window_node = node->as<WindowNode &>();
WindowDescription window_description;
window_description.window_name = calculateWindowNodeActionName(node, planner_context);
for (const auto & partition_by_node : window_node.getPartitionBy().getNodes())
{
auto partition_by_node_action_name = calculateActionNodeName(partition_by_node, planner_context);
auto partition_by_sort_column_description = SortColumnDescription(partition_by_node_action_name, 1 /* direction */, 1 /* nulls_direction */);
window_description.partition_by.push_back(std::move(partition_by_sort_column_description));
}
window_description.order_by = extractSortDescription(window_node.getOrderByNode(), planner_context);
window_description.full_sort_description = window_description.partition_by;
window_description.full_sort_description.insert(window_description.full_sort_description.end(), window_description.order_by.begin(), window_description.order_by.end());
/// WINDOW frame is validated during query analysis stage
window_description.frame = window_node.getWindowFrame();
const auto & query_context = planner_context.getQueryContext();
const auto & query_context_settings = query_context->getSettingsRef();
bool compile_sort_description = query_context_settings.compile_sort_description;
size_t min_count_to_compile_sort_description = query_context_settings.min_count_to_compile_sort_description;
window_description.partition_by.compile_sort_description = compile_sort_description;
window_description.partition_by.min_count_to_compile_sort_description = min_count_to_compile_sort_description;
window_description.order_by.compile_sort_description = compile_sort_description;
window_description.order_by.min_count_to_compile_sort_description = min_count_to_compile_sort_description;
window_description.full_sort_description.compile_sort_description = compile_sort_description;
window_description.full_sort_description.min_count_to_compile_sort_description = min_count_to_compile_sort_description;
return window_description;
}
}
std::vector<WindowDescription> extractWindowDescriptions(const QueryTreeNodes & window_function_nodes, const PlannerContext & planner_context)
{
std::unordered_map<std::string, WindowDescription> window_name_to_description;
for (const auto & window_function_node : window_function_nodes)
{
auto & window_function_node_typed = window_function_node->as<FunctionNode &>();
auto function_window_description = extractWindowDescriptionFromWindowNode(window_function_node_typed.getWindowNode(), planner_context);
auto frame_type = function_window_description.frame.type;
if (frame_type != WindowFrame::FrameType::ROWS && frame_type != WindowFrame::FrameType::RANGE)
throw Exception(ErrorCodes::NOT_IMPLEMENTED, "Window frame '{}' is not implemented", frame_type);
auto window_name = function_window_description.window_name;
auto [it, _] = window_name_to_description.emplace(window_name, std::move(function_window_description));
auto & window_description = it->second;
WindowFunctionDescription window_function;
window_function.function_node = nullptr;
window_function.column_name = calculateActionNodeName(window_function_node, planner_context);
window_function.aggregate_function = window_function_node_typed.getAggregateFunction();
const auto & parameters_nodes = window_function_node_typed.getParameters().getNodes();
window_function.function_parameters.reserve(parameters_nodes.size());
for (const auto & parameter_node : parameters_nodes)
{
/// Function parameters constness validated during analysis stage
window_function.function_parameters.push_back(parameter_node->as<ConstantNode &>().getValue());
}
const auto & arguments_nodes = window_function_node_typed.getArguments().getNodes();
size_t arguments_nodes_size = arguments_nodes.size();
window_function.argument_names.reserve(arguments_nodes_size);
window_function.argument_types.reserve(arguments_nodes_size);
for (const auto & argument_node : arguments_nodes)
{
String argument_node_name = calculateActionNodeName(argument_node, planner_context);
window_function.argument_names.emplace_back(std::move(argument_node_name));
window_function.argument_types.emplace_back(argument_node->getResultType());
}
window_description.window_functions.push_back(window_function);
}
std::vector<WindowDescription> result;
result.reserve(window_name_to_description.size());
for (auto && [_, window_description] : window_name_to_description)
result.push_back(std::move(window_description));
return result;
}
void sortWindowDescriptions(std::vector<WindowDescription> & window_descriptions)
{
auto window_description_comparator = [](const WindowDescription & lhs, const WindowDescription & rhs)
{
const auto & left = lhs.full_sort_description;
const auto & right = rhs.full_sort_description;
for (size_t i = 0; i < std::min(left.size(), right.size()); ++i)
{
if (left[i].column_name < right[i].column_name)
return true;
else if (left[i].column_name > right[i].column_name)
return false;
else if (left[i].direction < right[i].direction)
return true;
else if (left[i].direction > right[i].direction)
return false;
else if (left[i].nulls_direction < right[i].nulls_direction)
return true;
else if (left[i].nulls_direction > right[i].nulls_direction)
return false;
assert(left[i] == right[i]);
}
/** Note that we check the length last, because we want to put together the
* sort orders that have common prefix but different length.
*/
return left.size() > right.size();
};
::sort(window_descriptions.begin(), window_descriptions.end(), window_description_comparator);
}
}
|