@@ -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+
173184impl 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