1#include "duckdb/parser/expression/window_expression.hpp"
2
3#include "duckdb/common/limits.hpp"
4#include "duckdb/common/field_writer.hpp"
5#include "duckdb/common/string_util.hpp"
6
7#include "duckdb/common/enum_util.hpp"
8#include "duckdb/common/serializer/format_serializer.hpp"
9#include "duckdb/common/serializer/format_deserializer.hpp"
10
11namespace duckdb {
12
13WindowExpression::WindowExpression(ExpressionType type, string catalog_name, string schema, const string &function_name)
14 : ParsedExpression(type, ExpressionClass::WINDOW), catalog(std::move(catalog_name)), schema(std::move(schema)),
15 function_name(StringUtil::Lower(str: function_name)), ignore_nulls(false) {
16 switch (type) {
17 case ExpressionType::WINDOW_AGGREGATE:
18 case ExpressionType::WINDOW_ROW_NUMBER:
19 case ExpressionType::WINDOW_FIRST_VALUE:
20 case ExpressionType::WINDOW_LAST_VALUE:
21 case ExpressionType::WINDOW_NTH_VALUE:
22 case ExpressionType::WINDOW_RANK:
23 case ExpressionType::WINDOW_RANK_DENSE:
24 case ExpressionType::WINDOW_PERCENT_RANK:
25 case ExpressionType::WINDOW_CUME_DIST:
26 case ExpressionType::WINDOW_LEAD:
27 case ExpressionType::WINDOW_LAG:
28 case ExpressionType::WINDOW_NTILE:
29 break;
30 default:
31 throw NotImplementedException("Window aggregate type %s not supported", ExpressionTypeToString(type).c_str());
32 }
33}
34
35ExpressionType WindowExpression::WindowToExpressionType(string &fun_name) {
36 if (fun_name == "rank") {
37 return ExpressionType::WINDOW_RANK;
38 } else if (fun_name == "rank_dense" || fun_name == "dense_rank") {
39 return ExpressionType::WINDOW_RANK_DENSE;
40 } else if (fun_name == "percent_rank") {
41 return ExpressionType::WINDOW_PERCENT_RANK;
42 } else if (fun_name == "row_number") {
43 return ExpressionType::WINDOW_ROW_NUMBER;
44 } else if (fun_name == "first_value" || fun_name == "first") {
45 return ExpressionType::WINDOW_FIRST_VALUE;
46 } else if (fun_name == "last_value" || fun_name == "last") {
47 return ExpressionType::WINDOW_LAST_VALUE;
48 } else if (fun_name == "nth_value") {
49 return ExpressionType::WINDOW_NTH_VALUE;
50 } else if (fun_name == "cume_dist") {
51 return ExpressionType::WINDOW_CUME_DIST;
52 } else if (fun_name == "lead") {
53 return ExpressionType::WINDOW_LEAD;
54 } else if (fun_name == "lag") {
55 return ExpressionType::WINDOW_LAG;
56 } else if (fun_name == "ntile") {
57 return ExpressionType::WINDOW_NTILE;
58 }
59 return ExpressionType::WINDOW_AGGREGATE;
60}
61
62string WindowExpression::ToString() const {
63 return ToString<WindowExpression, ParsedExpression, OrderByNode>(entry: *this, schema, function_name);
64}
65
66bool WindowExpression::Equal(const WindowExpression &a, const WindowExpression &b) {
67 // check if the child expressions are equivalent
68 if (a.ignore_nulls != b.ignore_nulls) {
69 return false;
70 }
71 if (!ParsedExpression::ListEquals(left: a.children, right: b.children)) {
72 return false;
73 }
74 if (a.start != b.start || a.end != b.end) {
75 return false;
76 }
77 // check if the framing expressions are equivalentbind_
78 if (!ParsedExpression::Equals(left: a.start_expr, right: b.start_expr) || !ParsedExpression::Equals(left: a.end_expr, right: b.end_expr) ||
79 !ParsedExpression::Equals(left: a.offset_expr, right: b.offset_expr) ||
80 !ParsedExpression::Equals(left: a.default_expr, right: b.default_expr)) {
81 return false;
82 }
83
84 // check if the partitions are equivalent
85 if (!ParsedExpression::ListEquals(left: a.partitions, right: b.partitions)) {
86 return false;
87 }
88 // check if the orderings are equivalent
89 if (a.orders.size() != b.orders.size()) {
90 return false;
91 }
92 for (idx_t i = 0; i < a.orders.size(); i++) {
93 if (a.orders[i].type != b.orders[i].type) {
94 return false;
95 }
96 if (!a.orders[i].expression->Equals(other: *b.orders[i].expression)) {
97 return false;
98 }
99 }
100 // check if the filter clauses are equivalent
101 if (!ParsedExpression::Equals(left: a.filter_expr, right: b.filter_expr)) {
102 return false;
103 }
104
105 return true;
106}
107
108unique_ptr<ParsedExpression> WindowExpression::Copy() const {
109 auto new_window = make_uniq<WindowExpression>(args: type, args: catalog, args: schema, args: function_name);
110 new_window->CopyProperties(other: *this);
111
112 for (auto &child : children) {
113 new_window->children.push_back(x: child->Copy());
114 }
115
116 for (auto &e : partitions) {
117 new_window->partitions.push_back(x: e->Copy());
118 }
119
120 for (auto &o : orders) {
121 new_window->orders.emplace_back(args: o.type, args: o.null_order, args: o.expression->Copy());
122 }
123
124 new_window->filter_expr = filter_expr ? filter_expr->Copy() : nullptr;
125
126 new_window->start = start;
127 new_window->end = end;
128 new_window->start_expr = start_expr ? start_expr->Copy() : nullptr;
129 new_window->end_expr = end_expr ? end_expr->Copy() : nullptr;
130 new_window->offset_expr = offset_expr ? offset_expr->Copy() : nullptr;
131 new_window->default_expr = default_expr ? default_expr->Copy() : nullptr;
132 new_window->ignore_nulls = ignore_nulls;
133
134 return std::move(new_window);
135}
136
137void WindowExpression::Serialize(FieldWriter &writer) const {
138 auto &serializer = writer.GetSerializer();
139
140 writer.WriteString(val: function_name);
141 writer.WriteString(val: schema);
142 writer.WriteSerializableList(elements: children);
143 writer.WriteSerializableList(elements: partitions);
144 // FIXME: should not use serializer here (probably)?
145 D_ASSERT(orders.size() <= NumericLimits<uint32_t>::Maximum());
146 writer.WriteField<uint32_t>(element: (uint32_t)orders.size());
147 for (auto &order : orders) {
148 order.Serialize(serializer);
149 }
150 writer.WriteField<WindowBoundary>(element: start);
151 writer.WriteField<WindowBoundary>(element: end);
152
153 writer.WriteOptional(element: start_expr);
154 writer.WriteOptional(element: end_expr);
155 writer.WriteOptional(element: offset_expr);
156 writer.WriteOptional(element: default_expr);
157 writer.WriteField<bool>(element: ignore_nulls);
158 writer.WriteOptional(element: filter_expr);
159 writer.WriteString(val: catalog);
160}
161
162void WindowExpression::FormatSerialize(FormatSerializer &serializer) const {
163 ParsedExpression::FormatSerialize(serializer);
164 serializer.WriteProperty(tag: "function_name", value: function_name);
165 serializer.WriteProperty(tag: "schema", value: schema);
166 serializer.WriteProperty(tag: "children", value: children);
167 serializer.WriteProperty(tag: "partitions", value: partitions);
168 serializer.WriteProperty(tag: "orders", value: orders);
169 serializer.WriteProperty(tag: "start", value: start);
170 serializer.WriteProperty(tag: "end", value: end);
171 serializer.WriteOptionalProperty(tag: "start_expr", ptr: start_expr);
172 serializer.WriteOptionalProperty(tag: "end_expr", ptr: end_expr);
173 serializer.WriteOptionalProperty(tag: "offset_expr", ptr: offset_expr);
174 serializer.WriteOptionalProperty(tag: "default_expr", ptr: default_expr);
175 serializer.WriteProperty(tag: "ignore_nulls", value: ignore_nulls);
176 serializer.WriteOptionalProperty(tag: "filter_expr", ptr: filter_expr);
177 serializer.WriteProperty(tag: "catalog", value: catalog);
178}
179
180unique_ptr<ParsedExpression> WindowExpression::FormatDeserialize(ExpressionType type,
181 FormatDeserializer &deserializer) {
182 auto function_name = deserializer.ReadProperty<string>(tag: "function_name");
183 auto schema = deserializer.ReadProperty<string>(tag: "schema");
184 auto expr = make_uniq<WindowExpression>(args&: type, INVALID_CATALOG, args: std::move(schema), args&: function_name);
185
186 deserializer.ReadProperty(tag: "children", ret&: expr->children);
187 deserializer.ReadProperty(tag: "partitions", ret&: expr->partitions);
188 deserializer.ReadProperty(tag: "orders", ret&: expr->orders);
189 deserializer.ReadProperty(tag: "start", ret&: expr->start);
190 deserializer.ReadProperty(tag: "end", ret&: expr->end);
191 deserializer.ReadOptionalProperty(tag: "start_expr", ret&: expr->start_expr);
192 deserializer.ReadOptionalProperty(tag: "end_expr", ret&: expr->end_expr);
193 deserializer.ReadOptionalProperty(tag: "offset_expr", ret&: expr->offset_expr);
194 deserializer.ReadOptionalProperty(tag: "default_expr", ret&: expr->default_expr);
195 deserializer.ReadProperty(tag: "ignore_nulls", ret&: expr->ignore_nulls);
196 deserializer.ReadOptionalProperty(tag: "filter_expr", ret&: expr->filter_expr);
197 deserializer.ReadProperty(tag: "catalog", ret&: expr->catalog);
198 return std::move(expr);
199}
200
201unique_ptr<ParsedExpression> WindowExpression::Deserialize(ExpressionType type, FieldReader &reader) {
202 auto function_name = reader.ReadRequired<string>();
203 auto schema = reader.ReadRequired<string>();
204 auto expr = make_uniq<WindowExpression>(args&: type, INVALID_CATALOG, args: std::move(schema), args&: function_name);
205 expr->children = reader.ReadRequiredSerializableList<ParsedExpression>();
206 expr->partitions = reader.ReadRequiredSerializableList<ParsedExpression>();
207
208 auto order_count = reader.ReadRequired<uint32_t>();
209 auto &source = reader.GetSource();
210 for (idx_t i = 0; i < order_count; i++) {
211 expr->orders.push_back(x: OrderByNode::Deserialize(source));
212 }
213 expr->start = reader.ReadRequired<WindowBoundary>();
214 expr->end = reader.ReadRequired<WindowBoundary>();
215
216 expr->start_expr = reader.ReadOptional<ParsedExpression>(default_value: nullptr);
217 expr->end_expr = reader.ReadOptional<ParsedExpression>(default_value: nullptr);
218 expr->offset_expr = reader.ReadOptional<ParsedExpression>(default_value: nullptr);
219 expr->default_expr = reader.ReadOptional<ParsedExpression>(default_value: nullptr);
220 expr->ignore_nulls = reader.ReadRequired<bool>();
221 expr->filter_expr = reader.ReadOptional<ParsedExpression>(default_value: nullptr);
222 expr->catalog = reader.ReadField<string>(INVALID_CATALOG);
223 return std::move(expr);
224}
225
226} // namespace duckdb
227