From 11edab31e00324b4f07e704ffa67c33eb1d607cf Mon Sep 17 00:00:00 2001 From: Jianhong Shi Date: Sun, 2 Aug 2026 14:25:09 -0500 Subject: [PATCH] update create_filter lifting logic --- src/operators/logical_create_filter.cpp | 4 +- src/operators/logical_create_filter.hpp | 1 + src/operators/logical_probe_filter.cpp | 4 +- src/operators/logical_probe_filter.hpp | 1 + src/optimizer/robust_optimizer.cpp | 76 +++++++++++++++++++++---- 5 files changed, 71 insertions(+), 15 deletions(-) diff --git a/src/operators/logical_create_filter.cpp b/src/operators/logical_create_filter.cpp index f01ab33..52a5eb4 100644 --- a/src/operators/logical_create_filter.cpp +++ b/src/operators/logical_create_filter.cpp @@ -15,7 +15,7 @@ LogicalCreateFilter::LogicalCreateFilter() : LogicalExtensionOperator() { } LogicalCreateFilter::LogicalCreateFilter(const FilterOperation &filter_op) - : LogicalExtensionOperator(), filter_operation(filter_op) { + : LogicalExtensionOperator(), filter_operation(filter_op), input_bindings(filter_op.build_columns) { this->type = LogicalOperatorType::LOGICAL_EXTENSION_OPERATOR; message = "CREATE_FILTER"; } @@ -82,7 +82,7 @@ PhysicalOperator &LogicalCreateFilter::CreatePlan(ClientContext &context, Physic // built. // TODO: optimize: Use a map for filter_operation.build_columns to speed up lookup vector resolved_indices; - for (const ColumnBinding &column_binding : filter_operation.build_columns) { + for (const ColumnBinding &column_binding : input_bindings) { // find the position of the filter column ColumnBinding in the chunk columns for (idx_t i = 0; i < child_bindings.size(); i++) { if (child_bindings[i].table_index == column_binding.table_index && diff --git a/src/operators/logical_create_filter.hpp b/src/operators/logical_create_filter.hpp index c24d877..5ec1ac5 100644 --- a/src/operators/logical_create_filter.hpp +++ b/src/operators/logical_create_filter.hpp @@ -28,6 +28,7 @@ class LogicalCreateFilter : public LogicalExtensionOperator { bool can_stop = false; FilterOperation filter_operation; + vector input_bindings; PhysicalCreateFilter *physical = nullptr; vector related_probe_filter; diff --git a/src/operators/logical_probe_filter.cpp b/src/operators/logical_probe_filter.cpp index 59172d9..ac33b81 100644 --- a/src/operators/logical_probe_filter.cpp +++ b/src/operators/logical_probe_filter.cpp @@ -9,7 +9,7 @@ LogicalProbeFilter::LogicalProbeFilter() : LogicalExtensionOperator() { } LogicalProbeFilter::LogicalProbeFilter(const FilterOperation &filter_op) - : LogicalExtensionOperator(), filter_operation(filter_op) { + : LogicalExtensionOperator(), filter_operation(filter_op), input_bindings(filter_op.probe_columns) { this->type = LogicalOperatorType::LOGICAL_EXTENSION_OPERATOR; } @@ -67,7 +67,7 @@ PhysicalOperator &LogicalProbeFilter::CreatePlan(ClientContext &context, Physica } #endif - for (const ColumnBinding &column_binding : filter_operation.probe_columns) { + for (const ColumnBinding &column_binding : input_bindings) { D_PRINTF("[RESOLVE] Looking for probe_column: table_idx=%llu, col_idx=%llu", (unsigned long long)column_binding.table_index, (unsigned long long)column_binding.column_index); // find the position of the filter column ColumnBinding in the chunk columns diff --git a/src/operators/logical_probe_filter.hpp b/src/operators/logical_probe_filter.hpp index 5a826a1..12d48eb 100644 --- a/src/operators/logical_probe_filter.hpp +++ b/src/operators/logical_probe_filter.hpp @@ -28,6 +28,7 @@ class LogicalProbeFilter final : public LogicalExtensionOperator { FilterOperation filter_operation; LogicalCreateFilter *related_create_filter = nullptr; bool is_passthrough = false; + vector input_bindings; PhysicalProbeFilter *physical = nullptr; diff --git a/src/optimizer/robust_optimizer.cpp b/src/optimizer/robust_optimizer.cpp index 547754b..5e4b96c 100644 --- a/src/optimizer/robust_optimizer.cpp +++ b/src/optimizer/robust_optimizer.cpp @@ -1583,6 +1583,38 @@ static LogicalOperator *FindDeepestCreateFilter(LogicalOperator *node) { return deepest; } +// find the deepest FILTER chain starting with a PROBE_FILTER +static pair FindDeepestFilterChain(LogicalOperator *node) { + LogicalOperator *deepest = nullptr; + LogicalOperator *parent = nullptr; + LogicalOperator *create = nullptr; + while (node) { + if (node->children.size() != 1 || node->children[0]->type == LogicalOperatorType::LOGICAL_DELIM_JOIN || + node->children[0]->type == LogicalOperatorType::LOGICAL_MATERIALIZED_CTE) { + break; + } + if (node->children[0]->type == LogicalOperatorType::LOGICAL_EXTENSION_OPERATOR) { + deepest = node; + node = node->children[0].get(); + while (node->type == LogicalOperatorType::LOGICAL_EXTENSION_OPERATOR) { + if (node->children.size() != 1 || node->children[0]->type == LogicalOperatorType::LOGICAL_DELIM_JOIN || + node->children[0]->type == LogicalOperatorType::LOGICAL_MATERIALIZED_CTE) { + break; + } + if (node->type == LogicalOperatorType::LOGICAL_EXTENSION_OPERATOR && + dynamic_cast(node)) { + parent = deepest; + create = node; + } + node = node->children[0].get(); + } + return {parent, create}; + } + node = node->children[0].get(); + } + return {parent, create}; +} + void RobustOptimizerContextState::LiftCreateFilterAboveMarkJoin(unique_ptr &plan) { if (!plan) { return; @@ -1628,19 +1660,41 @@ void RobustOptimizerContextState::LiftCreateFilterAboveFilter(unique_ptrchildren[0].get()); - if (!deepest) { + auto p = FindDeepestFilterChain(plan.get()); + LogicalOperator *parent = p.first; + LogicalOperator *create = p.second; + if (!parent || !create) { return; } - - // same block-detach logic as LiftCreateFilterAboveMarkJoin - auto below_deepest = std::move(deepest->children[0]); - deepest->children.clear(); - auto block = std::move(plan->children[0]); - plan->children[0] = std::move(below_deepest); - - deepest->AddChild(std::move(plan)); - plan = std::move(block); + auto beginning = std::move(parent->children[0]); + parent->children[0] = std::move(create->children[0]); + create->children[0] = (std::move(plan)); + plan = std::move(beginning); + LogicalOperator *cur = plan.get(); + while (cur->type == LogicalOperatorType::LOGICAL_EXTENSION_OPERATOR) { + if (auto *createCur = dynamic_cast(cur)) { + auto &filter = createCur->filter_operation; + createCur->input_bindings.clear(); + for (auto &baseBinding : filter.build_columns) { + for (auto &binding : createCur->GetColumnBindings()) { + if (ResolveColumnBinding(binding) == ResolveColumnBinding(baseBinding)) { + createCur->input_bindings.push_back(binding); + } + } + } + } else if (auto *probeCur = dynamic_cast(cur)) { + auto &filter = probeCur->filter_operation; + probeCur->input_bindings.clear(); + for (auto &baseBinding : filter.probe_columns) { + for (auto &binding : probeCur->GetColumnBindings()) { + if (ResolveColumnBinding(binding) == ResolveColumnBinding(baseBinding)) { + probeCur->input_bindings.push_back(binding); + } + } + } + } + cur = cur->children[0].get(); + } } unique_ptr RobustOptimizerContextState::PreOptimize(unique_ptr plan) {