@@ -213,3 +213,228 @@ async fn subquery_not_allowed() -> Result<()> {
213
213
214
214
Ok ( ( ) )
215
215
}
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