Describe the bug
AggregateExec::gather_filters_for_pushdown can reorder the parent filter results it returns to the filter pushdown optimizer.
The filter pushdown optimizer maps child pushdown results back to parent filters by position. AggregateExec currently splits incoming filters into safe_filters and unsafe_filters, builds the child filter description from the safe filters, then appends the unsupported unsafe filters. For mixed filters this changes the result order.
For example, with a filter above an aggregate such as:
where cnt is an aggregate output and b is a grouping column:
b@1 = bar is safe to push below the aggregate
cnt@2 = 1 must remain above the aggregate
Because the results are reordered, the optimizer can interpret the pushed-down grouping-column filter result as belonging to the aggregate-output filter. The aggregate-output filter can then be removed incorrectly, while the already pushed-down grouping-column filter remains above the aggregate.
To Reproduce
Add a regression test with a mixed predicate above AggregateExec:
FilterExec: cnt@2 = 1 AND b@1 = bar
AggregateExec: mode=Final, gby=[a@0 as a, b@1 as b], aggr=[cnt]
DataSourceExec: ...
The expected optimized plan should keep only cnt@2 = 1 above the aggregate and push b@1 = bar into the scan.
On current main, the resulting plan keeps b@1 = bar above the aggregate instead.
Expected behavior
AggregateExec::gather_filters_for_pushdown should preserve the order of parent_filters in its returned parent filter results, marking unsupported filters in place rather than moving them to the end.
Additional context
This affects correctness for mixed aggregate-output and grouping-column predicates during physical filter pushdown.
Describe the bug
AggregateExec::gather_filters_for_pushdowncan reorder the parent filter results it returns to the filter pushdown optimizer.The filter pushdown optimizer maps child pushdown results back to parent filters by position.
AggregateExeccurrently splits incoming filters intosafe_filtersandunsafe_filters, builds the child filter description from the safe filters, then appends the unsupported unsafe filters. For mixed filters this changes the result order.For example, with a filter above an aggregate such as:
where
cntis an aggregate output andbis a grouping column:b@1 = baris safe to push below the aggregatecnt@2 = 1must remain above the aggregateBecause the results are reordered, the optimizer can interpret the pushed-down grouping-column filter result as belonging to the aggregate-output filter. The aggregate-output filter can then be removed incorrectly, while the already pushed-down grouping-column filter remains above the aggregate.
To Reproduce
Add a regression test with a mixed predicate above
AggregateExec:The expected optimized plan should keep only
cnt@2 = 1above the aggregate and pushb@1 = barinto the scan.On current
main, the resulting plan keepsb@1 = barabove the aggregate instead.Expected behavior
AggregateExec::gather_filters_for_pushdownshould preserve the order ofparent_filtersin its returned parent filter results, marking unsupported filters in place rather than moving them to the end.Additional context
This affects correctness for mixed aggregate-output and grouping-column predicates during physical filter pushdown.