1
1
use byteorder:: { ByteOrder , LittleEndian } ;
2
+ use std:: any:: type_name;
2
3
3
4
use crate :: decode:: Decode ;
4
5
use crate :: encode:: { Encode , IsNull } ;
@@ -27,7 +28,7 @@ impl Encode<'_, Mssql> for i8 {
27
28
28
29
impl Decode < ' _ , Mssql > for i8 {
29
30
fn decode ( value : MssqlValueRef < ' _ > ) -> Result < Self , BoxDynError > {
30
- Ok ( i8 :: from_le_bytes ( value. as_bytes ( ) ? [ 0 .. 1 ] . try_into ( ) ? ) )
31
+ decode_integer ( value)
31
32
}
32
33
}
33
34
@@ -37,7 +38,10 @@ impl Type<Mssql> for i16 {
37
38
}
38
39
39
40
fn compatible ( ty : & MssqlTypeInfo ) -> bool {
40
- matches ! ( ty. 0 . ty, DataType :: SmallInt | DataType :: IntN ) && ty. 0 . size == 2
41
+ matches ! (
42
+ ty. 0 . ty,
43
+ DataType :: TinyInt | DataType :: SmallInt | DataType :: Int | DataType :: IntN
44
+ ) && ty. 0 . size <= 2
41
45
}
42
46
}
43
47
@@ -51,7 +55,7 @@ impl Encode<'_, Mssql> for i16 {
51
55
52
56
impl Decode < ' _ , Mssql > for i16 {
53
57
fn decode ( value : MssqlValueRef < ' _ > ) -> Result < Self , BoxDynError > {
54
- Ok ( LittleEndian :: read_i16 ( value. as_bytes ( ) ? ) )
58
+ decode_integer ( value)
55
59
}
56
60
}
57
61
@@ -75,7 +79,7 @@ impl Encode<'_, Mssql> for i32 {
75
79
76
80
impl Decode < ' _ , Mssql > for i32 {
77
81
fn decode ( value : MssqlValueRef < ' _ > ) -> Result < Self , BoxDynError > {
78
- Ok ( LittleEndian :: read_i32 ( value. as_bytes ( ) ? ) )
82
+ decode_integer ( value)
79
83
}
80
84
}
81
85
@@ -110,30 +114,7 @@ impl Encode<'_, Mssql> for i64 {
110
114
111
115
impl Decode < ' _ , Mssql > for i64 {
112
116
fn decode ( value : MssqlValueRef < ' _ > ) -> Result < Self , BoxDynError > {
113
- let ty = value. type_info . 0 . ty ;
114
- let precision = value. type_info . 0 . precision ;
115
- let scale = value. type_info . 0 . scale ;
116
- match ty {
117
- DataType :: SmallInt
118
- | DataType :: Int
119
- | DataType :: TinyInt
120
- | DataType :: BigInt
121
- | DataType :: IntN => {
122
- let mut buf = [ 0u8 ; 8 ] ;
123
- let bytes_val = value. as_bytes ( ) ?;
124
- buf[ ..bytes_val. len ( ) ] . copy_from_slice ( bytes_val) ;
125
- Ok ( i64:: from_le_bytes ( buf) )
126
- }
127
- DataType :: Numeric | DataType :: NumericN | DataType :: Decimal | DataType :: DecimalN => {
128
- decode_numeric ( value. as_bytes ( ) ?, precision, scale)
129
- }
130
- _ => Err ( err_protocol ! (
131
- "Decoding {:?} as a float failed because type {:?} is not implemented" ,
132
- value,
133
- ty
134
- )
135
- . into ( ) ) ,
136
- }
117
+ decode_integer ( value)
137
118
}
138
119
}
139
120
@@ -150,3 +131,70 @@ fn decode_numeric(bytes: &[u8], _precision: u8, mut scale: u8) -> Result<i64, Bo
150
131
let n = i64:: try_from ( numerator) ?;
151
132
Ok ( n * if negative { -1 } else { 1 } )
152
133
}
134
+
135
+ fn decode_integer < T > ( value : MssqlValueRef < ' _ > ) -> Result < T , BoxDynError >
136
+ where
137
+ T : TryFrom < i64 > ,
138
+ T :: Error : std:: error:: Error + Send + Sync + ' static ,
139
+ {
140
+ let ty = value. type_info . 0 . ty ;
141
+ let precision = value. type_info . 0 . precision ;
142
+ let scale = value. type_info . 0 . scale ;
143
+
144
+ let type_name = type_name :: < T > ( ) ;
145
+
146
+ match ty {
147
+ DataType :: SmallInt
148
+ | DataType :: Int
149
+ | DataType :: TinyInt
150
+ | DataType :: BigInt
151
+ | DataType :: IntN => {
152
+ let mut buf = [ 0u8 ; 8 ] ;
153
+ let bytes_val = value. as_bytes ( ) ?;
154
+ let len = bytes_val. len ( ) ;
155
+
156
+ if len > buf. len ( ) {
157
+ return Err ( err_protocol ! (
158
+ "Decoding {:?} as a {} failed because type {:?} has more than {} bytes" ,
159
+ value,
160
+ type_name,
161
+ ty,
162
+ buf. len( )
163
+ )
164
+ . into ( ) ) ;
165
+ }
166
+
167
+ buf[ ..len] . copy_from_slice ( & bytes_val) ;
168
+
169
+ let i64_val = i64:: from_le_bytes ( buf) ;
170
+ T :: try_from ( i64_val) . map_err ( |_| {
171
+ err_protocol ! (
172
+ "Decoding {:?} as a {} failed because value {} is out of range" ,
173
+ value,
174
+ type_name,
175
+ i64_val
176
+ )
177
+ . into ( )
178
+ } )
179
+ }
180
+ DataType :: Numeric | DataType :: NumericN | DataType :: Decimal | DataType :: DecimalN => {
181
+ let n = decode_numeric ( value. as_bytes ( ) ?, precision, scale) ?;
182
+ T :: try_from ( n) . map_err ( |_| {
183
+ err_protocol ! (
184
+ "Decoding {:?} as a {} failed because value {} is out of range" ,
185
+ value,
186
+ type_name,
187
+ n
188
+ )
189
+ . into ( )
190
+ } )
191
+ }
192
+ _ => Err ( err_protocol ! (
193
+ "Decoding {:?} as a {} failed because type {:?} is not implemented" ,
194
+ value,
195
+ type_name,
196
+ ty
197
+ )
198
+ . into ( ) ) ,
199
+ }
200
+ }
0 commit comments