Skip to content

Commit bcabb89

Browse files
committed
fix(odbc): update type retrieval for integer and float conversions
This commit modifies the type retrieval logic in the OdbcValueRef implementation to use `std::any::type_name` for better accuracy. Additionally, it updates the handling of column data in the OdbcBridge, ensuring correct data types are used for SQLite's INTEGER and enhancing null handling in data fetching methods.
1 parent 1e079ac commit bcabb89

File tree

3 files changed

+27
-26
lines changed

3 files changed

+27
-26
lines changed

sqlx-core/src/odbc/connection/odbc_bridge.rs

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use flume::{SendError, Sender};
1010
use odbc_api::buffers::{AnySlice, BufferDesc, ColumnarAnyBuffer};
1111
use odbc_api::handles::{AsStatementRef, CDataMut, Nullability, Statement};
1212
use odbc_api::parameter::CElement;
13-
use odbc_api::{Cursor, IntoParameter, ResultSetMetadata};
13+
use odbc_api::{Cursor, IntoParameter, Nullable, ResultSetMetadata};
1414
use std::sync::Arc;
1515

1616
// Bulk fetch implementation using columnar buffers instead of row-by-row fetching
@@ -281,10 +281,11 @@ fn build_columns_from_cursor<C>(cursor: &mut C) -> Vec<OdbcColumn>
281281
where
282282
C: ResultSetMetadata,
283283
{
284-
let column_count = cursor.num_result_cols().unwrap_or(0);
285-
let mut columns = Vec::with_capacity(column_count as usize);
284+
let column_count = cursor.num_result_cols().expect("no column count found");
285+
let column_count = u16::try_from(column_count).expect("invalid column count");
286+
let mut columns = Vec::with_capacity(usize::from(column_count));
286287
for index in 1..=column_count {
287-
columns.push(create_column(cursor, index as u16));
288+
columns.push(create_column(cursor, index));
288289
}
289290
columns
290291
}
@@ -408,7 +409,7 @@ where
408409
match dt {
409410
DataType::TinyInt => OdbcValueVec::TinyInt(Vec::with_capacity(capacity)),
410411
DataType::SmallInt => OdbcValueVec::SmallInt(Vec::with_capacity(capacity)),
411-
DataType::Integer => OdbcValueVec::Integer(Vec::with_capacity(capacity)),
412+
DataType::Integer => OdbcValueVec::BigInt(Vec::with_capacity(capacity)), // the SQLite driver reports "INTEGER" even though it supports 64-bit integers
412413
DataType::BigInt => OdbcValueVec::BigInt(Vec::with_capacity(capacity)),
413414
DataType::Real => OdbcValueVec::Real(Vec::with_capacity(capacity)),
414415
DataType::Float { .. } | DataType::Double => {
@@ -430,63 +431,62 @@ where
430431
col_index: u16,
431432
vec: &mut Vec<T>,
432433
nulls: &mut Vec<bool>,
433-
) {
434-
push_get_data_with_default(cursor_row, col_index, vec, nulls, T::default());
435-
}
436-
437-
fn push_get_data_with_default<T: Copy + CElement + CDataMut>(
438-
cursor_row: &mut odbc_api::CursorRow<'_>,
439-
col_index: u16,
440-
vec: &mut Vec<T>,
441-
nulls: &mut Vec<bool>,
442-
default_val: T,
443-
) {
444-
let mut tmp = default_val;
445-
nulls.push(cursor_row.get_data(col_index, &mut tmp).is_err());
446-
vec.push(tmp);
434+
) -> Result<(), odbc_api::Error>
435+
where
436+
Nullable<T>: CElement + CDataMut,
437+
{
438+
let mut tmp = Nullable::null();
439+
cursor_row.get_data(col_index, &mut tmp)?;
440+
let option = tmp.into_opt();
441+
nulls.push(option.is_none());
442+
vec.push(option.unwrap_or_default());
443+
Ok(())
447444
}
448445

449446
fn push_binary(
450447
cursor_row: &mut odbc_api::CursorRow<'_>,
451448
col_index: u16,
452449
vec: &mut Vec<Vec<u8>>,
453450
nulls: &mut Vec<bool>,
454-
) {
451+
) -> Result<(), odbc_api::Error> {
455452
let mut buf = Vec::new();
456453
nulls.push(cursor_row.get_binary(col_index, &mut buf).is_err());
457454
vec.push(buf);
455+
Ok(())
458456
}
459457

460458
fn push_text(
461459
cursor_row: &mut odbc_api::CursorRow<'_>,
462460
col_index: u16,
463461
vec: &mut Vec<String>,
464462
nulls: &mut Vec<bool>,
465-
) {
463+
) -> Result<(), odbc_api::Error> {
466464
let mut buf = Vec::<u16>::new();
467465
let txt = cursor_row.get_wide_text(col_index, &mut buf);
468466
vec.push(String::from_utf16_lossy(&buf).to_string());
469467
nulls.push(!txt.unwrap_or(false));
468+
Ok(())
470469
}
471470

472471
fn push_bit(
473472
cursor_row: &mut odbc_api::CursorRow<'_>,
474473
col_index: u16,
475474
vec: &mut Vec<bool>,
476475
nulls: &mut Vec<bool>,
477-
) {
476+
) -> Result<(), odbc_api::Error> {
478477
let mut bit_val = odbc_api::Bit(0);
479478
let result = cursor_row.get_data(col_index, &mut bit_val);
480479
vec.push(bit_val.as_bool());
481480
nulls.push(result.is_err());
481+
Ok(())
482482
}
483483

484484
fn push_from_cursor_row(
485485
cursor_row: &mut odbc_api::CursorRow<'_>,
486486
col_index: u16,
487487
values: &mut OdbcValueVec,
488488
nulls: &mut Vec<bool>,
489-
) {
489+
) -> Result<(), odbc_api::Error> {
490490
match values {
491491
OdbcValueVec::TinyInt(v) => push_get_data(cursor_row, col_index, v, nulls),
492492
OdbcValueVec::SmallInt(v) => push_get_data(cursor_row, col_index, v, nulls),
@@ -522,7 +522,7 @@ where
522522
col_idx,
523523
&mut value_vecs[col],
524524
&mut nulls_vecs[col],
525-
);
525+
)?;
526526
}
527527
num_rows += 1;
528528
if num_rows == batch_size {

sqlx-core/src/odbc/value.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ impl<'r> OdbcValueRef<'r> {
159159
pub fn try_int<T: TryFromInt + crate::types::Type<Odbc>>(&self) -> crate::error::Result<T> {
160160
self.int::<T>().ok_or_else(|| {
161161
crate::error::Error::Decode(Box::new(crate::error::MismatchedTypeError {
162-
rust_type: T::type_info().name().to_string(),
162+
rust_type: std::any::type_name::<T>().to_string(),
163163
rust_sql_type: T::type_info().name().to_string(),
164164
sql_type: self.batch.column_data[self.column_index]
165165
.type_info
@@ -173,7 +173,7 @@ impl<'r> OdbcValueRef<'r> {
173173
pub fn try_float<T: TryFromFloat + crate::types::Type<Odbc>>(&self) -> crate::error::Result<T> {
174174
self.float::<T>().ok_or_else(|| {
175175
crate::error::Error::Decode(Box::new(crate::error::MismatchedTypeError {
176-
rust_type: T::type_info().name().to_string(),
176+
rust_type: std::any::type_name::<T>().to_string(),
177177
rust_sql_type: T::type_info().name().to_string(),
178178
sql_type: self.batch.column_data[self.column_index]
179179
.type_info

tests/odbc/odbc.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,7 @@ async fn it_handles_mixed_null_and_values() -> anyhow::Result<()> {
543543
.fetch_all(&mut conn)
544544
.await?;
545545

546+
dbg!(&rows);
546547
assert_eq!(rows.len(), 2, "should have 2 rows");
547548
assert_eq!(rows[0].get::<Option<i32>, _>(0), Some(42));
548549
assert_eq!(rows[0].get::<Option<i32>, _>(1), None);

0 commit comments

Comments
 (0)