1#include "duckdb/common/enum_util.hpp"
2#include "duckdb/common/string_util.hpp"
3#include "duckdb/common/to_string.hpp"
4#include "duckdb/parser/expression/case_expression.hpp"
5#include "duckdb/parser/expression/cast_expression.hpp"
6#include "duckdb/parser/expression/constant_expression.hpp"
7#include "duckdb/parser/expression/function_expression.hpp"
8
9#include "duckdb/parser/expression/operator_expression.hpp"
10#include "duckdb/parser/expression/star_expression.hpp"
11#include "duckdb/parser/expression/window_expression.hpp"
12#include "duckdb/parser/transformer.hpp"
13
14namespace duckdb {
15
16void Transformer::TransformWindowDef(duckdb_libpgquery::PGWindowDef &window_spec, WindowExpression &expr,
17 const char *window_name) {
18 // next: partitioning/ordering expressions
19 if (window_spec.partitionClause) {
20 if (window_name && !expr.partitions.empty()) {
21 throw ParserException("Cannot override PARTITION BY clause of window \"%s\"", window_name);
22 }
23 TransformExpressionList(list&: *window_spec.partitionClause, result&: expr.partitions);
24 }
25 if (window_spec.orderClause) {
26 if (window_name && !expr.orders.empty()) {
27 throw ParserException("Cannot override ORDER BY clause of window \"%s\"", window_name);
28 }
29 TransformOrderBy(order: window_spec.orderClause, result&: expr.orders);
30 }
31}
32
33void Transformer::TransformWindowFrame(duckdb_libpgquery::PGWindowDef &window_spec, WindowExpression &expr) {
34 // finally: specifics of bounds
35 expr.start_expr = TransformExpression(node: window_spec.startOffset);
36 expr.end_expr = TransformExpression(node: window_spec.endOffset);
37
38 if ((window_spec.frameOptions & FRAMEOPTION_END_UNBOUNDED_PRECEDING) ||
39 (window_spec.frameOptions & FRAMEOPTION_START_UNBOUNDED_FOLLOWING)) {
40 throw InternalException(
41 "Window frames starting with unbounded following or ending in unbounded preceding make no sense");
42 }
43
44 const bool rangeMode = (window_spec.frameOptions & FRAMEOPTION_RANGE) != 0;
45 if (window_spec.frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING) {
46 expr.start = WindowBoundary::UNBOUNDED_PRECEDING;
47 } else if (window_spec.frameOptions & FRAMEOPTION_START_VALUE_PRECEDING) {
48 expr.start = rangeMode ? WindowBoundary::EXPR_PRECEDING_RANGE : WindowBoundary::EXPR_PRECEDING_ROWS;
49 } else if (window_spec.frameOptions & FRAMEOPTION_START_VALUE_FOLLOWING) {
50 expr.start = rangeMode ? WindowBoundary::EXPR_FOLLOWING_RANGE : WindowBoundary::EXPR_FOLLOWING_ROWS;
51 } else if (window_spec.frameOptions & FRAMEOPTION_START_CURRENT_ROW) {
52 expr.start = rangeMode ? WindowBoundary::CURRENT_ROW_RANGE : WindowBoundary::CURRENT_ROW_ROWS;
53 }
54
55 if (window_spec.frameOptions & FRAMEOPTION_END_UNBOUNDED_FOLLOWING) {
56 expr.end = WindowBoundary::UNBOUNDED_FOLLOWING;
57 } else if (window_spec.frameOptions & FRAMEOPTION_END_VALUE_PRECEDING) {
58 expr.end = rangeMode ? WindowBoundary::EXPR_PRECEDING_RANGE : WindowBoundary::EXPR_PRECEDING_ROWS;
59 } else if (window_spec.frameOptions & FRAMEOPTION_END_VALUE_FOLLOWING) {
60 expr.end = rangeMode ? WindowBoundary::EXPR_FOLLOWING_RANGE : WindowBoundary::EXPR_FOLLOWING_ROWS;
61 } else if (window_spec.frameOptions & FRAMEOPTION_END_CURRENT_ROW) {
62 expr.end = rangeMode ? WindowBoundary::CURRENT_ROW_RANGE : WindowBoundary::CURRENT_ROW_ROWS;
63 }
64
65 D_ASSERT(expr.start != WindowBoundary::INVALID && expr.end != WindowBoundary::INVALID);
66 if (((window_spec.frameOptions & (FRAMEOPTION_START_VALUE_PRECEDING | FRAMEOPTION_START_VALUE_FOLLOWING)) &&
67 !expr.start_expr) ||
68 ((window_spec.frameOptions & (FRAMEOPTION_END_VALUE_PRECEDING | FRAMEOPTION_END_VALUE_FOLLOWING)) &&
69 !expr.end_expr)) {
70 throw InternalException("Failed to transform window boundary expression");
71 }
72}
73
74bool Transformer::ExpressionIsEmptyStar(ParsedExpression &expr) {
75 if (expr.expression_class != ExpressionClass::STAR) {
76 return false;
77 }
78 auto &star = expr.Cast<StarExpression>();
79 if (!star.columns && star.exclude_list.empty() && star.replace_list.empty()) {
80 return true;
81 }
82 return false;
83}
84
85bool Transformer::InWindowDefinition() {
86 if (in_window_definition) {
87 return true;
88 }
89 if (parent) {
90 return parent->InWindowDefinition();
91 }
92 return false;
93}
94
95unique_ptr<ParsedExpression> Transformer::TransformFuncCall(duckdb_libpgquery::PGFuncCall &root) {
96 auto name = root.funcname;
97 string catalog, schema, function_name;
98 if (name->length == 3) {
99 // catalog + schema + name
100 catalog = PGPointerCast<duckdb_libpgquery::PGValue>(ptr: name->head->data.ptr_value)->val.str;
101 schema = PGPointerCast<duckdb_libpgquery::PGValue>(ptr: name->head->next->data.ptr_value)->val.str;
102 function_name = PGPointerCast<duckdb_libpgquery::PGValue>(ptr: name->head->next->next->data.ptr_value)->val.str;
103 } else if (name->length == 2) {
104 // schema + name
105 catalog = INVALID_CATALOG;
106 schema = PGPointerCast<duckdb_libpgquery::PGValue>(ptr: name->head->data.ptr_value)->val.str;
107 function_name = PGPointerCast<duckdb_libpgquery::PGValue>(ptr: name->head->next->data.ptr_value)->val.str;
108 } else if (name->length == 1) {
109 // unqualified name
110 catalog = INVALID_CATALOG;
111 schema = INVALID_SCHEMA;
112 function_name = PGPointerCast<duckdb_libpgquery::PGValue>(ptr: name->head->data.ptr_value)->val.str;
113 } else {
114 throw ParserException("TransformFuncCall - Expected 1, 2 or 3 qualifications");
115 }
116
117 // transform children
118 vector<unique_ptr<ParsedExpression>> children;
119 if (root.args) {
120 TransformExpressionList(list&: *root.args, result&: children);
121 }
122 if (children.size() == 1 && ExpressionIsEmptyStar(expr&: *children[0]) && !root.agg_distinct && !root.agg_order) {
123 // COUNT(*) gets translated into COUNT()
124 children.clear();
125 }
126
127 auto lowercase_name = StringUtil::Lower(str: function_name);
128 if (root.over) {
129 if (InWindowDefinition()) {
130 throw ParserException("window functions are not allowed in window definitions");
131 }
132
133 const auto win_fun_type = WindowExpression::WindowToExpressionType(fun_name&: lowercase_name);
134 if (win_fun_type == ExpressionType::INVALID) {
135 throw InternalException("Unknown/unsupported window function");
136 }
137
138 if (root.agg_distinct) {
139 throw ParserException("DISTINCT is not implemented for window functions!");
140 }
141
142 if (root.agg_order) {
143 throw ParserException("ORDER BY is not implemented for window functions!");
144 }
145
146 if (win_fun_type != ExpressionType::WINDOW_AGGREGATE && root.agg_filter) {
147 throw ParserException("FILTER is not implemented for non-aggregate window functions!");
148 }
149 if (root.export_state) {
150 throw ParserException("EXPORT_STATE is not supported for window functions!");
151 }
152
153 if (win_fun_type == ExpressionType::WINDOW_AGGREGATE && root.agg_ignore_nulls) {
154 throw ParserException("IGNORE NULLS is not supported for windowed aggregates");
155 }
156
157 auto expr = make_uniq<WindowExpression>(args: win_fun_type, args: std::move(catalog), args: std::move(schema), args&: lowercase_name);
158 expr->ignore_nulls = root.agg_ignore_nulls;
159
160 if (root.agg_filter) {
161 auto filter_expr = TransformExpression(node: root.agg_filter);
162 expr->filter_expr = std::move(filter_expr);
163 }
164
165 if (win_fun_type == ExpressionType::WINDOW_AGGREGATE) {
166 expr->children = std::move(children);
167 } else {
168 if (!children.empty()) {
169 expr->children.push_back(x: std::move(children[0]));
170 }
171 if (win_fun_type == ExpressionType::WINDOW_LEAD || win_fun_type == ExpressionType::WINDOW_LAG) {
172 if (children.size() > 1) {
173 expr->offset_expr = std::move(children[1]);
174 }
175 if (children.size() > 2) {
176 expr->default_expr = std::move(children[2]);
177 }
178 if (children.size() > 3) {
179 throw ParserException("Incorrect number of parameters for function %s", lowercase_name);
180 }
181 } else if (win_fun_type == ExpressionType::WINDOW_NTH_VALUE) {
182 if (children.size() > 1) {
183 expr->children.push_back(x: std::move(children[1]));
184 }
185 if (children.size() > 2) {
186 throw ParserException("Incorrect number of parameters for function %s", lowercase_name);
187 }
188 } else {
189 if (children.size() > 1) {
190 throw ParserException("Incorrect number of parameters for function %s", lowercase_name);
191 }
192 }
193 }
194 auto window_spec = PGPointerCast<duckdb_libpgquery::PGWindowDef>(ptr: root.over);
195 if (window_spec->name) {
196 auto it = window_clauses.find(x: StringUtil::Lower(str: string(window_spec->name)));
197 if (it == window_clauses.end()) {
198 throw ParserException("window \"%s\" does not exist", window_spec->name);
199 }
200 window_spec = it->second;
201 D_ASSERT(window_spec);
202 }
203 auto window_ref = window_spec;
204 auto window_name = window_ref->refname;
205 if (window_ref->refname) {
206 auto it = window_clauses.find(x: StringUtil::Lower(str: string(window_spec->refname)));
207 if (it == window_clauses.end()) {
208 throw ParserException("window \"%s\" does not exist", window_spec->refname);
209 }
210 window_ref = it->second;
211 D_ASSERT(window_ref);
212 }
213 in_window_definition = true;
214 TransformWindowDef(window_spec&: *window_ref, expr&: *expr);
215 if (window_ref != window_spec) {
216 TransformWindowDef(window_spec&: *window_spec, expr&: *expr, window_name);
217 }
218 TransformWindowFrame(window_spec&: *window_spec, expr&: *expr);
219 in_window_definition = false;
220 expr->query_location = root.location;
221 return std::move(expr);
222 }
223
224 if (root.agg_ignore_nulls) {
225 throw ParserException("IGNORE NULLS is not supported for non-window functions");
226 }
227
228 unique_ptr<ParsedExpression> filter_expr;
229 if (root.agg_filter) {
230 filter_expr = TransformExpression(node: root.agg_filter);
231 }
232
233 auto order_bys = make_uniq<OrderModifier>();
234 TransformOrderBy(order: root.agg_order, result&: order_bys->orders);
235
236 // Ordered aggregates can be either WITHIN GROUP or after the function arguments
237 if (root.agg_within_group) {
238 // https://www.postgresql.org/docs/current/functions-aggregate.html#FUNCTIONS-ORDEREDSET-TABLE
239 // Since we implement "ordered aggregates" without sorting,
240 // we map all the ones we support to the corresponding aggregate function.
241 if (order_bys->orders.size() != 1) {
242 throw ParserException("Cannot use multiple ORDER BY clauses with WITHIN GROUP");
243 }
244 if (lowercase_name == "percentile_cont") {
245 if (children.size() != 1) {
246 throw ParserException("Wrong number of arguments for PERCENTILE_CONT");
247 }
248 lowercase_name = "quantile_cont";
249 } else if (lowercase_name == "percentile_disc") {
250 if (children.size() != 1) {
251 throw ParserException("Wrong number of arguments for PERCENTILE_DISC");
252 }
253 lowercase_name = "quantile_disc";
254 } else if (lowercase_name == "mode") {
255 if (!children.empty()) {
256 throw ParserException("Wrong number of arguments for MODE");
257 }
258 lowercase_name = "mode";
259 } else {
260 throw ParserException("Unknown ordered aggregate \"%s\".", function_name);
261 }
262 }
263
264 // star gets eaten in the parser
265 if (lowercase_name == "count" && children.empty()) {
266 lowercase_name = "count_star";
267 }
268
269 if (lowercase_name == "if") {
270 if (children.size() != 3) {
271 throw ParserException("Wrong number of arguments to IF.");
272 }
273 auto expr = make_uniq<CaseExpression>();
274 CaseCheck check;
275 check.when_expr = std::move(children[0]);
276 check.then_expr = std::move(children[1]);
277 expr->case_checks.push_back(x: std::move(check));
278 expr->else_expr = std::move(children[2]);
279 return std::move(expr);
280 } else if (lowercase_name == "construct_array") {
281 auto construct_array = make_uniq<OperatorExpression>(args: ExpressionType::ARRAY_CONSTRUCTOR);
282 construct_array->children = std::move(children);
283 return std::move(construct_array);
284 } else if (lowercase_name == "ifnull") {
285 if (children.size() != 2) {
286 throw ParserException("Wrong number of arguments to IFNULL.");
287 }
288
289 // Two-argument COALESCE
290 auto coalesce_op = make_uniq<OperatorExpression>(args: ExpressionType::OPERATOR_COALESCE);
291 coalesce_op->children.push_back(x: std::move(children[0]));
292 coalesce_op->children.push_back(x: std::move(children[1]));
293 return std::move(coalesce_op);
294 } else if (lowercase_name == "list" && order_bys->orders.size() == 1) {
295 // list(expr ORDER BY expr <sense> <nulls>) => list_sort(list(expr), <sense>, <nulls>)
296 if (children.size() != 1) {
297 throw ParserException("Wrong number of arguments to LIST.");
298 }
299 auto arg_expr = children[0].get();
300 auto &order_by = order_bys->orders[0];
301 if (arg_expr->Equals(other: *order_by.expression)) {
302 auto sense = make_uniq<ConstantExpression>(args: EnumUtil::ToChars(value: order_by.type));
303 auto nulls = make_uniq<ConstantExpression>(args: EnumUtil::ToChars(value: order_by.null_order));
304 order_bys = nullptr;
305 auto unordered = make_uniq<FunctionExpression>(args&: catalog, args&: schema, args: lowercase_name.c_str(), args: std::move(children),
306 args: std::move(filter_expr), args: std::move(order_bys),
307 args&: root.agg_distinct, args: false, args&: root.export_state);
308 lowercase_name = "list_sort";
309 order_bys.reset(); // NOLINT
310 filter_expr.reset(); // NOLINT
311 children.clear(); // NOLINT
312 root.agg_distinct = false;
313 children.emplace_back(args: std::move(unordered));
314 children.emplace_back(args: std::move(sense));
315 children.emplace_back(args: std::move(nulls));
316 }
317 }
318
319 auto function = make_uniq<FunctionExpression>(args: std::move(catalog), args: std::move(schema), args: lowercase_name.c_str(),
320 args: std::move(children), args: std::move(filter_expr), args: std::move(order_bys),
321 args&: root.agg_distinct, args: false, args&: root.export_state);
322 function->query_location = root.location;
323
324 return std::move(function);
325}
326
327unique_ptr<ParsedExpression> Transformer::TransformSQLValueFunction(duckdb_libpgquery::PGSQLValueFunction &node) {
328 throw InternalException("SQL value functions should not be emitted by the parser");
329}
330
331} // namespace duckdb
332