Skip to content

Commit 1dc8628

Browse files
committed
add u64 codec in mssql and sqlite
1 parent 659cf57 commit 1dc8628

File tree

2 files changed

+120
-0
lines changed

2 files changed

+120
-0
lines changed

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

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,92 @@ impl Decode<'_, Mssql> for u8 {
2828
Ok(value.as_bytes()?[0])
2929
}
3030
}
31+
32+
impl Type<Mssql> for u16 {
33+
fn type_info() -> MssqlTypeInfo {
34+
MssqlTypeInfo(TypeInfo::new(DataType::IntN, 4))
35+
}
36+
37+
fn compatible(ty: &MssqlTypeInfo) -> bool {
38+
matches!(ty.0.ty, DataType::Int | DataType::IntN) && ty.0.size == 4
39+
}
40+
}
41+
42+
impl Encode<'_, Mssql> for u16 {
43+
fn encode_by_ref(&self, buf: &mut Vec<u8>) -> IsNull {
44+
let value = i32::from(*self);
45+
buf.extend(&value.to_le_bytes());
46+
IsNull::No
47+
}
48+
}
49+
50+
impl Decode<'_, Mssql> for u16 {
51+
fn decode(value: MssqlValueRef<'_>) -> Result<Self, BoxDynError> {
52+
let bytes = value.as_bytes()?;
53+
let val = i32::from_le_bytes(bytes.try_into()?);
54+
u16::try_from(val).map_err(Into::into)
55+
}
56+
}
57+
58+
impl Type<Mssql> for u32 {
59+
fn type_info() -> MssqlTypeInfo {
60+
MssqlTypeInfo(TypeInfo::new(DataType::IntN, 8))
61+
}
62+
63+
fn compatible(ty: &MssqlTypeInfo) -> bool {
64+
matches!(ty.0.ty, DataType::BigInt | DataType::IntN) && ty.0.size == 8
65+
}
66+
}
67+
68+
impl Encode<'_, Mssql> for u32 {
69+
fn encode_by_ref(&self, buf: &mut Vec<u8>) -> IsNull {
70+
let value = i64::from(*self);
71+
buf.extend(&value.to_le_bytes());
72+
IsNull::No
73+
}
74+
}
75+
76+
impl Decode<'_, Mssql> for u32 {
77+
fn decode(value: MssqlValueRef<'_>) -> Result<Self, BoxDynError> {
78+
let bytes = value.as_bytes()?;
79+
let val = i64::from_le_bytes(bytes.try_into()?);
80+
u32::try_from(val).map_err(Into::into)
81+
}
82+
}
83+
84+
impl Type<Mssql> for u64 {
85+
fn type_info() -> MssqlTypeInfo {
86+
MssqlTypeInfo(TypeInfo::new(DataType::Numeric, 0))
87+
}
88+
89+
fn compatible(ty: &MssqlTypeInfo) -> bool {
90+
matches!(ty.0.ty, DataType::Numeric | DataType::Decimal)
91+
}
92+
}
93+
94+
impl Encode<'_, Mssql> for u64 {
95+
fn encode_by_ref(&self, buf: &mut Vec<u8>) -> IsNull {
96+
let bytes = self.to_le_bytes();
97+
let scale = 0i8;
98+
let len = 17u8;
99+
100+
buf.push(len);
101+
buf.push(scale.to_le_bytes()[0]);
102+
buf.extend(&bytes);
103+
buf.extend(&[0u8; 8]);
104+
105+
IsNull::No
106+
}
107+
}
108+
109+
impl Decode<'_, Mssql> for u64 {
110+
fn decode(value: MssqlValueRef<'_>) -> Result<Self, BoxDynError> {
111+
let bytes = value.as_bytes()?;
112+
if bytes.len() < 17 {
113+
return Err("Invalid numeric value length".into());
114+
}
115+
116+
let value_bytes = &bytes[2..10];
117+
Ok(u64::from_le_bytes(value_bytes.try_into()?))
118+
}
119+
}

sqlx-core/src/sqlite/types/uint.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,34 @@ impl<'r> Decode<'r, Sqlite> for u32 {
7676
Ok(value.int64().try_into()?)
7777
}
7878
}
79+
80+
impl Type<Sqlite> for u64 {
81+
fn type_info() -> SqliteTypeInfo {
82+
SqliteTypeInfo(DataType::Int64)
83+
}
84+
85+
fn compatible(ty: &SqliteTypeInfo) -> bool {
86+
matches!(ty.0, DataType::Int | DataType::Int64)
87+
}
88+
}
89+
90+
impl<'q> Encode<'q, Sqlite> for u64 {
91+
fn encode_by_ref(&self, args: &mut Vec<SqliteArgumentValue<'q>>) -> IsNull {
92+
match i64::try_from(*self) {
93+
Ok(value) => {
94+
args.push(SqliteArgumentValue::Int64(value));
95+
IsNull::No
96+
}
97+
Err(_) => {
98+
log::warn!("u64 value {} too large for sqlite, encoding as NULL", self);
99+
IsNull::Yes
100+
}
101+
}
102+
}
103+
}
104+
105+
impl<'r> Decode<'r, Sqlite> for u64 {
106+
fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {
107+
Ok(value.int64().try_into()?)
108+
}
109+
}

0 commit comments

Comments
 (0)