Skip to content

Commit c2bd4a2

Browse files
committed
Refactor join input unparsing
1 parent e6f6858 commit c2bd4a2

1 file changed

Lines changed: 110 additions & 107 deletions

File tree

‎datafusion/sql/src/unparser/plan.rs‎

Lines changed: 110 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,17 @@ struct DerivedInputScope<'a> {
170170
schema: &'a DFSchema,
171171
}
172172

173+
/// Left-side joins can be chained in the surrounding `FROM`, while right-side
174+
/// joins need nesting. ASOF inputs also preserve derived boundaries because
175+
/// their input shaping is part of candidate matching.
176+
#[derive(Clone, Copy)]
177+
enum JoinInputMode {
178+
RegularLeft,
179+
RegularRight,
180+
AsOfLeft,
181+
AsOfRight,
182+
}
183+
173184
impl Unparser<'_> {
174185
pub fn plan_to_sql(&self, plan: &LogicalPlan) -> Result<ast::Statement> {
175186
let mut plan = normalize_union_schema(plan)?;
@@ -1452,45 +1463,29 @@ impl Unparser<'_> {
14521463
left_plan,
14531464
&mut table_scan_filters,
14541465
)?;
1455-
let left_plan = if already_projected {
1456-
Self::unwrap_qualified_passthrough_join_projection(left_plan)
1457-
} else {
1458-
left_plan
1459-
};
1460-
1461-
self.select_to_sql_recursively(
1462-
left_plan.as_ref(),
1466+
let left_projection = self.unparse_join_input(
1467+
&left_plan,
14631468
query,
14641469
select,
14651470
relation,
1471+
already_projected,
1472+
JoinInputMode::RegularLeft,
14661473
)?;
14671474

1468-
let left_projection: Option<Vec<ast::SelectItem>> = if !already_projected
1469-
{
1470-
Some(select.pop_projections())
1471-
} else {
1472-
None
1473-
};
1474-
14751475
let right_plan = Self::extract_join_input_table_scan_filters(
14761476
right_plan,
14771477
&mut table_scan_filters,
14781478
)?;
14791479

14801480
let mut right_relation = RelationBuilder::default();
1481-
if already_projected
1482-
&& let Some(nested_relation) =
1483-
self.join_input_to_nested_relation(right_plan.as_ref(), query)?
1484-
{
1485-
right_relation = nested_relation;
1486-
} else {
1487-
self.select_to_sql_recursively(
1488-
right_plan.as_ref(),
1489-
query,
1490-
select,
1491-
&mut right_relation,
1492-
)?;
1493-
}
1481+
let right_projection = self.unparse_join_input(
1482+
&right_plan,
1483+
query,
1484+
select,
1485+
&mut right_relation,
1486+
already_projected,
1487+
JoinInputMode::RegularRight,
1488+
)?;
14941489

14951490
let (join_filters, where_filters) = Self::split_join_on_and_where_filters(
14961491
join.join_type,
@@ -1508,13 +1503,6 @@ impl Unparser<'_> {
15081503
join_filters.as_ref(),
15091504
)?;
15101505

1511-
let right_projection: Option<Vec<ast::SelectItem>> = if !already_projected
1512-
{
1513-
Some(select.pop_projections())
1514-
} else {
1515-
None
1516-
};
1517-
15181506
match join.join_type {
15191507
JoinType::LeftSemi
15201508
| JoinType::LeftAnti
@@ -1927,78 +1915,24 @@ impl Unparser<'_> {
19271915
relation: &mut RelationBuilder,
19281916
) -> Result<()> {
19291917
let already_projected = select.already_projected();
1930-
let left_plan =
1931-
Self::unwrap_qualified_passthrough_join_projection(Arc::clone(&join.left));
1932-
let inline_left_join = matches!(
1933-
left_plan.as_ref(),
1934-
LogicalPlan::Join(_) | LogicalPlan::AsOfJoin(_)
1935-
);
1936-
let left_projection = if already_projected {
1937-
None
1938-
} else if inline_left_join {
1939-
self.select_to_sql_recursively(left_plan.as_ref(), query, select, relation)?;
1940-
select.pop_projections();
1941-
Some(self.derived_input_projection(join.left.as_ref(), None)?)
1942-
} else if Self::asof_input_requires_derived(join.left.as_ref()) {
1943-
let qualifier = self.derive_asof_input(join.left.as_ref(), relation)?;
1944-
Some(self.derived_input_projection(join.left.as_ref(), qualifier.as_ref())?)
1945-
} else {
1946-
self.select_to_sql_recursively(join.left.as_ref(), query, select, relation)?;
1947-
Some(select.pop_projections())
1948-
};
1949-
if already_projected {
1950-
if inline_left_join {
1951-
self.select_to_sql_recursively(
1952-
left_plan.as_ref(),
1953-
query,
1954-
select,
1955-
relation,
1956-
)?;
1957-
} else if Self::asof_input_requires_derived(join.left.as_ref()) {
1958-
self.derive_asof_input(join.left.as_ref(), relation)?;
1959-
} else {
1960-
self.select_to_sql_recursively(
1961-
join.left.as_ref(),
1962-
query,
1963-
select,
1964-
relation,
1965-
)?;
1966-
}
1967-
}
1918+
let left_projection = self.unparse_join_input(
1919+
&join.left,
1920+
query,
1921+
select,
1922+
relation,
1923+
already_projected,
1924+
JoinInputMode::AsOfLeft,
1925+
)?;
19681926

19691927
let mut right_relation = RelationBuilder::default();
1970-
let nested_right =
1971-
self.join_input_to_nested_relation(join.right.as_ref(), query)?;
1972-
let right_projection = if already_projected {
1973-
if let Some(nested_right) = nested_right {
1974-
right_relation = nested_right;
1975-
} else if Self::asof_input_requires_derived(join.right.as_ref()) {
1976-
self.derive_asof_input(join.right.as_ref(), &mut right_relation)?;
1977-
} else {
1978-
self.select_to_sql_recursively(
1979-
join.right.as_ref(),
1980-
query,
1981-
select,
1982-
&mut right_relation,
1983-
)?;
1984-
}
1985-
None
1986-
} else if let Some(nested_right) = nested_right {
1987-
right_relation = nested_right;
1988-
Some(self.derived_input_projection(join.right.as_ref(), None)?)
1989-
} else if Self::asof_input_requires_derived(join.right.as_ref()) {
1990-
let qualifier =
1991-
self.derive_asof_input(join.right.as_ref(), &mut right_relation)?;
1992-
Some(self.derived_input_projection(join.right.as_ref(), qualifier.as_ref())?)
1993-
} else {
1994-
self.select_to_sql_recursively(
1995-
join.right.as_ref(),
1996-
query,
1997-
select,
1998-
&mut right_relation,
1999-
)?;
2000-
Some(select.pop_projections())
2001-
};
1928+
let right_projection = self.unparse_join_input(
1929+
&join.right,
1930+
query,
1931+
select,
1932+
&mut right_relation,
1933+
already_projected,
1934+
JoinInputMode::AsOfRight,
1935+
)?;
20021936
let Ok(Some(relation)) = right_relation.build() else {
20031937
return internal_err!("Failed to build ASOF right relation");
20041938
};
@@ -2338,7 +2272,76 @@ impl Unparser<'_> {
23382272
)
23392273
}
23402274

2341-
fn asof_input_requires_derived(plan: &LogicalPlan) -> bool {
2275+
fn unparse_join_input(
2276+
&self,
2277+
plan: &Arc<LogicalPlan>,
2278+
query: &mut Option<QueryBuilder>,
2279+
select: &mut SelectBuilder,
2280+
relation: &mut RelationBuilder,
2281+
already_projected: bool,
2282+
mode: JoinInputMode,
2283+
) -> Result<Option<Vec<ast::SelectItem>>> {
2284+
let preserve_boundary =
2285+
matches!(mode, JoinInputMode::AsOfLeft | JoinInputMode::AsOfRight);
2286+
let is_left =
2287+
matches!(mode, JoinInputMode::RegularLeft | JoinInputMode::AsOfLeft);
2288+
let unwrapped_plan = if preserve_boundary || already_projected {
2289+
Self::unwrap_qualified_passthrough_join_projection(Arc::clone(plan))
2290+
} else {
2291+
Arc::clone(plan)
2292+
};
2293+
let inline_left_join = is_left
2294+
&& matches!(
2295+
unwrapped_plan.as_ref(),
2296+
LogicalPlan::Join(_) | LogicalPlan::AsOfJoin(_)
2297+
);
2298+
2299+
if !is_left
2300+
&& (preserve_boundary || already_projected)
2301+
&& let Some(nested_relation) =
2302+
self.join_input_to_nested_relation(plan.as_ref(), query)?
2303+
{
2304+
*relation = nested_relation;
2305+
return if already_projected {
2306+
Ok(None)
2307+
} else {
2308+
Ok(Some(self.derived_input_projection(plan.as_ref(), None)?))
2309+
};
2310+
}
2311+
2312+
if preserve_boundary
2313+
&& !inline_left_join
2314+
&& Self::join_input_requires_derived(plan.as_ref())
2315+
{
2316+
let qualifier = self.derive_join_input(plan.as_ref(), relation)?;
2317+
return if already_projected {
2318+
Ok(None)
2319+
} else {
2320+
Ok(Some(self.derived_input_projection(
2321+
plan.as_ref(),
2322+
qualifier.as_ref(),
2323+
)?))
2324+
};
2325+
}
2326+
2327+
let recursive_plan = if inline_left_join {
2328+
unwrapped_plan.as_ref()
2329+
} else {
2330+
plan.as_ref()
2331+
};
2332+
self.select_to_sql_recursively(recursive_plan, query, select, relation)?;
2333+
2334+
if already_projected {
2335+
Ok(None)
2336+
} else if preserve_boundary && inline_left_join {
2337+
select.pop_projections();
2338+
Ok(Some(self.derived_input_projection(plan.as_ref(), None)?))
2339+
} else {
2340+
Ok(Some(select.pop_projections()))
2341+
}
2342+
}
2343+
2344+
fn join_input_requires_derived(plan: &LogicalPlan) -> bool {
23422345
let simple_scan =
23432346
|scan: &TableScan| scan.filters.is_empty() && scan.fetch.is_none();
23442347
match plan {
@@ -2350,7 +2353,7 @@ impl Unparser<'_> {
23502353
}
23512354
}
23522355

2353-
fn derive_asof_input(
2356+
fn derive_join_input(
23542357
&self,
23552358
plan: &LogicalPlan,
23562359
relation: &mut RelationBuilder,

0 commit comments

Comments
 (0)