Skip to content

Commit aa5d658

Browse files
committed
feat: Add support for unsigned integers and slice types in ODBC
This commit introduces decoding implementations for unsigned integer types (u8, u16, u32, u64) and slice types (&[u8]) in the ODBC module. It enhances the type compatibility checks and adds tests to verify the correct handling of these types, ensuring robust functionality in ODBC interactions. Additionally, it includes tests for UUID, JSON, BigDecimal, and Rust Decimal types, further improving the coverage of the ODBC implementation.
1 parent de6c9e9 commit aa5d658

File tree

6 files changed

+845
-1
lines changed

6 files changed

+845
-1
lines changed

sqlx-core/src/odbc/arguments.rs

Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,271 @@ impl<'q> Encode<'q, Odbc> for Vec<u8> {
118118
}
119119
}
120120

121+
impl<'q> Encode<'q, Odbc> for &'q [u8] {
122+
fn encode(self, buf: &mut Vec<OdbcArgumentValue<'q>>) -> crate::encode::IsNull {
123+
buf.push(OdbcArgumentValue::Bytes(self.to_vec()));
124+
crate::encode::IsNull::No
125+
}
126+
127+
fn encode_by_ref(&self, buf: &mut Vec<OdbcArgumentValue<'q>>) -> crate::encode::IsNull {
128+
buf.push(OdbcArgumentValue::Bytes(self.to_vec()));
129+
crate::encode::IsNull::No
130+
}
131+
}
132+
133+
impl<'q> Encode<'q, Odbc> for i16 {
134+
fn encode(self, buf: &mut Vec<OdbcArgumentValue<'q>>) -> crate::encode::IsNull {
135+
buf.push(OdbcArgumentValue::Int(self as i64));
136+
crate::encode::IsNull::No
137+
}
138+
139+
fn encode_by_ref(&self, buf: &mut Vec<OdbcArgumentValue<'q>>) -> crate::encode::IsNull {
140+
buf.push(OdbcArgumentValue::Int(*self as i64));
141+
crate::encode::IsNull::No
142+
}
143+
}
144+
145+
impl<'q> Encode<'q, Odbc> for i8 {
146+
fn encode(self, buf: &mut Vec<OdbcArgumentValue<'q>>) -> crate::encode::IsNull {
147+
buf.push(OdbcArgumentValue::Int(self as i64));
148+
crate::encode::IsNull::No
149+
}
150+
151+
fn encode_by_ref(&self, buf: &mut Vec<OdbcArgumentValue<'q>>) -> crate::encode::IsNull {
152+
buf.push(OdbcArgumentValue::Int(*self as i64));
153+
crate::encode::IsNull::No
154+
}
155+
}
156+
157+
impl<'q> Encode<'q, Odbc> for u8 {
158+
fn encode(self, buf: &mut Vec<OdbcArgumentValue<'q>>) -> crate::encode::IsNull {
159+
buf.push(OdbcArgumentValue::Int(self as i64));
160+
crate::encode::IsNull::No
161+
}
162+
163+
fn encode_by_ref(&self, buf: &mut Vec<OdbcArgumentValue<'q>>) -> crate::encode::IsNull {
164+
buf.push(OdbcArgumentValue::Int(*self as i64));
165+
crate::encode::IsNull::No
166+
}
167+
}
168+
169+
impl<'q> Encode<'q, Odbc> for u16 {
170+
fn encode(self, buf: &mut Vec<OdbcArgumentValue<'q>>) -> crate::encode::IsNull {
171+
buf.push(OdbcArgumentValue::Int(self as i64));
172+
crate::encode::IsNull::No
173+
}
174+
175+
fn encode_by_ref(&self, buf: &mut Vec<OdbcArgumentValue<'q>>) -> crate::encode::IsNull {
176+
buf.push(OdbcArgumentValue::Int(*self as i64));
177+
crate::encode::IsNull::No
178+
}
179+
}
180+
181+
impl<'q> Encode<'q, Odbc> for u32 {
182+
fn encode(self, buf: &mut Vec<OdbcArgumentValue<'q>>) -> crate::encode::IsNull {
183+
buf.push(OdbcArgumentValue::Int(self as i64));
184+
crate::encode::IsNull::No
185+
}
186+
187+
fn encode_by_ref(&self, buf: &mut Vec<OdbcArgumentValue<'q>>) -> crate::encode::IsNull {
188+
buf.push(OdbcArgumentValue::Int(*self as i64));
189+
crate::encode::IsNull::No
190+
}
191+
}
192+
193+
impl<'q> Encode<'q, Odbc> for u64 {
194+
fn encode(self, buf: &mut Vec<OdbcArgumentValue<'q>>) -> crate::encode::IsNull {
195+
match i64::try_from(self) {
196+
Ok(value) => {
197+
buf.push(OdbcArgumentValue::Int(value));
198+
crate::encode::IsNull::No
199+
}
200+
Err(_) => {
201+
log::warn!("u64 value {} too large for ODBC, encoding as NULL", self);
202+
buf.push(OdbcArgumentValue::Null);
203+
crate::encode::IsNull::Yes
204+
}
205+
}
206+
}
207+
208+
fn encode_by_ref(&self, buf: &mut Vec<OdbcArgumentValue<'q>>) -> crate::encode::IsNull {
209+
match i64::try_from(*self) {
210+
Ok(value) => {
211+
buf.push(OdbcArgumentValue::Int(value));
212+
crate::encode::IsNull::No
213+
}
214+
Err(_) => {
215+
log::warn!("u64 value {} too large for ODBC, encoding as NULL", self);
216+
buf.push(OdbcArgumentValue::Null);
217+
crate::encode::IsNull::Yes
218+
}
219+
}
220+
}
221+
}
222+
223+
impl<'q> Encode<'q, Odbc> for bool {
224+
fn encode(self, buf: &mut Vec<OdbcArgumentValue<'q>>) -> crate::encode::IsNull {
225+
buf.push(OdbcArgumentValue::Int(if self { 1 } else { 0 }));
226+
crate::encode::IsNull::No
227+
}
228+
229+
fn encode_by_ref(&self, buf: &mut Vec<OdbcArgumentValue<'q>>) -> crate::encode::IsNull {
230+
buf.push(OdbcArgumentValue::Int(if *self { 1 } else { 0 }));
231+
crate::encode::IsNull::No
232+
}
233+
}
234+
235+
// Feature-gated Encode implementations
236+
#[cfg(feature = "chrono")]
237+
mod chrono_encode {
238+
use super::*;
239+
use chrono::{DateTime, FixedOffset, Local, NaiveDate, NaiveDateTime, NaiveTime, Utc};
240+
241+
impl<'q> Encode<'q, Odbc> for NaiveDate {
242+
fn encode(self, buf: &mut Vec<OdbcArgumentValue<'q>>) -> crate::encode::IsNull {
243+
buf.push(OdbcArgumentValue::Text(self.format("%Y-%m-%d").to_string()));
244+
crate::encode::IsNull::No
245+
}
246+
247+
fn encode_by_ref(&self, buf: &mut Vec<OdbcArgumentValue<'q>>) -> crate::encode::IsNull {
248+
buf.push(OdbcArgumentValue::Text(self.format("%Y-%m-%d").to_string()));
249+
crate::encode::IsNull::No
250+
}
251+
}
252+
253+
impl<'q> Encode<'q, Odbc> for NaiveTime {
254+
fn encode(self, buf: &mut Vec<OdbcArgumentValue<'q>>) -> crate::encode::IsNull {
255+
buf.push(OdbcArgumentValue::Text(self.format("%H:%M:%S").to_string()));
256+
crate::encode::IsNull::No
257+
}
258+
259+
fn encode_by_ref(&self, buf: &mut Vec<OdbcArgumentValue<'q>>) -> crate::encode::IsNull {
260+
buf.push(OdbcArgumentValue::Text(self.format("%H:%M:%S").to_string()));
261+
crate::encode::IsNull::No
262+
}
263+
}
264+
265+
impl<'q> Encode<'q, Odbc> for NaiveDateTime {
266+
fn encode(self, buf: &mut Vec<OdbcArgumentValue<'q>>) -> crate::encode::IsNull {
267+
buf.push(OdbcArgumentValue::Text(self.format("%Y-%m-%d %H:%M:%S").to_string()));
268+
crate::encode::IsNull::No
269+
}
270+
271+
fn encode_by_ref(&self, buf: &mut Vec<OdbcArgumentValue<'q>>) -> crate::encode::IsNull {
272+
buf.push(OdbcArgumentValue::Text(self.format("%Y-%m-%d %H:%M:%S").to_string()));
273+
crate::encode::IsNull::No
274+
}
275+
}
276+
277+
impl<'q> Encode<'q, Odbc> for DateTime<Utc> {
278+
fn encode(self, buf: &mut Vec<OdbcArgumentValue<'q>>) -> crate::encode::IsNull {
279+
buf.push(OdbcArgumentValue::Text(self.format("%Y-%m-%d %H:%M:%S").to_string()));
280+
crate::encode::IsNull::No
281+
}
282+
283+
fn encode_by_ref(&self, buf: &mut Vec<OdbcArgumentValue<'q>>) -> crate::encode::IsNull {
284+
buf.push(OdbcArgumentValue::Text(self.format("%Y-%m-%d %H:%M:%S").to_string()));
285+
crate::encode::IsNull::No
286+
}
287+
}
288+
289+
impl<'q> Encode<'q, Odbc> for DateTime<FixedOffset> {
290+
fn encode(self, buf: &mut Vec<OdbcArgumentValue<'q>>) -> crate::encode::IsNull {
291+
buf.push(OdbcArgumentValue::Text(self.format("%Y-%m-%d %H:%M:%S").to_string()));
292+
crate::encode::IsNull::No
293+
}
294+
295+
fn encode_by_ref(&self, buf: &mut Vec<OdbcArgumentValue<'q>>) -> crate::encode::IsNull {
296+
buf.push(OdbcArgumentValue::Text(self.format("%Y-%m-%d %H:%M:%S").to_string()));
297+
crate::encode::IsNull::No
298+
}
299+
}
300+
301+
impl<'q> Encode<'q, Odbc> for DateTime<Local> {
302+
fn encode(self, buf: &mut Vec<OdbcArgumentValue<'q>>) -> crate::encode::IsNull {
303+
buf.push(OdbcArgumentValue::Text(self.format("%Y-%m-%d %H:%M:%S").to_string()));
304+
crate::encode::IsNull::No
305+
}
306+
307+
fn encode_by_ref(&self, buf: &mut Vec<OdbcArgumentValue<'q>>) -> crate::encode::IsNull {
308+
buf.push(OdbcArgumentValue::Text(self.format("%Y-%m-%d %H:%M:%S").to_string()));
309+
crate::encode::IsNull::No
310+
}
311+
}
312+
}
313+
314+
#[cfg(feature = "json")]
315+
mod json_encode {
316+
use super::*;
317+
use serde_json::Value;
318+
319+
impl<'q> Encode<'q, Odbc> for Value {
320+
fn encode(self, buf: &mut Vec<OdbcArgumentValue<'q>>) -> crate::encode::IsNull {
321+
buf.push(OdbcArgumentValue::Text(self.to_string()));
322+
crate::encode::IsNull::No
323+
}
324+
325+
fn encode_by_ref(&self, buf: &mut Vec<OdbcArgumentValue<'q>>) -> crate::encode::IsNull {
326+
buf.push(OdbcArgumentValue::Text(self.to_string()));
327+
crate::encode::IsNull::No
328+
}
329+
}
330+
}
331+
332+
#[cfg(feature = "bigdecimal")]
333+
mod bigdecimal_encode {
334+
use super::*;
335+
use bigdecimal::BigDecimal;
336+
337+
impl<'q> Encode<'q, Odbc> for BigDecimal {
338+
fn encode(self, buf: &mut Vec<OdbcArgumentValue<'q>>) -> crate::encode::IsNull {
339+
buf.push(OdbcArgumentValue::Text(self.to_string()));
340+
crate::encode::IsNull::No
341+
}
342+
343+
fn encode_by_ref(&self, buf: &mut Vec<OdbcArgumentValue<'q>>) -> crate::encode::IsNull {
344+
buf.push(OdbcArgumentValue::Text(self.to_string()));
345+
crate::encode::IsNull::No
346+
}
347+
}
348+
}
349+
350+
#[cfg(feature = "decimal")]
351+
mod decimal_encode {
352+
use super::*;
353+
use rust_decimal::Decimal;
354+
355+
impl<'q> Encode<'q, Odbc> for Decimal {
356+
fn encode(self, buf: &mut Vec<OdbcArgumentValue<'q>>) -> crate::encode::IsNull {
357+
buf.push(OdbcArgumentValue::Text(self.to_string()));
358+
crate::encode::IsNull::No
359+
}
360+
361+
fn encode_by_ref(&self, buf: &mut Vec<OdbcArgumentValue<'q>>) -> crate::encode::IsNull {
362+
buf.push(OdbcArgumentValue::Text(self.to_string()));
363+
crate::encode::IsNull::No
364+
}
365+
}
366+
}
367+
368+
#[cfg(feature = "uuid")]
369+
mod uuid_encode {
370+
use super::*;
371+
use uuid::Uuid;
372+
373+
impl<'q> Encode<'q, Odbc> for Uuid {
374+
fn encode(self, buf: &mut Vec<OdbcArgumentValue<'q>>) -> crate::encode::IsNull {
375+
buf.push(OdbcArgumentValue::Text(self.to_string()));
376+
crate::encode::IsNull::No
377+
}
378+
379+
fn encode_by_ref(&self, buf: &mut Vec<OdbcArgumentValue<'q>>) -> crate::encode::IsNull {
380+
buf.push(OdbcArgumentValue::Text(self.to_string()));
381+
crate::encode::IsNull::No
382+
}
383+
}
384+
}
385+
121386
impl<'q, T> Encode<'q, Odbc> for Option<T>
122387
where
123388
T: Encode<'q, Odbc> + Type<Odbc> + 'q,

0 commit comments

Comments
 (0)