@@ -87,7 +87,9 @@ pub fn coerce_types(
87
87
| Operator :: BitwiseShiftRight => bitwise_coercion ( lhs_type, rhs_type) ,
88
88
Operator :: And | Operator :: Or => match ( lhs_type, rhs_type) {
89
89
// logical binary boolean operators can only be evaluated in bools
90
- ( DataType :: Boolean , DataType :: Boolean ) => Some ( DataType :: Boolean ) ,
90
+ ( DataType :: Boolean , DataType :: Boolean )
91
+ | ( DataType :: Boolean , DataType :: Null )
92
+ | ( DataType :: Null , DataType :: Boolean ) => Some ( DataType :: Boolean ) ,
91
93
_ => None ,
92
94
} ,
93
95
// logical equality operators have their own rules, and always return a boolean
@@ -164,6 +166,11 @@ pub fn comparison_eq_coercion(
164
166
// same type => equality is possible
165
167
return Some ( lhs_type. clone ( ) ) ;
166
168
}
169
+ match ( lhs_type, rhs_type) {
170
+ ( _, DataType :: Null ) if !is_dictionary ( lhs_type) => return Some ( lhs_type. clone ( ) ) ,
171
+ ( DataType :: Null , _) if !is_dictionary ( rhs_type) => return Some ( rhs_type. clone ( ) ) ,
172
+ _ => ( ) ,
173
+ } ;
167
174
comparison_binary_numeric_coercion ( lhs_type, rhs_type)
168
175
. or_else ( || string_boolean_equality_coercion ( lhs_type, rhs_type) )
169
176
. or_else ( || dictionary_coercion ( lhs_type, rhs_type) )
@@ -205,6 +212,11 @@ fn comparison_order_coercion(
205
212
// same type => all good
206
213
return Some ( lhs_type. clone ( ) ) ;
207
214
}
215
+ match ( lhs_type, rhs_type) {
216
+ ( _, DataType :: Null ) if !is_dictionary ( lhs_type) => return Some ( lhs_type. clone ( ) ) ,
217
+ ( DataType :: Null , _) if !is_dictionary ( rhs_type) => return Some ( rhs_type. clone ( ) ) ,
218
+ _ => ( ) ,
219
+ } ;
208
220
comparison_binary_numeric_coercion ( lhs_type, rhs_type)
209
221
. or_else ( || string_coercion ( lhs_type, rhs_type) )
210
222
. or_else ( || dictionary_coercion ( lhs_type, rhs_type) )
@@ -314,6 +326,9 @@ fn mathematics_numerical_coercion(
314
326
( Decimal ( _, _) , Decimal ( _, _) ) => {
315
327
coercion_decimal_mathematics_type ( mathematics_op, lhs_type, rhs_type)
316
328
}
329
+ ( Decimal ( precision, scale) , Null ) | ( Null , Decimal ( precision, scale) ) => {
330
+ Some ( Decimal ( * precision, * scale) )
331
+ }
317
332
( Decimal ( _, _) , _) => {
318
333
let converted_decimal_type = coerce_numeric_type_to_decimal ( rhs_type) ;
319
334
match converted_decimal_type {
@@ -415,6 +430,7 @@ pub fn is_signed_numeric(dt: &DataType) -> bool {
415
430
| DataType :: Float32
416
431
| DataType :: Float64
417
432
| DataType :: Decimal ( _, _)
433
+ | DataType :: Null
418
434
)
419
435
}
420
436
@@ -498,6 +514,8 @@ fn string_coercion(lhs_type: &DataType, rhs_type: &DataType) -> Option<DataType>
498
514
( LargeUtf8 , Utf8 ) => Some ( LargeUtf8 ) ,
499
515
( Utf8 , LargeUtf8 ) => Some ( LargeUtf8 ) ,
500
516
( LargeUtf8 , LargeUtf8 ) => Some ( LargeUtf8 ) ,
517
+ ( Utf8 , Null ) | ( Null , Utf8 ) => Some ( Utf8 ) ,
518
+ ( LargeUtf8 , Null ) | ( Null , LargeUtf8 ) => Some ( LargeUtf8 ) ,
501
519
_ => None ,
502
520
}
503
521
}
@@ -622,6 +640,11 @@ fn eq_coercion(lhs_type: &DataType, rhs_type: &DataType) -> Option<DataType> {
622
640
// same type => equality is possible
623
641
return Some ( lhs_type. clone ( ) ) ;
624
642
}
643
+ match ( lhs_type, rhs_type) {
644
+ ( _, DataType :: Null ) if !is_dictionary ( lhs_type) => return Some ( lhs_type. clone ( ) ) ,
645
+ ( DataType :: Null , _) if !is_dictionary ( rhs_type) => return Some ( rhs_type. clone ( ) ) ,
646
+ _ => ( ) ,
647
+ } ;
625
648
numerical_coercion ( lhs_type, rhs_type)
626
649
. or_else ( || dictionary_coercion ( lhs_type, rhs_type) )
627
650
. or_else ( || temporal_coercion ( lhs_type, rhs_type) )
@@ -642,14 +665,22 @@ pub fn interval_coercion(
642
665
match op {
643
666
Operator :: Plus | Operator :: Minus => match ( lhs_type, rhs_type) {
644
667
( Timestamp ( unit, zone) , Interval ( _) )
645
- | ( Interval ( _) , Timestamp ( unit, zone) ) => {
668
+ | ( Interval ( _) , Timestamp ( unit, zone) )
669
+ | ( Timestamp ( unit, zone) , Null )
670
+ | ( Null , Timestamp ( unit, zone) ) => {
646
671
Some ( Timestamp ( unit. clone ( ) , zone. clone ( ) ) )
647
672
}
648
- ( Date32 , Interval ( _) ) | ( Interval ( _) , Date32 ) => {
673
+ ( Date32 , Interval ( _) )
674
+ | ( Interval ( _) , Date32 )
675
+ | ( Date32 , Null )
676
+ | ( Null , Date32 ) => {
649
677
// TODO: this is not correct and should be replaced with correctly typed timestamp
650
678
Some ( Date32 )
651
679
}
652
- ( Date64 , Interval ( _) ) | ( Interval ( _) , Date64 ) => {
680
+ ( Date64 , Interval ( _) )
681
+ | ( Interval ( _) , Date64 )
682
+ | ( Date64 , Null )
683
+ | ( Null , Date64 ) => {
653
684
// TODO: this is not correct and should be replaced with correctly typed timestamp
654
685
Some ( Date64 )
655
686
}
@@ -679,7 +710,9 @@ pub fn interval_coercion(
679
710
| ( UInt8 , Interval ( itype) )
680
711
| ( Interval ( itype) , UInt8 )
681
712
| ( Decimal ( _, _) , Interval ( itype) )
682
- | ( Interval ( itype) , Decimal ( _, _) ) => Some ( Interval ( itype. clone ( ) ) ) ,
713
+ | ( Interval ( itype) , Decimal ( _, _) )
714
+ | ( Null , Interval ( itype) )
715
+ | ( Interval ( itype) , Null ) => Some ( Interval ( itype. clone ( ) ) ) ,
683
716
_ => None ,
684
717
} ,
685
718
_ => None ,
@@ -699,7 +732,7 @@ pub fn date_coercion(
699
732
// that the coercion removes the least amount of information
700
733
match op {
701
734
Operator :: Minus => match ( lhs_type, rhs_type) {
702
- ( Date32 , Date32 ) => Some ( Int32 ) ,
735
+ ( Date32 , Date32 ) | ( Date32 , Null ) | ( Null , Date32 ) => Some ( Int32 ) ,
703
736
( Timestamp ( _, _) , Timestamp ( _, _) ) => Some ( Interval ( MonthDayNano ) ) ,
704
737
_ => None ,
705
738
} ,
0 commit comments