/src/duckdb/src/optimizer/outer_join_simplification.cpp
Line | Count | Source |
1 | | #include "duckdb/optimizer/outer_join_simplification.hpp" |
2 | | |
3 | | #include "duckdb/planner/operator/list.hpp" |
4 | | #include "duckdb/planner/expression/bound_cast_expression.hpp" |
5 | | #include "duckdb/planner/expression/bound_columnref_expression.hpp" |
6 | | #include "duckdb/planner/expression/bound_comparison_expression.hpp" |
7 | | #include "duckdb/planner/expression/bound_constant_expression.hpp" |
8 | | #include "duckdb/planner/expression/bound_operator_expression.hpp" |
9 | | #include "duckdb/planner/expression/bound_function_expression.hpp" |
10 | | #include "duckdb/planner/expression_iterator.hpp" |
11 | | |
12 | | namespace duckdb { |
13 | | |
14 | | //===--------------------------------------------------------------------===// |
15 | | // Setup |
16 | | //===--------------------------------------------------------------------===// |
17 | | |
18 | 63.9k | OuterJoinSimplification::OuterJoinSimplification() { |
19 | 63.9k | } |
20 | | |
21 | | OuterJoinSimplification::OuterJoinSimplification(column_binding_set_t required_columns_p) |
22 | 143k | : required_columns(std::move(required_columns_p)), initialized_required_columns(true) { |
23 | 143k | } |
24 | | |
25 | | //===--------------------------------------------------------------------===// |
26 | | // Column Binding Helpers |
27 | | //===--------------------------------------------------------------------===// |
28 | | |
29 | 417k | void OuterJoinSimplification::AddColumnReferences(const Expression &expr, column_binding_set_t &bindings) { |
30 | 417k | ExpressionIterator::VisitExpression<BoundColumnRefExpression>(expr, [&](const BoundColumnRefExpression &colref) { |
31 | 106k | if (colref.Depth() == 0) { |
32 | 106k | bindings.insert(colref.Binding()); |
33 | 106k | } |
34 | 106k | }); |
35 | 417k | } |
36 | | |
37 | 345k | void OuterJoinSimplification::AddRequiredColumns(const Expression &expr) { |
38 | 345k | AddColumnReferences(expr, required_columns); |
39 | 345k | } |
40 | | |
41 | 0 | void OuterJoinSimplification::AddRequiredColumns(const JoinCondition &condition) { |
42 | 0 | if (condition.IsComparison()) { |
43 | 0 | AddRequiredColumns(condition.GetLHS()); |
44 | 0 | AddRequiredColumns(condition.GetRHS()); |
45 | 0 | } else { |
46 | 0 | AddRequiredColumns(condition.GetJoinExpression()); |
47 | 0 | } |
48 | 0 | } |
49 | | |
50 | 0 | void OuterJoinSimplification::AddRequiredColumns(const vector<JoinCondition> &conditions) { |
51 | 0 | for (const auto &condition : conditions) { |
52 | 0 | AddRequiredColumns(condition); |
53 | 0 | } |
54 | 0 | } |
55 | | |
56 | 0 | bool OuterJoinSimplification::GetColumnBinding(const Expression &expr, ColumnBinding &binding) { |
57 | 0 | if (expr.GetExpressionClass() != ExpressionClass::BOUND_COLUMN_REF) { |
58 | 0 | if (!BoundCastExpression::IsCast(expr)) { |
59 | 0 | return false; |
60 | 0 | } |
61 | 0 | auto &cast = expr.Cast<BoundFunctionExpression>(); |
62 | 0 | return GetColumnBinding(BoundCastExpression::Child(cast), binding); |
63 | 0 | } |
64 | 0 | auto &colref = expr.Cast<BoundColumnRefExpression>(); |
65 | 0 | binding = colref.Binding(); |
66 | 0 | return true; |
67 | 0 | } |
68 | | |
69 | 0 | bool OuterJoinSimplification::GetNullPreservingColumnBinding(const Expression &expr, ColumnBinding &binding) { |
70 | 0 | if (expr.GetExpressionClass() != ExpressionClass::BOUND_COLUMN_REF) { |
71 | 0 | if (!BoundCastExpression::IsCast(expr)) { |
72 | 0 | return false; |
73 | 0 | } |
74 | 0 | auto &cast = expr.Cast<BoundFunctionExpression>(); |
75 | 0 | if (BoundCastExpression::IsTryCast(cast) || |
76 | 0 | !BoundCastExpression::CastIsInvertible(BoundCastExpression::SourceType(cast), cast.GetReturnType())) { |
77 | 0 | return false; |
78 | 0 | } |
79 | 0 | return GetNullPreservingColumnBinding(BoundCastExpression::Child(cast), binding); |
80 | 0 | } |
81 | 0 | auto &colref = expr.Cast<BoundColumnRefExpression>(); |
82 | 0 | binding = colref.Binding(); |
83 | 0 | return true; |
84 | 0 | } |
85 | | |
86 | | //===--------------------------------------------------------------------===// |
87 | | // NULL Constraint Tracking |
88 | | //===--------------------------------------------------------------------===// |
89 | | |
90 | 0 | void OuterJoinSimplification::HandleExpression(const Expression &expr) { |
91 | 0 | ColumnBinding binding; |
92 | 0 | if (GetColumnBinding(expr, binding)) { |
93 | 0 | null_filtered_columns.insert(binding); |
94 | 0 | } |
95 | 0 | } |
96 | | |
97 | 15.4k | void OuterJoinSimplification::HandleFilterExpression(const Expression &expr) { |
98 | 15.4k | if (expr.GetExpressionClass() == ExpressionClass::BOUND_OPERATOR && |
99 | 15.4k | expr.GetExpressionType() == ExpressionType::OPERATOR_IS_NOT_NULL) { |
100 | 0 | const auto &is_not_null = expr.Cast<BoundOperatorExpression>(); |
101 | 0 | HandleExpression(*is_not_null.GetChildren()[0]); |
102 | 0 | AddRequiredColumns(expr); |
103 | 0 | return; |
104 | 0 | } |
105 | | |
106 | 15.4k | if (expr.GetExpressionClass() == ExpressionClass::BOUND_OPERATOR && |
107 | 15.4k | expr.GetExpressionType() == ExpressionType::OPERATOR_IS_NULL) { |
108 | 0 | const auto &is_null = expr.Cast<BoundOperatorExpression>(); |
109 | 0 | if (!HandleIsNullExpression(*is_null.GetChildren()[0])) { |
110 | 0 | AddRequiredColumns(expr); |
111 | 0 | } |
112 | 0 | return; |
113 | 0 | } |
114 | | |
115 | 15.4k | if (!BoundComparisonExpression::IsComparison(expr)) { |
116 | 15.4k | AddRequiredColumns(expr); |
117 | 15.4k | return; |
118 | 15.4k | } |
119 | | |
120 | 0 | AddRequiredColumns(expr); |
121 | 0 | if (!FiltersNulls(expr.GetExpressionType())) { |
122 | 0 | return; |
123 | 0 | } |
124 | 0 | const auto &comparison = expr.Cast<BoundFunctionExpression>(); |
125 | 0 | HandleExpression(BoundComparisonExpression::Left(comparison)); |
126 | 0 | HandleExpression(BoundComparisonExpression::Right(comparison)); |
127 | 0 | } |
128 | | |
129 | 0 | bool OuterJoinSimplification::HandleIsNullExpression(const Expression &expr) { |
130 | 0 | ColumnBinding binding; |
131 | 0 | if (GetNullPreservingColumnBinding(expr, binding)) { |
132 | 0 | null_required_columns.insert(binding); |
133 | 0 | return true; |
134 | 0 | } |
135 | 0 | return false; |
136 | 0 | } |
137 | | |
138 | 15.4k | bool OuterJoinSimplification::IsNullFilter(const Expression &expr, ColumnBinding &binding) { |
139 | 15.4k | if (expr.GetExpressionClass() != ExpressionClass::BOUND_OPERATOR || |
140 | 15.4k | expr.GetExpressionType() != ExpressionType::OPERATOR_IS_NULL) { |
141 | 15.4k | return false; |
142 | 15.4k | } |
143 | 0 | auto &is_null = expr.Cast<BoundOperatorExpression>(); |
144 | 0 | auto &child = *is_null.GetChildren()[0]; |
145 | 0 | return GetNullPreservingColumnBinding(child, binding); |
146 | 15.4k | } |
147 | | |
148 | 388k | void OuterJoinSimplification::InitializeRequiredColumns(LogicalOperator &op) { |
149 | 388k | if (initialized_required_columns) { |
150 | 324k | return; |
151 | 324k | } |
152 | 1.84M | for (const auto &binding : op.GetColumnBindings()) { |
153 | 1.84M | required_columns.insert(binding); |
154 | 1.84M | } |
155 | 63.9k | initialized_required_columns = true; |
156 | 63.9k | } |
157 | | |
158 | 0 | bool OuterJoinSimplification::FiltersNulls(ExpressionType comparison_type) { |
159 | 0 | return comparison_type != ExpressionType::COMPARE_DISTINCT_FROM && |
160 | 0 | comparison_type != ExpressionType::COMPARE_NOT_DISTINCT_FROM; |
161 | 0 | } |
162 | | |
163 | | //===--------------------------------------------------------------------===// |
164 | | // Join Rewrite Helpers |
165 | | //===--------------------------------------------------------------------===// |
166 | | |
167 | 0 | vector<ColumnBinding> OuterJoinSimplification::GetRightBindings(LogicalJoin &join) { |
168 | 0 | return LogicalOperator::MapBindings(join.children[1]->GetColumnBindings(), join.right_projection_map); |
169 | 0 | } |
170 | | |
171 | 0 | bool OuterJoinSimplification::HasNullRequiredColumns(const vector<ColumnBinding> &bindings) { |
172 | 0 | for (const auto &binding : bindings) { |
173 | 0 | if (null_required_columns.find(binding) != null_required_columns.end()) { |
174 | 0 | return true; |
175 | 0 | } |
176 | 0 | } |
177 | 0 | return false; |
178 | 0 | } |
179 | | |
180 | 0 | bool OuterJoinSimplification::HasRequiredColumns(const vector<ColumnBinding> &bindings) { |
181 | 0 | for (const auto &binding : bindings) { |
182 | 0 | if (required_columns.find(binding) != required_columns.end()) { |
183 | 0 | return true; |
184 | 0 | } |
185 | 0 | } |
186 | 0 | return false; |
187 | 0 | } |
188 | | |
189 | 0 | void OuterJoinSimplification::EraseNullRequiredColumns(LogicalOperator &child) { |
190 | 0 | for (const auto &binding : child.GetColumnBindings()) { |
191 | 0 | null_required_columns.erase(binding); |
192 | 0 | } |
193 | 0 | } |
194 | | |
195 | 0 | void OuterJoinSimplification::MarkEliminatedNullColumns(const vector<ColumnBinding> &bindings) { |
196 | 0 | for (const auto &binding : bindings) { |
197 | 0 | eliminated_null_columns.insert(binding); |
198 | 0 | } |
199 | 0 | } |
200 | | |
201 | 0 | bool OuterJoinSimplification::TryConvertLeftToAntiJoin(LogicalComparisonJoin &join) { |
202 | 0 | if (join.join_type != JoinType::LEFT) { |
203 | 0 | return false; |
204 | 0 | } |
205 | | |
206 | 0 | auto right_bindings = GetRightBindings(join); |
207 | 0 | if (!HasNullRequiredColumns(right_bindings) || HasRequiredColumns(right_bindings)) { |
208 | 0 | return false; |
209 | 0 | } |
210 | | |
211 | 0 | column_binding_set_t match_non_null_rhs; |
212 | 0 | for (const auto &condition : join.conditions) { |
213 | 0 | if (!condition.IsComparison() || !FiltersNulls(condition.GetComparisonType())) { |
214 | 0 | continue; |
215 | 0 | } |
216 | 0 | ColumnBinding rhs_binding; |
217 | 0 | if (!GetColumnBinding(condition.GetRHS(), rhs_binding)) { |
218 | 0 | continue; |
219 | 0 | } |
220 | 0 | match_non_null_rhs.insert(rhs_binding); |
221 | 0 | } |
222 | |
|
223 | 0 | for (const auto &binding : right_bindings) { |
224 | 0 | if (null_required_columns.find(binding) == null_required_columns.end()) { |
225 | 0 | continue; |
226 | 0 | } |
227 | 0 | if (match_non_null_rhs.find(binding) == match_non_null_rhs.end()) { |
228 | 0 | continue; |
229 | 0 | } |
230 | 0 | join.join_type = JoinType::ANTI; |
231 | 0 | return true; |
232 | 0 | } |
233 | 0 | return false; |
234 | 0 | } |
235 | | |
236 | 0 | void OuterJoinSimplification::SimplifyOuterJoinType(LogicalComparisonJoin &join) { |
237 | 0 | bool preserves_null_extended_rows[2] = {join.join_type == JoinType::LEFT || join.join_type == JoinType::OUTER, |
238 | 0 | join.join_type == JoinType::RIGHT || join.join_type == JoinType::OUTER}; |
239 | 0 | for (idx_t child_idx = 0; child_idx < 2; child_idx++) { |
240 | 0 | for (const auto &binding : join.children[child_idx]->GetColumnBindings()) { |
241 | 0 | if (null_filtered_columns.find(binding) != null_filtered_columns.end()) { |
242 | | // Rejecting NULLs in one child removes preservation of NULL extended rows for the other child. |
243 | 0 | preserves_null_extended_rows[1 - child_idx] = false; |
244 | 0 | break; |
245 | 0 | } |
246 | 0 | } |
247 | 0 | } |
248 | |
|
249 | 0 | if (!preserves_null_extended_rows[0] && !preserves_null_extended_rows[1]) { |
250 | 0 | join.join_type = JoinType::INNER; |
251 | 0 | return; |
252 | 0 | } |
253 | | |
254 | 0 | if (preserves_null_extended_rows[0] && !preserves_null_extended_rows[1]) { |
255 | 0 | D_ASSERT(join.join_type == JoinType::LEFT || join.join_type == JoinType::OUTER); |
256 | 0 | join.join_type = JoinType::LEFT; |
257 | 0 | } else if (!preserves_null_extended_rows[0] && preserves_null_extended_rows[1]) { |
258 | 0 | D_ASSERT(join.join_type == JoinType::RIGHT || join.join_type == JoinType::OUTER); |
259 | 0 | join.join_type = JoinType::RIGHT; |
260 | 0 | } else { |
261 | 0 | D_ASSERT(join.join_type == JoinType::OUTER); |
262 | 0 | join.join_type = JoinType::OUTER; |
263 | 0 | } |
264 | 0 | } |
265 | | |
266 | | //===--------------------------------------------------------------------===// |
267 | | // Operator Visitors |
268 | | //===--------------------------------------------------------------------===// |
269 | | |
270 | 32.8k | void OuterJoinSimplification::VisitComparisonJoin(LogicalComparisonJoin &join, LogicalOperator &op) { |
271 | 32.8k | switch (join.join_type) { |
272 | 0 | case JoinType::INNER: |
273 | 0 | case JoinType::SEMI: |
274 | 0 | VisitInnerOrSemiJoin(join, op); |
275 | 0 | return; |
276 | 0 | case JoinType::LEFT: |
277 | 0 | case JoinType::RIGHT: |
278 | 0 | case JoinType::OUTER: |
279 | 0 | VisitOuterJoin(join, op); |
280 | 0 | return; |
281 | 32.8k | default: |
282 | 32.8k | break; |
283 | 32.8k | } |
284 | 32.8k | VisitUnsupportedOperator(op); |
285 | 32.8k | } |
286 | | |
287 | 0 | void OuterJoinSimplification::VisitInnerOrSemiJoin(LogicalComparisonJoin &join, LogicalOperator &op) { |
288 | 0 | for (const auto &condition : join.conditions) { |
289 | 0 | if (!condition.IsComparison()) { |
290 | 0 | continue; |
291 | 0 | } |
292 | 0 | AddRequiredColumns(condition); |
293 | 0 | if (!FiltersNulls(condition.GetComparisonType())) { |
294 | 0 | continue; |
295 | 0 | } |
296 | 0 | HandleExpression(condition.GetLHS()); |
297 | 0 | HandleExpression(condition.GetRHS()); |
298 | 0 | } |
299 | 0 | VisitOperatorChildren(op); |
300 | 0 | } |
301 | | |
302 | 0 | void OuterJoinSimplification::VisitOuterJoin(LogicalComparisonJoin &join, LogicalOperator &op) { |
303 | 0 | if (TryConvertLeftToAntiJoin(join)) { |
304 | 0 | auto right_bindings = GetRightBindings(join); |
305 | 0 | AddRequiredColumns(join.conditions); |
306 | 0 | EraseNullRequiredColumns(*join.children[1]); |
307 | 0 | VisitOperatorChildren(op); |
308 | | // only operators above the join see the right side as NULL, not the right child itself |
309 | 0 | MarkEliminatedNullColumns(right_bindings); |
310 | 0 | return; |
311 | 0 | } |
312 | | |
313 | 0 | SimplifyOuterJoinType(join); |
314 | 0 | if (join.join_type == JoinType::INNER) { |
315 | 0 | VisitOperator(op); |
316 | 0 | return; |
317 | 0 | } |
318 | | |
319 | 0 | AddRequiredColumns(join.conditions); |
320 | | // NULL values in the NULL-extended side can be introduced by this join itself, |
321 | | // so columns of that side are not guaranteed to be NULL below the join |
322 | 0 | if (join.join_type == JoinType::LEFT || join.join_type == JoinType::OUTER) { |
323 | 0 | EraseNullRequiredColumns(*join.children[1]); |
324 | 0 | } |
325 | 0 | if (join.join_type == JoinType::RIGHT || join.join_type == JoinType::OUTER) { |
326 | 0 | EraseNullRequiredColumns(*join.children[0]); |
327 | 0 | } |
328 | 0 | VisitOperatorChildren(op); |
329 | 0 | } |
330 | | |
331 | 165k | void OuterJoinSimplification::VisitProjection(LogicalProjection &projection, LogicalOperator &op) { |
332 | 165k | vector<pair<idx_t, ColumnBinding>> direct_projection_map; |
333 | 2.31M | for (idx_t col_idx = 0; col_idx < projection.expressions.size(); col_idx++) { |
334 | 2.15M | auto &expr = *projection.expressions[col_idx]; |
335 | 2.15M | const ColumnBinding binding(projection.table_index, ProjectionIndex(col_idx)); |
336 | 2.15M | if (expr.GetExpressionClass() != ExpressionClass::BOUND_COLUMN_REF) { |
337 | 329k | AddRequiredColumns(expr); |
338 | 329k | continue; |
339 | 329k | } |
340 | | |
341 | 1.82M | auto input_binding = expr.Cast<BoundColumnRefExpression>().Binding(); |
342 | 1.82M | direct_projection_map.emplace_back(col_idx, input_binding); |
343 | 1.82M | if (null_filtered_columns.find(binding) != null_filtered_columns.end()) { |
344 | 0 | null_filtered_columns.insert(input_binding); |
345 | 0 | } |
346 | 1.82M | if (null_required_columns.find(binding) != null_required_columns.end()) { |
347 | 0 | null_required_columns.insert(input_binding); |
348 | 0 | } |
349 | 1.82M | } |
350 | 165k | VisitOperatorChildren(op); |
351 | | |
352 | 1.82M | for (const auto &entry : direct_projection_map) { |
353 | 1.82M | auto col_idx = entry.first; |
354 | 1.82M | auto input_binding = entry.second; |
355 | 1.82M | if (eliminated_null_columns.find(input_binding) == eliminated_null_columns.end()) { |
356 | 1.82M | continue; |
357 | 1.82M | } |
358 | 0 | const ColumnBinding output_binding(projection.table_index, ProjectionIndex(col_idx)); |
359 | 0 | auto type = projection.expressions[col_idx]->GetReturnType(); |
360 | 0 | projection.expressions[col_idx] = make_uniq<BoundConstantExpression>(Value(type)); |
361 | 0 | eliminated_null_columns.insert(output_binding); |
362 | 0 | } |
363 | 165k | } |
364 | | |
365 | 15.4k | void OuterJoinSimplification::VisitFilter(LogicalFilter &filter, LogicalOperator &op) { |
366 | 15.4k | filter.SplitPredicates(filter.expressions); |
367 | 15.4k | for (const auto &expr : filter.expressions) { |
368 | 15.4k | HandleFilterExpression(*expr); |
369 | 15.4k | } |
370 | 15.4k | VisitOperatorChildren(op); |
371 | | |
372 | 30.8k | for (idx_t i = 0; i < filter.expressions.size(); i++) { |
373 | 15.4k | ColumnBinding binding; |
374 | 15.4k | if (!IsNullFilter(*filter.expressions[i], binding)) { |
375 | 15.4k | continue; |
376 | 15.4k | } |
377 | 0 | if (eliminated_null_columns.find(binding) == eliminated_null_columns.end()) { |
378 | 0 | continue; |
379 | 0 | } |
380 | 0 | filter.expressions.erase_at(i); |
381 | 0 | i--; |
382 | 0 | } |
383 | 15.4k | } |
384 | | |
385 | 230 | void OuterJoinSimplification::VisitOrder(LogicalOrder &order, LogicalOperator &op) { |
386 | 230 | for (const auto &order_node : order.orders) { |
387 | 230 | AddRequiredColumns(*order_node.expression); |
388 | 230 | } |
389 | 230 | VisitOperatorChildren(op); |
390 | 230 | } |
391 | | |
392 | 0 | void OuterJoinSimplification::VisitTopN(LogicalTopN &top_n, LogicalOperator &op) { |
393 | 0 | for (const auto &order_node : top_n.orders) { |
394 | 0 | AddRequiredColumns(*order_node.expression); |
395 | 0 | } |
396 | 0 | OuterJoinSimplification child_simplification(required_columns); |
397 | 0 | child_simplification.VisitOperator(*op.children[0]); |
398 | 0 | } |
399 | | |
400 | 34.5k | void OuterJoinSimplification::VisitAggregate(LogicalAggregate &aggregate, LogicalOperator &op) { |
401 | 34.5k | column_binding_set_t child_required_columns; |
402 | 71.3k | for (const auto &expr : aggregate.groups) { |
403 | 71.3k | AddColumnReferences(*expr, child_required_columns); |
404 | 71.3k | } |
405 | 34.5k | for (const auto &expr : aggregate.expressions) { |
406 | 167 | AddColumnReferences(*expr, child_required_columns); |
407 | 167 | } |
408 | 34.5k | OuterJoinSimplification child_simplification(std::move(child_required_columns)); |
409 | 34.5k | child_simplification.VisitOperator(*op.children[0]); |
410 | 34.5k | } |
411 | | |
412 | 164k | void OuterJoinSimplification::VisitUnsupportedOperator(LogicalOperator &op) { |
413 | 164k | for (auto &child : op.children) { |
414 | 100k | column_binding_set_t child_required_columns; |
415 | 270k | for (const auto &binding : child->GetColumnBindings()) { |
416 | 270k | child_required_columns.insert(binding); |
417 | 270k | } |
418 | 100k | OuterJoinSimplification outer_join_simplification(std::move(child_required_columns)); |
419 | 100k | outer_join_simplification.VisitOperator(*child); |
420 | 100k | } |
421 | 164k | } |
422 | | |
423 | 388k | void OuterJoinSimplification::VisitOperator(LogicalOperator &op) { |
424 | 388k | InitializeRequiredColumns(op); |
425 | | |
426 | 388k | switch (op.type) { |
427 | 32.8k | case LogicalOperatorType::LOGICAL_COMPARISON_JOIN: { |
428 | 32.8k | auto &join = op.Cast<LogicalComparisonJoin>(); |
429 | 32.8k | VisitComparisonJoin(join, op); |
430 | 32.8k | return; |
431 | 0 | } |
432 | 165k | case LogicalOperatorType::LOGICAL_PROJECTION: { |
433 | 165k | auto &projection = op.Cast<LogicalProjection>(); |
434 | 165k | VisitProjection(projection, op); |
435 | 165k | return; |
436 | 0 | } |
437 | 15.4k | case LogicalOperatorType::LOGICAL_FILTER: { |
438 | 15.4k | auto &filter = op.Cast<LogicalFilter>(); |
439 | 15.4k | VisitFilter(filter, op); |
440 | 15.4k | return; |
441 | 0 | } |
442 | 230 | case LogicalOperatorType::LOGICAL_ORDER_BY: { |
443 | 230 | auto &order = op.Cast<LogicalOrder>(); |
444 | 230 | VisitOrder(order, op); |
445 | 230 | return; |
446 | 0 | } |
447 | 0 | case LogicalOperatorType::LOGICAL_TOP_N: { |
448 | 0 | auto &top_n = op.Cast<LogicalTopN>(); |
449 | 0 | VisitTopN(top_n, op); |
450 | 0 | return; |
451 | 0 | } |
452 | 7.74k | case LogicalOperatorType::LOGICAL_LIMIT: { |
453 | 7.74k | OuterJoinSimplification child_simplification(required_columns); |
454 | 7.74k | child_simplification.VisitOperator(*op.children[0]); |
455 | 7.74k | return; |
456 | 0 | } |
457 | 34.5k | case LogicalOperatorType::LOGICAL_AGGREGATE_AND_GROUP_BY: { |
458 | 34.5k | auto &aggregate = op.Cast<LogicalAggregate>(); |
459 | 34.5k | VisitAggregate(aggregate, op); |
460 | 34.5k | return; |
461 | 0 | } |
462 | 132k | default: |
463 | | // Passthrough not supported. TODO: could pass through more operators like LOGICAL_UNION |
464 | 132k | break; |
465 | 388k | } |
466 | | |
467 | 132k | VisitUnsupportedOperator(op); |
468 | 132k | } |
469 | | |
470 | | } // namespace duckdb |