Skip to content

Commit b3dd6de

Browse files
committed
Fix decoding of small negative unsigned integer in Mssql
1 parent ee78845 commit b3dd6de

File tree

2 files changed

+83
-44
lines changed

2 files changed

+83
-44
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## 0.6.43
9+
- Fix decoding of small negative unsigned integer in Mssql.
10+
811
## 0.6.42
912
- Fix `QueryBuilder` for Microsoft SQL Server: https://github.com/sqlpage/sqlx-oldapi/issues/11
1013
- Add support for Microsoft SQL Server DateTime columns in sqlx macros: macros https://github.com/sqlpage/sqlx-oldapi/issues/16

sqlx-core/src/mssql/types/int.rs

Lines changed: 80 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use std::any::type_name;
22
use std::convert::TryFrom;
3-
use std::i16;
43

54
use crate::decode::Decode;
65
use crate::encode::{Encode, IsNull};
@@ -27,10 +26,85 @@ impl Encode<'_, Mssql> for i8 {
2726
}
2827
}
2928

29+
trait FromLeBytes<const N: usize> {
30+
fn from_le_bytes(bytes: [u8; N]) -> Self;
31+
}
32+
33+
impl FromLeBytes<1> for i8 {
34+
fn from_le_bytes(bytes: [u8; 1]) -> Self {
35+
i8::from_le_bytes(bytes)
36+
}
37+
}
38+
39+
impl FromLeBytes<2> for i16 {
40+
fn from_le_bytes(bytes: [u8; 2]) -> Self {
41+
i16::from_le_bytes(bytes)
42+
}
43+
}
44+
45+
impl FromLeBytes<4> for i32 {
46+
fn from_le_bytes(bytes: [u8; 4]) -> Self {
47+
i32::from_le_bytes(bytes)
48+
}
49+
}
50+
51+
impl FromLeBytes<8> for i64 {
52+
fn from_le_bytes(bytes: [u8; 8]) -> Self {
53+
i64::from_le_bytes(bytes)
54+
}
55+
}
56+
57+
fn decode_int_direct<T, const N: usize>(value: MssqlValueRef<'_>) -> Result<T, BoxDynError>
58+
where
59+
T: FromLeBytes<N> + TryFrom<i64>,
60+
T::Error: std::error::Error + Send + Sync + 'static,
61+
{
62+
let ty = value.type_info.0.ty;
63+
let precision = value.type_info.0.precision;
64+
let scale = value.type_info.0.scale;
65+
66+
match ty {
67+
DataType::SmallInt
68+
| DataType::Int
69+
| DataType::TinyInt
70+
| DataType::BigInt
71+
| DataType::IntN => {
72+
let bytes_val = value.as_bytes()?;
73+
let len = bytes_val.len();
74+
75+
if len > N {
76+
return Err(err_protocol!(
77+
"Decoding {:?} as {} failed because type {:?} has {} bytes, but can only handle {} bytes",
78+
value,
79+
type_name::<T>(),
80+
ty,
81+
len,
82+
N
83+
)
84+
.into());
85+
}
86+
87+
let mut buf = [0u8; N];
88+
buf[..len].copy_from_slice(bytes_val);
89+
Ok(T::from_le_bytes(buf))
90+
}
91+
DataType::Numeric | DataType::NumericN | DataType::Decimal | DataType::DecimalN => {
92+
let i64_val = decode_numeric(value.as_bytes()?, 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+
30105
impl 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::<Self, 1>(value)
34108
}
35109
}
36110

@@ -57,8 +131,7 @@ impl Encode<'_, Mssql> for i16 {
57131

58132
impl 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::<Self, 2>(value)
62135
}
63136
}
64137

@@ -82,8 +155,7 @@ impl Encode<'_, Mssql> for i32 {
82155

83156
impl 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::<Self, 4>(value)
87159
}
88160
}
89161

@@ -118,43 +190,7 @@ impl Encode<'_, Mssql> for i64 {
118190

119191
impl 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::<Self, 8>(value)
158194
}
159195
}
160196

0 commit comments

Comments
 (0)