Skip to content

Commit 5db2740

Browse files
authored
Improve TableScan with filters pushdown unparsing (multiple filters support) (#13131)
1 parent 146f16a commit 5db2740

File tree

2 files changed

+37
-1
lines changed

2 files changed

+37
-1
lines changed

datafusion/sql/src/unparser/ast.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,28 @@ impl SelectBuilder {
182182
self
183183
}
184184
pub fn selection(&mut self, value: Option<ast::Expr>) -> &mut Self {
185-
self.selection = value;
185+
// With filter pushdown optimization, the LogicalPlan can have filters defined as part of `TableScan` and `Filter` nodes.
186+
// To avoid overwriting one of the filters, we combine the existing filter with the additional filter.
187+
// Example: |
188+
// | Projection: customer.c_phone AS cntrycode, customer.c_acctbal |
189+
// | Filter: CAST(customer.c_acctbal AS Decimal128(38, 6)) > (<subquery>) |
190+
// | Subquery:
191+
// | .. |
192+
// | TableScan: customer, full_filters=[customer.c_mktsegment = Utf8("BUILDING")]
193+
match (&self.selection, value) {
194+
(Some(existing_selection), Some(new_selection)) => {
195+
self.selection = Some(ast::Expr::BinaryOp {
196+
left: Box::new(existing_selection.clone()),
197+
op: ast::BinaryOperator::And,
198+
right: Box::new(new_selection),
199+
});
200+
}
201+
(None, Some(new_selection)) => {
202+
self.selection = Some(new_selection);
203+
}
204+
(_, None) => (),
205+
}
206+
186207
self
187208
}
188209
pub fn group_by(&mut self, value: ast::GroupByExpr) -> &mut Self {

datafusion/sql/tests/cases/plan_to_sql.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -968,6 +968,21 @@ fn test_table_scan_pushdown() -> Result<()> {
968968
table_scan_with_all.to_string(),
969969
"SELECT t1.id, t1.age FROM t1 WHERE (t1.id > t1.age) LIMIT 10"
970970
);
971+
972+
let table_scan_with_additional_filter = table_scan_with_filters(
973+
Some("t1"),
974+
&schema,
975+
None,
976+
vec![col("id").gt(col("age"))],
977+
)?
978+
.filter(col("id").eq(lit(5)))?
979+
.build()?;
980+
let table_scan_with_filter = plan_to_sql(&table_scan_with_additional_filter)?;
981+
assert_eq!(
982+
table_scan_with_filter.to_string(),
983+
"SELECT * FROM t1 WHERE (t1.id = 5) AND (t1.id > t1.age)"
984+
);
985+
971986
Ok(())
972987
}
973988

0 commit comments

Comments
 (0)