1515// specific language governing permissions and limitations
1616// under the License.
1717
18- use crate :: expressions:: try_cast;
18+ use crate :: expressions:: { try_cast, BinaryExpr , IsNotNullExpr , NotExpr } ;
1919use crate :: PhysicalExpr ;
20- use std:: borrow:: Cow ;
21- use std:: hash:: Hash ;
22- use std:: { any:: Any , sync:: Arc } ;
23-
2420use arrow:: array:: * ;
2521use arrow:: compute:: kernels:: zip:: zip;
2622use arrow:: compute:: { and, and_not, is_null, not, nullif, or, prep_null_mask_filter} ;
@@ -30,8 +26,13 @@ use datafusion_common::{
3026 exec_err, internal_datafusion_err, internal_err, DataFusionError , Result , ScalarValue ,
3127} ;
3228use datafusion_expr:: ColumnarValue ;
29+ use std:: borrow:: Cow ;
30+ use std:: hash:: Hash ;
31+ use std:: { any:: Any , sync:: Arc } ;
3332
3433use super :: { Column , Literal } ;
34+ use datafusion_expr_common:: dyn_eq:: DynEq ;
35+ use datafusion_expr_common:: operator:: Operator ;
3536use datafusion_physical_expr_common:: datum:: compare_with_eq;
3637use itertools:: Itertools ;
3738
@@ -481,6 +482,9 @@ impl PhysicalExpr for CaseExpr {
481482 let then_nullable = self
482483 . when_then_expr
483484 . iter ( )
485+ . filter ( |( w, t) | {
486+ !always_false_when_value_is_null ( w. as_ref ( ) , t. as_ref ( ) ) . unwrap_or ( false )
487+ } )
484488 . map ( |( _, t) | t. nullable ( input_schema) )
485489 . collect :: < Result < Vec < _ > > > ( ) ?;
486490 if then_nullable. contains ( & true ) {
@@ -588,6 +592,42 @@ impl PhysicalExpr for CaseExpr {
588592 }
589593}
590594
595+ fn always_false_when_value_is_null (
596+ predicate : & dyn PhysicalExpr ,
597+ value : & dyn PhysicalExpr ,
598+ ) -> Option < bool > {
599+ let predicate_any = predicate. as_any ( ) ;
600+ if let Some ( not_null) = predicate_any. downcast_ref :: < IsNotNullExpr > ( ) {
601+ Some ( not_null. arg ( ) . as_ref ( ) . dyn_eq ( value) )
602+ } else if let Some ( not) = predicate_any. downcast_ref :: < NotExpr > ( ) {
603+ always_false_when_value_is_null ( not. arg ( ) . as_ref ( ) , value) . map ( |b| !b)
604+ } else if let Some ( binary) = predicate_any. downcast_ref :: < BinaryExpr > ( ) {
605+ match binary. op ( ) {
606+ Operator :: And => {
607+ let l = always_false_when_value_is_null ( binary. left ( ) . as_ref ( ) , value) ;
608+ let r = always_false_when_value_is_null ( binary. right ( ) . as_ref ( ) , value) ;
609+ if l. is_some ( ) && r. is_some ( ) {
610+ Some ( l. unwrap ( ) || r. unwrap ( ) )
611+ } else {
612+ None
613+ }
614+ }
615+ Operator :: Or => {
616+ let l = always_false_when_value_is_null ( binary. left ( ) . as_ref ( ) , value) ;
617+ let r = always_false_when_value_is_null ( binary. right ( ) . as_ref ( ) , value) ;
618+ if l. is_some ( ) && r. is_some ( ) {
619+ Some ( l. unwrap ( ) && r. unwrap ( ) )
620+ } else {
621+ None
622+ }
623+ }
624+ _ => None ,
625+ }
626+ } else {
627+ None
628+ }
629+ }
630+
591631/// Create a CASE expression
592632pub fn case (
593633 expr : Option < Arc < dyn PhysicalExpr > > ,
0 commit comments