duckdb 0.7.2-dev886.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 (31) hide show
  1. package/package.json +1 -1
  2. package/src/duckdb/src/function/scalar/struct/struct_extract.cpp +1 -1
  3. package/src/duckdb/src/function/table/version/pragma_version.cpp +2 -2
  4. package/src/duckdb/src/include/duckdb/parser/tableref/pivotref.hpp +4 -2
  5. package/src/duckdb/src/include/duckdb/parser/transformer.hpp +2 -2
  6. package/src/duckdb/src/include/duckdb/planner/binder.hpp +3 -1
  7. package/src/duckdb/src/include/duckdb/planner/expression_binder/base_select_binder.hpp +64 -0
  8. package/src/duckdb/src/include/duckdb/planner/expression_binder/having_binder.hpp +2 -2
  9. package/src/duckdb/src/include/duckdb/planner/expression_binder/qualify_binder.hpp +2 -2
  10. package/src/duckdb/src/include/duckdb/planner/expression_binder/select_binder.hpp +9 -38
  11. package/src/duckdb/src/include/duckdb/planner/expression_binder.hpp +1 -1
  12. package/src/duckdb/src/include/duckdb/planner/query_node/bound_select_node.hpp +8 -2
  13. package/src/duckdb/src/parser/tableref/pivotref.cpp +35 -11
  14. package/src/duckdb/src/parser/transform/statement/transform_pivot_stmt.cpp +10 -6
  15. package/src/duckdb/src/parser/transform/tableref/transform_pivot.cpp +19 -3
  16. package/src/duckdb/src/planner/binder/expression/bind_aggregate_expression.cpp +2 -2
  17. package/src/duckdb/src/planner/binder/expression/bind_function_expression.cpp +1 -8
  18. package/src/duckdb/src/planner/binder/expression/bind_unnest_expression.cpp +163 -24
  19. package/src/duckdb/src/planner/binder/expression/bind_window_expression.cpp +2 -2
  20. package/src/duckdb/src/planner/binder/query_node/bind_select_node.cpp +23 -3
  21. package/src/duckdb/src/planner/binder/query_node/plan_select_node.cpp +9 -3
  22. package/src/duckdb/src/planner/binder/tableref/bind_pivot.cpp +7 -7
  23. package/src/duckdb/src/planner/expression_binder/base_select_binder.cpp +146 -0
  24. package/src/duckdb/src/planner/expression_binder/having_binder.cpp +3 -3
  25. package/src/duckdb/src/planner/expression_binder/qualify_binder.cpp +3 -3
  26. package/src/duckdb/src/planner/expression_binder/select_binder.cpp +1 -132
  27. package/src/duckdb/src/planner/expression_binder.cpp +9 -2
  28. package/src/duckdb/src/planner/expression_iterator.cpp +12 -10
  29. package/src/duckdb/third_party/libpg_query/include/nodes/parsenodes.hpp +1 -0
  30. package/src/duckdb/third_party/libpg_query/src_backend_parser_gram.cpp +14579 -14017
  31. package/src/duckdb/ub_src_planner_expression_binder.cpp +2 -0
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "duckdb",
3
3
  "main": "./lib/duckdb.js",
4
4
  "types": "./lib/duckdb.d.ts",
5
- "version": "0.7.2-dev886.0",
5
+ "version": "0.7.2-dev899.0",
6
6
  "description": "DuckDB node.js API",
7
7
  "gypfile": true,
8
8
  "dependencies": {
@@ -96,7 +96,7 @@ static unique_ptr<FunctionData> StructExtractBind(ClientContext &context, Scalar
96
96
  }
97
97
 
98
98
  bound_function.return_type = return_type;
99
- return make_unique<StructExtractBindData>(key, key_index, return_type);
99
+ return make_unique<StructExtractBindData>(std::move(key), key_index, std::move(return_type));
100
100
  }
101
101
 
102
102
  static unique_ptr<BaseStatistics> PropagateStructExtractStats(ClientContext &context, FunctionStatisticsInput &input) {
@@ -1,8 +1,8 @@
1
1
  #ifndef DUCKDB_VERSION
2
- #define DUCKDB_VERSION "0.7.2-dev886"
2
+ #define DUCKDB_VERSION "0.7.2-dev899"
3
3
  #endif
4
4
  #ifndef DUCKDB_SOURCE_ID
5
- #define DUCKDB_SOURCE_ID "7d73c6e6a8"
5
+ #define DUCKDB_SOURCE_ID "88b1bfa74d"
6
6
  #endif
7
7
  #include "duckdb/function/table/system_functions.hpp"
8
8
  #include "duckdb/main/database.hpp"
@@ -30,8 +30,10 @@ struct PivotColumnEntry {
30
30
  };
31
31
 
32
32
  struct PivotColumn {
33
- //! The column names to (un)pivot
34
- vector<string> names;
33
+ //! The set of expressions to pivot on
34
+ vector<unique_ptr<ParsedExpression>> pivot_expressions;
35
+ //! The set of unpivot names
36
+ vector<string> unpivot_names;
35
37
  //! The set of values to pivot on
36
38
  vector<PivotColumnEntry> entries;
37
39
  //! The enum to read pivot values from (if any)
@@ -42,7 +42,7 @@ class Transformer {
42
42
  struct CreatePivotEntry {
43
43
  string enum_name;
44
44
  unique_ptr<SelectNode> base;
45
- string column_name;
45
+ unique_ptr<ParsedExpression> column;
46
46
  };
47
47
 
48
48
  public:
@@ -108,7 +108,7 @@ private:
108
108
  return parent ? parent->HasNamedParameters() : !named_param_map.empty();
109
109
  }
110
110
 
111
- void AddPivotEntry(string enum_name, unique_ptr<SelectNode> source, string column_name);
111
+ void AddPivotEntry(string enum_name, unique_ptr<SelectNode> source, unique_ptr<ParsedExpression> column);
112
112
  unique_ptr<SQLStatement> GenerateCreateEnumStmt(unique_ptr<CreatePivotEntry> entry);
113
113
  bool HasPivotEntries();
114
114
  idx_t PivotEntryCount();
@@ -73,7 +73,6 @@ struct CorrelatedColumnInfo {
73
73
  */
74
74
  class Binder : public std::enable_shared_from_this<Binder> {
75
75
  friend class ExpressionBinder;
76
- friend class SelectBinder;
77
76
  friend class RecursiveSubqueryPlanner;
78
77
 
79
78
  public:
@@ -185,6 +184,9 @@ public:
185
184
  BindingMode GetBindingMode();
186
185
  void AddTableName(string table_name);
187
186
  const unordered_set<string> &GetTableNames();
187
+ SQLStatement *GetRootStatement() {
188
+ return root_statement;
189
+ }
188
190
 
189
191
  void SetCanContainNulls(bool can_contain_nulls);
190
192
 
@@ -0,0 +1,64 @@
1
+ //===----------------------------------------------------------------------===//
2
+ // DuckDB
3
+ //
4
+ // duckdb/planner/expression_binder/base_select_binder.hpp
5
+ //
6
+ //
7
+ //===----------------------------------------------------------------------===//
8
+
9
+ #pragma once
10
+
11
+ #include "duckdb/common/case_insensitive_map.hpp"
12
+ #include "duckdb/parser/expression_map.hpp"
13
+ #include "duckdb/planner/expression_binder.hpp"
14
+
15
+ namespace duckdb {
16
+ class BoundColumnRefExpression;
17
+ class WindowExpression;
18
+
19
+ class BoundSelectNode;
20
+
21
+ struct BoundGroupInformation {
22
+ expression_map_t<idx_t> map;
23
+ case_insensitive_map_t<idx_t> alias_map;
24
+ };
25
+
26
+ //! The BaseSelectBinder is the base binder of the SELECT, HAVING and QUALIFY binders. It can bind aggregates and window
27
+ //! functions.
28
+ class BaseSelectBinder : public ExpressionBinder {
29
+ public:
30
+ BaseSelectBinder(Binder &binder, ClientContext &context, BoundSelectNode &node, BoundGroupInformation &info,
31
+ case_insensitive_map_t<idx_t> alias_map);
32
+ BaseSelectBinder(Binder &binder, ClientContext &context, BoundSelectNode &node, BoundGroupInformation &info);
33
+
34
+ bool BoundAggregates() {
35
+ return bound_aggregate;
36
+ }
37
+ void ResetBindings() {
38
+ this->bound_aggregate = false;
39
+ this->bound_columns.clear();
40
+ }
41
+
42
+ protected:
43
+ BindResult BindExpression(unique_ptr<ParsedExpression> *expr_ptr, idx_t depth,
44
+ bool root_expression = false) override;
45
+
46
+ BindResult BindAggregate(FunctionExpression &expr, AggregateFunctionCatalogEntry *function, idx_t depth) override;
47
+
48
+ bool inside_window;
49
+ bool bound_aggregate = false;
50
+
51
+ BoundSelectNode &node;
52
+ BoundGroupInformation &info;
53
+ case_insensitive_map_t<idx_t> alias_map;
54
+
55
+ protected:
56
+ BindResult BindColumnRef(unique_ptr<ParsedExpression> *expr_ptr, idx_t depth);
57
+ BindResult BindGroupingFunction(OperatorExpression &op, idx_t depth) override;
58
+ BindResult BindWindow(WindowExpression &expr, idx_t depth);
59
+
60
+ idx_t TryBindGroup(ParsedExpression &expr, idx_t depth);
61
+ BindResult BindGroup(ParsedExpression &expr, idx_t depth, idx_t group_index);
62
+ };
63
+
64
+ } // namespace duckdb
@@ -8,14 +8,14 @@
8
8
 
9
9
  #pragma once
10
10
 
11
- #include "duckdb/planner/expression_binder/select_binder.hpp"
11
+ #include "duckdb/planner/expression_binder/base_select_binder.hpp"
12
12
  #include "duckdb/planner/expression_binder/column_alias_binder.hpp"
13
13
  #include "duckdb/common/enums/aggregate_handling.hpp"
14
14
 
15
15
  namespace duckdb {
16
16
 
17
17
  //! The HAVING binder is responsible for binding an expression within the HAVING clause of a SQL statement
18
- class HavingBinder : public SelectBinder {
18
+ class HavingBinder : public BaseSelectBinder {
19
19
  public:
20
20
  HavingBinder(Binder &binder, ClientContext &context, BoundSelectNode &node, BoundGroupInformation &info,
21
21
  case_insensitive_map_t<idx_t> &alias_map, AggregateHandling aggregate_handling);
@@ -8,13 +8,13 @@
8
8
 
9
9
  #pragma once
10
10
 
11
- #include "duckdb/planner/expression_binder/select_binder.hpp"
11
+ #include "duckdb/planner/expression_binder/base_select_binder.hpp"
12
12
  #include "duckdb/planner/expression_binder/column_alias_binder.hpp"
13
13
 
14
14
  namespace duckdb {
15
15
 
16
16
  //! The QUALIFY binder is responsible for binding an expression within the QUALIFY clause of a SQL statement
17
- class QualifyBinder : public SelectBinder {
17
+ class QualifyBinder : public BaseSelectBinder {
18
18
  public:
19
19
  QualifyBinder(Binder &binder, ClientContext &context, BoundSelectNode &node, BoundGroupInformation &info,
20
20
  case_insensitive_map_t<idx_t> &alias_map);
@@ -8,58 +8,29 @@
8
8
 
9
9
  #pragma once
10
10
 
11
- #include "duckdb/common/case_insensitive_map.hpp"
12
- #include "duckdb/parser/expression_map.hpp"
13
- #include "duckdb/planner/expression_binder.hpp"
11
+ #include "duckdb/planner/expression_binder/base_select_binder.hpp"
14
12
 
15
13
  namespace duckdb {
16
- class BoundColumnRefExpression;
17
- class WindowExpression;
18
-
19
- class BoundSelectNode;
20
-
21
- struct BoundGroupInformation {
22
- expression_map_t<idx_t> map;
23
- case_insensitive_map_t<idx_t> alias_map;
24
- };
25
14
 
26
15
  //! The SELECT binder is responsible for binding an expression within the SELECT clause of a SQL statement
27
- class SelectBinder : public ExpressionBinder {
16
+ class SelectBinder : public BaseSelectBinder {
28
17
  public:
29
18
  SelectBinder(Binder &binder, ClientContext &context, BoundSelectNode &node, BoundGroupInformation &info,
30
19
  case_insensitive_map_t<idx_t> alias_map);
31
20
  SelectBinder(Binder &binder, ClientContext &context, BoundSelectNode &node, BoundGroupInformation &info);
32
21
 
33
- bool BoundAggregates() {
34
- return bound_aggregate;
22
+ bool HasExpandedExpressions() {
23
+ return !expanded_expressions.empty();
35
24
  }
36
- void ResetBindings() {
37
- this->bound_aggregate = false;
38
- this->bound_columns.clear();
25
+ vector<unique_ptr<Expression>> &ExpandedExpressions() {
26
+ return expanded_expressions;
39
27
  }
40
28
 
41
29
  protected:
42
- BindResult BindExpression(unique_ptr<ParsedExpression> *expr_ptr, idx_t depth,
43
- bool root_expression = false) override;
44
-
45
- BindResult BindAggregate(FunctionExpression &expr, AggregateFunctionCatalogEntry *function, idx_t depth) override;
46
-
47
- BindResult BindUnnest(FunctionExpression &function, idx_t depth) override;
48
-
49
- bool inside_window;
50
- bool bound_aggregate = false;
51
-
52
- BoundSelectNode &node;
53
- BoundGroupInformation &info;
54
- case_insensitive_map_t<idx_t> alias_map;
55
-
56
- protected:
57
- BindResult BindColumnRef(unique_ptr<ParsedExpression> *expr_ptr, idx_t depth);
58
- BindResult BindGroupingFunction(OperatorExpression &op, idx_t depth) override;
59
- BindResult BindWindow(WindowExpression &expr, idx_t depth);
30
+ BindResult BindUnnest(FunctionExpression &function, idx_t depth, bool root_expression) override;
60
31
 
61
- idx_t TryBindGroup(ParsedExpression &expr, idx_t depth);
62
- BindResult BindGroup(ParsedExpression &expr, idx_t depth, idx_t group_index);
32
+ idx_t unnest_level = 0;
33
+ vector<unique_ptr<Expression>> expanded_expressions;
63
34
  };
64
35
 
65
36
  } // namespace duckdb
@@ -135,7 +135,7 @@ protected:
135
135
  virtual BindResult BindFunction(FunctionExpression &expr, ScalarFunctionCatalogEntry *function, idx_t depth);
136
136
  virtual BindResult BindLambdaFunction(FunctionExpression &expr, ScalarFunctionCatalogEntry *function, idx_t depth);
137
137
  virtual BindResult BindAggregate(FunctionExpression &expr, AggregateFunctionCatalogEntry *function, idx_t depth);
138
- virtual BindResult BindUnnest(FunctionExpression &expr, idx_t depth);
138
+ virtual BindResult BindUnnest(FunctionExpression &expr, idx_t depth, bool root_expression);
139
139
  virtual BindResult BindMacro(FunctionExpression &expr, ScalarMacroCatalogEntry *macro, idx_t depth,
140
140
  unique_ptr<ParsedExpression> *expr_ptr);
141
141
 
@@ -25,6 +25,13 @@ public:
25
25
  vector<GroupingSet> grouping_sets;
26
26
  };
27
27
 
28
+ struct BoundUnnestNode {
29
+ //! The index of the UNNEST node
30
+ idx_t index;
31
+ //! The set of expressions
32
+ vector<unique_ptr<Expression>> expressions;
33
+ };
34
+
28
35
  //! Bound equivalent of SelectNode
29
36
  class BoundSelectNode : public BoundQueryNode {
30
37
  public:
@@ -78,9 +85,8 @@ public:
78
85
  //! Window functions to compute (only used if HasWindow is true)
79
86
  vector<unique_ptr<Expression>> windows;
80
87
 
81
- idx_t unnest_index;
82
88
  //! Unnest expression
83
- vector<unique_ptr<Expression>> unnests;
89
+ unordered_map<idx_t, BoundUnnestNode> unnests;
84
90
 
85
91
  //! Index of pruned node
86
92
  idx_t prune_index;
@@ -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,21 +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"
13
14
  #include "duckdb/parser/expression/function_expression.hpp"
14
15
  #include "duckdb/parser/result_modifier.hpp"
15
16
  #include "duckdb/parser/tableref/subqueryref.hpp"
16
17
 
17
18
  namespace duckdb {
18
19
 
19
- 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) {
20
21
  if (parent) {
21
- 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));
22
23
  return;
23
24
  }
24
25
  auto result = make_unique<CreatePivotEntry>();
25
26
  result->enum_name = std::move(enum_name);
26
27
  result->base = std::move(base);
27
- result->column_name = std::move(column_name);
28
+ result->column = std::move(column);
28
29
 
29
30
  pivot_entries.push_back(std::move(result));
30
31
  }
@@ -56,10 +57,13 @@ unique_ptr<SQLStatement> Transformer::GenerateCreateEnumStmt(unique_ptr<CreatePi
56
57
 
57
58
  // generate the query that will result in the enum creation
58
59
  auto select_node = std::move(entry->base);
59
- auto columnref = make_unique<ColumnRefExpression>(std::move(entry->column_name));
60
+ auto columnref = entry->column->Copy();
60
61
  auto cast = make_unique<CastExpression>(LogicalType::VARCHAR, columnref->Copy());
61
62
  select_node->select_list.push_back(std::move(cast));
62
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
+
63
67
  // order by the column
64
68
  auto modifier = make_unique<OrderModifier>();
65
69
  modifier->orders.emplace_back(OrderType::ASCENDING, OrderByNullType::ORDER_DEFAULT, std::move(columnref));
@@ -135,7 +139,7 @@ unique_ptr<QueryNode> Transformer::TransformPivotStatement(duckdb_libpgquery::PG
135
139
  if (!col.pivot_enum.empty() || !col.entries.empty()) {
136
140
  continue;
137
141
  }
138
- if (col.names.size() != 1) {
142
+ if (col.pivot_expressions.size() != 1) {
139
143
  throw InternalException("PIVOT statement with multiple names in pivot entry!?");
140
144
  }
141
145
  auto enum_name = "__pivot_enum_" + std::to_string(pivot_idx) + "_" + std::to_string(c);
@@ -143,7 +147,7 @@ unique_ptr<QueryNode> Transformer::TransformPivotStatement(duckdb_libpgquery::PG
143
147
  auto new_select = make_unique<SelectNode>();
144
148
  ExtractCTEsRecursive(new_select->cte_map);
145
149
  new_select->from_table = source->Copy();
146
- AddPivotEntry(enum_name, std::move(new_select), col.names[0]);
150
+ AddPivotEntry(enum_name, std::move(new_select), col.pivot_expressions[0]->Copy());
147
151
  col.pivot_enum = enum_name;
148
152
  }
149
153
 
@@ -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