duckdb 0.7.2-dev904.0 → 0.7.2-dev982.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/common/enums/logical_operator_type.cpp +2 -0
- package/src/duckdb/src/common/serializer/enum_serializer.cpp +4 -0
- package/src/duckdb/src/common/types/value.cpp +46 -0
- package/src/duckdb/src/execution/column_binding_resolver.cpp +15 -5
- package/src/duckdb/src/execution/operator/join/physical_blockwise_nl_join.cpp +40 -19
- package/src/duckdb/src/execution/operator/join/physical_range_join.cpp +2 -0
- package/src/duckdb/src/execution/operator/persistent/base_csv_reader.cpp +3 -3
- package/src/duckdb/src/execution/operator/persistent/buffered_csv_reader.cpp +5 -13
- package/src/duckdb/src/execution/operator/projection/physical_projection.cpp +34 -0
- package/src/duckdb/src/execution/physical_plan/plan_asof_join.cpp +97 -0
- package/src/duckdb/src/execution/physical_plan_generator.cpp +3 -0
- package/src/duckdb/src/function/scalar/math/numeric.cpp +87 -0
- package/src/duckdb/src/function/scalar/math_functions.cpp +3 -0
- package/src/duckdb/src/function/scalar/string/hex.cpp +201 -0
- package/src/duckdb/src/function/scalar/string_functions.cpp +1 -0
- package/src/duckdb/src/function/table/read_csv.cpp +46 -0
- package/src/duckdb/src/function/table/version/pragma_version.cpp +2 -2
- package/src/duckdb/src/include/duckdb/common/enums/joinref_type.hpp +5 -4
- package/src/duckdb/src/include/duckdb/common/enums/logical_operator_type.hpp +1 -0
- package/src/duckdb/src/include/duckdb/common/string_util.hpp +13 -0
- package/src/duckdb/src/include/duckdb/common/types/value.hpp +11 -7
- package/src/duckdb/src/include/duckdb/common/vector_operations/unary_executor.hpp +2 -2
- package/src/duckdb/src/include/duckdb/execution/operator/join/physical_cross_product.hpp +2 -0
- package/src/duckdb/src/include/duckdb/execution/operator/persistent/csv_reader_options.hpp +6 -0
- package/src/duckdb/src/include/duckdb/execution/operator/projection/physical_projection.hpp +5 -0
- package/src/duckdb/src/include/duckdb/execution/physical_plan_generator.hpp +1 -0
- package/src/duckdb/src/include/duckdb/function/scalar/math_functions.hpp +8 -0
- package/src/duckdb/src/include/duckdb/function/scalar/string_functions.hpp +4 -0
- package/src/duckdb/src/include/duckdb/planner/logical_tokens.hpp +1 -0
- package/src/duckdb/src/include/duckdb/planner/operator/list.hpp +1 -0
- package/src/duckdb/src/include/duckdb/planner/operator/logical_asof_join.hpp +22 -0
- package/src/duckdb/src/include/duckdb/planner/operator/logical_comparison_join.hpp +5 -2
- package/src/duckdb/src/include/duckdb.h +1 -1
- package/src/duckdb/src/optimizer/column_lifetime_analyzer.cpp +1 -0
- package/src/duckdb/src/optimizer/filter_pullup.cpp +3 -1
- package/src/duckdb/src/optimizer/filter_pushdown.cpp +3 -1
- package/src/duckdb/src/optimizer/join_order/cardinality_estimator.cpp +4 -0
- package/src/duckdb/src/optimizer/join_order/join_order_optimizer.cpp +8 -4
- package/src/duckdb/src/optimizer/pullup/pullup_from_left.cpp +2 -2
- package/src/duckdb/src/optimizer/pushdown/pushdown_cross_product.cpp +1 -1
- package/src/duckdb/src/optimizer/pushdown/pushdown_inner_join.cpp +3 -0
- package/src/duckdb/src/optimizer/pushdown/pushdown_left_join.cpp +4 -2
- package/src/duckdb/src/optimizer/pushdown/pushdown_mark_join.cpp +1 -1
- package/src/duckdb/src/optimizer/remove_unused_columns.cpp +1 -0
- package/src/duckdb/src/optimizer/statistics/operator/propagate_join.cpp +1 -0
- package/src/duckdb/src/optimizer/statistics_propagator.cpp +1 -0
- package/src/duckdb/src/parser/tableref/joinref.cpp +4 -0
- package/src/duckdb/src/parser/transform/tableref/transform_join.cpp +8 -1
- package/src/duckdb/src/planner/binder/tableref/bind_joinref.cpp +10 -3
- package/src/duckdb/src/planner/binder/tableref/plan_joinref.cpp +60 -12
- package/src/duckdb/src/planner/logical_operator.cpp +3 -0
- package/src/duckdb/src/planner/logical_operator_visitor.cpp +1 -0
- package/src/duckdb/src/planner/operator/logical_asof_join.cpp +8 -0
- package/src/duckdb/src/planner/subquery/flatten_dependent_join.cpp +3 -1
- package/src/duckdb/third_party/libpg_query/include/nodes/nodes.hpp +32 -0
- package/src/duckdb/third_party/libpg_query/include/nodes/primnodes.hpp +3 -3
- package/src/duckdb/third_party/libpg_query/include/parser/gram.hpp +915 -913
- package/src/duckdb/third_party/libpg_query/include/parser/kwlist.hpp +1 -0
- package/src/duckdb/third_party/libpg_query/src_backend_parser_gram.cpp +17371 -17306
- package/src/duckdb/ub_src_execution_physical_plan.cpp +2 -0
- package/src/duckdb/ub_src_function_scalar_string.cpp +2 -0
- package/src/duckdb/ub_src_planner_operator.cpp +2 -0
@@ -113,7 +113,7 @@ bool JoinOrderOptimizer::ExtractJoinRelations(LogicalOperator &input_op, vector<
|
|
113
113
|
bool non_reorderable_operation = false;
|
114
114
|
if (op->type == LogicalOperatorType::LOGICAL_UNION || op->type == LogicalOperatorType::LOGICAL_EXCEPT ||
|
115
115
|
op->type == LogicalOperatorType::LOGICAL_INTERSECT || op->type == LogicalOperatorType::LOGICAL_DELIM_JOIN ||
|
116
|
-
op->type == LogicalOperatorType::LOGICAL_ANY_JOIN) {
|
116
|
+
op->type == LogicalOperatorType::LOGICAL_ANY_JOIN || op->type == LogicalOperatorType::LOGICAL_ASOF_JOIN) {
|
117
117
|
// set operation, optimize separately in children
|
118
118
|
non_reorderable_operation = true;
|
119
119
|
}
|
@@ -184,6 +184,7 @@ bool JoinOrderOptimizer::ExtractJoinRelations(LogicalOperator &input_op, vector<
|
|
184
184
|
}
|
185
185
|
|
186
186
|
switch (op->type) {
|
187
|
+
case LogicalOperatorType::LOGICAL_ASOF_JOIN:
|
187
188
|
case LogicalOperatorType::LOGICAL_COMPARISON_JOIN:
|
188
189
|
case LogicalOperatorType::LOGICAL_CROSS_PRODUCT: {
|
189
190
|
// inner join or cross product
|
@@ -866,7 +867,8 @@ JoinOrderOptimizer::GenerateJoins(vector<unique_ptr<LogicalOperator>> &extracted
|
|
866
867
|
result_operator->children[0] = std::move(comp_join);
|
867
868
|
}
|
868
869
|
} else {
|
869
|
-
D_ASSERT(node->type == LogicalOperatorType::LOGICAL_COMPARISON_JOIN
|
870
|
+
D_ASSERT(node->type == LogicalOperatorType::LOGICAL_COMPARISON_JOIN ||
|
871
|
+
node->type == LogicalOperatorType::LOGICAL_ASOF_JOIN);
|
870
872
|
auto &comp_join = (LogicalComparisonJoin &)*node;
|
871
873
|
comp_join.conditions.push_back(std::move(cond));
|
872
874
|
}
|
@@ -908,7 +910,8 @@ unique_ptr<LogicalOperator> JoinOrderOptimizer::RewritePlan(unique_ptr<LogicalOp
|
|
908
910
|
auto op = plan.get();
|
909
911
|
auto parent = plan.get();
|
910
912
|
while (op->type != LogicalOperatorType::LOGICAL_CROSS_PRODUCT &&
|
911
|
-
op->type != LogicalOperatorType::LOGICAL_COMPARISON_JOIN
|
913
|
+
op->type != LogicalOperatorType::LOGICAL_COMPARISON_JOIN &&
|
914
|
+
op->type != LogicalOperatorType::LOGICAL_ASOF_JOIN) {
|
912
915
|
D_ASSERT(op->children.size() == 1);
|
913
916
|
parent = op;
|
914
917
|
op = op->children[0].get();
|
@@ -943,7 +946,8 @@ unique_ptr<LogicalOperator> JoinOrderOptimizer::Optimize(unique_ptr<LogicalOpera
|
|
943
946
|
// filters in the process
|
944
947
|
expression_set_t filter_set;
|
945
948
|
for (auto &f_op : filter_operators) {
|
946
|
-
if (f_op->type == LogicalOperatorType::LOGICAL_COMPARISON_JOIN
|
949
|
+
if (f_op->type == LogicalOperatorType::LOGICAL_COMPARISON_JOIN ||
|
950
|
+
f_op->type == LogicalOperatorType::LOGICAL_ASOF_JOIN) {
|
947
951
|
auto &join = (LogicalComparisonJoin &)*f_op;
|
948
952
|
D_ASSERT(join.join_type == JoinType::INNER);
|
949
953
|
D_ASSERT(join.expressions.empty());
|
@@ -6,8 +6,8 @@ namespace duckdb {
|
|
6
6
|
|
7
7
|
unique_ptr<LogicalOperator> FilterPullup::PullupFromLeft(unique_ptr<LogicalOperator> op) {
|
8
8
|
D_ASSERT(op->type == LogicalOperatorType::LOGICAL_COMPARISON_JOIN ||
|
9
|
-
op->type == LogicalOperatorType::
|
10
|
-
op->type == LogicalOperatorType::LOGICAL_DELIM_JOIN);
|
9
|
+
op->type == LogicalOperatorType::LOGICAL_ASOF_JOIN || op->type == LogicalOperatorType::LOGICAL_ANY_JOIN ||
|
10
|
+
op->type == LogicalOperatorType::LOGICAL_EXCEPT || op->type == LogicalOperatorType::LOGICAL_DELIM_JOIN);
|
11
11
|
|
12
12
|
FilterPullup left_pullup(true, can_add_column);
|
13
13
|
FilterPullup right_pullup(false, can_add_column);
|
@@ -46,7 +46,7 @@ unique_ptr<LogicalOperator> FilterPushdown::PushdownCrossProduct(unique_ptr<Logi
|
|
46
46
|
right_bindings, join_expressions, conditions,
|
47
47
|
arbitrary_expressions);
|
48
48
|
// create the join from the join conditions
|
49
|
-
return LogicalComparisonJoin::CreateJoin(JoinType::INNER, std::move(op->children[0]),
|
49
|
+
return LogicalComparisonJoin::CreateJoin(JoinType::INNER, JoinRefType::REGULAR, std::move(op->children[0]),
|
50
50
|
std::move(op->children[1]), std::move(conditions),
|
51
51
|
std::move(arbitrary_expressions));
|
52
52
|
} else {
|
@@ -24,6 +24,9 @@ unique_ptr<LogicalOperator> FilterPushdown::PushdownInnerJoin(unique_ptr<Logical
|
|
24
24
|
// filter statically evaluates to false, strip tree
|
25
25
|
return make_unique<LogicalEmptyResult>(std::move(op));
|
26
26
|
}
|
27
|
+
} else if (op->type == LogicalOperatorType::LOGICAL_ASOF_JOIN) {
|
28
|
+
// Don't mess with non-standard condition interpretations
|
29
|
+
return FinishPushdown(std::move(op));
|
27
30
|
} else {
|
28
31
|
// comparison join
|
29
32
|
D_ASSERT(op->type == LogicalOperatorType::LOGICAL_COMPARISON_JOIN);
|
@@ -68,7 +68,9 @@ unique_ptr<LogicalOperator> FilterPushdown::PushdownLeftJoin(unique_ptr<LogicalO
|
|
68
68
|
// for a comparison join we create a FilterCombiner that checks if we can push conditions on LHS join conditions
|
69
69
|
// into the RHS of the join
|
70
70
|
FilterCombiner filter_combiner(optimizer);
|
71
|
-
|
71
|
+
const auto isComparison = (op->type == LogicalOperatorType::LOGICAL_COMPARISON_JOIN ||
|
72
|
+
op->type == LogicalOperatorType::LOGICAL_ASOF_JOIN);
|
73
|
+
if (isComparison) {
|
72
74
|
// add all comparison conditions
|
73
75
|
auto &comparison_join = (LogicalComparisonJoin &)*op;
|
74
76
|
for (auto &cond : comparison_join.conditions) {
|
@@ -82,7 +84,7 @@ unique_ptr<LogicalOperator> FilterPushdown::PushdownLeftJoin(unique_ptr<LogicalO
|
|
82
84
|
if (side == JoinSide::LEFT) {
|
83
85
|
// bindings match left side
|
84
86
|
// we can push the filter into the left side
|
85
|
-
if (
|
87
|
+
if (isComparison) {
|
86
88
|
// we MIGHT be able to push it down the RHS as well, but only if it is a comparison that matches the
|
87
89
|
// join predicates we use the FilterCombiner to figure this out add the expression to the FilterCombiner
|
88
90
|
filter_combiner.AddFilter(filters[i]->filter->Copy());
|
@@ -13,7 +13,7 @@ unique_ptr<LogicalOperator> FilterPushdown::PushdownMarkJoin(unique_ptr<LogicalO
|
|
13
13
|
auto &comp_join = (LogicalComparisonJoin &)*op;
|
14
14
|
D_ASSERT(join.join_type == JoinType::MARK);
|
15
15
|
D_ASSERT(op->type == LogicalOperatorType::LOGICAL_COMPARISON_JOIN ||
|
16
|
-
op->type == LogicalOperatorType::LOGICAL_DELIM_JOIN);
|
16
|
+
op->type == LogicalOperatorType::LOGICAL_DELIM_JOIN || op->type == LogicalOperatorType::LOGICAL_ASOF_JOIN);
|
17
17
|
|
18
18
|
right_bindings.insert(comp_join.mark_index);
|
19
19
|
FilterPushdown left_pushdown(optimizer), right_pushdown(optimizer);
|
@@ -71,6 +71,7 @@ void RemoveUnusedColumns::VisitOperator(LogicalOperator &op) {
|
|
71
71
|
remove.VisitOperator(*op.children[0]);
|
72
72
|
return;
|
73
73
|
}
|
74
|
+
case LogicalOperatorType::LOGICAL_ASOF_JOIN:
|
74
75
|
case LogicalOperatorType::LOGICAL_DELIM_JOIN:
|
75
76
|
case LogicalOperatorType::LOGICAL_COMPARISON_JOIN: {
|
76
77
|
if (!everything_referenced) {
|
@@ -195,6 +195,7 @@ unique_ptr<NodeStatistics> StatisticsPropagator::PropagateStatistics(LogicalJoin
|
|
195
195
|
switch (join.type) {
|
196
196
|
case LogicalOperatorType::LOGICAL_COMPARISON_JOIN:
|
197
197
|
case LogicalOperatorType::LOGICAL_DELIM_JOIN:
|
198
|
+
case LogicalOperatorType::LOGICAL_ASOF_JOIN:
|
198
199
|
PropagateStatistics((LogicalComparisonJoin &)join, node_ptr);
|
199
200
|
break;
|
200
201
|
case LogicalOperatorType::LOGICAL_ANY_JOIN:
|
@@ -36,6 +36,7 @@ unique_ptr<NodeStatistics> StatisticsPropagator::PropagateStatistics(LogicalOper
|
|
36
36
|
case LogicalOperatorType::LOGICAL_PROJECTION:
|
37
37
|
return PropagateStatistics((LogicalProjection &)node, node_ptr);
|
38
38
|
case LogicalOperatorType::LOGICAL_ANY_JOIN:
|
39
|
+
case LogicalOperatorType::LOGICAL_ASOF_JOIN:
|
39
40
|
case LogicalOperatorType::LOGICAL_COMPARISON_JOIN:
|
40
41
|
case LogicalOperatorType::LOGICAL_JOIN:
|
41
42
|
case LogicalOperatorType::LOGICAL_DELIM_JOIN:
|
@@ -18,6 +18,10 @@ string JoinRef::ToString() const {
|
|
18
18
|
result += "NATURAL ";
|
19
19
|
result += JoinTypeToString(type) + " JOIN ";
|
20
20
|
break;
|
21
|
+
case JoinRefType::ASOF:
|
22
|
+
result += "ASOF ";
|
23
|
+
result += JoinTypeToString(type) + " JOIN ";
|
24
|
+
break;
|
21
25
|
case JoinRefType::CROSS:
|
22
26
|
result += ", ";
|
23
27
|
break;
|
@@ -44,8 +44,15 @@ unique_ptr<TableRef> Transformer::TransformJoin(duckdb_libpgquery::PGJoinExpr *r
|
|
44
44
|
// Check the type of left arg and right arg before transform
|
45
45
|
result->left = TransformTableRefNode(root->larg);
|
46
46
|
result->right = TransformTableRefNode(root->rarg);
|
47
|
-
|
47
|
+
switch (root->joinreftype) {
|
48
|
+
case duckdb_libpgquery::PG_JOIN_NATURAL:
|
48
49
|
result->ref_type = JoinRefType::NATURAL;
|
50
|
+
break;
|
51
|
+
case duckdb_libpgquery::PG_JOIN_ASOF:
|
52
|
+
result->ref_type = JoinRefType::ASOF;
|
53
|
+
break;
|
54
|
+
default:
|
55
|
+
break;
|
49
56
|
}
|
50
57
|
result->query_location = root->location;
|
51
58
|
|
@@ -25,11 +25,11 @@ static unique_ptr<ParsedExpression> BindColumn(Binder &binder, ClientContext &co
|
|
25
25
|
|
26
26
|
static unique_ptr<ParsedExpression> AddCondition(ClientContext &context, Binder &left_binder, Binder &right_binder,
|
27
27
|
const string &left_alias, const string &right_alias,
|
28
|
-
const string &column_name) {
|
28
|
+
const string &column_name, ExpressionType type) {
|
29
29
|
ExpressionBinder expr_binder(left_binder, context);
|
30
30
|
auto left = BindColumn(left_binder, context, left_alias, column_name);
|
31
31
|
auto right = BindColumn(right_binder, context, right_alias, column_name);
|
32
|
-
return make_unique<ComparisonExpression>(
|
32
|
+
return make_unique<ComparisonExpression>(type, std::move(left), std::move(right));
|
33
33
|
}
|
34
34
|
|
35
35
|
bool Binder::TryFindBinding(const string &using_column, const string &join_side, string &result) {
|
@@ -198,12 +198,14 @@ unique_ptr<BoundTableRef> Binder::Bind(JoinRef &ref) {
|
|
198
198
|
break;
|
199
199
|
}
|
200
200
|
case JoinRefType::REGULAR:
|
201
|
+
case JoinRefType::ASOF:
|
201
202
|
if (!ref.using_columns.empty()) {
|
202
203
|
// USING columns
|
203
204
|
D_ASSERT(!result->condition);
|
204
205
|
extra_using_columns = ref.using_columns;
|
205
206
|
}
|
206
207
|
break;
|
208
|
+
|
207
209
|
case JoinRefType::CROSS:
|
208
210
|
case JoinRefType::POSITIONAL:
|
209
211
|
break;
|
@@ -241,8 +243,13 @@ unique_ptr<BoundTableRef> Binder::Bind(JoinRef &ref) {
|
|
241
243
|
left_binding = RetrieveUsingBinding(left_binder, left_using_binding, using_column, "left", set.get());
|
242
244
|
right_binding = RetrieveUsingBinding(right_binder, right_using_binding, using_column, "right", set.get());
|
243
245
|
|
246
|
+
// Last column of ASOF JOIN ... USING is >=
|
247
|
+
const auto type = (ref.ref_type == JoinRefType::ASOF && i == extra_using_columns.size() - 1)
|
248
|
+
? ExpressionType::COMPARE_GREATERTHANOREQUALTO
|
249
|
+
: ExpressionType::COMPARE_EQUAL;
|
250
|
+
|
244
251
|
extra_conditions.push_back(
|
245
|
-
AddCondition(context, left_binder, right_binder, left_binding, right_binding, using_column));
|
252
|
+
AddCondition(context, left_binder, right_binder, left_binding, right_binding, using_column, type));
|
246
253
|
|
247
254
|
AddUsingBindings(*set, left_using_binding, left_binding);
|
248
255
|
AddUsingBindings(*set, right_using_binding, right_binding);
|
@@ -7,6 +7,7 @@
|
|
7
7
|
#include "duckdb/planner/expression_iterator.hpp"
|
8
8
|
#include "duckdb/planner/binder.hpp"
|
9
9
|
#include "duckdb/planner/operator/logical_any_join.hpp"
|
10
|
+
#include "duckdb/planner/operator/logical_asof_join.hpp"
|
10
11
|
#include "duckdb/planner/operator/logical_comparison_join.hpp"
|
11
12
|
#include "duckdb/planner/operator/logical_cross_product.hpp"
|
12
13
|
#include "duckdb/planner/operator/logical_filter.hpp"
|
@@ -104,12 +105,43 @@ void LogicalComparisonJoin::ExtractJoinConditions(JoinType type, unique_ptr<Logi
|
|
104
105
|
return ExtractJoinConditions(type, left_child, right_child, expressions, conditions, arbitrary_expressions);
|
105
106
|
}
|
106
107
|
|
107
|
-
unique_ptr<LogicalOperator> LogicalComparisonJoin::CreateJoin(JoinType type,
|
108
|
+
unique_ptr<LogicalOperator> LogicalComparisonJoin::CreateJoin(JoinType type, JoinRefType reftype,
|
109
|
+
unique_ptr<LogicalOperator> left_child,
|
108
110
|
unique_ptr<LogicalOperator> right_child,
|
109
111
|
vector<JoinCondition> conditions,
|
110
112
|
vector<unique_ptr<Expression>> arbitrary_expressions) {
|
113
|
+
// Validate the conditions
|
111
114
|
bool need_to_consider_arbitrary_expressions = true;
|
112
|
-
|
115
|
+
switch (reftype) {
|
116
|
+
case JoinRefType::ASOF: {
|
117
|
+
need_to_consider_arbitrary_expressions = false;
|
118
|
+
auto asof_idx = conditions.size();
|
119
|
+
for (size_t c = 0; c < conditions.size(); ++c) {
|
120
|
+
auto &cond = conditions[c];
|
121
|
+
switch (cond.comparison) {
|
122
|
+
case ExpressionType::COMPARE_EQUAL:
|
123
|
+
case ExpressionType::COMPARE_NOT_DISTINCT_FROM:
|
124
|
+
break;
|
125
|
+
case ExpressionType::COMPARE_GREATERTHANOREQUALTO:
|
126
|
+
if (asof_idx < conditions.size()) {
|
127
|
+
throw BinderException("Multiple ASOF JOIN inequalities");
|
128
|
+
}
|
129
|
+
asof_idx = c;
|
130
|
+
break;
|
131
|
+
default:
|
132
|
+
throw BinderException("Invalid ASOF JOIN comparison");
|
133
|
+
}
|
134
|
+
}
|
135
|
+
if (asof_idx == conditions.size()) {
|
136
|
+
throw BinderException("Missing ASOF JOIN inequality");
|
137
|
+
}
|
138
|
+
break;
|
139
|
+
}
|
140
|
+
default:
|
141
|
+
break;
|
142
|
+
}
|
143
|
+
|
144
|
+
if (type == JoinType::INNER && reftype == JoinRefType::REGULAR) {
|
113
145
|
// for inner joins we can push arbitrary expressions as a filter
|
114
146
|
// here we prefer to create a comparison join if possible
|
115
147
|
// that way we can use the much faster hash join to process the main join
|
@@ -144,7 +176,12 @@ unique_ptr<LogicalOperator> LogicalComparisonJoin::CreateJoin(JoinType type, uni
|
|
144
176
|
} else {
|
145
177
|
// we successfully converted expressions into JoinConditions
|
146
178
|
// create a LogicalComparisonJoin
|
147
|
-
|
179
|
+
unique_ptr<LogicalComparisonJoin> comp_join;
|
180
|
+
if (reftype == JoinRefType::ASOF) {
|
181
|
+
comp_join = make_unique<LogicalAsOfJoin>(type);
|
182
|
+
} else {
|
183
|
+
comp_join = make_unique<LogicalComparisonJoin>(type);
|
184
|
+
}
|
148
185
|
comp_join->conditions = std::move(conditions);
|
149
186
|
comp_join->children.push_back(std::move(left_child));
|
150
187
|
comp_join->children.push_back(std::move(right_child));
|
@@ -179,15 +216,16 @@ static bool HasCorrelatedColumns(Expression &expression) {
|
|
179
216
|
return has_correlated_columns;
|
180
217
|
}
|
181
218
|
|
182
|
-
unique_ptr<LogicalOperator> LogicalComparisonJoin::CreateJoin(JoinType type,
|
219
|
+
unique_ptr<LogicalOperator> LogicalComparisonJoin::CreateJoin(JoinType type, JoinRefType reftype,
|
220
|
+
unique_ptr<LogicalOperator> left_child,
|
183
221
|
unique_ptr<LogicalOperator> right_child,
|
184
222
|
unique_ptr<Expression> condition) {
|
185
223
|
vector<JoinCondition> conditions;
|
186
224
|
vector<unique_ptr<Expression>> arbitrary_expressions;
|
187
225
|
LogicalComparisonJoin::ExtractJoinConditions(type, left_child, right_child, std::move(condition), conditions,
|
188
226
|
arbitrary_expressions);
|
189
|
-
return LogicalComparisonJoin::CreateJoin(type, std::move(left_child), std::move(right_child),
|
190
|
-
std::move(arbitrary_expressions));
|
227
|
+
return LogicalComparisonJoin::CreateJoin(type, reftype, std::move(left_child), std::move(right_child),
|
228
|
+
std::move(conditions), std::move(arbitrary_expressions));
|
191
229
|
}
|
192
230
|
|
193
231
|
unique_ptr<LogicalOperator> Binder::CreatePlan(BoundJoinRef &ref) {
|
@@ -201,7 +239,8 @@ unique_ptr<LogicalOperator> Binder::CreatePlan(BoundJoinRef &ref) {
|
|
201
239
|
// we reduce expression depth of all columns in the "ref.correlated_columns" set by 1
|
202
240
|
LateralBinder::ReduceExpressionDepth(*right, ref.correlated_columns);
|
203
241
|
}
|
204
|
-
if (ref.type == JoinType::RIGHT &&
|
242
|
+
if (ref.type == JoinType::RIGHT && ref.ref_type != JoinRefType::ASOF &&
|
243
|
+
ClientConfig::GetConfig(context).enable_optimizer) {
|
205
244
|
// we turn any right outer joins into left outer joins for optimization purposes
|
206
245
|
// they are the same but with sides flipped, so treating them the same simplifies life
|
207
246
|
ref.type = JoinType::LEFT;
|
@@ -220,7 +259,8 @@ unique_ptr<LogicalOperator> Binder::CreatePlan(BoundJoinRef &ref) {
|
|
220
259
|
default:
|
221
260
|
break;
|
222
261
|
}
|
223
|
-
if (ref.type == JoinType::INNER && (ref.condition->HasSubquery() || HasCorrelatedColumns(*ref.condition))
|
262
|
+
if (ref.type == JoinType::INNER && (ref.condition->HasSubquery() || HasCorrelatedColumns(*ref.condition)) &&
|
263
|
+
ref.ref_type == JoinRefType::REGULAR) {
|
224
264
|
// inner join, generate a cross product + filter
|
225
265
|
// this will be later turned into a proper join by the join order optimizer
|
226
266
|
auto root = LogicalCrossProduct::Create(std::move(left), std::move(right));
|
@@ -235,8 +275,8 @@ unique_ptr<LogicalOperator> Binder::CreatePlan(BoundJoinRef &ref) {
|
|
235
275
|
}
|
236
276
|
|
237
277
|
// now create the join operator from the join condition
|
238
|
-
auto result =
|
239
|
-
|
278
|
+
auto result = LogicalComparisonJoin::CreateJoin(ref.type, ref.ref_type, std::move(left), std::move(right),
|
279
|
+
std::move(ref.condition));
|
240
280
|
|
241
281
|
LogicalOperator *join;
|
242
282
|
if (result->type == LogicalOperatorType::LOGICAL_FILTER) {
|
@@ -254,7 +294,9 @@ unique_ptr<LogicalOperator> Binder::CreatePlan(BoundJoinRef &ref) {
|
|
254
294
|
}
|
255
295
|
|
256
296
|
// we visit the expressions depending on the type of join
|
257
|
-
|
297
|
+
switch (join->type) {
|
298
|
+
case LogicalOperatorType::LOGICAL_ASOF_JOIN:
|
299
|
+
case LogicalOperatorType::LOGICAL_COMPARISON_JOIN: {
|
258
300
|
// comparison join
|
259
301
|
// in this join we visit the expressions on the LHS with the LHS as root node
|
260
302
|
// and the expressions on the RHS with the RHS as root node
|
@@ -263,12 +305,18 @@ unique_ptr<LogicalOperator> Binder::CreatePlan(BoundJoinRef &ref) {
|
|
263
305
|
PlanSubqueries(&comp_join.conditions[i].left, &comp_join.children[0]);
|
264
306
|
PlanSubqueries(&comp_join.conditions[i].right, &comp_join.children[1]);
|
265
307
|
}
|
266
|
-
|
308
|
+
break;
|
309
|
+
}
|
310
|
+
case LogicalOperatorType::LOGICAL_ANY_JOIN: {
|
267
311
|
auto &any_join = (LogicalAnyJoin &)*join;
|
268
312
|
// for the any join we just visit the condition
|
269
313
|
if (any_join.condition->HasSubquery()) {
|
270
314
|
throw NotImplementedException("Cannot perform non-inner join on subquery!");
|
271
315
|
}
|
316
|
+
break;
|
317
|
+
}
|
318
|
+
default:
|
319
|
+
break;
|
272
320
|
}
|
273
321
|
return result;
|
274
322
|
}
|
@@ -257,6 +257,9 @@ unique_ptr<LogicalOperator> LogicalOperator::Deserialize(Deserializer &deseriali
|
|
257
257
|
case LogicalOperatorType::LOGICAL_DELIM_JOIN:
|
258
258
|
result = LogicalDelimJoin::Deserialize(state, reader);
|
259
259
|
break;
|
260
|
+
case LogicalOperatorType::LOGICAL_ASOF_JOIN:
|
261
|
+
result = LogicalAsOfJoin::Deserialize(state, reader);
|
262
|
+
break;
|
260
263
|
case LogicalOperatorType::LOGICAL_COMPARISON_JOIN:
|
261
264
|
result = LogicalComparisonJoin::Deserialize(state, reader);
|
262
265
|
break;
|
@@ -65,6 +65,7 @@ void LogicalOperatorVisitor::EnumerateExpressions(LogicalOperator &op,
|
|
65
65
|
}
|
66
66
|
break;
|
67
67
|
}
|
68
|
+
case LogicalOperatorType::LOGICAL_ASOF_JOIN:
|
68
69
|
case LogicalOperatorType::LOGICAL_DELIM_JOIN:
|
69
70
|
case LogicalOperatorType::LOGICAL_COMPARISON_JOIN: {
|
70
71
|
if (op.type == LogicalOperatorType::LOGICAL_DELIM_JOIN) {
|
@@ -262,6 +262,7 @@ unique_ptr<LogicalOperator> FlattenDependentJoins::PushDownDependentJoinInternal
|
|
262
262
|
return std::move(join);
|
263
263
|
}
|
264
264
|
case LogicalOperatorType::LOGICAL_ANY_JOIN:
|
265
|
+
case LogicalOperatorType::LOGICAL_ASOF_JOIN:
|
265
266
|
case LogicalOperatorType::LOGICAL_COMPARISON_JOIN: {
|
266
267
|
auto &join = (LogicalJoin &)*plan;
|
267
268
|
D_ASSERT(plan->children.size() == 2);
|
@@ -334,7 +335,8 @@ unique_ptr<LogicalOperator> FlattenDependentJoins::PushDownDependentJoinInternal
|
|
334
335
|
auto right = make_unique<BoundColumnRefExpression>(
|
335
336
|
correlated_columns[i].type, ColumnBinding(right_binding.table_index, right_binding.column_index + i));
|
336
337
|
|
337
|
-
if (join.type == LogicalOperatorType::LOGICAL_COMPARISON_JOIN
|
338
|
+
if (join.type == LogicalOperatorType::LOGICAL_COMPARISON_JOIN ||
|
339
|
+
join.type == LogicalOperatorType::LOGICAL_ASOF_JOIN) {
|
338
340
|
JoinCondition cond;
|
339
341
|
cond.left = std::move(left);
|
340
342
|
cond.right = std::move(right);
|
@@ -681,6 +681,38 @@ typedef enum PGJoinType {
|
|
681
681
|
*/
|
682
682
|
} PGJoinType;
|
683
683
|
|
684
|
+
/*
|
685
|
+
* PGJoinRefType -
|
686
|
+
* enums for the types of implied conditions
|
687
|
+
*
|
688
|
+
* PGJoinRefType specifies the semantics of interpreting the join conditions.
|
689
|
+
* These can be explicit (e.g., REGULAR) implied (e.g., NATURAL)
|
690
|
+
* or interpreted in a particular manner (e.g., ASOF)
|
691
|
+
*
|
692
|
+
* This is a generalisation of the old Postgres isNatural flag.
|
693
|
+
*/
|
694
|
+
typedef enum PGJoinRefType {
|
695
|
+
PG_JOIN_REGULAR, /* Join conditions are interpreted as is */
|
696
|
+
PG_JOIN_NATURAL, /* Join conditions are inferred from the column names */
|
697
|
+
|
698
|
+
/*
|
699
|
+
* ASOF joins are joins with a single inequality predicate
|
700
|
+
* and optional equality predicates.
|
701
|
+
* The semantics are equivalent to the following window join:
|
702
|
+
* times t
|
703
|
+
* <jointype> JOIN (
|
704
|
+
* SELECT *,
|
705
|
+
* LEAD(begin, 1, 'infinity') OVER ([PARTITION BY key] ORDER BY begin) AS end)
|
706
|
+
* FROM events) e
|
707
|
+
* ON t.ts >= e.begin AND t.ts < e.end [AND t.key = e.key]
|
708
|
+
*/
|
709
|
+
PG_JOIN_ASOF
|
710
|
+
|
711
|
+
/*
|
712
|
+
* Positional join is a candidate to move here
|
713
|
+
*/
|
714
|
+
} PGJoinRefType;
|
715
|
+
|
684
716
|
/*
|
685
717
|
* OUTER joins are those for which pushed-down quals must behave differently
|
686
718
|
* from the join's own quals. This is in fact everything except INNER and
|
@@ -1324,7 +1324,7 @@ typedef struct PGRangeTblRef {
|
|
1324
1324
|
/*----------
|
1325
1325
|
* PGJoinExpr - for SQL JOIN expressions
|
1326
1326
|
*
|
1327
|
-
*
|
1327
|
+
* joinreftype, usingClause, and quals are interdependent. The user can write
|
1328
1328
|
* only one of NATURAL, USING(), or ON() (this is enforced by the grammar).
|
1329
1329
|
* If he writes NATURAL then parse analysis generates the equivalent USING()
|
1330
1330
|
* list, and from that fills in "quals" with the right equality comparisons.
|
@@ -1347,7 +1347,7 @@ typedef struct PGRangeTblRef {
|
|
1347
1347
|
typedef struct PGJoinExpr {
|
1348
1348
|
PGNodeTag type;
|
1349
1349
|
PGJoinType jointype; /* type of join */
|
1350
|
-
|
1350
|
+
PGJoinRefType joinreftype; /* Regular/Natural/AsOf join? Will need to shape table */
|
1351
1351
|
PGNode *larg; /* left subtree */
|
1352
1352
|
PGNode *rarg; /* right subtree */
|
1353
1353
|
PGList *usingClause; /* USING clause, if any (list of String) */
|
@@ -1398,4 +1398,4 @@ typedef struct PGOnConflictExpr {
|
|
1398
1398
|
PGList *exclRelTlist; /* tlist of the EXCLUDED pseudo relation */
|
1399
1399
|
} PGOnConflictExpr;
|
1400
1400
|
|
1401
|
-
}
|
1401
|
+
}
|