You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
// Same predicate in both TableScan and Filter (Inexact pushdown, no alias)
3022
+
let scan = table_scan_with_filters(
3023
+
Some("nation"),
3024
+
&schema,
3025
+
Some(vec![0,1]),
3026
+
vec![col("n_name").eq(lit("FRANCE"))],
3027
+
)?
3028
+
.build()?;
3029
+
3030
+
let filtered = LogicalPlanBuilder::from(scan)
3031
+
.filter(col("nation.n_name").eq(lit("FRANCE")))?
3032
+
.build()?;
3033
+
3034
+
let sql = plan_to_sql(&filtered)?;
3035
+
// Duplicate filter: same predicate in Filter node and TableScan pushdown.
3036
+
// Dedup for Inexact/partial pushdown duplicates does not affect correctness
3037
+
// and can be optimized separately.
3038
+
assert_snapshot!(
3039
+
sql,
3040
+
@"SELECT nation.n_nationkey, nation.n_name FROM nation WHERE (nation.n_name = 'FRANCE') AND (nation.n_name = 'FRANCE')"
3041
+
);
3042
+
3043
+
// Filter has additional predicate beyond what was pushed down
3044
+
let scan = table_scan_with_filters(
3045
+
Some("nation"),
3046
+
&schema,
3047
+
Some(vec![0,1]),
3048
+
vec![col("n_name").eq(lit("FRANCE"))],
3049
+
)?
3050
+
.build()?;
3051
+
3052
+
let filtered = LogicalPlanBuilder::from(scan)
3053
+
.filter(
3054
+
col("nation.n_name")
3055
+
.eq(lit("FRANCE"))
3056
+
.and(col("nation.n_nationkey").gt(lit(10))),
3057
+
)?
3058
+
.build()?;
3059
+
3060
+
let sql = plan_to_sql(&filtered)?;
3061
+
// `n_name = 'FRANCE'` appears in both Filter and TableScan — redundant
3062
+
// but correct. Dedup can be optimized separately.
3063
+
assert_snapshot!(
3064
+
sql,
3065
+
@"SELECT nation.n_nationkey, nation.n_name FROM nation WHERE ((nation.n_name = 'FRANCE') AND (nation.n_nationkey > 10)) AND (nation.n_name = 'FRANCE')"
3066
+
);
3067
+
3068
+
// Disjoint predicates — Filter and TableScan have different predicates
3069
+
let scan = table_scan_with_filters(
3070
+
Some("nation"),
3071
+
&schema,
3072
+
Some(vec![0,1]),
3073
+
vec![col("n_name").eq(lit("FRANCE"))],
3074
+
)?
3075
+
.build()?;
3076
+
3077
+
let filtered = LogicalPlanBuilder::from(scan)
3078
+
.filter(col("nation.n_nationkey").gt(lit(10)))?
3079
+
.build()?;
3080
+
3081
+
let sql = plan_to_sql(&filtered)?;
3082
+
// No duplicate: Filter predicate differs from TableScan pushdown filter.
3083
+
assert_snapshot!(
3084
+
sql,
3085
+
@"SELECT nation.n_nationkey, nation.n_name FROM nation WHERE (nation.n_nationkey > 10) AND (nation.n_name = 'FRANCE')"
3086
+
);
3087
+
3088
+
Ok(())
3089
+
}
3090
+
3091
+
/// Verifies that when `SubqueryAlias(Filter(TableScan))` is used inside a JOIN,
3092
+
/// `try_transform_to_simple_table_scan_with_filters` rewrites the Filter
3093
+
/// predicate with the alias so `nation.n_name` becomes `n1.n_name` and the
// The filter predicate should use alias n1 (not original table name "nation").
3147
+
// With Inexact pushdown, the Filter and TableScan carry the same predicate;
3148
+
// after alias rewriting both become identical and are deduplicated.
3149
+
assert_snapshot!(
3150
+
sql,
3151
+
@r#"SELECT supplier.s_suppkey, supplier.s_nationkey, n1.n_nationkey, n1.n_name FROM supplier INNER JOIN nation AS n1 ON supplier.s_nationkey = n1.n_nationkey AND ((n1.n_name = 'FRANCE') OR (n1.n_name = 'GERMANY'))"#
3152
+
);
3153
+
3154
+
Ok(())
3155
+
}
3156
+
3157
+
/// Verifies that when a `Filter` predicate contains subquery expressions
3158
+
/// (e.g. `NOT EXISTS`), `unparse_table_scan_pushdown` returns `None` so the
3159
+
/// caller's `SubqueryAlias` handler falls back to wrapping the inner plan as a
3160
+
/// derived table: `(SELECT ... FROM table WHERE ...) AS alias`.
3161
+
///
3162
+
/// This preserves the original table name inside the derived table, which is
3163
+
/// required for `OuterReferenceColumn` expressions (e.g. `outer_ref(customer.c_custkey)`)
3164
+
/// that refer to the original table name rather than the alias.
// The subquery produces a derived table that preserves the original "customer" table name,
3217
+
// so outer_ref(customer.c_custkey) remains valid inside the NOT EXISTS subquery.
3218
+
assert_snapshot!(
3219
+
sql,
3220
+
@"SELECT * FROM (SELECT customer.c_custkey, customer.c_acctbal FROM customer WHERE ((customer.c_acctbal > 0.0) AND NOT EXISTS (SELECT orders.o_orderkey, orders.o_custkey FROM orders WHERE (orders.o_custkey = customer.c_custkey))) AND (customer.c_acctbal > 0.0)) AS custsale"
0 commit comments