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.
- package/package.json +1 -1
- package/src/duckdb/src/catalog/default/default_functions.cpp +3 -0
- package/src/duckdb/src/catalog/duck_catalog.cpp +34 -7
- package/src/duckdb/src/common/box_renderer.cpp +109 -23
- package/src/duckdb/src/function/scalar/struct/struct_extract.cpp +1 -1
- package/src/duckdb/src/function/table/version/pragma_version.cpp +2 -2
- package/src/duckdb/src/include/duckdb/catalog/duck_catalog.hpp +2 -1
- package/src/duckdb/src/include/duckdb/common/box_renderer.hpp +8 -2
- package/src/duckdb/src/include/duckdb/optimizer/filter_pushdown.hpp +2 -0
- package/src/duckdb/src/include/duckdb/parser/tableref/pivotref.hpp +4 -2
- package/src/duckdb/src/include/duckdb/parser/transformer.hpp +2 -2
- package/src/duckdb/src/include/duckdb/planner/binder.hpp +3 -1
- package/src/duckdb/src/include/duckdb/planner/expression_binder/base_select_binder.hpp +64 -0
- package/src/duckdb/src/include/duckdb/planner/expression_binder/having_binder.hpp +2 -2
- package/src/duckdb/src/include/duckdb/planner/expression_binder/qualify_binder.hpp +2 -2
- package/src/duckdb/src/include/duckdb/planner/expression_binder/select_binder.hpp +9 -38
- package/src/duckdb/src/include/duckdb/planner/expression_binder.hpp +1 -1
- package/src/duckdb/src/include/duckdb/planner/query_node/bound_select_node.hpp +8 -2
- package/src/duckdb/src/optimizer/filter_pushdown.cpp +11 -7
- package/src/duckdb/src/optimizer/pushdown/pushdown_left_join.cpp +1 -10
- package/src/duckdb/src/optimizer/pushdown/pushdown_mark_join.cpp +1 -1
- package/src/duckdb/src/optimizer/pushdown/pushdown_single_join.cpp +1 -1
- package/src/duckdb/src/parser/tableref/pivotref.cpp +35 -11
- package/src/duckdb/src/parser/transform/statement/transform_pivot_stmt.cpp +41 -12
- package/src/duckdb/src/parser/transform/tableref/transform_pivot.cpp +19 -3
- package/src/duckdb/src/planner/binder/expression/bind_aggregate_expression.cpp +2 -2
- package/src/duckdb/src/planner/binder/expression/bind_function_expression.cpp +1 -8
- package/src/duckdb/src/planner/binder/expression/bind_unnest_expression.cpp +163 -24
- package/src/duckdb/src/planner/binder/expression/bind_window_expression.cpp +2 -2
- package/src/duckdb/src/planner/binder/query_node/bind_select_node.cpp +23 -3
- package/src/duckdb/src/planner/binder/query_node/plan_select_node.cpp +9 -3
- package/src/duckdb/src/planner/binder/tableref/bind_pivot.cpp +8 -8
- package/src/duckdb/src/planner/expression_binder/base_select_binder.cpp +146 -0
- package/src/duckdb/src/planner/expression_binder/having_binder.cpp +3 -3
- package/src/duckdb/src/planner/expression_binder/qualify_binder.cpp +3 -3
- package/src/duckdb/src/planner/expression_binder/select_binder.cpp +1 -132
- package/src/duckdb/src/planner/expression_binder.cpp +9 -2
- package/src/duckdb/src/planner/expression_iterator.cpp +12 -10
- package/src/duckdb/third_party/libpg_query/include/nodes/parsenodes.hpp +1 -0
- package/src/duckdb/third_party/libpg_query/src_backend_parser_gram.cpp +11817 -11167
- 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
|
-
|
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
|
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
|
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 (
|
16
|
-
|
17
|
-
|
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 <
|
33
|
+
for (idx_t n = 0; n < pivot_expressions.size(); n++) {
|
20
34
|
if (n > 0) {
|
21
35
|
result += ", ";
|
22
36
|
}
|
23
|
-
result +=
|
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.
|
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
|
-
|
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.
|
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("
|
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.
|
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("
|
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,
|
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(
|
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->
|
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 =
|
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.
|
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.
|
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->
|
135
|
-
|
159
|
+
if (pivot->unpivots) {
|
160
|
+
pivot_ref->unpivot_names = TransformStringList(pivot->unpivots);
|
136
161
|
} else {
|
137
|
-
if (
|
138
|
-
|
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
|
-
|
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.
|
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.
|
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/
|
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
|
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
|
-
|
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
|
-
|
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 (
|
35
|
-
|
36
|
-
|
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
|
-
|
44
|
-
|
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
|
-
|
51
|
-
|
116
|
+
idx_t list_unnests;
|
117
|
+
idx_t struct_unnests = 0;
|
52
118
|
|
53
|
-
auto
|
54
|
-
|
55
|
-
|
56
|
-
|
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
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
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
|
-
|
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
|
122
|
+
BindResult BaseSelectBinder::BindWindow(WindowExpression &window, idx_t depth) {
|
123
123
|
auto name = window.GetName();
|
124
124
|
|
125
|
-
QueryErrorContext error_context(binder.
|
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 (
|
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
|
-
|
92
|
-
auto
|
93
|
-
|
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);
|