1#include "duckdb/parser/tableref/pivotref.hpp"
2
3#include "duckdb/common/limits.hpp"
4#include "duckdb/common/field_writer.hpp"
5#include "duckdb/common/serializer/format_serializer.hpp"
6#include "duckdb/common/serializer/format_deserializer.hpp"
7
8namespace duckdb {
9
10//===--------------------------------------------------------------------===//
11// PivotColumn
12//===--------------------------------------------------------------------===//
13string PivotColumn::ToString() const {
14 string result;
15 if (!unpivot_names.empty()) {
16 D_ASSERT(pivot_expressions.empty());
17 // unpivot
18 if (unpivot_names.size() == 1) {
19 result += KeywordHelper::WriteOptionallyQuoted(text: unpivot_names[0]);
20 } else {
21 result += "(";
22 for (idx_t n = 0; n < unpivot_names.size(); n++) {
23 if (n > 0) {
24 result += ", ";
25 }
26 result += KeywordHelper::WriteOptionallyQuoted(text: unpivot_names[n]);
27 }
28 result += ")";
29 }
30 } else if (!pivot_expressions.empty()) {
31 // pivot
32 result += "(";
33 for (idx_t n = 0; n < pivot_expressions.size(); n++) {
34 if (n > 0) {
35 result += ", ";
36 }
37 result += pivot_expressions[n]->ToString();
38 }
39 result += ")";
40 }
41 result += " IN ";
42 if (pivot_enum.empty()) {
43 result += "(";
44 for (idx_t e = 0; e < entries.size(); e++) {
45 auto &entry = entries[e];
46 if (e > 0) {
47 result += ", ";
48 }
49 if (entry.star_expr) {
50 D_ASSERT(entry.values.empty());
51 result += entry.star_expr->ToString();
52 } else if (entry.values.size() == 1) {
53 result += entry.values[0].ToSQLString();
54 } else {
55 result += "(";
56 for (idx_t v = 0; v < entry.values.size(); v++) {
57 if (v > 0) {
58 result += ", ";
59 }
60 result += entry.values[v].ToSQLString();
61 }
62 result += ")";
63 }
64 if (!entry.alias.empty()) {
65 result += " AS " + KeywordHelper::WriteOptionallyQuoted(text: entry.alias);
66 }
67 }
68 result += ")";
69 } else {
70 result += KeywordHelper::WriteOptionallyQuoted(text: pivot_enum);
71 }
72 return result;
73}
74
75bool PivotColumnEntry::Equals(const PivotColumnEntry &other) const {
76 if (alias != other.alias) {
77 return false;
78 }
79 if (values.size() != other.values.size()) {
80 return false;
81 }
82 for (idx_t i = 0; i < values.size(); i++) {
83 if (!Value::NotDistinctFrom(lvalue: values[i], rvalue: other.values[i])) {
84 return false;
85 }
86 }
87 return true;
88}
89
90bool PivotColumn::Equals(const PivotColumn &other) const {
91 if (!ExpressionUtil::ListEquals(a: pivot_expressions, b: other.pivot_expressions)) {
92 return false;
93 }
94 if (other.unpivot_names != unpivot_names) {
95 return false;
96 }
97 if (other.pivot_enum != pivot_enum) {
98 return false;
99 }
100 if (other.entries.size() != entries.size()) {
101 return false;
102 }
103 for (idx_t i = 0; i < entries.size(); i++) {
104 if (!entries[i].Equals(other: other.entries[i])) {
105 return false;
106 }
107 }
108 return true;
109}
110
111PivotColumn PivotColumn::Copy() const {
112 PivotColumn result;
113 for (auto &expr : pivot_expressions) {
114 result.pivot_expressions.push_back(x: expr->Copy());
115 }
116 result.unpivot_names = unpivot_names;
117 for (auto &entry : entries) {
118 result.entries.push_back(x: entry.Copy());
119 }
120 result.pivot_enum = pivot_enum;
121 return result;
122}
123
124void PivotColumn::Serialize(Serializer &serializer) const {
125 FieldWriter writer(serializer);
126 writer.WriteSerializableList(elements: pivot_expressions);
127 writer.WriteList<string>(elements: unpivot_names);
128 writer.WriteRegularSerializableList(elements: entries);
129 writer.WriteString(val: pivot_enum);
130 writer.Finalize();
131}
132
133void PivotColumn::FormatSerialize(FormatSerializer &serializer) const {
134 serializer.WriteProperty(tag: "pivot_expressions", value: pivot_expressions);
135 serializer.WriteProperty(tag: "unpivot_names", value: unpivot_names);
136 serializer.WriteProperty(tag: "entries", value: entries);
137 serializer.WriteProperty(tag: "pivot_enum", value: pivot_enum);
138}
139
140PivotColumn PivotColumn::Deserialize(Deserializer &source) {
141 PivotColumn result;
142 FieldReader reader(source);
143 result.pivot_expressions = reader.ReadRequiredSerializableList<ParsedExpression>();
144 result.unpivot_names = reader.ReadRequiredList<string>();
145 result.entries = reader.ReadRequiredSerializableList<PivotColumnEntry, PivotColumnEntry>();
146 result.pivot_enum = reader.ReadRequired<string>();
147 reader.Finalize();
148 return result;
149}
150
151PivotColumn PivotColumn::FormatDeserialize(FormatDeserializer &source) {
152 PivotColumn result;
153 source.ReadProperty(tag: "pivot_expressions", ret&: result.pivot_expressions);
154 source.ReadProperty(tag: "unpivot_names", ret&: result.unpivot_names);
155 source.ReadProperty(tag: "entries", ret&: result.entries);
156 source.ReadProperty(tag: "pivot_enum", ret&: result.pivot_enum);
157 return result;
158}
159
160//===--------------------------------------------------------------------===//
161// PivotColumnEntry
162//===--------------------------------------------------------------------===//
163PivotColumnEntry PivotColumnEntry::Copy() const {
164 PivotColumnEntry result;
165 result.values = values;
166 result.star_expr = star_expr ? star_expr->Copy() : nullptr;
167 result.alias = alias;
168 return result;
169}
170
171void PivotColumnEntry::Serialize(Serializer &serializer) const {
172 FieldWriter writer(serializer);
173 writer.WriteRegularSerializableList(elements: values);
174 writer.WriteOptional(element: star_expr);
175 writer.WriteString(val: alias);
176 writer.Finalize();
177}
178
179void PivotColumnEntry::FormatSerialize(FormatSerializer &serializer) const {
180 serializer.WriteProperty(tag: "values", value: values);
181 serializer.WriteOptionalProperty(tag: "star_expr", ptr: star_expr);
182 serializer.WriteProperty(tag: "alias", value: alias);
183}
184
185PivotColumnEntry PivotColumnEntry::Deserialize(Deserializer &source) {
186 PivotColumnEntry result;
187 FieldReader reader(source);
188 result.values = reader.ReadRequiredSerializableList<Value, Value>();
189 result.star_expr = reader.ReadOptional<ParsedExpression>(default_value: nullptr);
190 result.alias = reader.ReadRequired<string>();
191 reader.Finalize();
192 return result;
193}
194
195PivotColumnEntry PivotColumnEntry::FormatDeserialize(FormatDeserializer &source) {
196 PivotColumnEntry result;
197 source.ReadProperty(tag: "values", ret&: result.values);
198 source.ReadOptionalProperty(tag: "star_expr", ret&: result.star_expr);
199 source.ReadProperty(tag: "alias", ret&: result.alias);
200 return result;
201}
202
203//===--------------------------------------------------------------------===//
204// PivotRef
205//===--------------------------------------------------------------------===//
206string PivotRef::ToString() const {
207 string result;
208 result = source->ToString();
209 if (!aggregates.empty()) {
210 // pivot
211 result += " PIVOT (";
212 for (idx_t aggr_idx = 0; aggr_idx < aggregates.size(); aggr_idx++) {
213 if (aggr_idx > 0) {
214 result += ", ";
215 }
216 result += aggregates[aggr_idx]->ToString();
217 if (!aggregates[aggr_idx]->alias.empty()) {
218 result += " AS " + KeywordHelper::WriteOptionallyQuoted(text: aggregates[aggr_idx]->alias);
219 }
220 }
221 } else {
222 // unpivot
223 result += " UNPIVOT ";
224 if (include_nulls) {
225 result += "INCLUDE NULLS ";
226 }
227 result += "(";
228 if (unpivot_names.size() == 1) {
229 result += KeywordHelper::WriteOptionallyQuoted(text: unpivot_names[0]);
230 } else {
231 result += "(";
232 for (idx_t n = 0; n < unpivot_names.size(); n++) {
233 if (n > 0) {
234 result += ", ";
235 }
236 result += KeywordHelper::WriteOptionallyQuoted(text: unpivot_names[n]);
237 }
238 result += ")";
239 }
240 }
241 result += " FOR";
242 for (auto &pivot : pivots) {
243 result += " ";
244 result += pivot.ToString();
245 }
246 if (!groups.empty()) {
247 result += " GROUP BY ";
248 for (idx_t i = 0; i < groups.size(); i++) {
249 if (i > 0) {
250 result += ", ";
251 }
252 result += groups[i];
253 }
254 }
255 result += ")";
256 if (!alias.empty()) {
257 result += " AS " + KeywordHelper::WriteOptionallyQuoted(text: alias);
258 if (!column_name_alias.empty()) {
259 result += "(";
260 for (idx_t i = 0; i < column_name_alias.size(); i++) {
261 if (i > 0) {
262 result += ", ";
263 }
264 result += KeywordHelper::WriteOptionallyQuoted(text: column_name_alias[i]);
265 }
266 result += ")";
267 }
268 }
269 return result;
270}
271
272bool PivotRef::Equals(const TableRef &other_p) const {
273 if (!TableRef::Equals(other: other_p)) {
274 return false;
275 }
276 auto &other = other_p.Cast<PivotRef>();
277 if (!source->Equals(other: *other.source)) {
278 return false;
279 }
280 if (!ParsedExpression::ListEquals(left: aggregates, right: other.aggregates)) {
281 return false;
282 }
283 if (pivots.size() != other.pivots.size()) {
284 return false;
285 }
286 for (idx_t i = 0; i < pivots.size(); i++) {
287 if (!pivots[i].Equals(other: other.pivots[i])) {
288 return false;
289 }
290 }
291 if (unpivot_names != other.unpivot_names) {
292 return false;
293 }
294 if (alias != other.alias) {
295 return false;
296 }
297 if (groups != other.groups) {
298 return false;
299 }
300 if (include_nulls != other.include_nulls) {
301 return false;
302 }
303 return true;
304}
305
306unique_ptr<TableRef> PivotRef::Copy() {
307 auto copy = make_uniq<PivotRef>();
308 copy->source = source->Copy();
309 for (auto &aggr : aggregates) {
310 copy->aggregates.push_back(x: aggr->Copy());
311 }
312 copy->unpivot_names = unpivot_names;
313 for (auto &entry : pivots) {
314 copy->pivots.push_back(x: entry.Copy());
315 }
316 copy->groups = groups;
317 copy->column_name_alias = column_name_alias;
318 copy->include_nulls = include_nulls;
319 copy->alias = alias;
320 return std::move(copy);
321}
322
323void PivotRef::Serialize(FieldWriter &writer) const {
324 writer.WriteSerializable(element: *source);
325 writer.WriteSerializableList(elements: aggregates);
326 writer.WriteList<string>(elements: unpivot_names);
327 writer.WriteRegularSerializableList(elements: pivots);
328 writer.WriteList<string>(elements: groups);
329 writer.WriteList<string>(elements: column_name_alias);
330 writer.WriteField<bool>(element: include_nulls);
331}
332
333void PivotRef::FormatSerialize(FormatSerializer &serializer) const {
334 TableRef::FormatSerialize(serializer);
335 serializer.WriteProperty(tag: "source", value: source);
336 serializer.WriteProperty(tag: "aggregates", value: aggregates);
337 serializer.WriteProperty(tag: "unpivot_names", value: unpivot_names);
338 serializer.WriteProperty(tag: "pivots", value: pivots);
339 serializer.WriteProperty(tag: "groups", value: groups);
340 serializer.WriteProperty(tag: "column_name_alias", value: column_name_alias);
341 serializer.WriteProperty(tag: "include_nulls", value: include_nulls);
342}
343
344unique_ptr<TableRef> PivotRef::Deserialize(FieldReader &reader) {
345 auto result = make_uniq<PivotRef>();
346 result->source = reader.ReadRequiredSerializable<TableRef>();
347 result->aggregates = reader.ReadRequiredSerializableList<ParsedExpression>();
348 result->unpivot_names = reader.ReadRequiredList<string>();
349 result->pivots = reader.ReadRequiredSerializableList<PivotColumn, PivotColumn>();
350 result->groups = reader.ReadRequiredList<string>();
351 result->column_name_alias = reader.ReadRequiredList<string>();
352 result->include_nulls = reader.ReadRequired<bool>();
353 return std::move(result);
354}
355
356unique_ptr<TableRef> PivotRef::FormatDeserialize(FormatDeserializer &source) {
357 auto result = make_uniq<PivotRef>();
358 source.ReadProperty(tag: "source", ret&: result->source);
359 source.ReadProperty(tag: "aggregates", ret&: result->aggregates);
360 source.ReadProperty(tag: "unpivot_names", ret&: result->unpivot_names);
361 source.ReadProperty(tag: "pivots", ret&: result->pivots);
362 source.ReadProperty(tag: "groups", ret&: result->groups);
363 source.ReadProperty(tag: "column_name_alias", ret&: result->column_name_alias);
364 source.ReadProperty(tag: "include_nulls", ret&: result->include_nulls);
365 return std::move(result);
366}
367
368} // namespace duckdb
369