duckdb 0.7.2-dev402.0 → 0.7.2-dev457.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/extension/parquet/include/parquet_timestamp.hpp +0 -1
- package/src/duckdb/extension/parquet/parquet_timestamp.cpp +8 -6
- package/src/duckdb/src/execution/physical_plan/plan_aggregate.cpp +9 -1
- package/src/duckdb/src/execution/physical_plan/plan_distinct.cpp +5 -8
- package/src/duckdb/src/function/aggregate/distributive/bool.cpp +2 -0
- package/src/duckdb/src/function/aggregate/distributive/count.cpp +1 -0
- package/src/duckdb/src/function/aggregate/distributive/minmax.cpp +2 -0
- package/src/duckdb/src/function/aggregate/distributive/sum.cpp +8 -0
- package/src/duckdb/src/function/aggregate/holistic/quantile.cpp +15 -0
- package/src/duckdb/src/function/aggregate/sorted_aggregate_function.cpp +42 -11
- package/src/duckdb/src/function/function_binder.cpp +1 -8
- package/src/duckdb/src/function/scalar/date/current.cpp +0 -2
- package/src/duckdb/src/function/table/version/pragma_version.cpp +2 -2
- package/src/duckdb/src/include/duckdb/execution/physical_plan_generator.hpp +0 -3
- package/src/duckdb/src/include/duckdb/function/aggregate_function.hpp +6 -3
- package/src/duckdb/src/include/duckdb/function/function_binder.hpp +3 -6
- package/src/duckdb/src/include/duckdb/optimizer/rule/list.hpp +1 -0
- package/src/duckdb/src/include/duckdb/optimizer/rule/ordered_aggregate_optimizer.hpp +24 -0
- package/src/duckdb/src/include/duckdb/parser/expression/function_expression.hpp +2 -2
- package/src/duckdb/src/include/duckdb/parser/expression/star_expression.hpp +2 -2
- package/src/duckdb/src/include/duckdb/parser/transformer.hpp +2 -0
- package/src/duckdb/src/include/duckdb/planner/binder.hpp +4 -3
- package/src/duckdb/src/include/duckdb/planner/bound_result_modifier.hpp +3 -0
- package/src/duckdb/src/include/duckdb/planner/expression/bound_aggregate_expression.hpp +3 -0
- package/src/duckdb/src/include/duckdb/planner/expression_binder/order_binder.hpp +4 -1
- package/src/duckdb/src/include/duckdb/planner/operator/logical_distinct.hpp +3 -0
- package/src/duckdb/src/optimizer/optimizer.cpp +1 -0
- package/src/duckdb/src/optimizer/rule/ordered_aggregate_optimizer.cpp +30 -0
- package/src/duckdb/src/parser/expression/star_expression.cpp +6 -6
- package/src/duckdb/src/parser/parsed_expression_iterator.cpp +7 -1
- package/src/duckdb/src/parser/transform/expression/transform_columnref.cpp +17 -2
- package/src/duckdb/src/parser/transform/expression/transform_function.cpp +45 -40
- package/src/duckdb/src/parser/transform/helpers/transform_groupby.cpp +7 -0
- package/src/duckdb/src/parser/transform/helpers/transform_orderby.cpp +0 -7
- package/src/duckdb/src/planner/bind_context.cpp +2 -25
- package/src/duckdb/src/planner/binder/expression/bind_aggregate_expression.cpp +6 -4
- package/src/duckdb/src/planner/binder/expression/bind_lambda.cpp +3 -2
- package/src/duckdb/src/planner/binder/expression/bind_star_expression.cpp +176 -0
- package/src/duckdb/src/planner/binder/query_node/bind_select_node.cpp +57 -82
- package/src/duckdb/src/planner/binder/query_node/plan_query_node.cpp +11 -0
- package/src/duckdb/src/planner/binder/statement/bind_delete.cpp +1 -1
- package/src/duckdb/src/planner/binder/statement/bind_insert.cpp +2 -2
- package/src/duckdb/src/planner/binder/statement/bind_update.cpp +1 -1
- package/src/duckdb/src/planner/binder.cpp +12 -23
- package/src/duckdb/src/planner/bound_result_modifier.cpp +26 -0
- package/src/duckdb/src/planner/expression/bound_aggregate_expression.cpp +9 -2
- package/src/duckdb/src/planner/expression_iterator.cpp +5 -0
- package/src/duckdb/src/planner/logical_operator_visitor.cpp +5 -0
- package/src/duckdb/src/planner/operator/logical_distinct.cpp +3 -0
- package/src/duckdb/src/storage/storage_info.cpp +1 -1
- package/src/duckdb/third_party/libpg_query/include/nodes/parsenodes.hpp +1 -1
- package/src/duckdb/third_party/libpg_query/src_backend_parser_gram.cpp +8141 -8313
- package/src/duckdb/ub_src_optimizer_rule.cpp +2 -0
- package/src/duckdb/ub_src_planner_binder_expression.cpp +2 -0
@@ -32,10 +32,13 @@ public:
|
|
32
32
|
idx_t MaxCount() const {
|
33
33
|
return max_count;
|
34
34
|
}
|
35
|
-
|
36
35
|
bool HasExtraList() const {
|
37
36
|
return extra_list;
|
38
37
|
}
|
38
|
+
const vector<Binder *> &GetBinders() const {
|
39
|
+
return binders;
|
40
|
+
}
|
41
|
+
|
39
42
|
unique_ptr<Expression> CreateExtraReference(unique_ptr<ParsedExpression> expr);
|
40
43
|
|
41
44
|
private:
|
@@ -9,6 +9,7 @@
|
|
9
9
|
#pragma once
|
10
10
|
|
11
11
|
#include "duckdb/planner/logical_operator.hpp"
|
12
|
+
#include "duckdb/planner/bound_result_modifier.hpp"
|
12
13
|
|
13
14
|
namespace duckdb {
|
14
15
|
|
@@ -22,6 +23,8 @@ public:
|
|
22
23
|
}
|
23
24
|
//! The set of distinct targets (optional).
|
24
25
|
vector<unique_ptr<Expression>> distinct_targets;
|
26
|
+
//! The order by modifier (optional, only for distinct on)
|
27
|
+
unique_ptr<BoundOrderModifier> order_by;
|
25
28
|
|
26
29
|
public:
|
27
30
|
string ParamsToString() const override;
|
@@ -39,6 +39,7 @@ Optimizer::Optimizer(Binder &binder, ClientContext &context) : context(context),
|
|
39
39
|
rewriter.rules.push_back(make_unique<EqualOrNullSimplification>(rewriter));
|
40
40
|
rewriter.rules.push_back(make_unique<MoveConstantsRule>(rewriter));
|
41
41
|
rewriter.rules.push_back(make_unique<LikeOptimizationRule>(rewriter));
|
42
|
+
rewriter.rules.push_back(make_unique<OrderedAggregateOptimizer>(rewriter));
|
42
43
|
rewriter.rules.push_back(make_unique<RegexOptimizationRule>(rewriter));
|
43
44
|
rewriter.rules.push_back(make_unique<EmptyNeedleRemovalRule>(rewriter));
|
44
45
|
rewriter.rules.push_back(make_unique<EnumComparisonRule>(rewriter));
|
@@ -0,0 +1,30 @@
|
|
1
|
+
#include "duckdb/optimizer/rule/ordered_aggregate_optimizer.hpp"
|
2
|
+
|
3
|
+
#include "duckdb/optimizer/matcher/expression_matcher.hpp"
|
4
|
+
#include "duckdb/planner/expression/bound_aggregate_expression.hpp"
|
5
|
+
|
6
|
+
namespace duckdb {
|
7
|
+
|
8
|
+
OrderedAggregateOptimizer::OrderedAggregateOptimizer(ExpressionRewriter &rewriter) : Rule(rewriter) {
|
9
|
+
// we match on an OR expression within a LogicalFilter node
|
10
|
+
root = make_unique<ExpressionMatcher>();
|
11
|
+
root->expr_class = ExpressionClass::BOUND_AGGREGATE;
|
12
|
+
}
|
13
|
+
|
14
|
+
unique_ptr<Expression> OrderedAggregateOptimizer::Apply(LogicalOperator &op, vector<Expression *> &bindings,
|
15
|
+
bool &changes_made, bool is_root) {
|
16
|
+
auto aggr = (BoundAggregateExpression *)bindings[0];
|
17
|
+
if (!aggr->order_bys) {
|
18
|
+
// no ORDER BYs defined
|
19
|
+
return nullptr;
|
20
|
+
}
|
21
|
+
if (aggr->function.order_dependent == AggregateOrderDependent::NOT_ORDER_DEPENDENT) {
|
22
|
+
// not an order dependent aggregate but we have an ORDER BY clause - remove it
|
23
|
+
aggr->order_bys.reset();
|
24
|
+
changes_made = true;
|
25
|
+
return nullptr;
|
26
|
+
}
|
27
|
+
return nullptr;
|
28
|
+
}
|
29
|
+
|
30
|
+
} // namespace duckdb
|
@@ -10,9 +10,9 @@ StarExpression::StarExpression(string relation_name_p)
|
|
10
10
|
}
|
11
11
|
|
12
12
|
string StarExpression::ToString() const {
|
13
|
-
if (
|
13
|
+
if (expr) {
|
14
14
|
D_ASSERT(columns);
|
15
|
-
return "COLUMNS(
|
15
|
+
return "COLUMNS(" + expr->ToString() + ")";
|
16
16
|
}
|
17
17
|
string result;
|
18
18
|
if (columns) {
|
@@ -70,7 +70,7 @@ bool StarExpression::Equal(const StarExpression *a, const StarExpression *b) {
|
|
70
70
|
return false;
|
71
71
|
}
|
72
72
|
}
|
73
|
-
if (a->
|
73
|
+
if (!BaseExpression::Equals(a->expr.get(), b->expr.get())) {
|
74
74
|
return false;
|
75
75
|
}
|
76
76
|
return true;
|
@@ -93,7 +93,7 @@ void StarExpression::Serialize(FieldWriter &writer) const {
|
|
93
93
|
entry.second->Serialize(serializer);
|
94
94
|
}
|
95
95
|
writer.WriteField<bool>(columns);
|
96
|
-
writer.
|
96
|
+
writer.WriteOptional(expr);
|
97
97
|
}
|
98
98
|
|
99
99
|
unique_ptr<ParsedExpression> StarExpression::Deserialize(ExpressionType type, FieldReader &reader) {
|
@@ -112,7 +112,7 @@ unique_ptr<ParsedExpression> StarExpression::Deserialize(ExpressionType type, Fi
|
|
112
112
|
result->replace_list.insert(make_pair(name, std::move(expr)));
|
113
113
|
}
|
114
114
|
result->columns = reader.ReadField<bool>(false);
|
115
|
-
result->
|
115
|
+
result->expr = reader.ReadOptional<ParsedExpression>(nullptr);
|
116
116
|
return std::move(result);
|
117
117
|
}
|
118
118
|
|
@@ -123,7 +123,7 @@ unique_ptr<ParsedExpression> StarExpression::Copy() const {
|
|
123
123
|
copy->replace_list[entry.first] = entry.second->Copy();
|
124
124
|
}
|
125
125
|
copy->columns = columns;
|
126
|
-
copy->
|
126
|
+
copy->expr = expr ? expr->Copy() : nullptr;
|
127
127
|
copy->CopyProperties(*this);
|
128
128
|
return std::move(copy);
|
129
129
|
}
|
@@ -96,6 +96,13 @@ void ParsedExpressionIterator::EnumerateChildren(
|
|
96
96
|
}
|
97
97
|
break;
|
98
98
|
}
|
99
|
+
case ExpressionClass::STAR: {
|
100
|
+
auto &star_expr = (StarExpression &)expr;
|
101
|
+
if (star_expr.expr) {
|
102
|
+
callback(star_expr.expr);
|
103
|
+
}
|
104
|
+
break;
|
105
|
+
}
|
99
106
|
case ExpressionClass::SUBQUERY: {
|
100
107
|
auto &subquery_expr = (SubqueryExpression &)expr;
|
101
108
|
if (subquery_expr.child) {
|
@@ -135,7 +142,6 @@ void ParsedExpressionIterator::EnumerateChildren(
|
|
135
142
|
case ExpressionClass::COLUMN_REF:
|
136
143
|
case ExpressionClass::CONSTANT:
|
137
144
|
case ExpressionClass::DEFAULT:
|
138
|
-
case ExpressionClass::STAR:
|
139
145
|
case ExpressionClass::PARAMETER:
|
140
146
|
case ExpressionClass::POSITIONAL_REFERENCE:
|
141
147
|
// these node types have no children
|
@@ -1,5 +1,6 @@
|
|
1
1
|
#include "duckdb/common/exception.hpp"
|
2
2
|
#include "duckdb/parser/expression/columnref_expression.hpp"
|
3
|
+
#include "duckdb/parser/expression/function_expression.hpp"
|
3
4
|
#include "duckdb/parser/expression/star_expression.hpp"
|
4
5
|
#include "duckdb/parser/transformer.hpp"
|
5
6
|
|
@@ -36,13 +37,27 @@ unique_ptr<ParsedExpression> Transformer::TransformStarExpression(duckdb_libpgqu
|
|
36
37
|
result->replace_list.insert(make_pair(std::move(exclude_entry), std::move(replace_expression)));
|
37
38
|
}
|
38
39
|
}
|
39
|
-
if (star->
|
40
|
+
if (star->expr) {
|
41
|
+
D_ASSERT(star->columns);
|
40
42
|
D_ASSERT(result->relation_name.empty());
|
41
43
|
D_ASSERT(result->exclude_list.empty());
|
42
44
|
D_ASSERT(result->replace_list.empty());
|
43
|
-
result->
|
45
|
+
result->expr = TransformExpression(star->expr);
|
46
|
+
if (result->expr->type == ExpressionType::STAR) {
|
47
|
+
auto child_star = (StarExpression *)result->expr.get();
|
48
|
+
result->exclude_list = std::move(child_star->exclude_list);
|
49
|
+
result->replace_list = std::move(child_star->replace_list);
|
50
|
+
result->expr.reset();
|
51
|
+
} else if (result->expr->type == ExpressionType::LAMBDA) {
|
52
|
+
vector<unique_ptr<ParsedExpression>> children;
|
53
|
+
children.push_back(make_unique<StarExpression>());
|
54
|
+
children.push_back(std::move(result->expr));
|
55
|
+
auto list_filter = make_unique<FunctionExpression>("list_filter", std::move(children));
|
56
|
+
result->expr = std::move(list_filter);
|
57
|
+
}
|
44
58
|
}
|
45
59
|
result->columns = star->columns;
|
60
|
+
result->query_location = star->location;
|
46
61
|
return std::move(result);
|
47
62
|
}
|
48
63
|
|
@@ -94,6 +94,17 @@ void Transformer::TransformWindowFrame(duckdb_libpgquery::PGWindowDef *window_sp
|
|
94
94
|
}
|
95
95
|
}
|
96
96
|
|
97
|
+
bool Transformer::ExpressionIsEmptyStar(ParsedExpression &expr) {
|
98
|
+
if (expr.expression_class != ExpressionClass::STAR) {
|
99
|
+
return false;
|
100
|
+
}
|
101
|
+
auto &star = (StarExpression &)expr;
|
102
|
+
if (!star.columns && star.exclude_list.empty() && star.replace_list.empty()) {
|
103
|
+
return true;
|
104
|
+
}
|
105
|
+
return false;
|
106
|
+
}
|
107
|
+
|
97
108
|
unique_ptr<ParsedExpression> Transformer::TransformFuncCall(duckdb_libpgquery::PGFuncCall *root) {
|
98
109
|
auto name = root->funcname;
|
99
110
|
string catalog, schema, function_name;
|
@@ -116,8 +127,17 @@ unique_ptr<ParsedExpression> Transformer::TransformFuncCall(duckdb_libpgquery::P
|
|
116
127
|
throw InternalException("TransformFuncCall - Expected 1, 2 or 3 qualifications");
|
117
128
|
}
|
118
129
|
|
119
|
-
|
130
|
+
// transform children
|
131
|
+
vector<unique_ptr<ParsedExpression>> children;
|
132
|
+
if (root->args) {
|
133
|
+
TransformExpressionList(*root->args, children);
|
134
|
+
}
|
135
|
+
if (children.size() == 1 && ExpressionIsEmptyStar(*children[0]) && !root->agg_distinct && !root->agg_order) {
|
136
|
+
// COUNT(*) gets translated into COUNT()
|
137
|
+
children.clear();
|
138
|
+
}
|
120
139
|
|
140
|
+
auto lowercase_name = StringUtil::Lower(function_name);
|
121
141
|
if (root->over) {
|
122
142
|
const auto win_fun_type = WindowToExpressionType(lowercase_name);
|
123
143
|
if (win_fun_type == ExpressionType::INVALID) {
|
@@ -151,39 +171,32 @@ unique_ptr<ParsedExpression> Transformer::TransformFuncCall(duckdb_libpgquery::P
|
|
151
171
|
expr->filter_expr = std::move(filter_expr);
|
152
172
|
}
|
153
173
|
|
154
|
-
if (
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
174
|
+
if (win_fun_type == ExpressionType::WINDOW_AGGREGATE) {
|
175
|
+
expr->children = std::move(children);
|
176
|
+
} else {
|
177
|
+
if (!children.empty()) {
|
178
|
+
expr->children.push_back(std::move(children[0]));
|
179
|
+
}
|
180
|
+
if (win_fun_type == ExpressionType::WINDOW_LEAD || win_fun_type == ExpressionType::WINDOW_LAG) {
|
181
|
+
if (children.size() > 1) {
|
182
|
+
expr->offset_expr = std::move(children[1]);
|
161
183
|
}
|
162
|
-
|
163
|
-
|
164
|
-
|
184
|
+
if (children.size() > 2) {
|
185
|
+
expr->default_expr = std::move(children[2]);
|
186
|
+
}
|
187
|
+
if (children.size() > 3) {
|
188
|
+
throw ParserException("Incorrect number of parameters for function %s", lowercase_name);
|
189
|
+
}
|
190
|
+
} else if (win_fun_type == ExpressionType::WINDOW_NTH_VALUE) {
|
191
|
+
if (children.size() > 1) {
|
192
|
+
expr->children.push_back(std::move(children[1]));
|
165
193
|
}
|
166
|
-
if (
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
}
|
173
|
-
if (function_list.size() > 3) {
|
174
|
-
throw ParserException("Incorrect number of parameters for function %s", lowercase_name);
|
175
|
-
}
|
176
|
-
} else if (win_fun_type == ExpressionType::WINDOW_NTH_VALUE) {
|
177
|
-
if (function_list.size() > 1) {
|
178
|
-
expr->children.push_back(std::move(function_list[1]));
|
179
|
-
}
|
180
|
-
if (function_list.size() > 2) {
|
181
|
-
throw ParserException("Incorrect number of parameters for function %s", lowercase_name);
|
182
|
-
}
|
183
|
-
} else {
|
184
|
-
if (function_list.size() > 1) {
|
185
|
-
throw ParserException("Incorrect number of parameters for function %s", lowercase_name);
|
186
|
-
}
|
194
|
+
if (children.size() > 2) {
|
195
|
+
throw ParserException("Incorrect number of parameters for function %s", lowercase_name);
|
196
|
+
}
|
197
|
+
} else {
|
198
|
+
if (children.size() > 1) {
|
199
|
+
throw ParserException("Incorrect number of parameters for function %s", lowercase_name);
|
187
200
|
}
|
188
201
|
}
|
189
202
|
}
|
@@ -215,14 +228,6 @@ unique_ptr<ParsedExpression> Transformer::TransformFuncCall(duckdb_libpgquery::P
|
|
215
228
|
throw ParserException("IGNORE NULLS is not supported for non-window functions");
|
216
229
|
}
|
217
230
|
|
218
|
-
// TransformExpressionList??
|
219
|
-
vector<unique_ptr<ParsedExpression>> children;
|
220
|
-
if (root->args != nullptr) {
|
221
|
-
for (auto node = root->args->head; node != nullptr; node = node->next) {
|
222
|
-
auto child_expr = TransformExpression((duckdb_libpgquery::PGNode *)node->data.ptr_value);
|
223
|
-
children.push_back(std::move(child_expr));
|
224
|
-
}
|
225
|
-
}
|
226
231
|
unique_ptr<ParsedExpression> filter_expr;
|
227
232
|
if (root->agg_filter) {
|
228
233
|
filter_expr = TransformExpression(root->agg_filter);
|
@@ -176,6 +176,13 @@ bool Transformer::TransformGroupBy(duckdb_libpgquery::PGList *group, SelectNode
|
|
176
176
|
result.grouping_sets = std::move(new_sets);
|
177
177
|
}
|
178
178
|
}
|
179
|
+
if (result.group_expressions.size() == 1 && result.grouping_sets.size() == 1 &&
|
180
|
+
ExpressionIsEmptyStar(*result.group_expressions[0])) {
|
181
|
+
// GROUP BY *
|
182
|
+
result.group_expressions.clear();
|
183
|
+
result.grouping_sets.clear();
|
184
|
+
select_node.aggregate_handling = AggregateHandling::FORCE_AGGREGATES;
|
185
|
+
}
|
179
186
|
return true;
|
180
187
|
}
|
181
188
|
|
@@ -36,13 +36,6 @@ bool Transformer::TransformOrderBy(duckdb_libpgquery::PGList *order, vector<Orde
|
|
36
36
|
throw NotImplementedException("Unimplemented order by type");
|
37
37
|
}
|
38
38
|
auto order_expression = TransformExpression(target);
|
39
|
-
if (order_expression->GetExpressionClass() == ExpressionClass::STAR) {
|
40
|
-
auto &star_expr = (StarExpression &)*order_expression;
|
41
|
-
D_ASSERT(star_expr.relation_name.empty());
|
42
|
-
if (star_expr.columns) {
|
43
|
-
throw ParserException("COLUMNS expr is not supported in ORDER BY");
|
44
|
-
}
|
45
|
-
}
|
46
39
|
result.emplace_back(type, null_order, std::move(order_expression));
|
47
40
|
} else {
|
48
41
|
throw NotImplementedException("ORDER BY list member type %d\n", temp->type);
|
@@ -13,7 +13,7 @@
|
|
13
13
|
#include "duckdb/planner/bound_query_node.hpp"
|
14
14
|
#include "duckdb/planner/expression/bound_columnref_expression.hpp"
|
15
15
|
#include "duckdb/catalog/catalog_entry/table_catalog_entry.hpp"
|
16
|
-
#include "
|
16
|
+
#include "duckdb/planner/expression_binder/constant_binder.hpp"
|
17
17
|
|
18
18
|
#include <algorithm>
|
19
19
|
|
@@ -319,31 +319,15 @@ bool BindContext::CheckExclusionList(StarExpression &expr, Binding *binding, con
|
|
319
319
|
return false;
|
320
320
|
}
|
321
321
|
|
322
|
-
bool CheckRegex(const string &column_name, duckdb_re2::RE2 *regex) {
|
323
|
-
if (!regex) {
|
324
|
-
return true;
|
325
|
-
}
|
326
|
-
return RE2::PartialMatch(column_name, *regex);
|
327
|
-
}
|
328
|
-
|
329
322
|
void BindContext::GenerateAllColumnExpressions(StarExpression &expr,
|
330
323
|
vector<unique_ptr<ParsedExpression>> &new_select_list) {
|
331
324
|
if (bindings_list.empty()) {
|
332
|
-
throw BinderException("
|
325
|
+
throw BinderException("* expression without FROM clause!");
|
333
326
|
}
|
334
327
|
case_insensitive_set_t excluded_columns;
|
335
328
|
if (expr.relation_name.empty()) {
|
336
329
|
// SELECT * case
|
337
330
|
// bind all expressions of each table in-order
|
338
|
-
unique_ptr<duckdb_re2::RE2> regex;
|
339
|
-
bool found_match = true;
|
340
|
-
if (!expr.regex.empty()) {
|
341
|
-
regex = make_unique<duckdb_re2::RE2>(expr.regex);
|
342
|
-
if (!regex->error().empty()) {
|
343
|
-
throw BinderException("Failed to compile regex \"%s\": %s", expr.regex, regex->error());
|
344
|
-
}
|
345
|
-
found_match = false;
|
346
|
-
}
|
347
331
|
unordered_set<UsingColumnSet *> handled_using_columns;
|
348
332
|
for (auto &entry : bindings_list) {
|
349
333
|
auto binding = entry.second;
|
@@ -351,10 +335,6 @@ void BindContext::GenerateAllColumnExpressions(StarExpression &expr,
|
|
351
335
|
if (CheckExclusionList(expr, binding, column_name, new_select_list, excluded_columns)) {
|
352
336
|
continue;
|
353
337
|
}
|
354
|
-
if (!CheckRegex(column_name, regex.get())) {
|
355
|
-
continue;
|
356
|
-
}
|
357
|
-
found_match = true;
|
358
338
|
// check if this column is a USING column
|
359
339
|
auto using_binding = GetUsingBinding(column_name, binding->alias);
|
360
340
|
if (using_binding) {
|
@@ -384,9 +364,6 @@ void BindContext::GenerateAllColumnExpressions(StarExpression &expr,
|
|
384
364
|
new_select_list.push_back(make_unique<ColumnRefExpression>(column_name, binding->alias));
|
385
365
|
}
|
386
366
|
}
|
387
|
-
if (!found_match) {
|
388
|
-
throw BinderException("No matching columns found that match regex \"%s\"", expr.regex);
|
389
|
-
}
|
390
367
|
} else {
|
391
368
|
// SELECT tbl.* case
|
392
369
|
// SELECT struct.* case
|
@@ -208,8 +208,9 @@ BindResult SelectBinder::BindAggregate(FunctionExpression &aggr, AggregateFuncti
|
|
208
208
|
auto bound_function = func->functions.GetFunctionByOffset(best_function);
|
209
209
|
|
210
210
|
// Bind any sort columns, unless the aggregate is order-insensitive
|
211
|
-
|
211
|
+
unique_ptr<BoundOrderModifier> order_bys;
|
212
212
|
if (!aggr.order_bys->orders.empty()) {
|
213
|
+
order_bys = make_unique<BoundOrderModifier>();
|
213
214
|
auto &config = DBConfig::GetConfig(context);
|
214
215
|
for (auto &order : aggr.order_bys->orders) {
|
215
216
|
auto &order_expr = (BoundExpression &)*order.expression;
|
@@ -222,12 +223,13 @@ BindResult SelectBinder::BindAggregate(FunctionExpression &aggr, AggregateFuncti
|
|
222
223
|
}
|
223
224
|
}
|
224
225
|
|
225
|
-
auto aggregate =
|
226
|
-
bound_function, std::move(children), std::move(bound_filter),
|
227
|
-
|
226
|
+
auto aggregate =
|
227
|
+
function_binder.BindAggregateFunction(bound_function, std::move(children), std::move(bound_filter),
|
228
|
+
aggr.distinct ? AggregateType::DISTINCT : AggregateType::NON_DISTINCT);
|
228
229
|
if (aggr.export_state) {
|
229
230
|
aggregate = ExportAggregateFunction::Bind(std::move(aggregate));
|
230
231
|
}
|
232
|
+
aggregate->order_bys = std::move(order_bys);
|
231
233
|
|
232
234
|
// check for all the aggregates if this aggregate already exists
|
233
235
|
idx_t aggr_index;
|
@@ -48,7 +48,6 @@ BindResult ExpressionBinder::BindExpression(LambdaExpression &expr, idx_t depth,
|
|
48
48
|
|
49
49
|
// positional parameters as column references
|
50
50
|
for (idx_t i = 0; i < expr.params.size(); i++) {
|
51
|
-
|
52
51
|
if (expr.params[i]->GetExpressionClass() != ExpressionClass::COLUMN_REF) {
|
53
52
|
throw BinderException("Parameter must be a column name.");
|
54
53
|
}
|
@@ -80,7 +79,9 @@ BindResult ExpressionBinder::BindExpression(LambdaExpression &expr, idx_t depth,
|
|
80
79
|
// bind the parameter expressions
|
81
80
|
for (idx_t i = 0; i < expr.params.size(); i++) {
|
82
81
|
auto result = BindExpression(&expr.params[i], depth, false);
|
83
|
-
|
82
|
+
if (result.HasError()) {
|
83
|
+
throw InternalException("Error during lambda binding: %s", result.error);
|
84
|
+
}
|
84
85
|
}
|
85
86
|
|
86
87
|
auto result = BindExpression(&expr.expr, depth, false);
|
@@ -0,0 +1,176 @@
|
|
1
|
+
#include "duckdb/planner/binder.hpp"
|
2
|
+
#include "duckdb/parser/expression/star_expression.hpp"
|
3
|
+
#include "duckdb/parser/expression/constant_expression.hpp"
|
4
|
+
#include "duckdb/planner/expression_binder/table_function_binder.hpp"
|
5
|
+
#include "duckdb/parser/parsed_expression_iterator.hpp"
|
6
|
+
#include "duckdb/execution/expression_executor.hpp"
|
7
|
+
#include "re2/re2.h"
|
8
|
+
|
9
|
+
namespace duckdb {
|
10
|
+
|
11
|
+
bool Binder::FindStarExpression(unique_ptr<ParsedExpression> &expr, StarExpression **star, bool is_root,
|
12
|
+
bool in_columns) {
|
13
|
+
bool has_star = false;
|
14
|
+
if (expr->GetExpressionClass() == ExpressionClass::STAR) {
|
15
|
+
auto current_star = (StarExpression *)expr.get();
|
16
|
+
if (!current_star->columns) {
|
17
|
+
if (is_root) {
|
18
|
+
*star = current_star;
|
19
|
+
return true;
|
20
|
+
}
|
21
|
+
if (!in_columns) {
|
22
|
+
throw BinderException(
|
23
|
+
"STAR expression is only allowed as the root element of an expression. Use COLUMNS(*) instead.");
|
24
|
+
}
|
25
|
+
// star expression inside a COLUMNS - convert to a constant list
|
26
|
+
if (!current_star->replace_list.empty()) {
|
27
|
+
throw BinderException(
|
28
|
+
"STAR expression with REPLACE list is only allowed as the root element of COLUMNS");
|
29
|
+
}
|
30
|
+
vector<unique_ptr<ParsedExpression>> star_list;
|
31
|
+
bind_context.GenerateAllColumnExpressions(*current_star, star_list);
|
32
|
+
|
33
|
+
vector<Value> values;
|
34
|
+
values.reserve(star_list.size());
|
35
|
+
for (auto &expr : star_list) {
|
36
|
+
values.emplace_back(expr->ToString());
|
37
|
+
}
|
38
|
+
D_ASSERT(!values.empty());
|
39
|
+
|
40
|
+
expr = make_unique<ConstantExpression>(Value::LIST(LogicalType::VARCHAR, values));
|
41
|
+
return true;
|
42
|
+
}
|
43
|
+
if (in_columns) {
|
44
|
+
throw BinderException("COLUMNS expression is not allowed inside another COLUMNS expression");
|
45
|
+
}
|
46
|
+
in_columns = true;
|
47
|
+
if (*star) {
|
48
|
+
// we can have multiple
|
49
|
+
if (!StarExpression::Equal(*star, current_star)) {
|
50
|
+
throw BinderException(
|
51
|
+
FormatError(*expr, "Multiple different STAR/COLUMNS in the same expression are not supported"));
|
52
|
+
}
|
53
|
+
return true;
|
54
|
+
}
|
55
|
+
*star = current_star;
|
56
|
+
has_star = true;
|
57
|
+
}
|
58
|
+
ParsedExpressionIterator::EnumerateChildren(*expr, [&](unique_ptr<ParsedExpression> &child_expr) {
|
59
|
+
if (FindStarExpression(child_expr, star, false, in_columns)) {
|
60
|
+
has_star = true;
|
61
|
+
}
|
62
|
+
});
|
63
|
+
return has_star;
|
64
|
+
}
|
65
|
+
|
66
|
+
void Binder::ReplaceStarExpression(unique_ptr<ParsedExpression> &expr, unique_ptr<ParsedExpression> &replacement) {
|
67
|
+
D_ASSERT(expr);
|
68
|
+
if (expr->GetExpressionClass() == ExpressionClass::STAR) {
|
69
|
+
D_ASSERT(replacement);
|
70
|
+
expr = replacement->Copy();
|
71
|
+
return;
|
72
|
+
}
|
73
|
+
ParsedExpressionIterator::EnumerateChildren(
|
74
|
+
*expr, [&](unique_ptr<ParsedExpression> &child_expr) { ReplaceStarExpression(child_expr, replacement); });
|
75
|
+
}
|
76
|
+
|
77
|
+
void Binder::ExpandStarExpression(unique_ptr<ParsedExpression> expr,
|
78
|
+
vector<unique_ptr<ParsedExpression>> &new_select_list) {
|
79
|
+
StarExpression *star = nullptr;
|
80
|
+
if (!FindStarExpression(expr, &star, true, false)) {
|
81
|
+
// no star expression: add it as-is
|
82
|
+
D_ASSERT(!star);
|
83
|
+
new_select_list.push_back(std::move(expr));
|
84
|
+
return;
|
85
|
+
}
|
86
|
+
D_ASSERT(star);
|
87
|
+
vector<unique_ptr<ParsedExpression>> star_list;
|
88
|
+
// we have star expressions! expand the list of star expressions
|
89
|
+
bind_context.GenerateAllColumnExpressions(*star, star_list);
|
90
|
+
|
91
|
+
if (star->expr) {
|
92
|
+
// COLUMNS with an expression
|
93
|
+
// two options:
|
94
|
+
// VARCHAR parameter <- this is a regular expression
|
95
|
+
// LIST of VARCHAR parameters <- this is a set of columns
|
96
|
+
TableFunctionBinder binder(*this, context);
|
97
|
+
auto child = star->expr->Copy();
|
98
|
+
auto result = binder.Bind(child);
|
99
|
+
if (!result->IsFoldable()) {
|
100
|
+
// cannot resolve parameters here
|
101
|
+
if (star->expr->HasParameter()) {
|
102
|
+
throw ParameterNotResolvedException();
|
103
|
+
} else {
|
104
|
+
throw BinderException("Unsupported expression in COLUMNS");
|
105
|
+
}
|
106
|
+
}
|
107
|
+
auto val = ExpressionExecutor::EvaluateScalar(context, *result);
|
108
|
+
if (val.type().id() == LogicalTypeId::VARCHAR) {
|
109
|
+
// regex
|
110
|
+
if (val.IsNull()) {
|
111
|
+
throw BinderException("COLUMNS does not support NULL as regex argument");
|
112
|
+
}
|
113
|
+
auto ®ex_str = StringValue::Get(val);
|
114
|
+
duckdb_re2::RE2 regex(regex_str);
|
115
|
+
if (!regex.error().empty()) {
|
116
|
+
auto err = StringUtil::Format("Failed to compile regex \"%s\": %s", regex_str, regex.error());
|
117
|
+
throw BinderException(FormatError(*star, err));
|
118
|
+
}
|
119
|
+
vector<unique_ptr<ParsedExpression>> new_list;
|
120
|
+
for (idx_t i = 0; i < star_list.size(); i++) {
|
121
|
+
auto &colref = (ColumnRefExpression &)*star_list[i];
|
122
|
+
if (!RE2::PartialMatch(colref.GetColumnName(), regex)) {
|
123
|
+
continue;
|
124
|
+
}
|
125
|
+
new_list.push_back(std::move(star_list[i]));
|
126
|
+
}
|
127
|
+
if (new_list.empty()) {
|
128
|
+
auto err = StringUtil::Format("No matching columns found that match regex \"%s\"", regex_str);
|
129
|
+
throw BinderException(FormatError(*star, err));
|
130
|
+
}
|
131
|
+
star_list = std::move(new_list);
|
132
|
+
} else if (val.type().id() == LogicalTypeId::LIST &&
|
133
|
+
ListType::GetChildType(val.type()).id() == LogicalTypeId::VARCHAR) {
|
134
|
+
// list of varchar columns
|
135
|
+
if (val.IsNull() || ListValue::GetChildren(val).empty()) {
|
136
|
+
auto err =
|
137
|
+
StringUtil::Format("Star expression \"%s\" resulted in an empty set of columns", star->ToString());
|
138
|
+
throw BinderException(FormatError(*star, err));
|
139
|
+
}
|
140
|
+
auto &children = ListValue::GetChildren(val);
|
141
|
+
vector<unique_ptr<ParsedExpression>> new_list;
|
142
|
+
for (auto &child : children) {
|
143
|
+
auto qname = QualifiedName::Parse(StringValue::Get(child));
|
144
|
+
vector<string> names;
|
145
|
+
if (!qname.catalog.empty()) {
|
146
|
+
names.push_back(qname.catalog);
|
147
|
+
}
|
148
|
+
if (!qname.schema.empty()) {
|
149
|
+
names.push_back(qname.schema);
|
150
|
+
}
|
151
|
+
names.push_back(qname.name);
|
152
|
+
new_list.push_back(make_unique<ColumnRefExpression>(std::move(names)));
|
153
|
+
}
|
154
|
+
star_list = std::move(new_list);
|
155
|
+
} else {
|
156
|
+
throw BinderException(FormatError(
|
157
|
+
*star, "COLUMNS expects either a VARCHAR argument (regex) or a LIST of VARCHAR (list of columns)"));
|
158
|
+
}
|
159
|
+
}
|
160
|
+
|
161
|
+
// now perform the replacement
|
162
|
+
for (idx_t i = 0; i < star_list.size(); i++) {
|
163
|
+
auto new_expr = expr->Copy();
|
164
|
+
ReplaceStarExpression(new_expr, star_list[i]);
|
165
|
+
new_select_list.push_back(std::move(new_expr));
|
166
|
+
}
|
167
|
+
}
|
168
|
+
|
169
|
+
void Binder::ExpandStarExpressions(vector<unique_ptr<ParsedExpression>> &select_list,
|
170
|
+
vector<unique_ptr<ParsedExpression>> &new_select_list) {
|
171
|
+
for (auto &select_element : select_list) {
|
172
|
+
ExpandStarExpression(std::move(select_element), new_select_list);
|
173
|
+
}
|
174
|
+
}
|
175
|
+
|
176
|
+
} // namespace duckdb
|