duckdb 0.7.2-dev865.0 → 0.7.2-dev899.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/package.json +1 -1
  2. package/src/duckdb/src/catalog/default/default_functions.cpp +3 -0
  3. package/src/duckdb/src/catalog/duck_catalog.cpp +34 -7
  4. package/src/duckdb/src/common/box_renderer.cpp +109 -23
  5. package/src/duckdb/src/function/scalar/struct/struct_extract.cpp +1 -1
  6. package/src/duckdb/src/function/table/version/pragma_version.cpp +2 -2
  7. package/src/duckdb/src/include/duckdb/catalog/duck_catalog.hpp +2 -1
  8. package/src/duckdb/src/include/duckdb/common/box_renderer.hpp +8 -2
  9. package/src/duckdb/src/include/duckdb/optimizer/filter_pushdown.hpp +2 -0
  10. package/src/duckdb/src/include/duckdb/parser/tableref/pivotref.hpp +4 -2
  11. package/src/duckdb/src/include/duckdb/parser/transformer.hpp +2 -2
  12. package/src/duckdb/src/include/duckdb/planner/binder.hpp +3 -1
  13. package/src/duckdb/src/include/duckdb/planner/expression_binder/base_select_binder.hpp +64 -0
  14. package/src/duckdb/src/include/duckdb/planner/expression_binder/having_binder.hpp +2 -2
  15. package/src/duckdb/src/include/duckdb/planner/expression_binder/qualify_binder.hpp +2 -2
  16. package/src/duckdb/src/include/duckdb/planner/expression_binder/select_binder.hpp +9 -38
  17. package/src/duckdb/src/include/duckdb/planner/expression_binder.hpp +1 -1
  18. package/src/duckdb/src/include/duckdb/planner/query_node/bound_select_node.hpp +8 -2
  19. package/src/duckdb/src/optimizer/filter_pushdown.cpp +11 -7
  20. package/src/duckdb/src/optimizer/pushdown/pushdown_left_join.cpp +1 -10
  21. package/src/duckdb/src/optimizer/pushdown/pushdown_mark_join.cpp +1 -1
  22. package/src/duckdb/src/optimizer/pushdown/pushdown_single_join.cpp +1 -1
  23. package/src/duckdb/src/parser/tableref/pivotref.cpp +35 -11
  24. package/src/duckdb/src/parser/transform/statement/transform_pivot_stmt.cpp +41 -12
  25. package/src/duckdb/src/parser/transform/tableref/transform_pivot.cpp +19 -3
  26. package/src/duckdb/src/planner/binder/expression/bind_aggregate_expression.cpp +2 -2
  27. package/src/duckdb/src/planner/binder/expression/bind_function_expression.cpp +1 -8
  28. package/src/duckdb/src/planner/binder/expression/bind_unnest_expression.cpp +163 -24
  29. package/src/duckdb/src/planner/binder/expression/bind_window_expression.cpp +2 -2
  30. package/src/duckdb/src/planner/binder/query_node/bind_select_node.cpp +23 -3
  31. package/src/duckdb/src/planner/binder/query_node/plan_select_node.cpp +9 -3
  32. package/src/duckdb/src/planner/binder/tableref/bind_pivot.cpp +8 -8
  33. package/src/duckdb/src/planner/expression_binder/base_select_binder.cpp +146 -0
  34. package/src/duckdb/src/planner/expression_binder/having_binder.cpp +3 -3
  35. package/src/duckdb/src/planner/expression_binder/qualify_binder.cpp +3 -3
  36. package/src/duckdb/src/planner/expression_binder/select_binder.cpp +1 -132
  37. package/src/duckdb/src/planner/expression_binder.cpp +9 -2
  38. package/src/duckdb/src/planner/expression_iterator.cpp +12 -10
  39. package/src/duckdb/third_party/libpg_query/include/nodes/parsenodes.hpp +1 -0
  40. package/src/duckdb/third_party/libpg_query/src_backend_parser_gram.cpp +11817 -11167
  41. package/src/duckdb/ub_src_planner_expression_binder.cpp +2 -0
@@ -122,16 +122,7 @@ unique_ptr<LogicalOperator> FilterPushdown::PushdownLeftJoin(unique_ptr<LogicalO
122
122
  right_pushdown.GenerateFilters();
123
123
  op->children[0] = left_pushdown.Rewrite(std::move(op->children[0]));
124
124
  op->children[1] = right_pushdown.Rewrite(std::move(op->children[1]));
125
- if (filters.empty()) {
126
- // no filters to push
127
- return op;
128
- }
129
- auto filter = make_unique<LogicalFilter>();
130
- for (auto &f : filters) {
131
- filter->expressions.push_back(std::move(f->filter));
132
- }
133
- filter->children.push_back(std::move(op));
134
- return std::move(filter);
125
+ return PushFinalFilters(std::move(op));
135
126
  }
136
127
 
137
128
  } // namespace duckdb
@@ -77,7 +77,7 @@ unique_ptr<LogicalOperator> FilterPushdown::PushdownMarkJoin(unique_ptr<LogicalO
77
77
  }
78
78
  op->children[0] = left_pushdown.Rewrite(std::move(op->children[0]));
79
79
  op->children[1] = right_pushdown.Rewrite(std::move(op->children[1]));
80
- return FinishPushdown(std::move(op));
80
+ return PushFinalFilters(std::move(op));
81
81
  }
82
82
 
83
83
  } // namespace duckdb
@@ -23,7 +23,7 @@ unique_ptr<LogicalOperator> FilterPushdown::PushdownSingleJoin(unique_ptr<Logica
23
23
  }
24
24
  op->children[0] = left_pushdown.Rewrite(std::move(op->children[0]));
25
25
  op->children[1] = right_pushdown.Rewrite(std::move(op->children[1]));
26
- return FinishPushdown(std::move(op));
26
+ return PushFinalFilters(std::move(op));
27
27
  }
28
28
 
29
29
  } // namespace duckdb
@@ -12,15 +12,29 @@ namespace duckdb {
12
12
  //===--------------------------------------------------------------------===//
13
13
  string PivotColumn::ToString() const {
14
14
  string result;
15
- if (names.size() == 1) {
16
- result += KeywordHelper::WriteOptionallyQuoted(names[0]);
17
- } else {
15
+ if (!unpivot_names.empty()) {
16
+ D_ASSERT(pivot_expressions.empty());
17
+ // unpivot
18
+ if (unpivot_names.size() == 1) {
19
+ result += KeywordHelper::WriteOptionallyQuoted(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(unpivot_names[n]);
27
+ }
28
+ result += ")";
29
+ }
30
+ } else if (!pivot_expressions.empty()) {
31
+ // pivot
18
32
  result += "(";
19
- for (idx_t n = 0; n < names.size(); n++) {
33
+ for (idx_t n = 0; n < pivot_expressions.size(); n++) {
20
34
  if (n > 0) {
21
35
  result += ", ";
22
36
  }
23
- result += KeywordHelper::WriteOptionallyQuoted(names[n]);
37
+ result += pivot_expressions[n]->ToString();
24
38
  }
25
39
  result += ")";
26
40
  }
@@ -74,7 +88,10 @@ bool PivotColumnEntry::Equals(const PivotColumnEntry &other) const {
74
88
  }
75
89
 
76
90
  bool PivotColumn::Equals(const PivotColumn &other) const {
77
- if (other.names != names) {
91
+ if (!ExpressionUtil::ListEquals(pivot_expressions, other.pivot_expressions)) {
92
+ return false;
93
+ }
94
+ if (other.unpivot_names != unpivot_names) {
78
95
  return false;
79
96
  }
80
97
  if (other.pivot_enum != pivot_enum) {
@@ -93,7 +110,10 @@ bool PivotColumn::Equals(const PivotColumn &other) const {
93
110
 
94
111
  PivotColumn PivotColumn::Copy() const {
95
112
  PivotColumn result;
96
- result.names = names;
113
+ for (auto &expr : pivot_expressions) {
114
+ result.pivot_expressions.push_back(expr->Copy());
115
+ }
116
+ result.unpivot_names = unpivot_names;
97
117
  for (auto &entry : entries) {
98
118
  result.entries.push_back(entry.Copy());
99
119
  }
@@ -103,14 +123,16 @@ PivotColumn PivotColumn::Copy() const {
103
123
 
104
124
  void PivotColumn::Serialize(Serializer &serializer) const {
105
125
  FieldWriter writer(serializer);
106
- writer.WriteList<string>(names);
126
+ writer.WriteSerializableList(pivot_expressions);
127
+ writer.WriteList<string>(unpivot_names);
107
128
  writer.WriteRegularSerializableList(entries);
108
129
  writer.WriteString(pivot_enum);
109
130
  writer.Finalize();
110
131
  }
111
132
 
112
133
  void PivotColumn::FormatSerialize(FormatSerializer &serializer) const {
113
- serializer.WriteProperty("names", names);
134
+ serializer.WriteProperty("pivot_expressions", pivot_expressions);
135
+ serializer.WriteProperty("unpivot_names", unpivot_names);
114
136
  serializer.WriteProperty("entries", entries);
115
137
  serializer.WriteProperty("pivot_enum", pivot_enum);
116
138
  }
@@ -118,7 +140,8 @@ void PivotColumn::FormatSerialize(FormatSerializer &serializer) const {
118
140
  PivotColumn PivotColumn::Deserialize(Deserializer &source) {
119
141
  PivotColumn result;
120
142
  FieldReader reader(source);
121
- result.names = reader.ReadRequiredList<string>();
143
+ result.pivot_expressions = reader.ReadRequiredSerializableList<ParsedExpression>();
144
+ result.unpivot_names = reader.ReadRequiredList<string>();
122
145
  result.entries = reader.ReadRequiredSerializableList<PivotColumnEntry, PivotColumnEntry>();
123
146
  result.pivot_enum = reader.ReadRequired<string>();
124
147
  reader.Finalize();
@@ -127,7 +150,8 @@ PivotColumn PivotColumn::Deserialize(Deserializer &source) {
127
150
 
128
151
  PivotColumn PivotColumn::FormatDeserialize(FormatDeserializer &source) {
129
152
  PivotColumn result;
130
- source.ReadProperty("names", result.names);
153
+ source.ReadProperty("pivot_expressions", result.pivot_expressions);
154
+ source.ReadProperty("unpivot_names", result.unpivot_names);
131
155
  source.ReadProperty("entries", result.entries);
132
156
  source.ReadProperty("pivot_enum", result.pivot_enum);
133
157
  return result;
@@ -10,20 +10,22 @@
10
10
  #include "duckdb/parser/statement/drop_statement.hpp"
11
11
  #include "duckdb/parser/parsed_data/drop_info.hpp"
12
12
  #include "duckdb/parser/expression/cast_expression.hpp"
13
+ #include "duckdb/parser/expression/operator_expression.hpp"
14
+ #include "duckdb/parser/expression/function_expression.hpp"
13
15
  #include "duckdb/parser/result_modifier.hpp"
14
16
  #include "duckdb/parser/tableref/subqueryref.hpp"
15
17
 
16
18
  namespace duckdb {
17
19
 
18
- void Transformer::AddPivotEntry(string enum_name, unique_ptr<SelectNode> base, string column_name) {
20
+ void Transformer::AddPivotEntry(string enum_name, unique_ptr<SelectNode> base, unique_ptr<ParsedExpression> column) {
19
21
  if (parent) {
20
- parent->AddPivotEntry(std::move(enum_name), std::move(base), std::move(column_name));
22
+ parent->AddPivotEntry(std::move(enum_name), std::move(base), std::move(column));
21
23
  return;
22
24
  }
23
25
  auto result = make_unique<CreatePivotEntry>();
24
26
  result->enum_name = std::move(enum_name);
25
27
  result->base = std::move(base);
26
- result->column_name = std::move(column_name);
28
+ result->column = std::move(column);
27
29
 
28
30
  pivot_entries.push_back(std::move(result));
29
31
  }
@@ -55,10 +57,13 @@ unique_ptr<SQLStatement> Transformer::GenerateCreateEnumStmt(unique_ptr<CreatePi
55
57
 
56
58
  // generate the query that will result in the enum creation
57
59
  auto select_node = std::move(entry->base);
58
- auto columnref = make_unique<ColumnRefExpression>(std::move(entry->column_name));
60
+ auto columnref = entry->column->Copy();
59
61
  auto cast = make_unique<CastExpression>(LogicalType::VARCHAR, columnref->Copy());
60
62
  select_node->select_list.push_back(std::move(cast));
61
63
 
64
+ auto is_not_null = make_unique<OperatorExpression>(ExpressionType::OPERATOR_IS_NOT_NULL, std::move(entry->column));
65
+ select_node->where_clause = std::move(is_not_null);
66
+
62
67
  // order by the column
63
68
  auto modifier = make_unique<OrderModifier>();
64
69
  modifier->orders.emplace_back(OrderType::ASCENDING, OrderByNullType::ORDER_DEFAULT, std::move(columnref));
@@ -99,22 +104,42 @@ unique_ptr<SQLStatement> Transformer::CreatePivotStatement(unique_ptr<SQLStateme
99
104
  unique_ptr<QueryNode> Transformer::TransformPivotStatement(duckdb_libpgquery::PGSelectStmt *stmt) {
100
105
  auto pivot = stmt->pivot;
101
106
  auto source = TransformTableRefNode(pivot->source);
102
- auto columns = TransformPivotList(pivot->columns);
103
107
 
104
108
  auto select_node = make_unique<SelectNode>();
105
109
  // handle the CTEs
106
110
  if (stmt->withClause) {
107
111
  TransformCTE(reinterpret_cast<duckdb_libpgquery::PGWithClause *>(stmt->withClause), select_node->cte_map);
108
112
  }
113
+ if (!pivot->columns) {
114
+ // no pivot columns - not actually a pivot
115
+ select_node->from_table = std::move(source);
116
+ if (pivot->groups) {
117
+ auto groups = TransformStringList(pivot->groups);
118
+ GroupingSet set;
119
+ for (idx_t gr = 0; gr < groups.size(); gr++) {
120
+ auto &group = groups[gr];
121
+ auto colref = make_unique<ColumnRefExpression>(group);
122
+ select_node->select_list.push_back(colref->Copy());
123
+ select_node->groups.group_expressions.push_back(std::move(colref));
124
+ set.insert(gr);
125
+ }
126
+ select_node->groups.grouping_sets.push_back(std::move(set));
127
+ }
128
+ if (pivot->aggrs) {
129
+ TransformExpressionList(*pivot->aggrs, select_node->select_list);
130
+ }
131
+ return std::move(select_node);
132
+ }
109
133
 
110
134
  // generate CREATE TYPE statements for each of the columns that do not have an IN list
135
+ auto columns = TransformPivotList(pivot->columns);
111
136
  auto pivot_idx = PivotEntryCount();
112
137
  for (idx_t c = 0; c < columns.size(); c++) {
113
138
  auto &col = columns[c];
114
139
  if (!col.pivot_enum.empty() || !col.entries.empty()) {
115
140
  continue;
116
141
  }
117
- if (col.names.size() != 1) {
142
+ if (col.pivot_expressions.size() != 1) {
118
143
  throw InternalException("PIVOT statement with multiple names in pivot entry!?");
119
144
  }
120
145
  auto enum_name = "__pivot_enum_" + std::to_string(pivot_idx) + "_" + std::to_string(c);
@@ -122,7 +147,7 @@ unique_ptr<QueryNode> Transformer::TransformPivotStatement(duckdb_libpgquery::PG
122
147
  auto new_select = make_unique<SelectNode>();
123
148
  ExtractCTEsRecursive(new_select->cte_map);
124
149
  new_select->from_table = source->Copy();
125
- AddPivotEntry(enum_name, std::move(new_select), col.names[0]);
150
+ AddPivotEntry(enum_name, std::move(new_select), col.pivot_expressions[0]->Copy());
126
151
  col.pivot_enum = enum_name;
127
152
  }
128
153
 
@@ -131,13 +156,17 @@ unique_ptr<QueryNode> Transformer::TransformPivotStatement(duckdb_libpgquery::PG
131
156
 
132
157
  auto pivot_ref = make_unique<PivotRef>();
133
158
  pivot_ref->source = std::move(source);
134
- if (pivot->aggrs) {
135
- TransformExpressionList(*pivot->aggrs, pivot_ref->aggregates);
159
+ if (pivot->unpivots) {
160
+ pivot_ref->unpivot_names = TransformStringList(pivot->unpivots);
136
161
  } else {
137
- if (!pivot->unpivots) {
138
- throw InternalException("No unpivots and no aggrs");
162
+ if (pivot->aggrs) {
163
+ TransformExpressionList(*pivot->aggrs, pivot_ref->aggregates);
164
+ } else {
165
+ // pivot but no aggregates specified - push a count star
166
+ vector<unique_ptr<ParsedExpression>> children;
167
+ auto function = make_unique<FunctionExpression>("count_star", std::move(children));
168
+ pivot_ref->aggregates.push_back(std::move(function));
139
169
  }
140
- pivot_ref->unpivot_names = TransformStringList(pivot->unpivots);
141
170
  }
142
171
  if (pivot->groups) {
143
172
  pivot_ref->groups = TransformStringList(pivot->groups);
@@ -34,7 +34,21 @@ static void TransformPivotInList(unique_ptr<ParsedExpression> &expr, PivotColumn
34
34
 
35
35
  PivotColumn Transformer::TransformPivotColumn(duckdb_libpgquery::PGPivot *pivot) {
36
36
  PivotColumn col;
37
- col.names = TransformStringList(pivot->pivot_columns);
37
+ if (pivot->pivot_columns) {
38
+ TransformExpressionList(*pivot->pivot_columns, col.pivot_expressions);
39
+ for (auto &expr : col.pivot_expressions) {
40
+ if (expr->IsScalar()) {
41
+ throw ParserException("Cannot pivot on constant value \"%s\"", expr->ToString());
42
+ }
43
+ if (expr->HasSubquery()) {
44
+ throw ParserException("Cannot pivot on subquery \"%s\"", expr->ToString());
45
+ }
46
+ }
47
+ } else if (pivot->unpivot_columns) {
48
+ col.unpivot_names = TransformStringList(pivot->unpivot_columns);
49
+ } else {
50
+ throw InternalException("Either pivot_columns or unpivot_columns must be defined");
51
+ }
38
52
  if (pivot->pivot_value) {
39
53
  for (auto node = pivot->pivot_value->head; node != nullptr; node = node->next) {
40
54
  auto n = (duckdb_libpgquery::PGNode *)node->data.ptr_value;
@@ -78,13 +92,15 @@ unique_ptr<TableRef> Transformer::TransformPivot(duckdb_libpgquery::PGPivotExpr
78
92
  bool is_pivot = result->unpivot_names.empty();
79
93
  if (!result->unpivot_names.empty()) {
80
94
  // unpivot
81
- if (pivot.names.size() != 1) {
95
+ if (pivot.unpivot_names.size() != 1) {
82
96
  throw ParserException("UNPIVOT requires a single column name for the PIVOT IN clause");
83
97
  }
98
+ D_ASSERT(pivot.pivot_expressions.empty());
84
99
  expected_size = pivot.entries[0].values.size();
85
100
  } else {
86
101
  // pivot
87
- expected_size = pivot.names.size();
102
+ expected_size = pivot.pivot_expressions.size();
103
+ D_ASSERT(pivot.unpivot_names.empty());
88
104
  }
89
105
  for (auto &entry : pivot.entries) {
90
106
  if (entry.star_expr && is_pivot) {
@@ -7,7 +7,7 @@
7
7
  #include "duckdb/planner/expression/bound_columnref_expression.hpp"
8
8
  #include "duckdb/planner/expression/bound_constant_expression.hpp"
9
9
  #include "duckdb/planner/expression_binder/aggregate_binder.hpp"
10
- #include "duckdb/planner/expression_binder/select_binder.hpp"
10
+ #include "duckdb/planner/expression_binder/base_select_binder.hpp"
11
11
  #include "duckdb/planner/query_node/bound_select_node.hpp"
12
12
  #include "duckdb/execution/expression_executor.hpp"
13
13
  #include "duckdb/function/scalar/generic_functions.hpp"
@@ -81,7 +81,7 @@ static void NegatePercentileFractions(ClientContext &context, unique_ptr<ParsedE
81
81
  }
82
82
  }
83
83
 
84
- BindResult SelectBinder::BindAggregate(FunctionExpression &aggr, AggregateFunctionCatalogEntry *func, idx_t depth) {
84
+ BindResult BaseSelectBinder::BindAggregate(FunctionExpression &aggr, AggregateFunctionCatalogEntry *func, idx_t depth) {
85
85
  // first bind the child of the aggregate expression (if any)
86
86
  this->bound_aggregate = true;
87
87
  unique_ptr<Expression> bound_filter;
@@ -18,13 +18,6 @@ BindResult ExpressionBinder::BindExpression(FunctionExpression &function, idx_t
18
18
  unique_ptr<ParsedExpression> *expr_ptr) {
19
19
  // lookup the function in the catalog
20
20
  QueryErrorContext error_context(binder.root_statement, function.query_location);
21
-
22
- if (function.function_name == "unnest" || function.function_name == "unlist") {
23
- // special case, not in catalog
24
- // TODO make sure someone does not create such a function OR
25
- // have unnest live in catalog, too
26
- return BindUnnest(function, depth);
27
- }
28
21
  auto func = Catalog::GetEntry(context, CatalogType::SCALAR_FUNCTION_ENTRY, function.catalog, function.schema,
29
22
  function.function_name, true, error_context);
30
23
  if (!func) {
@@ -246,7 +239,7 @@ BindResult ExpressionBinder::BindAggregate(FunctionExpression &expr, AggregateFu
246
239
  return BindResult(binder.FormatError(expr, UnsupportedAggregateMessage()));
247
240
  }
248
241
 
249
- BindResult ExpressionBinder::BindUnnest(FunctionExpression &expr, idx_t depth) {
242
+ BindResult ExpressionBinder::BindUnnest(FunctionExpression &expr, idx_t depth, bool root_expression) {
250
243
  return BindResult(binder.FormatError(expr, UnsupportedUnnestMessage()));
251
244
  }
252
245
 
@@ -3,21 +3,86 @@
3
3
  #include "duckdb/parser/expression/function_expression.hpp"
4
4
  #include "duckdb/planner/expression/bound_aggregate_expression.hpp"
5
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"
6
8
  #include "duckdb/planner/expression/bound_parameter_expression.hpp"
7
9
  #include "duckdb/planner/expression_binder/aggregate_binder.hpp"
8
10
  #include "duckdb/planner/expression_binder/select_binder.hpp"
9
11
  #include "duckdb/planner/query_node/bound_select_node.hpp"
10
12
  #include "duckdb/planner/expression/bound_unnest_expression.hpp"
11
13
  #include "duckdb/planner/binder.hpp"
14
+ #include "duckdb/function/scalar/nested_functions.hpp"
15
+ #include "duckdb/execution/expression_executor.hpp"
12
16
 
13
17
  namespace duckdb {
14
18
 
15
- BindResult SelectBinder::BindUnnest(FunctionExpression &function, idx_t depth) {
19
+ unique_ptr<Expression> CreateBoundStructExtract(ClientContext &context, unique_ptr<Expression> expr, string key) {
20
+ vector<unique_ptr<Expression>> arguments;
21
+ arguments.push_back(std::move(expr));
22
+ arguments.push_back(make_unique<BoundConstantExpression>(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_unique<BoundFunctionExpression>(return_type, std::move(extract_function), std::move(arguments),
27
+ std::move(bind_info));
28
+ result->alias = std::move(key);
29
+ return std::move(result);
30
+ }
31
+
32
+ BindResult SelectBinder::BindUnnest(FunctionExpression &function, idx_t depth, bool root_expression) {
16
33
  // bind the children of the function expression
34
+ if (depth > 0) {
35
+ return BindResult(binder.FormatError(function, "UNNEST() for correlated expressions is not supported yet"));
36
+ }
17
37
  string error;
38
+ if (function.children.empty()) {
39
+ return BindResult(binder.FormatError(function, "UNNEST() requires a single argument"));
40
+ }
41
+ idx_t max_depth = 1;
18
42
  if (function.children.size() != 1) {
19
- return BindResult(binder.FormatError(function, "Unnest() needs exactly one child expressions"));
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(function, "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(function.children[i], depth, error);
57
+ if (!error.empty()) {
58
+ return BindResult(error);
59
+ }
60
+ auto &const_child = (BoundExpression &)*function.children[i];
61
+ auto value = ExpressionExecutor::EvaluateScalar(context, *const_child.expr, 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(function, "UNNEST - unsupported extra argument, unnest only supports "
82
+ "recursive := [true/false] or max_depth := #"));
83
+ }
20
84
  }
85
+ unnest_level++;
21
86
  BindChild(function.children[0], depth, error);
22
87
  if (!error.empty()) {
23
88
  // failed to bind
@@ -30,37 +95,111 @@ BindResult SelectBinder::BindUnnest(FunctionExpression &function, idx_t depth) {
30
95
  }
31
96
  auto &child = (BoundExpression &)*function.children[0];
32
97
  auto &child_type = child.expr->return_type;
98
+ unnest_level--;
33
99
 
34
- if (child_type.id() != LogicalTypeId::LIST && child_type.id() != LogicalTypeId::SQLNULL &&
35
- child_type.id() != LogicalTypeId::UNKNOWN) {
36
- return BindResult(binder.FormatError(function, "Unnest() can only be applied to lists and NULL"));
37
- }
38
-
39
- if (depth > 0) {
40
- throw BinderException(binder.FormatError(function, "Unnest() for correlated expressions is not supported yet"));
100
+ if (unnest_level > 0) {
101
+ throw BinderException(
102
+ "Nested UNNEST calls are not supported - use UNNEST(x, recursive := true) to unnest multiple levels");
41
103
  }
42
104
 
43
- auto return_type = LogicalType(LogicalTypeId::SQLNULL);
44
- if (child_type.id() == LogicalTypeId::LIST) {
45
- return_type = ListType::GetChildType(child_type);
46
- } else if (child_type.id() == LogicalTypeId::UNKNOWN) {
105
+ switch (child_type.id()) {
106
+ case LogicalTypeId::UNKNOWN:
47
107
  throw ParameterNotResolvedException();
108
+ case LogicalTypeId::LIST:
109
+ case LogicalTypeId::STRUCT:
110
+ case LogicalTypeId::SQLNULL:
111
+ break;
112
+ default:
113
+ return BindResult(binder.FormatError(function, "UNNEST() can only be applied to lists, structs and NULL"));
48
114
  }
49
115
 
50
- auto result = make_unique<BoundUnnestExpression>(return_type);
51
- result->child = std::move(child.expr);
116
+ idx_t list_unnests;
117
+ idx_t struct_unnests = 0;
52
118
 
53
- auto unnest_index = node.unnests.size();
54
- node.unnests.push_back(std::move(result));
55
-
56
- // TODO what if we have multiple unnests in the same projection list? ignore for now
119
+ auto unnest_expr = std::move(child.expr);
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
+ function, "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(return_type);
147
+ }
148
+ auto result = make_unique<BoundUnnestExpression>(return_type);
149
+ result->child = std::move(unnest_expr);
150
+ auto alias = function.alias.empty() ? result->ToString() : function.alias;
57
151
 
58
- // now create a column reference referring to the unnest
59
- auto colref = make_unique<BoundColumnRefExpression>(
60
- function.alias.empty() ? node.unnests[unnest_index]->ToString() : function.alias, return_type,
61
- ColumnBinding(node.unnest_index, unnest_index), depth);
152
+ auto current_level = unnest_level + list_unnests - current_depth - 1;
153
+ auto entry = node.unnests.find(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(std::move(result));
160
+ unnest_table_index = unnest_node.index;
161
+ unnest_column_index = 0;
162
+ node.unnests.insert(make_pair(current_level, 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(std::move(result));
167
+ }
168
+ // now create a column reference referring to the unnest
169
+ unnest_expr = make_unique<BoundColumnRefExpression>(
170
+ std::move(alias), return_type, ColumnBinding(unnest_table_index, unnest_column_index), 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(std::move(unnest_expr));
62
176
 
63
- return BindResult(std::move(colref));
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(expr->return_type);
185
+ for (auto &entry : child_types) {
186
+ new_expressions.push_back(CreateBoundStructExtract(context, expr->Copy(), entry.first));
187
+ }
188
+ has_structs = true;
189
+ } else {
190
+ // not a struct - push as-is
191
+ new_expressions.push_back(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_unique<BoundConstantExpression>(Value(42));
201
+ }
202
+ return BindResult(std::move(unnest_expr));
64
203
  }
65
204
 
66
205
  } // namespace duckdb
@@ -119,10 +119,10 @@ static LogicalType BindRangeExpression(ClientContext &context, const string &nam
119
119
  return bound.expr->return_type;
120
120
  }
121
121
 
122
- BindResult SelectBinder::BindWindow(WindowExpression &window, idx_t depth) {
122
+ BindResult BaseSelectBinder::BindWindow(WindowExpression &window, idx_t depth) {
123
123
  auto name = window.GetName();
124
124
 
125
- QueryErrorContext error_context(binder.root_statement, window.query_location);
125
+ QueryErrorContext error_context(binder.GetRootStatement(), window.query_location);
126
126
  if (inside_window) {
127
127
  throw BinderException(error_context.FormatError("window function calls cannot be nested"));
128
128
  }
@@ -316,7 +316,6 @@ unique_ptr<BoundQueryNode> Binder::BindSelectNode(SelectNode &statement, unique_
316
316
  result->aggregate_index = GenerateTableIndex();
317
317
  result->groupings_index = GenerateTableIndex();
318
318
  result->window_index = GenerateTableIndex();
319
- result->unnest_index = GenerateTableIndex();
320
319
  result->prune_index = GenerateTableIndex();
321
320
 
322
321
  result->from_table = std::move(from_table);
@@ -427,14 +426,32 @@ unique_ptr<BoundQueryNode> Binder::BindSelectNode(SelectNode &statement, unique_
427
426
  SelectBinder select_binder(*this, context, *result, info, alias_map);
428
427
  vector<LogicalType> internal_sql_types;
429
428
  vector<idx_t> group_by_all_indexes;
429
+ vector<string> new_names;
430
430
  for (idx_t i = 0; i < statement.select_list.size(); i++) {
431
431
  bool is_window = statement.select_list[i]->IsWindow();
432
432
  idx_t unnest_count = result->unnests.size();
433
433
  LogicalType result_type;
434
- auto expr = select_binder.Bind(statement.select_list[i], &result_type);
434
+ auto expr = select_binder.Bind(statement.select_list[i], &result_type, true);
435
435
  bool is_original_column = i < result->column_count;
436
436
  bool can_group_by_all =
437
437
  statement.aggregate_handling == AggregateHandling::FORCE_AGGREGATES && is_original_column;
438
+ if (select_binder.HasExpandedExpressions()) {
439
+ if (!is_original_column) {
440
+ throw InternalException("Only original columns can have expanded expressions");
441
+ }
442
+ if (statement.aggregate_handling == AggregateHandling::FORCE_AGGREGATES) {
443
+ throw BinderException("UNNEST of struct cannot be combined with GROUP BY ALL");
444
+ }
445
+ auto &struct_expressions = select_binder.ExpandedExpressions();
446
+ D_ASSERT(!struct_expressions.empty());
447
+ for (auto &struct_expr : struct_expressions) {
448
+ new_names.push_back(struct_expr->GetName());
449
+ result->types.push_back(struct_expr->return_type);
450
+ result->select_list.push_back(std::move(struct_expr));
451
+ }
452
+ struct_expressions.clear();
453
+ continue;
454
+ }
438
455
  if (can_group_by_all && select_binder.HasBoundColumns()) {
439
456
  if (select_binder.BoundAggregates()) {
440
457
  throw BinderException("Cannot mix aggregates with non-aggregated columns!");
@@ -450,7 +467,8 @@ unique_ptr<BoundQueryNode> Binder::BindSelectNode(SelectNode &statement, unique_
450
467
  group_by_all_indexes.push_back(i);
451
468
  }
452
469
  result->select_list.push_back(std::move(expr));
453
- if (i < result->column_count) {
470
+ if (is_original_column) {
471
+ new_names.push_back(std::move(result->names[i]));
454
472
  result->types.push_back(result_type);
455
473
  }
456
474
  internal_sql_types.push_back(result_type);
@@ -466,6 +484,8 @@ unique_ptr<BoundQueryNode> Binder::BindSelectNode(SelectNode &statement, unique_
466
484
  result->groups.group_expressions.push_back(std::move(expr));
467
485
  expr = std::move(group_ref);
468
486
  }
487
+ result->column_count = new_names.size();
488
+ result->names = std::move(new_names);
469
489
  result->need_prune = result->select_list.size() > result->column_count;
470
490
 
471
491
  // in the normal select binder, we bind columns as if there is no aggregation
@@ -88,9 +88,15 @@ unique_ptr<LogicalOperator> Binder::CreatePlan(BoundSelectNode &statement) {
88
88
  root = std::move(qualify);
89
89
  }
90
90
 
91
- if (!statement.unnests.empty()) {
92
- auto unnest = make_unique<LogicalUnnest>(statement.unnest_index);
93
- unnest->expressions = std::move(statement.unnests);
91
+ for (idx_t i = statement.unnests.size(); i > 0; i--) {
92
+ auto unnest_level = i - 1;
93
+ auto entry = statement.unnests.find(unnest_level);
94
+ if (entry == statement.unnests.end()) {
95
+ throw InternalException("unnests specified at level %d but none were found", unnest_level);
96
+ }
97
+ auto &unnest_node = entry->second;
98
+ auto unnest = make_unique<LogicalUnnest>(unnest_node.index);
99
+ unnest->expressions = std::move(unnest_node.expressions);
94
100
  // visit the unnest expressions
95
101
  for (auto &expr : unnest->expressions) {
96
102
  PlanSubqueries(&expr, &root);