@@ -1385,29 +1385,26 @@ impl<S: SimplifyInfo> TreeNodeRewriter for Simplifier<'_, S> {
1385
1385
when_then_expr,
1386
1386
else_expr,
1387
1387
} ) if !when_then_expr. is_empty ( )
1388
- && when_then_expr. len ( ) < 3 // The rewrite is O(n! ) so limit to small number
1388
+ && when_then_expr. len ( ) < 3 // The rewrite is O(n² ) so limit to small number
1389
1389
&& info. is_boolean_type ( & when_then_expr[ 0 ] . 1 ) ? =>
1390
1390
{
1391
- // The disjunction of all the when predicates encountered so far
1391
+ // String disjunction of all the when predicates encountered so far. Not nullable.
1392
1392
let mut filter_expr = lit ( false ) ;
1393
1393
// The disjunction of all the cases
1394
1394
let mut out_expr = lit ( false ) ;
1395
1395
1396
1396
for ( when, then) in when_then_expr {
1397
- let case_expr = when
1398
- . as_ref ( )
1399
- . clone ( )
1400
- . and ( filter_expr. clone ( ) . not ( ) )
1401
- . and ( * then) ;
1397
+ let when = is_exactly_true ( * when, info) ?;
1398
+ let case_expr =
1399
+ when. clone ( ) . and ( filter_expr. clone ( ) . not ( ) ) . and ( * then) ;
1402
1400
1403
1401
out_expr = out_expr. or ( case_expr) ;
1404
- filter_expr = filter_expr. or ( * when) ;
1402
+ filter_expr = filter_expr. or ( when) ;
1405
1403
}
1406
1404
1407
- if let Some ( else_expr) = else_expr {
1408
- let case_expr = filter_expr. not ( ) . and ( * else_expr) ;
1409
- out_expr = out_expr. or ( case_expr) ;
1410
- }
1405
+ let else_expr = else_expr. map ( |b| * b) . unwrap_or_else ( lit_bool_null) ;
1406
+ let case_expr = filter_expr. not ( ) . and ( else_expr) ;
1407
+ out_expr = out_expr. or ( case_expr) ;
1411
1408
1412
1409
// Do a first pass at simplification
1413
1410
out_expr. rewrite ( self ) ?
@@ -1881,6 +1878,19 @@ fn inlist_except(mut l1: InList, l2: &InList) -> Result<Expr> {
1881
1878
Ok ( Expr :: InList ( l1) )
1882
1879
}
1883
1880
1881
+ /// Returns expression testing a boolean `expr` for being exactly `true` (not `false` or NULL).
1882
+ fn is_exactly_true ( expr : Expr , info : & impl SimplifyInfo ) -> Result < Expr > {
1883
+ if !info. nullable ( & expr) ? {
1884
+ Ok ( expr)
1885
+ } else {
1886
+ Ok ( Expr :: BinaryExpr ( BinaryExpr {
1887
+ left : Box :: new ( expr) ,
1888
+ op : Operator :: IsNotDistinctFrom ,
1889
+ right : Box :: new ( lit ( true ) ) ,
1890
+ } ) )
1891
+ }
1892
+ }
1893
+
1884
1894
#[ cfg( test) ]
1885
1895
mod tests {
1886
1896
use crate :: simplify_expressions:: SimplifyContext ;
@@ -3272,12 +3282,12 @@ mod tests {
3272
3282
simplify( Expr :: Case ( Case :: new(
3273
3283
None ,
3274
3284
vec![ (
3275
- Box :: new( col( "c2 " ) . not_eq( lit( false ) ) ) ,
3285
+ Box :: new( col( "c2_non_null " ) . not_eq( lit( false ) ) ) ,
3276
3286
Box :: new( lit( "ok" ) . eq( lit( "not_ok" ) ) ) ,
3277
3287
) ] ,
3278
- Some ( Box :: new( col( "c2 " ) . eq( lit( true ) ) ) ) ,
3288
+ Some ( Box :: new( col( "c2_non_null " ) . eq( lit( true ) ) ) ) ,
3279
3289
) ) ) ,
3280
- col ( "c2" ) . not ( ) . and ( col ( "c2" ) ) // #1716
3290
+ lit ( false ) // #1716
3281
3291
) ;
3282
3292
3283
3293
// CASE WHEN c2 != false THEN "ok" == "ok" ELSE c2
@@ -3292,12 +3302,12 @@ mod tests {
3292
3302
simplify( simplify( Expr :: Case ( Case :: new(
3293
3303
None ,
3294
3304
vec![ (
3295
- Box :: new( col( "c2 " ) . not_eq( lit( false ) ) ) ,
3305
+ Box :: new( col( "c2_non_null " ) . not_eq( lit( false ) ) ) ,
3296
3306
Box :: new( lit( "ok" ) . eq( lit( "ok" ) ) ) ,
3297
3307
) ] ,
3298
- Some ( Box :: new( col( "c2 " ) . eq( lit( true ) ) ) ) ,
3308
+ Some ( Box :: new( col( "c2_non_null " ) . eq( lit( true ) ) ) ) ,
3299
3309
) ) ) ) ,
3300
- col( "c2 " )
3310
+ col( "c2_non_null " )
3301
3311
) ;
3302
3312
3303
3313
// CASE WHEN ISNULL(c2) THEN true ELSE c2
@@ -3328,12 +3338,12 @@ mod tests {
3328
3338
simplify( simplify( Expr :: Case ( Case :: new(
3329
3339
None ,
3330
3340
vec![
3331
- ( Box :: new( col( "c1 " ) ) , Box :: new( lit( true ) ) , ) ,
3332
- ( Box :: new( col( "c2 " ) ) , Box :: new( lit( false ) ) , ) ,
3341
+ ( Box :: new( col( "c1_non_null " ) ) , Box :: new( lit( true ) ) , ) ,
3342
+ ( Box :: new( col( "c2_non_null " ) ) , Box :: new( lit( false ) ) , ) ,
3333
3343
] ,
3334
3344
Some ( Box :: new( lit( true ) ) ) ,
3335
3345
) ) ) ) ,
3336
- col( "c1 " ) . or( col( "c1 " ) . not( ) . and( col( "c2 " ) . not( ) ) )
3346
+ col( "c1_non_null " ) . or( col( "c1_non_null " ) . not( ) . and( col( "c2_non_null " ) . not( ) ) )
3337
3347
) ;
3338
3348
3339
3349
// CASE WHEN c1 then true WHEN c2 then true ELSE false
@@ -3347,13 +3357,53 @@ mod tests {
3347
3357
simplify( simplify( Expr :: Case ( Case :: new(
3348
3358
None ,
3349
3359
vec![
3350
- ( Box :: new( col( "c1 " ) ) , Box :: new( lit( true ) ) , ) ,
3351
- ( Box :: new( col( "c2 " ) ) , Box :: new( lit( false ) ) , ) ,
3360
+ ( Box :: new( col( "c1_non_null " ) ) , Box :: new( lit( true ) ) , ) ,
3361
+ ( Box :: new( col( "c2_non_null " ) ) , Box :: new( lit( false ) ) , ) ,
3352
3362
] ,
3353
3363
Some ( Box :: new( lit( true ) ) ) ,
3354
3364
) ) ) ) ,
3355
- col( "c1" ) . or( col( "c1" ) . not( ) . and( col( "c2" ) . not( ) ) )
3365
+ col( "c1_non_null" ) . or( col( "c1_non_null" ) . not( ) . and( col( "c2_non_null" ) . not( ) ) )
3366
+ ) ;
3367
+
3368
+ // CASE WHEN c > 0 THEN true END AS c1
3369
+ assert_eq ! (
3370
+ simplify( simplify( Expr :: Case ( Case :: new(
3371
+ None ,
3372
+ vec![ ( Box :: new( col( "c3" ) . gt( lit( 0_i64 ) ) ) , Box :: new( lit( true ) ) ) ] ,
3373
+ None ,
3374
+ ) ) ) ) ,
3375
+ not_distinct_from( col( "c3" ) . gt( lit( 0_i64 ) ) , lit( true ) ) . or( distinct_from(
3376
+ col( "c3" ) . gt( lit( 0_i64 ) ) ,
3377
+ lit( true )
3378
+ )
3379
+ . and( lit_bool_null( ) ) )
3356
3380
) ;
3381
+
3382
+ // CASE WHEN c > 0 THEN true ELSE false END AS c1
3383
+ assert_eq ! (
3384
+ simplify( simplify( Expr :: Case ( Case :: new(
3385
+ None ,
3386
+ vec![ ( Box :: new( col( "c3" ) . gt( lit( 0_i64 ) ) ) , Box :: new( lit( true ) ) ) ] ,
3387
+ Some ( Box :: new( lit( false ) ) ) ,
3388
+ ) ) ) ) ,
3389
+ not_distinct_from( col( "c3" ) . gt( lit( 0_i64 ) ) , lit( true ) )
3390
+ ) ;
3391
+ }
3392
+
3393
+ fn distinct_from ( left : impl Into < Expr > , right : impl Into < Expr > ) -> Expr {
3394
+ Expr :: BinaryExpr ( BinaryExpr {
3395
+ left : Box :: new ( left. into ( ) ) ,
3396
+ op : Operator :: IsDistinctFrom ,
3397
+ right : Box :: new ( right. into ( ) ) ,
3398
+ } )
3399
+ }
3400
+
3401
+ fn not_distinct_from ( left : impl Into < Expr > , right : impl Into < Expr > ) -> Expr {
3402
+ Expr :: BinaryExpr ( BinaryExpr {
3403
+ left : Box :: new ( left. into ( ) ) ,
3404
+ op : Operator :: IsNotDistinctFrom ,
3405
+ right : Box :: new ( right. into ( ) ) ,
3406
+ } )
3357
3407
}
3358
3408
3359
3409
#[ test]
0 commit comments