1#include "duckdb/catalog/catalog_entry/aggregate_function_catalog_entry.hpp"
2#include "duckdb/main/client_context.hpp"
3#include "duckdb/parser/expression/function_expression.hpp"
4#include "duckdb/planner/expression/bound_aggregate_expression.hpp"
5#include "duckdb/planner/expression/bound_columnref_expression.hpp"
6#include "duckdb/planner/expression/bound_constant_expression.hpp"
7#include "duckdb/planner/expression/bound_function_expression.hpp"
8#include "duckdb/planner/expression/bound_parameter_expression.hpp"
9#include "duckdb/planner/expression_binder/aggregate_binder.hpp"
10#include "duckdb/planner/expression_binder/select_binder.hpp"
11#include "duckdb/planner/query_node/bound_select_node.hpp"
12#include "duckdb/planner/expression/bound_unnest_expression.hpp"
13#include "duckdb/planner/binder.hpp"
14#include "duckdb/function/scalar/nested_functions.hpp"
15#include "duckdb/execution/expression_executor.hpp"
16
17namespace duckdb {
18
19unique_ptr<Expression> CreateBoundStructExtract(ClientContext &context, unique_ptr<Expression> expr, string key) {
20 vector<unique_ptr<Expression>> arguments;
21 arguments.push_back(x: std::move(expr));
22 arguments.push_back(x: make_uniq<BoundConstantExpression>(args: Value(key)));
23 auto extract_function = StructExtractFun::GetFunction();
24 auto bind_info = extract_function.bind(context, extract_function, arguments);
25 auto return_type = extract_function.return_type;
26 auto result = make_uniq<BoundFunctionExpression>(args&: return_type, args: std::move(extract_function), args: std::move(arguments),
27 args: std::move(bind_info));
28 result->alias = std::move(key);
29 return std::move(result);
30}
31
32BindResult SelectBinder::BindUnnest(FunctionExpression &function, idx_t depth, bool root_expression) {
33 // bind the children of the function expression
34 if (depth > 0) {
35 return BindResult(binder.FormatError(expr_context&: function, message: "UNNEST() for correlated expressions is not supported yet"));
36 }
37 string error;
38 if (function.children.empty()) {
39 return BindResult(binder.FormatError(expr_context&: function, message: "UNNEST() requires a single argument"));
40 }
41 idx_t max_depth = 1;
42 if (function.children.size() != 1) {
43 bool has_parameter = false;
44 bool supported_argument = false;
45 for (idx_t i = 1; i < function.children.size(); i++) {
46 if (has_parameter) {
47 return BindResult(binder.FormatError(expr_context&: function, message: "UNNEST() only supports a single additional argument"));
48 }
49 if (function.children[i]->HasParameter()) {
50 throw ParameterNotAllowedException("Parameter not allowed in unnest parameter");
51 }
52 if (!function.children[i]->IsScalar()) {
53 break;
54 }
55 auto alias = function.children[i]->alias;
56 BindChild(expr&: function.children[i], depth, error);
57 if (!error.empty()) {
58 return BindResult(error);
59 }
60 auto &const_child = BoundExpression::GetExpression(expr&: *function.children[i]);
61 auto value = ExpressionExecutor::EvaluateScalar(context, expr: *const_child, allow_unfoldable: true);
62 if (alias == "recursive") {
63 auto recursive = value.GetValue<bool>();
64 if (recursive) {
65 max_depth = NumericLimits<idx_t>::Maximum();
66 }
67 } else if (alias == "max_depth") {
68 max_depth = value.GetValue<uint32_t>();
69 if (max_depth == 0) {
70 throw BinderException("UNNEST cannot have a max depth of 0");
71 }
72 } else if (!alias.empty()) {
73 throw BinderException("Unsupported parameter \"%s\" for unnest", alias);
74 } else {
75 break;
76 }
77 has_parameter = true;
78 supported_argument = true;
79 }
80 if (!supported_argument) {
81 return BindResult(binder.FormatError(expr_context&: function, message: "UNNEST - unsupported extra argument, unnest only supports "
82 "recursive := [true/false] or max_depth := #"));
83 }
84 }
85 unnest_level++;
86 BindChild(expr&: function.children[0], depth, error);
87 if (!error.empty()) {
88 // failed to bind
89 // try to bind correlated columns manually
90 if (!BindCorrelatedColumns(expr&: function.children[0])) {
91 return BindResult(error);
92 }
93 auto &bound_expr = BoundExpression::GetExpression(expr&: *function.children[0]);
94 ExtractCorrelatedExpressions(binder, expr&: *bound_expr);
95 }
96 auto &child = BoundExpression::GetExpression(expr&: *function.children[0]);
97 auto &child_type = child->return_type;
98 unnest_level--;
99
100 if (unnest_level > 0) {
101 throw BinderException(
102 "Nested UNNEST calls are not supported - use UNNEST(x, recursive := true) to unnest multiple levels");
103 }
104
105 switch (child_type.id()) {
106 case LogicalTypeId::UNKNOWN:
107 throw ParameterNotResolvedException();
108 case LogicalTypeId::LIST:
109 case LogicalTypeId::STRUCT:
110 case LogicalTypeId::SQLNULL:
111 break;
112 default:
113 return BindResult(binder.FormatError(expr_context&: function, message: "UNNEST() can only be applied to lists, structs and NULL"));
114 }
115
116 idx_t list_unnests;
117 idx_t struct_unnests = 0;
118
119 auto unnest_expr = std::move(child);
120 if (child_type.id() == LogicalTypeId::SQLNULL) {
121 list_unnests = 1;
122 } else {
123 // first do all of the list unnests
124 auto type = child_type;
125 list_unnests = 0;
126 while (type.id() == LogicalTypeId::LIST) {
127 type = ListType::GetChildType(type);
128 list_unnests++;
129 if (list_unnests >= max_depth) {
130 break;
131 }
132 }
133 // unnest structs all the way afterwards, if there are any
134 if (type.id() == LogicalTypeId::STRUCT) {
135 struct_unnests = max_depth - list_unnests;
136 }
137 }
138 if (struct_unnests > 0 && !root_expression) {
139 return BindResult(binder.FormatError(
140 expr_context&: function, message: "UNNEST() on a struct column can only be applied as the root element of a SELECT expression"));
141 }
142 // perform all of the list unnests first
143 auto return_type = child_type;
144 for (idx_t current_depth = 0; current_depth < list_unnests; current_depth++) {
145 if (return_type.id() == LogicalTypeId::LIST) {
146 return_type = ListType::GetChildType(type: return_type);
147 }
148 auto result = make_uniq<BoundUnnestExpression>(args&: return_type);
149 result->child = std::move(unnest_expr);
150 auto alias = function.alias.empty() ? result->ToString() : function.alias;
151
152 auto current_level = unnest_level + list_unnests - current_depth - 1;
153 auto entry = node.unnests.find(x: current_level);
154 idx_t unnest_table_index;
155 idx_t unnest_column_index;
156 if (entry == node.unnests.end()) {
157 BoundUnnestNode unnest_node;
158 unnest_node.index = binder.GenerateTableIndex();
159 unnest_node.expressions.push_back(x: std::move(result));
160 unnest_table_index = unnest_node.index;
161 unnest_column_index = 0;
162 node.unnests.insert(x: make_pair(x&: current_level, y: std::move(unnest_node)));
163 } else {
164 unnest_table_index = entry->second.index;
165 unnest_column_index = entry->second.expressions.size();
166 entry->second.expressions.push_back(x: std::move(result));
167 }
168 // now create a column reference referring to the unnest
169 unnest_expr = make_uniq<BoundColumnRefExpression>(
170 args: std::move(alias), args&: return_type, args: ColumnBinding(unnest_table_index, unnest_column_index), args&: depth);
171 }
172 // now perform struct unnests, if any
173 if (struct_unnests > 0) {
174 vector<unique_ptr<Expression>> struct_expressions;
175 struct_expressions.push_back(x: std::move(unnest_expr));
176
177 for (idx_t i = 0; i < struct_unnests; i++) {
178 vector<unique_ptr<Expression>> new_expressions;
179 // check if there are any structs left
180 bool has_structs = false;
181 for (auto &expr : struct_expressions) {
182 if (expr->return_type.id() == LogicalTypeId::STRUCT) {
183 // struct! push a struct_extract
184 auto &child_types = StructType::GetChildTypes(type: expr->return_type);
185 for (auto &entry : child_types) {
186 new_expressions.push_back(x: CreateBoundStructExtract(context, expr: expr->Copy(), key: entry.first));
187 }
188 has_structs = true;
189 } else {
190 // not a struct - push as-is
191 new_expressions.push_back(x: std::move(expr));
192 }
193 }
194 struct_expressions = std::move(new_expressions);
195 if (!has_structs) {
196 break;
197 }
198 }
199 expanded_expressions = std::move(struct_expressions);
200 unnest_expr = make_uniq<BoundConstantExpression>(args: Value(42));
201 }
202 return BindResult(std::move(unnest_expr));
203}
204
205} // namespace duckdb
206