|  | 
| 16 | 16 | 
 | 
| 17 | 17 | use crate::datasource::datasource::TableProviderFilterPushDown; | 
| 18 | 18 | use crate::execution::context::ExecutionProps; | 
| 19 |  | -use crate::logical_plan::plan::{Aggregate, Filter, Join, Projection}; | 
|  | 19 | +use crate::logical_plan::plan::{Aggregate, Filter, Join, Projection, Union}; | 
| 20 | 20 | use crate::logical_plan::{ | 
| 21 |  | -    and, replace_col, Column, CrossJoin, JoinType, Limit, LogicalPlan, TableScan, | 
|  | 21 | +    and, col, replace_col, Column, CrossJoin, JoinType, Limit, LogicalPlan, TableScan, | 
| 22 | 22 | }; | 
| 23 | 23 | use crate::logical_plan::{DFSchema, Expr}; | 
| 24 | 24 | use crate::optimizer::optimizer::OptimizerRule; | 
| @@ -394,8 +394,29 @@ fn optimize(plan: &LogicalPlan, mut state: State) -> Result<LogicalPlan> { | 
| 394 | 394 |             // sort is filter-commutable | 
| 395 | 395 |             push_down(&state, plan) | 
| 396 | 396 |         } | 
| 397 |  | -        LogicalPlan::Union(_) => { | 
| 398 |  | -            // union all is filter-commutable | 
|  | 397 | +        LogicalPlan::Union(Union { | 
|  | 398 | +            inputs: _, | 
|  | 399 | +            schema, | 
|  | 400 | +            alias: _, | 
|  | 401 | +        }) => { | 
|  | 402 | +            // union changing all qualifiers while building logical plan so we need | 
|  | 403 | +            // to rewrite filters to push unqualified columns to inputs | 
|  | 404 | +            let projection = schema | 
|  | 405 | +                .fields() | 
|  | 406 | +                .iter() | 
|  | 407 | +                .map(|field| (field.qualified_name(), col(field.name()))) | 
|  | 408 | +                .collect::<HashMap<_, _>>(); | 
|  | 409 | + | 
|  | 410 | +            // rewriting predicate expressions using unqualified names as replacements | 
|  | 411 | +            if !projection.is_empty() { | 
|  | 412 | +                for (predicate, columns) in state.filters.iter_mut() { | 
|  | 413 | +                    *predicate = rewrite(predicate, &projection)?; | 
|  | 414 | + | 
|  | 415 | +                    columns.clear(); | 
|  | 416 | +                    utils::expr_to_columns(predicate, columns)?; | 
|  | 417 | +                } | 
|  | 418 | +            } | 
|  | 419 | + | 
| 399 | 420 |             push_down(&state, plan) | 
| 400 | 421 |         } | 
| 401 | 422 |         LogicalPlan::Limit(Limit { input, .. }) => { | 
| @@ -574,7 +595,9 @@ fn rewrite(expr: &Expr, projection: &HashMap<String, Expr>) -> Result<Expr> { | 
| 574 | 595 | mod tests { | 
| 575 | 596 |     use super::*; | 
| 576 | 597 |     use crate::datasource::TableProvider; | 
| 577 |  | -    use crate::logical_plan::{lit, sum, DFSchema, Expr, LogicalPlanBuilder, Operator}; | 
|  | 598 | +    use crate::logical_plan::{ | 
|  | 599 | +        lit, sum, union_with_alias, DFSchema, Expr, LogicalPlanBuilder, Operator, | 
|  | 600 | +    }; | 
| 578 | 601 |     use crate::physical_plan::ExecutionPlan; | 
| 579 | 602 |     use crate::test::*; | 
| 580 | 603 |     use crate::{logical_plan::col, prelude::JoinType}; | 
| @@ -901,6 +924,27 @@ mod tests { | 
| 901 | 924 |         Ok(()) | 
| 902 | 925 |     } | 
| 903 | 926 | 
 | 
|  | 927 | +    #[test] | 
|  | 928 | +    fn union_all_with_alias() -> Result<()> { | 
|  | 929 | +        let table_scan = test_table_scan()?; | 
|  | 930 | +        let union = | 
|  | 931 | +            union_with_alias(table_scan.clone(), table_scan, Some("t".to_string()))?; | 
|  | 932 | + | 
|  | 933 | +        let plan = LogicalPlanBuilder::from(union) | 
|  | 934 | +            .filter(col("t.a").eq(lit(1i64)))? | 
|  | 935 | +            .build()?; | 
|  | 936 | + | 
|  | 937 | +        // filter appears below Union without relation qualifier | 
|  | 938 | +        let expected = "\ | 
|  | 939 | +            Union\ | 
|  | 940 | +            \n  Filter: #a = Int64(1)\ | 
|  | 941 | +            \n    TableScan: test projection=None\ | 
|  | 942 | +            \n  Filter: #a = Int64(1)\ | 
|  | 943 | +            \n    TableScan: test projection=None"; | 
|  | 944 | +        assert_optimized_plan_eq(&plan, expected); | 
|  | 945 | +        Ok(()) | 
|  | 946 | +    } | 
|  | 947 | + | 
| 904 | 948 |     /// verifies that filters with the same columns are correctly placed | 
| 905 | 949 |     #[test] | 
| 906 | 950 |     fn filter_2_breaks_limits() -> Result<()> { | 
|  | 
0 commit comments