@@ -278,3 +278,263 @@ fn case_and(expr: &BoxScalarExpr) -> Option<(&BoxScalarExpr, &BoxScalarExpr)> {
278
278
279
279
None
280
280
}
281
+
282
+ #[ cfg( test) ]
283
+ mod tests {
284
+ use super :: * ;
285
+ use crate :: query_model:: model:: * ;
286
+ use crate :: query_model:: test:: util:: * ;
287
+
288
+ #[ test]
289
+ fn test_select_1 ( ) {
290
+ let mut model = Model :: new ( ) ;
291
+ let g_id = add_get ( & mut model) ;
292
+ let b_id = add_select ( & mut model, g_id, |input| {
293
+ vec ! [
294
+ // P0: (#0 - #1) + (#2 - #3)
295
+ exp:: add(
296
+ exp:: sub( exp:: cref( input, 0 ) , exp:: cref( input, 1 ) ) , // {#0, #1}
297
+ exp:: sub( exp:: cref( input, 2 ) , exp:: cref( input, 3 ) ) , // {#2, #3}
298
+ ) , // {#0, #1, #2, #3}
299
+ ]
300
+ } ) ;
301
+
302
+ assert_derived_attribute ( & mut model, b_id, |r#box| {
303
+ HashSet :: from ( [
304
+ cref ( input ( & r#box, 0 ) , 0 ) ,
305
+ cref ( input ( & r#box, 0 ) , 1 ) ,
306
+ cref ( input ( & r#box, 0 ) , 2 ) ,
307
+ cref ( input ( & r#box, 0 ) , 3 ) ,
308
+ ] ) // {#0, #1, #2, #3}
309
+ } ) ;
310
+ }
311
+
312
+ #[ test]
313
+ fn test_select_2 ( ) {
314
+ let mut model = Model :: new ( ) ;
315
+ let g_id = add_get ( & mut model) ;
316
+ let b_id = add_select ( & mut model, g_id, |input| {
317
+ vec ! [
318
+ // P0: (#0 > #1) || (#2 < #3)
319
+ exp:: and(
320
+ exp:: gt( exp:: cref( input, 0 ) , exp:: cref( input, 1 ) ) , // {#0, #1}
321
+ exp:: lt( exp:: cref( input, 2 ) , exp:: cref( input, 3 ) ) , // {#2, #3}
322
+ ) , // {#0, #1, #2, #3}
323
+ ]
324
+ } ) ;
325
+
326
+ assert_derived_attribute ( & mut model, b_id, |r#box| {
327
+ HashSet :: from ( [
328
+ cref ( input ( & r#box, 0 ) , 0 ) ,
329
+ cref ( input ( & r#box, 0 ) , 1 ) ,
330
+ cref ( input ( & r#box, 0 ) , 2 ) ,
331
+ cref ( input ( & r#box, 0 ) , 3 ) ,
332
+ ] ) // {#0, #1, #2, #3}
333
+ } ) ;
334
+ }
335
+
336
+ #[ test]
337
+ fn test_select_3 ( ) {
338
+ let mut model = Model :: new ( ) ;
339
+ let g_id = add_get ( & mut model) ;
340
+ let b_id = add_select ( & mut model, g_id, |input| {
341
+ vec ! [
342
+ // P0: OR(NOT(OR(#0 < #1, #1 < #2)), AND(!isnull(#1), AND(#0 = #2, #2 = #3))
343
+ exp:: or(
344
+ exp:: not( exp:: or(
345
+ exp:: lt( exp:: cref( input, 0 ) , exp:: cref( input, 1 ) ) , // { #0, #1 }
346
+ exp:: lt( exp:: cref( input, 1 ) , exp:: cref( input, 2 ) ) , // { #1, #2 }
347
+ ) ) , // { #0, #1, #2 }
348
+ exp:: and(
349
+ exp:: not( exp:: isnull( exp:: cref( input, 1 ) ) ) , // { #1 }
350
+ exp:: and(
351
+ exp:: eq( exp:: cref( input, 0 ) , exp:: cref( input, 2 ) ) , // { #0, #2 }
352
+ exp:: eq( exp:: cref( input, 2 ) , exp:: cref( input, 3 ) ) , // { #2, #3 }
353
+ ) , // { #0, #2, #3 }
354
+ ) , // { #0, #1, #2, #3 }
355
+ ) , // { #0, #1, #2 }
356
+ // P1: !isnull(#3)
357
+ exp:: not( exp:: isnull( exp:: cref( input, 3 ) ) ) , // { #3 }
358
+ ]
359
+ } ) ;
360
+
361
+ assert_derived_attribute ( & mut model, b_id, |r#box| {
362
+ HashSet :: from ( [
363
+ cref ( input ( & r#box, 0 ) , 0 ) ,
364
+ cref ( input ( & r#box, 0 ) , 1 ) ,
365
+ cref ( input ( & r#box, 0 ) , 2 ) ,
366
+ cref ( input ( & r#box, 0 ) , 3 ) ,
367
+ ] ) // {#0, #1, #2, #3}
368
+ } ) ;
369
+ }
370
+
371
+ #[ test]
372
+ fn test_select_4 ( ) {
373
+ let mut model = Model :: new ( ) ;
374
+ let g_id = add_get ( & mut model) ;
375
+ let b_id = add_select ( & mut model, g_id, |input| {
376
+ vec ! [
377
+ // P0: AND(NOT(AND(#0 < #1, #1 < #2)), OR(!isnull(#2), OR(#0 = #2, #2 = #3))
378
+ exp:: and(
379
+ exp:: not( exp:: and(
380
+ exp:: lt( exp:: cref( input, 0 ) , exp:: cref( input, 1 ) ) , // { #0, #1 }
381
+ exp:: lt( exp:: cref( input, 1 ) , exp:: cref( input, 2 ) ) , // { #1, #2 }
382
+ ) ) , // { #1 }
383
+ exp:: or(
384
+ exp:: not( exp:: isnull( exp:: cref( input, 2 ) ) ) , // { #2 }
385
+ exp:: or(
386
+ exp:: eq( exp:: cref( input, 0 ) , exp:: cref( input, 2 ) ) , // { #0, #2 }
387
+ exp:: eq( exp:: cref( input, 2 ) , exp:: cref( input, 3 ) ) , // { #2, #3 }
388
+ ) , // { #2 }
389
+ ) , // { #2 }
390
+ ) , // { #1, #2 }
391
+ // P1: !isnull(#3)
392
+ exp:: not( exp:: isnull( exp:: cref( input, 3 ) ) ) , // { #3 }
393
+ ]
394
+ } ) ;
395
+
396
+ assert_derived_attribute ( & mut model, b_id, |r#box| {
397
+ HashSet :: from ( [
398
+ cref ( input ( & r#box, 0 ) , 1 ) ,
399
+ cref ( input ( & r#box, 0 ) , 2 ) ,
400
+ cref ( input ( & r#box, 0 ) , 3 ) ,
401
+ ] ) // {#0, #2, #3}
402
+ } ) ;
403
+ }
404
+
405
+ #[ test]
406
+ fn test_left_outer_join_1 ( ) {
407
+ let mut model = Model :: new ( ) ;
408
+ let g_id = add_get ( & mut model) ;
409
+ let b_id = add_left_outer_join ( & mut model, g_id, g_id, |lhs, rhs| {
410
+ vec ! [
411
+ // P0: (lhs.#0 > rhs.#0)
412
+ exp:: gt( exp:: cref( lhs, 0 ) , exp:: cref( rhs, 0 ) ) ,
413
+ // P1: (lhs.#1 < rhs.#1)
414
+ exp:: lt( exp:: cref( lhs, 1 ) , exp:: cref( rhs, 1 ) ) ,
415
+ // P2: (lhs.#2 == rhs.#2)
416
+ exp:: eq( exp:: cref( lhs, 2 ) , exp:: cref( rhs, 2 ) ) ,
417
+ ]
418
+ } ) ;
419
+
420
+ assert_derived_attribute ( & mut model, b_id, |r#box| {
421
+ HashSet :: from ( [
422
+ cref ( input ( r#box, 1 ) , 0 ) ,
423
+ cref ( input ( r#box, 1 ) , 1 ) ,
424
+ cref ( input ( r#box, 1 ) , 2 ) ,
425
+ ] ) // {rhs.#0, rhs.#1, rhs.#2}
426
+ } ) ;
427
+ }
428
+
429
+ #[ test]
430
+ fn test_full_outer_join_1 ( ) {
431
+ let mut model = Model :: new ( ) ;
432
+ let g_id = add_get ( & mut model) ;
433
+ let b_id = add_full_outer_join ( & mut model, g_id, g_id, |lhs, rhs| {
434
+ vec ! [
435
+ // P0: (lhs.#0 >= rhs.#0)
436
+ exp:: gte( exp:: cref( lhs, 0 ) , exp:: cref( rhs, 0 ) ) ,
437
+ // P1: (lhs.#1 <= rhs.#1)
438
+ exp:: lte( exp:: cref( lhs, 1 ) , exp:: cref( rhs, 1 ) ) ,
439
+ // P2: (lhs.#2 != rhs.#2)
440
+ exp:: not_eq( exp:: cref( lhs, 2 ) , exp:: cref( rhs, 2 ) ) ,
441
+ ]
442
+ } ) ;
443
+
444
+ assert_derived_attribute ( & mut model, b_id, |_| {
445
+ HashSet :: from ( [ ] ) // {}
446
+ } ) ;
447
+ }
448
+
449
+ /// Adds a get box to the given model with a schema consisting of
450
+ /// for 32-bit nullable integers.
451
+ fn add_get ( model : & mut Model ) -> BoxId {
452
+ let get_id = model. make_box ( qgm:: get ( 0 ) . into ( ) ) ;
453
+
454
+ let mut b = model. get_mut_box ( get_id) ;
455
+ b. add_column ( exp:: base ( 0 , typ:: int32 ( true ) ) ) ;
456
+ b. add_column ( exp:: base ( 1 , typ:: int32 ( true ) ) ) ;
457
+ b. add_column ( exp:: base ( 2 , typ:: int32 ( true ) ) ) ;
458
+ b. add_column ( exp:: base ( 3 , typ:: int32 ( true ) ) ) ;
459
+
460
+ get_id
461
+ }
462
+
463
+ /// Adds a select join to the model and attaches the given `predicates`.
464
+ /// The select box has a single input connected to the `src_id` box.
465
+ fn add_select < F > ( model : & mut Model , src_id : BoxId , predicates : F ) -> BoxId
466
+ where
467
+ F : FnOnce ( QuantifierId ) -> Vec < BoxScalarExpr > ,
468
+ {
469
+ let tgt_id = model. make_box ( Select :: default ( ) . into ( ) ) ;
470
+ let inp_id = model. make_quantifier ( QuantifierType :: Foreach , src_id, tgt_id) ;
471
+
472
+ if let BoxType :: Select ( ref mut b) = model. get_mut_box ( tgt_id) . box_type {
473
+ b. predicates . extend_from_slice ( & predicates ( inp_id) ) ;
474
+ }
475
+
476
+ tgt_id
477
+ }
478
+
479
+ /// Adds a full outer join to the model and attaches the given `predicates`.
480
+ /// Both inputs are connected to the `lhs_id` and `rhs_id` boxes.
481
+ fn add_full_outer_join < F > (
482
+ model : & mut Model ,
483
+ lhs_id : BoxId ,
484
+ rhs_id : BoxId ,
485
+ predicates : F ,
486
+ ) -> BoxId
487
+ where
488
+ F : FnOnce ( QuantifierId , QuantifierId ) -> Vec < BoxScalarExpr > ,
489
+ {
490
+ let tgt_id = model. make_box ( OuterJoin :: default ( ) . into ( ) ) ;
491
+ let lhs_id = model. make_quantifier ( QuantifierType :: PreservedForeach , lhs_id, tgt_id) ;
492
+ let rhs_id = model. make_quantifier ( QuantifierType :: PreservedForeach , rhs_id, tgt_id) ;
493
+
494
+ if let BoxType :: OuterJoin ( ref mut b) = model. get_mut_box ( tgt_id) . box_type {
495
+ b. predicates . extend_from_slice ( & predicates ( lhs_id, rhs_id) ) ;
496
+ }
497
+
498
+ tgt_id
499
+ }
500
+
501
+ /// Adds a left outer join to the model and attaches the given `predicates`.
502
+ /// Both inputs are connected to the `lhs_id` and `rhs_id` boxes.
503
+ fn add_left_outer_join < F > (
504
+ model : & mut Model ,
505
+ lhs_id : BoxId ,
506
+ rhs_id : BoxId ,
507
+ predicates : F ,
508
+ ) -> BoxId
509
+ where
510
+ F : FnOnce ( QuantifierId , QuantifierId ) -> Vec < BoxScalarExpr > ,
511
+ {
512
+ let tgt_id = model. make_box ( OuterJoin :: default ( ) . into ( ) ) ;
513
+ let lhs_id = model. make_quantifier ( QuantifierType :: PreservedForeach , lhs_id, tgt_id) ;
514
+ let rhs_id = model. make_quantifier ( QuantifierType :: Foreach , rhs_id, tgt_id) ;
515
+
516
+ if let BoxType :: OuterJoin ( ref mut b) = model. get_mut_box ( tgt_id) . box_type {
517
+ b. predicates . extend_from_slice ( & predicates ( lhs_id, rhs_id) ) ;
518
+ }
519
+
520
+ tgt_id
521
+ }
522
+
523
+ /// Derives the `RejectedNulls` for the given `b_id` and asserts its value.
524
+ fn assert_derived_attribute < F > ( model : & mut Model , b_id : BoxId , exp_value : F )
525
+ where
526
+ F : FnOnce ( & QueryBox ) -> HashSet < ColumnReference > ,
527
+ {
528
+ RejectedNulls . derive ( model, b_id) ;
529
+
530
+ let r#box = model. get_box ( b_id) ;
531
+ let act_value = r#box. attributes . get :: < RejectedNulls > ( ) ;
532
+ let exp_value = & exp_value ( & r#box) ;
533
+
534
+ assert_eq ! ( act_value, exp_value) ;
535
+ }
536
+
537
+ fn input ( b : & QueryBox , i : usize ) -> QuantifierId {
538
+ b. quantifiers . iter ( ) . nth ( i) . unwrap ( ) . clone ( )
539
+ }
540
+ }
0 commit comments