Coverage Report

Created: 2025-06-12 07:25

/src/duckdb/src/parser/tableref/pivotref.cpp
Line
Count
Source (jump to first uncovered line)
1
#include "duckdb/parser/tableref/pivotref.hpp"
2
3
#include "duckdb/common/limits.hpp"
4
5
namespace duckdb {
6
7
//===--------------------------------------------------------------------===//
8
// PivotColumn
9
//===--------------------------------------------------------------------===//
10
0
string PivotColumn::ToString() const {
11
0
  string result;
12
0
  if (!unpivot_names.empty()) {
13
0
    D_ASSERT(pivot_expressions.empty());
14
    // unpivot
15
0
    if (unpivot_names.size() == 1) {
16
0
      result += KeywordHelper::WriteOptionallyQuoted(unpivot_names[0]);
17
0
    } else {
18
0
      result += "(";
19
0
      for (idx_t n = 0; n < unpivot_names.size(); n++) {
20
0
        if (n > 0) {
21
0
          result += ", ";
22
0
        }
23
0
        result += KeywordHelper::WriteOptionallyQuoted(unpivot_names[n]);
24
0
      }
25
0
      result += ")";
26
0
    }
27
0
  } else if (!pivot_expressions.empty()) {
28
    // pivot
29
0
    result += "(";
30
0
    for (idx_t n = 0; n < pivot_expressions.size(); n++) {
31
0
      if (n > 0) {
32
0
        result += ", ";
33
0
      }
34
0
      result += pivot_expressions[n]->ToString();
35
0
    }
36
0
    result += ")";
37
0
  }
38
0
  result += " IN ";
39
0
  if (pivot_enum.empty()) {
40
0
    result += "(";
41
0
    for (idx_t e = 0; e < entries.size(); e++) {
42
0
      auto &entry = entries[e];
43
0
      if (e > 0) {
44
0
        result += ", ";
45
0
      }
46
0
      if (entry.expr) {
47
0
        D_ASSERT(entry.values.empty());
48
0
        result += entry.expr->ToString();
49
0
      } else if (entry.values.size() == 1) {
50
0
        result += entry.values[0].ToSQLString();
51
0
      } else {
52
0
        result += "(";
53
0
        for (idx_t v = 0; v < entry.values.size(); v++) {
54
0
          if (v > 0) {
55
0
            result += ", ";
56
0
          }
57
0
          result += entry.values[v].ToSQLString();
58
0
        }
59
0
        result += ")";
60
0
      }
61
0
      if (!entry.alias.empty()) {
62
0
        result += " AS " + KeywordHelper::WriteOptionallyQuoted(entry.alias);
63
0
      }
64
0
    }
65
0
    result += ")";
66
0
  } else {
67
0
    result += KeywordHelper::WriteOptionallyQuoted(pivot_enum);
68
0
  }
69
0
  return result;
70
0
}
71
72
0
bool PivotColumnEntry::Equals(const PivotColumnEntry &other) const {
73
0
  if (alias != other.alias) {
74
0
    return false;
75
0
  }
76
0
  if (values.size() != other.values.size()) {
77
0
    return false;
78
0
  }
79
0
  for (idx_t i = 0; i < values.size(); i++) {
80
0
    if (!Value::NotDistinctFrom(values[i], other.values[i])) {
81
0
      return false;
82
0
    }
83
0
  }
84
0
  return true;
85
0
}
86
87
0
bool PivotColumn::Equals(const PivotColumn &other) const {
88
0
  if (!ExpressionUtil::ListEquals(pivot_expressions, other.pivot_expressions)) {
89
0
    return false;
90
0
  }
91
0
  if (other.unpivot_names != unpivot_names) {
92
0
    return false;
93
0
  }
94
0
  if (other.pivot_enum != pivot_enum) {
95
0
    return false;
96
0
  }
97
0
  if (other.entries.size() != entries.size()) {
98
0
    return false;
99
0
  }
100
0
  for (idx_t i = 0; i < entries.size(); i++) {
101
0
    if (!entries[i].Equals(other.entries[i])) {
102
0
      return false;
103
0
    }
104
0
  }
105
0
  return true;
106
0
}
107
108
0
PivotColumn PivotColumn::Copy() const {
109
0
  PivotColumn result;
110
0
  for (auto &expr : pivot_expressions) {
111
0
    result.pivot_expressions.push_back(expr->Copy());
112
0
  }
113
0
  result.unpivot_names = unpivot_names;
114
0
  for (auto &entry : entries) {
115
0
    result.entries.push_back(entry.Copy());
116
0
  }
117
0
  result.pivot_enum = pivot_enum;
118
0
  return result;
119
0
}
120
121
//===--------------------------------------------------------------------===//
122
// PivotColumnEntry
123
//===--------------------------------------------------------------------===//
124
0
PivotColumnEntry PivotColumnEntry::Copy() const {
125
0
  PivotColumnEntry result;
126
0
  result.values = values;
127
0
  result.expr = expr ? expr->Copy() : nullptr;
128
0
  result.alias = alias;
129
0
  return result;
130
0
}
131
132
//===--------------------------------------------------------------------===//
133
// PivotRef
134
//===--------------------------------------------------------------------===//
135
0
string PivotRef::ToString() const {
136
0
  string result;
137
0
  result = source->ToString();
138
0
  if (!aggregates.empty()) {
139
    // pivot
140
0
    result += " PIVOT (";
141
0
    for (idx_t aggr_idx = 0; aggr_idx < aggregates.size(); aggr_idx++) {
142
0
      if (aggr_idx > 0) {
143
0
        result += ", ";
144
0
      }
145
0
      result += aggregates[aggr_idx]->ToString();
146
0
      if (!aggregates[aggr_idx]->GetAlias().empty()) {
147
0
        result += " AS " + KeywordHelper::WriteOptionallyQuoted(aggregates[aggr_idx]->GetAlias());
148
0
      }
149
0
    }
150
0
  } else {
151
    // unpivot
152
0
    result += " UNPIVOT ";
153
0
    if (include_nulls) {
154
0
      result += "INCLUDE NULLS ";
155
0
    }
156
0
    result += "(";
157
0
    if (unpivot_names.size() == 1) {
158
0
      result += KeywordHelper::WriteOptionallyQuoted(unpivot_names[0]);
159
0
    } else {
160
0
      result += "(";
161
0
      for (idx_t n = 0; n < unpivot_names.size(); n++) {
162
0
        if (n > 0) {
163
0
          result += ", ";
164
0
        }
165
0
        result += KeywordHelper::WriteOptionallyQuoted(unpivot_names[n]);
166
0
      }
167
0
      result += ")";
168
0
    }
169
0
  }
170
0
  result += " FOR";
171
0
  for (auto &pivot : pivots) {
172
0
    result += " ";
173
0
    result += pivot.ToString();
174
0
  }
175
0
  if (!groups.empty()) {
176
0
    result += " GROUP BY ";
177
0
    for (idx_t i = 0; i < groups.size(); i++) {
178
0
      if (i > 0) {
179
0
        result += ", ";
180
0
      }
181
0
      result += groups[i];
182
0
    }
183
0
  }
184
0
  result += ")";
185
0
  if (!alias.empty()) {
186
0
    result += " AS " + KeywordHelper::WriteOptionallyQuoted(alias);
187
0
    if (!column_name_alias.empty()) {
188
0
      result += "(";
189
0
      for (idx_t i = 0; i < column_name_alias.size(); i++) {
190
0
        if (i > 0) {
191
0
          result += ", ";
192
0
        }
193
0
        result += KeywordHelper::WriteOptionallyQuoted(column_name_alias[i]);
194
0
      }
195
0
      result += ")";
196
0
    }
197
0
  }
198
0
  return result;
199
0
}
200
201
0
bool PivotRef::Equals(const TableRef &other_p) const {
202
0
  if (!TableRef::Equals(other_p)) {
203
0
    return false;
204
0
  }
205
0
  auto &other = other_p.Cast<PivotRef>();
206
0
  if (!source->Equals(*other.source)) {
207
0
    return false;
208
0
  }
209
0
  if (!ParsedExpression::ListEquals(aggregates, other.aggregates)) {
210
0
    return false;
211
0
  }
212
0
  if (pivots.size() != other.pivots.size()) {
213
0
    return false;
214
0
  }
215
0
  for (idx_t i = 0; i < pivots.size(); i++) {
216
0
    if (!pivots[i].Equals(other.pivots[i])) {
217
0
      return false;
218
0
    }
219
0
  }
220
0
  if (unpivot_names != other.unpivot_names) {
221
0
    return false;
222
0
  }
223
0
  if (alias != other.alias) {
224
0
    return false;
225
0
  }
226
0
  if (groups != other.groups) {
227
0
    return false;
228
0
  }
229
0
  if (include_nulls != other.include_nulls) {
230
0
    return false;
231
0
  }
232
0
  return true;
233
0
}
234
235
0
unique_ptr<TableRef> PivotRef::Copy() {
236
0
  auto copy = make_uniq<PivotRef>();
237
0
  copy->source = source->Copy();
238
0
  for (auto &aggr : aggregates) {
239
0
    copy->aggregates.push_back(aggr->Copy());
240
0
  }
241
0
  copy->unpivot_names = unpivot_names;
242
0
  for (auto &entry : pivots) {
243
0
    copy->pivots.push_back(entry.Copy());
244
0
  }
245
0
  copy->groups = groups;
246
0
  copy->column_name_alias = column_name_alias;
247
0
  copy->include_nulls = include_nulls;
248
0
  copy->alias = alias;
249
0
  return std::move(copy);
250
0
}
251
252
} // namespace duckdb