@@ -1384,29 +1384,26 @@ impl<'a, S: SimplifyInfo> TreeNodeRewriter for Simplifier<'a, S> {
1384
1384
when_then_expr,
1385
1385
else_expr,
1386
1386
} ) if !when_then_expr. is_empty ( )
1387
- && when_then_expr. len ( ) < 3 // The rewrite is O(n! ) so limit to small number
1387
+ && when_then_expr. len ( ) < 3 // The rewrite is O(n² ) so limit to small number
1388
1388
&& info. is_boolean_type ( & when_then_expr[ 0 ] . 1 ) ? =>
1389
1389
{
1390
- // The disjunction of all the when predicates encountered so far
1390
+ // String disjunction of all the when predicates encountered so far. Not nullable.
1391
1391
let mut filter_expr = lit ( false ) ;
1392
1392
// The disjunction of all the cases
1393
1393
let mut out_expr = lit ( false ) ;
1394
1394
1395
1395
for ( when, then) in when_then_expr {
1396
- let case_expr = when
1397
- . as_ref ( )
1398
- . clone ( )
1399
- . and ( filter_expr. clone ( ) . not ( ) )
1400
- . and ( * then) ;
1396
+ let when = is_exactly_true ( * when, info) ?;
1397
+ let case_expr =
1398
+ when. clone ( ) . and ( filter_expr. clone ( ) . not ( ) ) . and ( * then) ;
1401
1399
1402
1400
out_expr = out_expr. or ( case_expr) ;
1403
- filter_expr = filter_expr. or ( * when) ;
1401
+ filter_expr = filter_expr. or ( when) ;
1404
1402
}
1405
1403
1406
- if let Some ( else_expr) = else_expr {
1407
- let case_expr = filter_expr. not ( ) . and ( * else_expr) ;
1408
- out_expr = out_expr. or ( case_expr) ;
1409
- }
1404
+ let else_expr = else_expr. map ( |b| * b) . unwrap_or_else ( lit_bool_null) ;
1405
+ let case_expr = filter_expr. not ( ) . and ( else_expr) ;
1406
+ out_expr = out_expr. or ( case_expr) ;
1410
1407
1411
1408
// Do a first pass at simplification
1412
1409
out_expr. rewrite ( self ) ?
@@ -1826,6 +1823,19 @@ fn inlist_except(mut l1: InList, l2: &InList) -> Result<Expr> {
1826
1823
Ok ( Expr :: InList ( l1) )
1827
1824
}
1828
1825
1826
+ /// Returns expression testing a boolean `expr` for being exactly `true` (not `false` or NULL).
1827
+ fn is_exactly_true ( expr : Expr , info : & impl SimplifyInfo ) -> Result < Expr > {
1828
+ if !info. nullable ( & expr) ? {
1829
+ Ok ( expr)
1830
+ } else {
1831
+ Ok ( Expr :: BinaryExpr ( BinaryExpr {
1832
+ left : Box :: new ( expr) ,
1833
+ op : Operator :: IsNotDistinctFrom ,
1834
+ right : Box :: new ( lit ( true ) ) ,
1835
+ } ) )
1836
+ }
1837
+ }
1838
+
1829
1839
#[ cfg( test) ]
1830
1840
mod tests {
1831
1841
use crate :: simplify_expressions:: SimplifyContext ;
@@ -3243,12 +3253,12 @@ mod tests {
3243
3253
simplify( Expr :: Case ( Case :: new(
3244
3254
None ,
3245
3255
vec![ (
3246
- Box :: new( col( "c2 " ) . not_eq( lit( false ) ) ) ,
3256
+ Box :: new( col( "c2_non_null " ) . not_eq( lit( false ) ) ) ,
3247
3257
Box :: new( lit( "ok" ) . eq( lit( "not_ok" ) ) ) ,
3248
3258
) ] ,
3249
- Some ( Box :: new( col( "c2 " ) . eq( lit( true ) ) ) ) ,
3259
+ Some ( Box :: new( col( "c2_non_null " ) . eq( lit( true ) ) ) ) ,
3250
3260
) ) ) ,
3251
- col ( "c2" ) . not ( ) . and ( col ( "c2" ) ) // #1716
3261
+ lit ( false ) // #1716
3252
3262
) ;
3253
3263
3254
3264
// CASE WHEN c2 != false THEN "ok" == "ok" ELSE c2
@@ -3263,12 +3273,12 @@ mod tests {
3263
3273
simplify( simplify( Expr :: Case ( Case :: new(
3264
3274
None ,
3265
3275
vec![ (
3266
- Box :: new( col( "c2 " ) . not_eq( lit( false ) ) ) ,
3276
+ Box :: new( col( "c2_non_null " ) . not_eq( lit( false ) ) ) ,
3267
3277
Box :: new( lit( "ok" ) . eq( lit( "ok" ) ) ) ,
3268
3278
) ] ,
3269
- Some ( Box :: new( col( "c2 " ) . eq( lit( true ) ) ) ) ,
3279
+ Some ( Box :: new( col( "c2_non_null " ) . eq( lit( true ) ) ) ) ,
3270
3280
) ) ) ) ,
3271
- col( "c2 " )
3281
+ col( "c2_non_null " )
3272
3282
) ;
3273
3283
3274
3284
// CASE WHEN ISNULL(c2) THEN true ELSE c2
@@ -3299,12 +3309,12 @@ mod tests {
3299
3309
simplify( simplify( Expr :: Case ( Case :: new(
3300
3310
None ,
3301
3311
vec![
3302
- ( Box :: new( col( "c1 " ) ) , Box :: new( lit( true ) ) , ) ,
3303
- ( Box :: new( col( "c2 " ) ) , Box :: new( lit( false ) ) , ) ,
3312
+ ( Box :: new( col( "c1_non_null " ) ) , Box :: new( lit( true ) ) , ) ,
3313
+ ( Box :: new( col( "c2_non_null " ) ) , Box :: new( lit( false ) ) , ) ,
3304
3314
] ,
3305
3315
Some ( Box :: new( lit( true ) ) ) ,
3306
3316
) ) ) ) ,
3307
- col( "c1 " ) . or( col( "c1 " ) . not( ) . and( col( "c2 " ) . not( ) ) )
3317
+ col( "c1_non_null " ) . or( col( "c1_non_null " ) . not( ) . and( col( "c2_non_null " ) . not( ) ) )
3308
3318
) ;
3309
3319
3310
3320
// CASE WHEN c1 then true WHEN c2 then true ELSE false
@@ -3318,13 +3328,53 @@ mod tests {
3318
3328
simplify( simplify( Expr :: Case ( Case :: new(
3319
3329
None ,
3320
3330
vec![
3321
- ( Box :: new( col( "c1 " ) ) , Box :: new( lit( true ) ) , ) ,
3322
- ( Box :: new( col( "c2 " ) ) , Box :: new( lit( false ) ) , ) ,
3331
+ ( Box :: new( col( "c1_non_null " ) ) , Box :: new( lit( true ) ) , ) ,
3332
+ ( Box :: new( col( "c2_non_null " ) ) , Box :: new( lit( false ) ) , ) ,
3323
3333
] ,
3324
3334
Some ( Box :: new( lit( true ) ) ) ,
3325
3335
) ) ) ) ,
3326
- col( "c1" ) . or( col( "c1" ) . not( ) . and( col( "c2" ) . not( ) ) )
3336
+ col( "c1_non_null" ) . or( col( "c1_non_null" ) . not( ) . and( col( "c2_non_null" ) . not( ) ) )
3337
+ ) ;
3338
+
3339
+ // CASE WHEN c > 0 THEN true END AS c1
3340
+ assert_eq ! (
3341
+ simplify( simplify( Expr :: Case ( Case :: new(
3342
+ None ,
3343
+ vec![ ( Box :: new( col( "c3" ) . gt( lit( 0_i64 ) ) ) , Box :: new( lit( true ) ) ) ] ,
3344
+ None ,
3345
+ ) ) ) ) ,
3346
+ not_distinct_from( col( "c3" ) . gt( lit( 0_i64 ) ) , lit( true ) ) . or( distinct_from(
3347
+ col( "c3" ) . gt( lit( 0_i64 ) ) ,
3348
+ lit( true )
3349
+ )
3350
+ . and( lit_bool_null( ) ) )
3327
3351
) ;
3352
+
3353
+ // CASE WHEN c > 0 THEN true ELSE false END AS c1
3354
+ assert_eq ! (
3355
+ simplify( simplify( Expr :: Case ( Case :: new(
3356
+ None ,
3357
+ vec![ ( Box :: new( col( "c3" ) . gt( lit( 0_i64 ) ) ) , Box :: new( lit( true ) ) ) ] ,
3358
+ Some ( Box :: new( lit( false ) ) ) ,
3359
+ ) ) ) ) ,
3360
+ not_distinct_from( col( "c3" ) . gt( lit( 0_i64 ) ) , lit( true ) )
3361
+ ) ;
3362
+ }
3363
+
3364
+ fn distinct_from ( left : impl Into < Expr > , right : impl Into < Expr > ) -> Expr {
3365
+ Expr :: BinaryExpr ( BinaryExpr {
3366
+ left : Box :: new ( left. into ( ) ) ,
3367
+ op : Operator :: IsDistinctFrom ,
3368
+ right : Box :: new ( right. into ( ) ) ,
3369
+ } )
3370
+ }
3371
+
3372
+ fn not_distinct_from ( left : impl Into < Expr > , right : impl Into < Expr > ) -> Expr {
3373
+ Expr :: BinaryExpr ( BinaryExpr {
3374
+ left : Box :: new ( left. into ( ) ) ,
3375
+ op : Operator :: IsNotDistinctFrom ,
3376
+ right : Box :: new ( right. into ( ) ) ,
3377
+ } )
3328
3378
}
3329
3379
3330
3380
#[ test]
0 commit comments