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 | |
8 | namespace duckdb { |
9 | |
10 | //===--------------------------------------------------------------------===// |
11 | // PivotColumn |
12 | //===--------------------------------------------------------------------===// |
13 | string 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 | |
75 | bool 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 | |
90 | bool 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 | |
111 | PivotColumn 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 | |
124 | void 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 | |
133 | void 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 | |
140 | PivotColumn 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 | |
151 | PivotColumn 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 | //===--------------------------------------------------------------------===// |
163 | PivotColumnEntry 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 | |
171 | void 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 | |
179 | void 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 | |
185 | PivotColumnEntry 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 | |
195 | PivotColumnEntry 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 | //===--------------------------------------------------------------------===// |
206 | string 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 | |
272 | bool 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 | |
306 | unique_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 | |
323 | void 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 | |
333 | void 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 | |
344 | unique_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 | |
356 | unique_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 | |