@@ -656,6 +656,7 @@ macro_rules! numeric_binary_evaluator_definition {
656656 } ;
657657}
658658
659+ // GRCOV_EXCL_START
659660#[ cfg( all( test, not( target_arch = "wasm32" ) ) ) ]
660661mod test {
661662 use super :: * ;
@@ -664,14 +665,38 @@ mod test {
664665 use crate :: serdes:: { ReferenceSerialization , ReferenceTables } ;
665666 use crate :: storage:: rocksdb:: RocksTransaction ;
666667 use crate :: types:: evaluator:: BinaryEvaluatorRef ;
668+ use crate :: types:: value:: DataValue ;
667669 use crate :: types:: LogicalType ;
670+ use ordered_float:: OrderedFloat ;
671+ #[ cfg( feature = "decimal" ) ]
672+ use rust_decimal:: Decimal ;
668673 use std:: borrow:: Cow ;
669674 use std:: io:: { Cursor , Seek , SeekFrom } ;
670675
671676 fn create ( ty : LogicalType , op : BinaryOperator ) -> Result < BinaryEvaluatorRef , DatabaseError > {
672677 binary_create ( Cow :: Owned ( ty) , op)
673678 }
674679
680+ fn eval (
681+ ty : LogicalType ,
682+ op : BinaryOperator ,
683+ left : & DataValue ,
684+ right : & DataValue ,
685+ ) -> Result < DataValue , DatabaseError > {
686+ create ( ty, op) ?. binary_eval ( left, right)
687+ }
688+
689+ fn assert_panics ( f : impl FnOnce ( ) + std:: panic:: UnwindSafe ) {
690+ assert ! ( std:: panic:: catch_unwind( f) . is_err( ) ) ;
691+ }
692+
693+ fn assert_binary_ref_panics ( pos : u16 , params : BinaryEvaluatorParams , value : & DataValue ) {
694+ assert_panics ( || {
695+ let evaluator = BinaryEvaluatorRef :: new ( pos, params) ;
696+ let _ = evaluator. binary_eval ( value, value) . unwrap ( ) ;
697+ } ) ;
698+ }
699+
675700 #[ test]
676701 fn test_binary_evaluator_positions_are_stable ( ) -> Result < ( ) , DatabaseError > {
677702 assert_eq ! (
@@ -716,4 +741,181 @@ mod test {
716741
717742 Ok ( ( ) )
718743 }
744+
745+ #[ test]
746+ fn test_binary_create_dispatches_numeric_time_and_decimal_evaluators (
747+ ) -> Result < ( ) , DatabaseError > {
748+ let numeric_cases = vec ! [
749+ (
750+ LogicalType :: Tinyint ,
751+ DataValue :: Int8 ( 1 ) ,
752+ DataValue :: Int8 ( 2 ) ,
753+ DataValue :: Int8 ( 3 ) ,
754+ ) ,
755+ (
756+ LogicalType :: Smallint ,
757+ DataValue :: Int16 ( 1 ) ,
758+ DataValue :: Int16 ( 2 ) ,
759+ DataValue :: Int16 ( 3 ) ,
760+ ) ,
761+ (
762+ LogicalType :: Integer ,
763+ DataValue :: Int32 ( 1 ) ,
764+ DataValue :: Int32 ( 2 ) ,
765+ DataValue :: Int32 ( 3 ) ,
766+ ) ,
767+ (
768+ LogicalType :: Bigint ,
769+ DataValue :: Int64 ( 1 ) ,
770+ DataValue :: Int64 ( 2 ) ,
771+ DataValue :: Int64 ( 3 ) ,
772+ ) ,
773+ (
774+ LogicalType :: UTinyint ,
775+ DataValue :: UInt8 ( 1 ) ,
776+ DataValue :: UInt8 ( 2 ) ,
777+ DataValue :: UInt8 ( 3 ) ,
778+ ) ,
779+ (
780+ LogicalType :: USmallint ,
781+ DataValue :: UInt16 ( 1 ) ,
782+ DataValue :: UInt16 ( 2 ) ,
783+ DataValue :: UInt16 ( 3 ) ,
784+ ) ,
785+ (
786+ LogicalType :: UInteger ,
787+ DataValue :: UInt32 ( 1 ) ,
788+ DataValue :: UInt32 ( 2 ) ,
789+ DataValue :: UInt32 ( 3 ) ,
790+ ) ,
791+ (
792+ LogicalType :: UBigint ,
793+ DataValue :: UInt64 ( 1 ) ,
794+ DataValue :: UInt64 ( 2 ) ,
795+ DataValue :: UInt64 ( 3 ) ,
796+ ) ,
797+ (
798+ LogicalType :: Float ,
799+ DataValue :: Float32 ( OrderedFloat ( 1.0 ) ) ,
800+ DataValue :: Float32 ( 2.0 . into( ) ) ,
801+ DataValue :: Float32 ( 3.0 . into( ) ) ,
802+ ) ,
803+ (
804+ LogicalType :: Double ,
805+ DataValue :: Float64 ( OrderedFloat ( 1.0 ) ) ,
806+ DataValue :: Float64 ( 2.0 . into( ) ) ,
807+ DataValue :: Float64 ( 3.0 . into( ) ) ,
808+ ) ,
809+ ] ;
810+
811+ for ( ty, left, right, expected) in numeric_cases {
812+ assert_eq ! ( eval( ty, BinaryOperator :: Plus , & left, & right) ?, expected) ;
813+ }
814+
815+ assert_eq ! (
816+ eval(
817+ LogicalType :: DateTime ,
818+ BinaryOperator :: Eq ,
819+ & DataValue :: Date64 ( 1 ) ,
820+ & DataValue :: Date64 ( 1 ) ,
821+ ) ?,
822+ DataValue :: Boolean ( true )
823+ ) ;
824+ assert_eq ! (
825+ eval(
826+ LogicalType :: Time ( Some ( 0 ) ) ,
827+ BinaryOperator :: Plus ,
828+ & DataValue :: Time32 ( DataValue :: pack_time( 1 , 0 , 0 ) , 0 ) ,
829+ & DataValue :: Time32 ( DataValue :: pack_time( 2 , 0 , 0 ) , 0 ) ,
830+ ) ?,
831+ DataValue :: Time32 ( DataValue :: pack_time( 3 , 0 , 0 ) , 0 )
832+ ) ;
833+ assert_eq ! (
834+ eval(
835+ LogicalType :: Time ( Some ( 0 ) ) ,
836+ BinaryOperator :: Minus ,
837+ & DataValue :: Time32 ( DataValue :: pack_time( 3 , 0 , 0 ) , 0 ) ,
838+ & DataValue :: Time32 ( DataValue :: pack_time( 2 , 0 , 0 ) , 0 ) ,
839+ ) ?,
840+ DataValue :: Time32 ( DataValue :: pack_time( 1 , 0 , 0 ) , 0 )
841+ ) ;
842+ assert_eq ! (
843+ eval(
844+ LogicalType :: TimeStamp ( Some ( 0 ) , false ) ,
845+ BinaryOperator :: NotEq ,
846+ & DataValue :: Time64 ( 1 , 0 , false ) ,
847+ & DataValue :: Time64 ( 2 , 0 , false ) ,
848+ ) ?,
849+ DataValue :: Boolean ( true )
850+ ) ;
851+ assert_eq ! (
852+ eval(
853+ LogicalType :: Boolean ,
854+ BinaryOperator :: NotEq ,
855+ & DataValue :: Boolean ( true ) ,
856+ & DataValue :: Boolean ( false ) ,
857+ ) ?,
858+ DataValue :: Boolean ( true )
859+ ) ;
860+ #[ cfg( feature = "decimal" ) ]
861+ assert_eq ! (
862+ eval(
863+ LogicalType :: Decimal ( None , Some ( 1 ) ) ,
864+ BinaryOperator :: Plus ,
865+ & DataValue :: Decimal ( Decimal :: new( 10 , 1 ) ) ,
866+ & DataValue :: Decimal ( Decimal :: new( 20 , 1 ) ) ,
867+ ) ?,
868+ DataValue :: Decimal ( Decimal :: new( 30 , 1 ) )
869+ ) ;
870+
871+ Ok ( ( ) )
872+ }
873+
874+ #[ test]
875+ fn test_binary_create_rejects_unsupported_operators ( ) {
876+ let cases = vec ! [
877+ ( LogicalType :: Integer , BinaryOperator :: Like ( None ) ) ,
878+ ( LogicalType :: Time ( Some ( 0 ) ) , BinaryOperator :: Multiply ) ,
879+ ( LogicalType :: TimeStamp ( Some ( 0 ) , false ) , BinaryOperator :: Plus ) ,
880+ ( LogicalType :: Boolean , BinaryOperator :: Plus ) ,
881+ (
882+ LogicalType :: Varchar ( None , crate :: types:: CharLengthUnits :: Characters ) ,
883+ BinaryOperator :: Plus ,
884+ ) ,
885+ (
886+ LogicalType :: Tuple ( vec![ LogicalType :: Integer ] ) ,
887+ BinaryOperator :: Plus ,
888+ ) ,
889+ ] ;
890+
891+ for ( ty, op) in cases {
892+ assert ! ( matches!(
893+ create( ty, op) ,
894+ Err ( DatabaseError :: UnsupportedBinaryOperator ( ..) )
895+ ) ) ;
896+ }
897+ }
898+
899+ #[ test]
900+ fn test_binary_eval_rejects_invalid_positions_and_params ( ) {
901+ let value = DataValue :: Utf8 {
902+ value : "abc" . to_string ( ) ,
903+ ty : crate :: types:: value:: Utf8Type :: Variable ( None ) ,
904+ unit : crate :: types:: CharLengthUnits :: Characters ,
905+ } ;
906+ for offset in [ UTF8_LIKE_OFFSET , UTF8_NOT_LIKE_OFFSET ] {
907+ assert_binary_ref_panics (
908+ binary_pos ( BINARY_UTF8_BASE , offset) ,
909+ BinaryEvaluatorParams :: Unit ,
910+ & value,
911+ ) ;
912+ }
913+ assert_panics ( || {
914+ let evaluator = BinaryEvaluatorRef :: new ( u16:: MAX , BinaryEvaluatorParams :: Unit ) ;
915+ let _ = evaluator
916+ . binary_eval ( & DataValue :: Int32 ( 1 ) , & DataValue :: Int32 ( 1 ) )
917+ . unwrap ( ) ;
918+ } ) ;
919+ }
719920}
921+ // GRCOV_EXCL_STOP
0 commit comments