@@ -213,3 +213,228 @@ async fn subquery_not_allowed() -> Result<()> {
213213
214214 Ok ( ( ) )
215215}
216+
217+ #[ tokio:: test]
218+ async fn support_agg_correlated_columns ( ) -> Result < ( ) > {
219+ let ctx = create_join_context ( "t1_id" , "t2_id" , true ) ?;
220+
221+ let sql = "SELECT t1_id, t1_name FROM t1 WHERE EXISTS (SELECT sum(t1.t1_int + t2.t2_id) FROM t2 WHERE t1.t1_name = t2.t2_name)" ;
222+ let msg = format ! ( "Creating logical plan for '{sql}'" ) ;
223+ let dataframe = ctx. sql ( sql) . await . expect ( & msg) ;
224+ let plan = dataframe. into_optimized_plan ( ) ?;
225+
226+ let expected = vec ! [
227+ "Filter: EXISTS (<subquery>) [t1_id:UInt32;N, t1_name:Utf8;N]" ,
228+ " Subquery: [SUM(outer_ref(t1.t1_int) + t2.t2_id):UInt64;N]" ,
229+ " Projection: SUM(outer_ref(t1.t1_int) + t2.t2_id) [SUM(outer_ref(t1.t1_int) + t2.t2_id):UInt64;N]" ,
230+ " Aggregate: groupBy=[[]], aggr=[[SUM(outer_ref(t1.t1_int) + t2.t2_id)]] [SUM(outer_ref(t1.t1_int) + t2.t2_id):UInt64;N]" ,
231+ " Filter: outer_ref(t1.t1_name) = t2.t2_name [t2_id:UInt32;N, t2_name:Utf8;N, t2_int:UInt32;N]" ,
232+ " TableScan: t2 [t2_id:UInt32;N, t2_name:Utf8;N, t2_int:UInt32;N]" ,
233+ " TableScan: t1 projection=[t1_id, t1_name] [t1_id:UInt32;N, t1_name:Utf8;N]" ,
234+ ] ;
235+ let formatted = plan. display_indent_schema ( ) . to_string ( ) ;
236+ let actual: Vec < & str > = formatted. trim ( ) . lines ( ) . collect ( ) ;
237+ assert_eq ! (
238+ expected, actual,
239+ "\n \n expected:\n \n {expected:#?}\n actual:\n \n {actual:#?}\n \n "
240+ ) ;
241+
242+ Ok ( ( ) )
243+ }
244+
245+ #[ tokio:: test]
246+ async fn support_agg_correlated_columns2 ( ) -> Result < ( ) > {
247+ let ctx = create_join_context ( "t1_id" , "t2_id" , true ) ?;
248+
249+ let sql = "SELECT t1_id, t1_name FROM t1 WHERE EXISTS (SELECT count(*) FROM t2 WHERE t1.t1_name = t2.t2_name having sum(t1_int + t2_id) >0)" ;
250+ let msg = format ! ( "Creating logical plan for '{sql}'" ) ;
251+ let dataframe = ctx. sql ( sql) . await . expect ( & msg) ;
252+ let plan = dataframe. into_optimized_plan ( ) ?;
253+
254+ let expected = vec ! [
255+ "Filter: EXISTS (<subquery>) [t1_id:UInt32;N, t1_name:Utf8;N]" ,
256+ " Subquery: [COUNT(UInt8(1)):Int64;N]" ,
257+ " Projection: COUNT(UInt8(1)) [COUNT(UInt8(1)):Int64;N]" ,
258+ " Filter: CAST(SUM(outer_ref(t1.t1_int) + t2.t2_id) AS Int64) > Int64(0) [COUNT(UInt8(1)):Int64;N, SUM(outer_ref(t1.t1_int) + t2.t2_id):UInt64;N]" ,
259+ " Aggregate: groupBy=[[]], aggr=[[COUNT(UInt8(1)), SUM(outer_ref(t1.t1_int) + t2.t2_id)]] [COUNT(UInt8(1)):Int64;N, SUM(outer_ref(t1.t1_int) + t2.t2_id):UInt64;N]" ,
260+ " Filter: outer_ref(t1.t1_name) = t2.t2_name [t2_id:UInt32;N, t2_name:Utf8;N, t2_int:UInt32;N]" ,
261+ " TableScan: t2 [t2_id:UInt32;N, t2_name:Utf8;N, t2_int:UInt32;N]" ,
262+ " TableScan: t1 projection=[t1_id, t1_name] [t1_id:UInt32;N, t1_name:Utf8;N]" ,
263+ ] ;
264+ let formatted = plan. display_indent_schema ( ) . to_string ( ) ;
265+ let actual: Vec < & str > = formatted. trim ( ) . lines ( ) . collect ( ) ;
266+ assert_eq ! (
267+ expected, actual,
268+ "\n \n expected:\n \n {expected:#?}\n actual:\n \n {actual:#?}\n \n "
269+ ) ;
270+
271+ Ok ( ( ) )
272+ }
273+
274+ #[ tokio:: test]
275+ async fn support_join_correlated_columns ( ) -> Result < ( ) > {
276+ let ctx = create_sub_query_join_context ( "t0_id" , "t1_id" , "t2_id" , true ) ?;
277+ let sql = "SELECT t0_id, t0_name FROM t0 WHERE EXISTS (SELECT 1 FROM t1 INNER JOIN t2 ON(t1.t1_id = t2.t2_id and t1.t1_name = t0.t0_name))" ;
278+ let msg = format ! ( "Creating logical plan for '{sql}'" ) ;
279+ let dataframe = ctx. sql ( sql) . await . expect ( & msg) ;
280+ let plan = dataframe. into_optimized_plan ( ) ?;
281+
282+ let expected = vec ! [
283+ "Filter: EXISTS (<subquery>) [t0_id:UInt32;N, t0_name:Utf8;N]" ,
284+ " Subquery: [Int64(1):Int64]" ,
285+ " Projection: Int64(1) [Int64(1):Int64]" ,
286+ " Inner Join: Filter: t1.t1_id = t2.t2_id AND t1.t1_name = outer_ref(t0.t0_name) [t1_id:UInt32;N, t1_name:Utf8;N, t1_int:UInt32;N, t2_id:UInt32;N, t2_name:Utf8;N, t2_int:UInt32;N]" ,
287+ " TableScan: t1 [t1_id:UInt32;N, t1_name:Utf8;N, t1_int:UInt32;N]" ,
288+ " TableScan: t2 [t2_id:UInt32;N, t2_name:Utf8;N, t2_int:UInt32;N]" ,
289+ " TableScan: t0 projection=[t0_id, t0_name] [t0_id:UInt32;N, t0_name:Utf8;N]" ,
290+ ] ;
291+ let formatted = plan. display_indent_schema ( ) . to_string ( ) ;
292+ let actual: Vec < & str > = formatted. trim ( ) . lines ( ) . collect ( ) ;
293+ assert_eq ! (
294+ expected, actual,
295+ "\n \n expected:\n \n {expected:#?}\n actual:\n \n {actual:#?}\n \n "
296+ ) ;
297+
298+ Ok ( ( ) )
299+ }
300+
301+ #[ tokio:: test]
302+ async fn support_join_correlated_columns2 ( ) -> Result < ( ) > {
303+ let ctx = create_sub_query_join_context ( "t0_id" , "t1_id" , "t2_id" , true ) ?;
304+ let sql = "SELECT t0_id, t0_name FROM t0 WHERE EXISTS (SELECT 1 FROM t1 INNER JOIN (select * from t2 where t2.t2_name = t0.t0_name) as t2 ON(t1.t1_id = t2.t2_id ))" ;
305+ let msg = format ! ( "Creating logical plan for '{sql}'" ) ;
306+ let dataframe = ctx. sql ( sql) . await . expect ( & msg) ;
307+ let plan = dataframe. into_optimized_plan ( ) ?;
308+
309+ let expected = vec ! [
310+ "Filter: EXISTS (<subquery>) [t0_id:UInt32;N, t0_name:Utf8;N]" ,
311+ " Subquery: [Int64(1):Int64]" ,
312+ " Projection: Int64(1) [Int64(1):Int64]" ,
313+ " Inner Join: Filter: t1.t1_id = t2.t2_id [t1_id:UInt32;N, t1_name:Utf8;N, t1_int:UInt32;N, t2_id:UInt32;N, t2_name:Utf8;N, t2_int:UInt32;N]" ,
314+ " TableScan: t1 [t1_id:UInt32;N, t1_name:Utf8;N, t1_int:UInt32;N]" ,
315+ " SubqueryAlias: t2 [t2_id:UInt32;N, t2_name:Utf8;N, t2_int:UInt32;N]" ,
316+ " Projection: t2.t2_id, t2.t2_name, t2.t2_int [t2_id:UInt32;N, t2_name:Utf8;N, t2_int:UInt32;N]" ,
317+ " Filter: t2.t2_name = outer_ref(t0.t0_name) [t2_id:UInt32;N, t2_name:Utf8;N, t2_int:UInt32;N]" ,
318+ " TableScan: t2 [t2_id:UInt32;N, t2_name:Utf8;N, t2_int:UInt32;N]" ,
319+ " TableScan: t0 projection=[t0_id, t0_name] [t0_id:UInt32;N, t0_name:Utf8;N]" ,
320+ ] ;
321+ let formatted = plan. display_indent_schema ( ) . to_string ( ) ;
322+ let actual: Vec < & str > = formatted. trim ( ) . lines ( ) . collect ( ) ;
323+ assert_eq ! (
324+ expected, actual,
325+ "\n \n expected:\n \n {expected:#?}\n actual:\n \n {actual:#?}\n \n "
326+ ) ;
327+
328+ Ok ( ( ) )
329+ }
330+
331+ #[ tokio:: test]
332+ async fn support_order_by_correlated_columns ( ) -> Result < ( ) > {
333+ let ctx = create_join_context ( "t1_id" , "t2_id" , true ) ?;
334+
335+ let sql = "SELECT t1_id, t1_name FROM t1 WHERE EXISTS (SELECT * FROM t2 WHERE t2_id >= t1_id order by t1_id)" ;
336+ let msg = format ! ( "Creating logical plan for '{sql}'" ) ;
337+ let dataframe = ctx. sql ( sql) . await . expect ( & msg) ;
338+ let plan = dataframe. into_optimized_plan ( ) ?;
339+
340+ let expected = vec ! [
341+ "Filter: EXISTS (<subquery>) [t1_id:UInt32;N, t1_name:Utf8;N]" ,
342+ " Subquery: [t2_id:UInt32;N, t2_name:Utf8;N, t2_int:UInt32;N]" ,
343+ " Sort: outer_ref(t1.t1_id) ASC NULLS LAST [t2_id:UInt32;N, t2_name:Utf8;N, t2_int:UInt32;N]" ,
344+ " Projection: t2.t2_id, t2.t2_name, t2.t2_int [t2_id:UInt32;N, t2_name:Utf8;N, t2_int:UInt32;N]" ,
345+ " Filter: t2.t2_id >= outer_ref(t1.t1_id) [t2_id:UInt32;N, t2_name:Utf8;N, t2_int:UInt32;N]" ,
346+ " TableScan: t2 [t2_id:UInt32;N, t2_name:Utf8;N, t2_int:UInt32;N]" ,
347+ " TableScan: t1 projection=[t1_id, t1_name] [t1_id:UInt32;N, t1_name:Utf8;N]" ,
348+ ] ;
349+ let formatted = plan. display_indent_schema ( ) . to_string ( ) ;
350+ let actual: Vec < & str > = formatted. trim ( ) . lines ( ) . collect ( ) ;
351+ assert_eq ! (
352+ expected, actual,
353+ "\n \n expected:\n \n {expected:#?}\n actual:\n \n {actual:#?}\n \n "
354+ ) ;
355+
356+ Ok ( ( ) )
357+ }
358+
359+ #[ tokio:: test]
360+ async fn support_limit_subquery ( ) -> Result < ( ) > {
361+ let ctx = create_join_context ( "t1_id" , "t2_id" , true ) ?;
362+
363+ let sql = "SELECT t1_id, t1_name FROM t1 WHERE EXISTS (SELECT * FROM t2 WHERE t2_id = t1_id limit 1)" ;
364+ let msg = format ! ( "Creating logical plan for '{sql}'" ) ;
365+ let dataframe = ctx. sql ( sql) . await . expect ( & msg) ;
366+ let plan = dataframe. into_optimized_plan ( ) ?;
367+
368+ let expected = vec ! [
369+ "Filter: EXISTS (<subquery>) [t1_id:UInt32;N, t1_name:Utf8;N]" ,
370+ " Subquery: [t2_id:UInt32;N, t2_name:Utf8;N, t2_int:UInt32;N]" ,
371+ " Limit: skip=0, fetch=1 [t2_id:UInt32;N, t2_name:Utf8;N, t2_int:UInt32;N]" ,
372+ " Projection: t2.t2_id, t2.t2_name, t2.t2_int [t2_id:UInt32;N, t2_name:Utf8;N, t2_int:UInt32;N]" ,
373+ " Filter: t2.t2_id = outer_ref(t1.t1_id) [t2_id:UInt32;N, t2_name:Utf8;N, t2_int:UInt32;N]" ,
374+ " TableScan: t2 [t2_id:UInt32;N, t2_name:Utf8;N, t2_int:UInt32;N]" ,
375+ " TableScan: t1 projection=[t1_id, t1_name] [t1_id:UInt32;N, t1_name:Utf8;N]" ,
376+ ] ;
377+ let formatted = plan. display_indent_schema ( ) . to_string ( ) ;
378+ let actual: Vec < & str > = formatted. trim ( ) . lines ( ) . collect ( ) ;
379+ assert_eq ! (
380+ expected, actual,
381+ "\n \n expected:\n \n {expected:#?}\n actual:\n \n {actual:#?}\n \n "
382+ ) ;
383+
384+ let sql = "SELECT t1_id, t1_name FROM t1 WHERE t1_id in (SELECT t2_id FROM t2 where t1_name = t2_name limit 10)" ;
385+ let msg = format ! ( "Creating logical plan for '{sql}'" ) ;
386+ let dataframe = ctx. sql ( sql) . await . expect ( & msg) ;
387+ let plan = dataframe. into_optimized_plan ( ) ?;
388+
389+ let expected = vec ! [
390+ "Filter: t1.t1_id IN (<subquery>) [t1_id:UInt32;N, t1_name:Utf8;N]" ,
391+ " Subquery: [t2_id:UInt32;N]" ,
392+ " Limit: skip=0, fetch=10 [t2_id:UInt32;N]" ,
393+ " Projection: t2.t2_id [t2_id:UInt32;N]" ,
394+ " Filter: outer_ref(t1.t1_name) = t2.t2_name [t2_id:UInt32;N, t2_name:Utf8;N, t2_int:UInt32;N]" ,
395+ " TableScan: t2 [t2_id:UInt32;N, t2_name:Utf8;N, t2_int:UInt32;N]" ,
396+ " TableScan: t1 projection=[t1_id, t1_name] [t1_id:UInt32;N, t1_name:Utf8;N]" ,
397+ ] ;
398+ let formatted = plan. display_indent_schema ( ) . to_string ( ) ;
399+ let actual: Vec < & str > = formatted. trim ( ) . lines ( ) . collect ( ) ;
400+ assert_eq ! (
401+ expected, actual,
402+ "\n \n expected:\n \n {expected:#?}\n actual:\n \n {actual:#?}\n \n "
403+ ) ;
404+
405+ Ok ( ( ) )
406+ }
407+
408+ #[ tokio:: test]
409+ async fn support_union_subquery ( ) -> Result < ( ) > {
410+ let ctx = create_join_context ( "t1_id" , "t2_id" , true ) ?;
411+
412+ let sql = "SELECT t1_id, t1_name FROM t1 WHERE EXISTS \
413+ (SELECT * FROM t2 WHERE t2_id = t1_id UNION ALL \
414+ SELECT * FROM t2 WHERE upper(t2_name) = upper(t1.t1_name))";
415+
416+ let msg = format ! ( "Creating logical plan for '{sql}'" ) ;
417+ let dataframe = ctx. sql ( sql) . await . expect ( & msg) ;
418+ let plan = dataframe. into_optimized_plan ( ) ?;
419+
420+ let expected = vec ! [
421+ "Filter: EXISTS (<subquery>) [t1_id:UInt32;N, t1_name:Utf8;N]" ,
422+ " Subquery: [t2_id:UInt32;N, t2_name:Utf8;N, t2_int:UInt32;N]" ,
423+ " Union [t2_id:UInt32;N, t2_name:Utf8;N, t2_int:UInt32;N]" ,
424+ " Projection: t2.t2_id, t2.t2_name, t2.t2_int [t2_id:UInt32;N, t2_name:Utf8;N, t2_int:UInt32;N]" ,
425+ " Filter: t2.t2_id = outer_ref(t1.t1_id) [t2_id:UInt32;N, t2_name:Utf8;N, t2_int:UInt32;N]" ,
426+ " TableScan: t2 [t2_id:UInt32;N, t2_name:Utf8;N, t2_int:UInt32;N]" ,
427+ " Projection: t2.t2_id, t2.t2_name, t2.t2_int [t2_id:UInt32;N, t2_name:Utf8;N, t2_int:UInt32;N]" ,
428+ " Filter: upper(t2.t2_name) = upper(outer_ref(t1.t1_name)) [t2_id:UInt32;N, t2_name:Utf8;N, t2_int:UInt32;N]" ,
429+ " TableScan: t2 [t2_id:UInt32;N, t2_name:Utf8;N, t2_int:UInt32;N]" ,
430+ " TableScan: t1 projection=[t1_id, t1_name] [t1_id:UInt32;N, t1_name:Utf8;N]" ,
431+ ] ;
432+ let formatted = plan. display_indent_schema ( ) . to_string ( ) ;
433+ let actual: Vec < & str > = formatted. trim ( ) . lines ( ) . collect ( ) ;
434+ assert_eq ! (
435+ expected, actual,
436+ "\n \n expected:\n \n {expected:#?}\n actual:\n \n {actual:#?}\n \n "
437+ ) ;
438+
439+ Ok ( ( ) )
440+ }
0 commit comments