11use std:: any:: type_name;
22use std:: convert:: TryFrom ;
3- use std:: i16;
43
54use crate :: decode:: Decode ;
65use crate :: encode:: { Encode , IsNull } ;
@@ -27,10 +26,85 @@ impl Encode<'_, Mssql> for i8 {
2726 }
2827}
2928
29+ fn decode_int_bytes < T , U , const N : usize > (
30+ bytes : & [ u8 ] ,
31+ type_info : & MssqlTypeInfo ,
32+ from_le_bytes : impl Fn ( [ u8 ; N ] ) -> U ,
33+ ) -> Result < T , BoxDynError >
34+ where
35+ T : TryFrom < U > ,
36+ T :: Error : std:: error:: Error + Send + Sync + ' static ,
37+ U : std:: fmt:: Display + Copy ,
38+ {
39+ if bytes. len ( ) != N {
40+ return Err ( err_protocol ! (
41+ "{} should have exactly {} byte(s), got {}" ,
42+ type_info,
43+ N ,
44+ bytes. len( )
45+ )
46+ . into ( ) ) ;
47+ }
48+
49+ let mut buf = [ 0u8 ; N ] ;
50+ buf. copy_from_slice ( bytes) ;
51+ let val = from_le_bytes ( buf) ;
52+
53+ T :: try_from ( val) . map_err ( |err| {
54+ err_protocol ! (
55+ "Converting {} {} to {} failed: {}" ,
56+ type_info,
57+ val,
58+ type_name:: <T >( ) ,
59+ err
60+ )
61+ . into ( )
62+ } )
63+ }
64+
65+ fn decode_int_direct < T > ( value : MssqlValueRef < ' _ > ) -> Result < T , BoxDynError >
66+ where
67+ T : TryFrom < i64 > + TryFrom < u8 > + TryFrom < i16 > + TryFrom < i32 > ,
68+ <T as TryFrom < i64 > >:: Error : std:: error:: Error + Send + Sync + ' static ,
69+ <T as TryFrom < u8 > >:: Error : std:: error:: Error + Send + Sync + ' static ,
70+ <T as TryFrom < i16 > >:: Error : std:: error:: Error + Send + Sync + ' static ,
71+ <T as TryFrom < i32 > >:: Error : std:: error:: Error + Send + Sync + ' static ,
72+ {
73+ let type_info = & value. type_info ;
74+ let ty = type_info. 0 . ty ;
75+ let precision = type_info. 0 . precision ;
76+ let scale = type_info. 0 . scale ;
77+ let bytes_val = value. as_bytes ( ) ?;
78+
79+ match ty {
80+ DataType :: TinyInt => decode_int_bytes ( bytes_val, type_info, u8:: from_le_bytes) ,
81+ DataType :: SmallInt => decode_int_bytes ( bytes_val, type_info, i16:: from_le_bytes) ,
82+ DataType :: Int => decode_int_bytes ( bytes_val, type_info, i32:: from_le_bytes) ,
83+ DataType :: BigInt => decode_int_bytes ( bytes_val, type_info, i64:: from_le_bytes) ,
84+ DataType :: IntN => match bytes_val. len ( ) {
85+ 1 => decode_int_bytes ( bytes_val, type_info, u8:: from_le_bytes) ,
86+ 2 => decode_int_bytes ( bytes_val, type_info, i16:: from_le_bytes) ,
87+ 4 => decode_int_bytes ( bytes_val, type_info, i32:: from_le_bytes) ,
88+ 8 => decode_int_bytes ( bytes_val, type_info, i64:: from_le_bytes) ,
89+ len => Err ( err_protocol ! ( "IntN with {} bytes is not supported" , len) . into ( ) ) ,
90+ } ,
91+ DataType :: Numeric | DataType :: NumericN | DataType :: Decimal | DataType :: DecimalN => {
92+ let i64_val = decode_numeric ( bytes_val, precision, scale) ?;
93+ convert_integer :: < T > ( i64_val)
94+ }
95+ _ => Err ( err_protocol ! (
96+ "Decoding {:?} as {} failed because type {:?} is not supported" ,
97+ value,
98+ type_name:: <T >( ) ,
99+ ty
100+ )
101+ . into ( ) ) ,
102+ }
103+ }
104+
30105impl Decode < ' _ , Mssql > for i8 {
31106 fn decode ( value : MssqlValueRef < ' _ > ) -> Result < Self , BoxDynError > {
32- let i64_val = <i64 as Decode < Mssql > >:: decode ( value) ?;
33- convert_integer :: < Self > ( i64_val)
107+ decode_int_direct ( value)
34108 }
35109}
36110
@@ -57,8 +131,7 @@ impl Encode<'_, Mssql> for i16 {
57131
58132impl Decode < ' _ , Mssql > for i16 {
59133 fn decode ( value : MssqlValueRef < ' _ > ) -> Result < Self , BoxDynError > {
60- let i64_val = <i64 as Decode < Mssql > >:: decode ( value) ?;
61- convert_integer :: < Self > ( i64_val)
134+ decode_int_direct ( value)
62135 }
63136}
64137
@@ -82,8 +155,7 @@ impl Encode<'_, Mssql> for i32 {
82155
83156impl Decode < ' _ , Mssql > for i32 {
84157 fn decode ( value : MssqlValueRef < ' _ > ) -> Result < Self , BoxDynError > {
85- let i64_val = <i64 as Decode < Mssql > >:: decode ( value) ?;
86- convert_integer :: < Self > ( i64_val)
158+ decode_int_direct ( value)
87159 }
88160}
89161
@@ -118,43 +190,7 @@ impl Encode<'_, Mssql> for i64 {
118190
119191impl Decode < ' _ , Mssql > for i64 {
120192 fn decode ( value : MssqlValueRef < ' _ > ) -> Result < Self , BoxDynError > {
121- let ty = value. type_info . 0 . ty ;
122- let precision = value. type_info . 0 . precision ;
123- let scale = value. type_info . 0 . scale ;
124-
125- match ty {
126- DataType :: SmallInt
127- | DataType :: Int
128- | DataType :: TinyInt
129- | DataType :: BigInt
130- | DataType :: IntN => {
131- let mut buf = [ 0u8 ; 8 ] ;
132- let bytes_val = value. as_bytes ( ) ?;
133- let len = bytes_val. len ( ) ;
134-
135- if len > buf. len ( ) {
136- return Err ( err_protocol ! (
137- "Decoding {:?} as a i64 failed because type {:?} has more than {} bytes" ,
138- value,
139- ty,
140- buf. len( )
141- )
142- . into ( ) ) ;
143- }
144-
145- buf[ ..len] . copy_from_slice ( bytes_val) ;
146- Ok ( i64:: from_le_bytes ( buf) )
147- }
148- DataType :: Numeric | DataType :: NumericN | DataType :: Decimal | DataType :: DecimalN => {
149- decode_numeric ( value. as_bytes ( ) ?, precision, scale)
150- }
151- _ => Err ( err_protocol ! (
152- "Decoding {:?} as a i64 failed because type {:?} is not implemented" ,
153- value,
154- ty
155- )
156- . into ( ) ) ,
157- }
193+ decode_int_direct ( value)
158194 }
159195}
160196
@@ -164,9 +200,12 @@ fn decode_numeric(bytes: &[u8], _precision: u8, mut scale: u8) -> Result<i64, Bo
164200 let mut fixed_bytes = [ 0u8 ; 16 ] ;
165201 fixed_bytes[ 0 ..rest. len ( ) ] . copy_from_slice ( rest) ;
166202 let mut numerator = u128:: from_le_bytes ( fixed_bytes) ;
167- while scale > 0 {
168- scale -= 1 ;
203+ while numerator % 10 == 0 && scale > 0 {
169204 numerator /= 10 ;
205+ scale -= 1 ;
206+ }
207+ if scale > 0 {
208+ numerator /= 10u128 . pow ( scale as u32 ) ;
170209 }
171210 let n = i64:: try_from ( numerator) ?;
172211 Ok ( n * if negative { -1 } else { 1 } )
0 commit comments