|
17 | 17 |
|
18 | 18 | use std::{collections::HashSet, fmt::Debug, sync::Arc}; |
19 | 19 |
|
20 | | -use datafusion_common::{Result, plan_datafusion_err, plan_err}; |
| 20 | +use datafusion_common::{Result, plan_datafusion_err, plan_err, tree_node::TreeNode}; |
21 | 21 | use datafusion_expr::{Expr, Filter, JoinConstraint, JoinType, LogicalPlan}; |
22 | 22 |
|
23 | 23 | use crate::reorder_join::{ |
@@ -75,6 +75,13 @@ pub fn optimal_left_deep_join_plan( |
75 | 75 | plan: LogicalPlan, |
76 | 76 | cost_estimator: &dyn JoinCostEstimator, |
77 | 77 | ) -> Result<LogicalPlan> { |
| 78 | + // No joins anywhere in the plan: nothing to reorder. Returning the |
| 79 | + // input unchanged lets callers wire this in unconditionally without |
| 80 | + // having to pre-check. |
| 81 | + if !plan.exists(|p| Ok(matches!(p, LogicalPlan::Join(_))))? { |
| 82 | + return Ok(plan); |
| 83 | + } |
| 84 | + |
78 | 85 | // Convert join subtree to query graph |
79 | 86 | let (query_graph, wrappers) = JoinGraph::try_from_logical_plan(plan)?; |
80 | 87 |
|
@@ -829,6 +836,24 @@ mod tests { |
829 | 836 | Ok(()) |
830 | 837 | } |
831 | 838 |
|
| 839 | + /// A plan with no joins anywhere should pass through untouched — |
| 840 | + /// previously the entry point errored out with "Plan does not contain |
| 841 | + /// any join nodes" which made it unsafe to wire in unconditionally. |
| 842 | + #[test] |
| 843 | + fn test_plan_without_joins_passes_through() -> Result<()> { |
| 844 | + use datafusion_expr::{col, lit}; |
| 845 | + |
| 846 | + let plan = LogicalPlanBuilder::from(scan_tpch_table("customer")) |
| 847 | + .filter(col("c_custkey").gt(lit(100)))? |
| 848 | + .project(vec![col("c_name")])? |
| 849 | + .build()?; |
| 850 | + |
| 851 | + let before = format!("{}", plan.display_indent()); |
| 852 | + let after = optimal_left_deep_join_plan(plan, &TestCostEstimator)?; |
| 853 | + assert_eq!(before, format!("{}", after.display_indent())); |
| 854 | + Ok(()) |
| 855 | + } |
| 856 | + |
832 | 857 | /// Repro: one outer Join with multi-pair `on` where the two equi-pairs |
833 | 858 | /// connect *different* node pairs after extraction. Without |
834 | 859 | /// per-pair edge construction the customer↔lineitem edge would carry |
|
0 commit comments