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