Skip to content

Commit 6d525cf

Browse files
adriangbclaude
andcommitted
Add preferred_ordering field to TableScan
This commit adds a new optional field `preferred_ordering` to the `TableScan` logical plan node to support sort pushdown optimizations. Changes include: - Add `preferred_ordering: Option<Vec<SortExpr>>` field to `TableScan` struct - Add `try_new_with_preferred_ordering` constructor method - Update all `TableScan` constructors throughout the codebase to include the new field - Update `Debug`, `PartialEq`, `Hash`, and `PartialOrd` implementations - Update pattern matching in optimizer and other modules The preferred_ordering field is currently not used by any optimization rules but provides the foundation for future sort pushdown implementations. This is part 2 of 2 PRs split from apache#17273 as requested in apache#17273 (comment) 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent b6a8a0e commit 6d525cf

File tree

5 files changed

+32
-1
lines changed

5 files changed

+32
-1
lines changed

datafusion/expr/src/logical_plan/plan.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2525,6 +2525,8 @@ pub struct TableScan {
25252525
pub filters: Vec<Expr>,
25262526
/// Optional number of rows to read
25272527
pub fetch: Option<usize>,
2528+
/// Optional preferred ordering for the scan
2529+
pub preferred_ordering: Option<Vec<SortExpr>>,
25282530
}
25292531

25302532
impl Debug for TableScan {
@@ -2536,6 +2538,7 @@ impl Debug for TableScan {
25362538
.field("projected_schema", &self.projected_schema)
25372539
.field("filters", &self.filters)
25382540
.field("fetch", &self.fetch)
2541+
.field("preferred_ordering", &self.preferred_ordering)
25392542
.finish_non_exhaustive()
25402543
}
25412544
}
@@ -2547,6 +2550,7 @@ impl PartialEq for TableScan {
25472550
&& self.projected_schema == other.projected_schema
25482551
&& self.filters == other.filters
25492552
&& self.fetch == other.fetch
2553+
&& self.preferred_ordering == other.preferred_ordering
25502554
}
25512555
}
25522556

@@ -2566,18 +2570,22 @@ impl PartialOrd for TableScan {
25662570
pub filters: &'a Vec<Expr>,
25672571
/// Optional number of rows to read
25682572
pub fetch: &'a Option<usize>,
2573+
/// Optional preferred ordering for the scan
2574+
pub preferred_ordering: &'a Option<Vec<SortExpr>>,
25692575
}
25702576
let comparable_self = ComparableTableScan {
25712577
table_name: &self.table_name,
25722578
projection: &self.projection,
25732579
filters: &self.filters,
25742580
fetch: &self.fetch,
2581+
preferred_ordering: &self.preferred_ordering,
25752582
};
25762583
let comparable_other = ComparableTableScan {
25772584
table_name: &other.table_name,
25782585
projection: &other.projection,
25792586
filters: &other.filters,
25802587
fetch: &other.fetch,
2588+
preferred_ordering: &other.preferred_ordering,
25812589
};
25822590
comparable_self.partial_cmp(&comparable_other)
25832591
}
@@ -2590,6 +2598,7 @@ impl Hash for TableScan {
25902598
self.projected_schema.hash(state);
25912599
self.filters.hash(state);
25922600
self.fetch.hash(state);
2601+
self.preferred_ordering.hash(state);
25932602
}
25942603
}
25952604

@@ -2643,8 +2652,22 @@ impl TableScan {
26432652
projected_schema,
26442653
filters,
26452654
fetch,
2655+
preferred_ordering: None,
26462656
})
26472657
}
2658+
2659+
pub fn try_new_with_preferred_ordering(
2660+
table_name: impl Into<TableReference>,
2661+
table_source: Arc<dyn TableSource>,
2662+
projection: Option<Vec<usize>>,
2663+
filters: Vec<Expr>,
2664+
fetch: Option<usize>,
2665+
preferred_ordering: Option<Vec<SortExpr>>,
2666+
) -> Result<Self> {
2667+
let mut table_scan = Self::try_new(table_name, table_source, projection, filters, fetch)?;
2668+
table_scan.preferred_ordering = preferred_ordering;
2669+
Ok(table_scan)
2670+
}
26482671
}
26492672

26502673
// Repartition the plan based on a partitioning scheme.
@@ -4814,6 +4837,7 @@ mod tests {
48144837
projected_schema: Arc::clone(&schema),
48154838
filters: vec![],
48164839
fetch: None,
4840+
preferred_ordering: None,
48174841
}));
48184842
let col = schema.field_names()[0].clone();
48194843

@@ -4844,6 +4868,7 @@ mod tests {
48444868
projected_schema: Arc::clone(&unique_schema),
48454869
filters: vec![],
48464870
fetch: None,
4871+
preferred_ordering: None,
48474872
}));
48484873
let col = schema.field_names()[0].clone();
48494874

datafusion/expr/src/logical_plan/tree_node.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,7 @@ impl LogicalPlan {
599599
projected_schema,
600600
filters,
601601
fetch,
602+
preferred_ordering,
602603
}) => filters.map_elements(f)?.update_data(|filters| {
603604
LogicalPlan::TableScan(TableScan {
604605
table_name,
@@ -607,6 +608,7 @@ impl LogicalPlan {
607608
projected_schema,
608609
filters,
609610
fetch,
611+
preferred_ordering,
610612
})
611613
}),
612614
LogicalPlan::Distinct(Distinct::On(DistinctOn {

datafusion/optimizer/src/optimize_projections/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ fn optimize_projections(
242242
filters,
243243
fetch,
244244
projected_schema: _,
245+
preferred_ordering,
245246
} = table_scan;
246247

247248
// Get indices referred to in the original (schema with all fields)
@@ -250,12 +251,13 @@ fn optimize_projections(
250251
Some(projection) => indices.into_mapped_indices(|idx| projection[idx]),
251252
None => indices.into_inner(),
252253
};
253-
return TableScan::try_new(
254+
return TableScan::try_new_with_preferred_ordering(
254255
table_name,
255256
source,
256257
Some(projection),
257258
filters,
258259
fetch,
260+
preferred_ordering,
259261
)
260262
.map(LogicalPlan::TableScan)
261263
.map(Transformed::yes);

datafusion/optimizer/src/push_down_filter.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3055,6 +3055,7 @@ mod tests {
30553055
projection,
30563056
source: Arc::new(test_provider),
30573057
fetch: None,
3058+
preferred_ordering: None,
30583059
});
30593060

30603061
Ok(LogicalPlanBuilder::from(table_scan))

datafusion/proto/src/logical_plan/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,7 @@ fn from_table_source(
271271
projected_schema,
272272
filters: vec![],
273273
fetch: None,
274+
preferred_ordering: None,
274275
});
275276

276277
LogicalPlanNode::try_from_logical_plan(&r, extension_codec)

0 commit comments

Comments
 (0)