Skip to content

Commit eb20995

Browse files
committed
feat: Introduce OdbcDataType enum and enhance OdbcTypeInfo structure
This commit adds the OdbcDataType enum to represent various ODBC data types and refines the OdbcTypeInfo structure to include data type, precision, scale, and length. It updates type information implementations for several types (i32, i64, f32, f64, String, &str, Vec<u8>, i16, i8, bool) to utilize the new OdbcDataType, improving clarity and maintainability. Additionally, it enhances the connection worker to map ODBC API data types to the new enum, ensuring better integration with the ODBC API.
1 parent ea50336 commit eb20995

File tree

4 files changed

+305
-72
lines changed

4 files changed

+305
-72
lines changed

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

Lines changed: 68 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,73 @@ use futures_intrusive::sync::Mutex;
66

77
use crate::error::Error;
88
use crate::odbc::{
9-
OdbcArgumentValue, OdbcColumn, OdbcConnectOptions, OdbcQueryResult, OdbcRow, OdbcTypeInfo,
9+
OdbcArgumentValue, OdbcColumn, OdbcConnectOptions, OdbcQueryResult, OdbcRow, OdbcTypeInfo, OdbcDataType,
1010
};
1111
#[allow(unused_imports)]
1212
use crate::row::Row as SqlxRow;
1313
use either::Either;
14-
use odbc_api::{Cursor, CursorRow, IntoParameter, ResultSetMetadata};
14+
use odbc_api::{Cursor, CursorRow, IntoParameter, ResultSetMetadata, DataType};
15+
16+
/// Map ODBC API DataType to our OdbcDataType
17+
fn map_odbc_data_type(data_type: DataType) -> OdbcTypeInfo {
18+
let odbc_data_type = match data_type {
19+
DataType::BigInt => OdbcDataType::BigInt,
20+
DataType::Binary { .. } => OdbcDataType::Binary,
21+
DataType::Bit => OdbcDataType::Bit,
22+
DataType::Char { .. } => OdbcDataType::Char,
23+
DataType::Date => OdbcDataType::Date,
24+
DataType::Decimal { .. } => OdbcDataType::Decimal,
25+
DataType::Double => OdbcDataType::Double,
26+
DataType::Float { .. } => OdbcDataType::Float,
27+
DataType::Integer => OdbcDataType::Integer,
28+
DataType::LongVarbinary { .. } => OdbcDataType::LongVarbinary,
29+
DataType::LongVarchar { .. } => OdbcDataType::LongVarchar,
30+
DataType::Numeric { .. } => OdbcDataType::Numeric,
31+
DataType::Real => OdbcDataType::Real,
32+
DataType::SmallInt => OdbcDataType::SmallInt,
33+
DataType::Time { .. } => OdbcDataType::Time,
34+
DataType::Timestamp { .. } => OdbcDataType::Timestamp,
35+
DataType::TinyInt => OdbcDataType::TinyInt,
36+
DataType::Varbinary { .. } => OdbcDataType::Varbinary,
37+
DataType::Varchar { .. } => OdbcDataType::Varchar,
38+
DataType::WChar { .. } => OdbcDataType::WChar,
39+
DataType::WLongVarchar { .. } => OdbcDataType::WLongVarchar,
40+
DataType::WVarchar { .. } => OdbcDataType::WVarchar,
41+
DataType::Other { .. } => OdbcDataType::Unknown,
42+
DataType::Unknown => OdbcDataType::Unknown,
43+
};
44+
45+
// Extract precision, scale, and length information where available
46+
match data_type {
47+
DataType::Decimal { precision, scale } => {
48+
OdbcTypeInfo::with_precision_and_scale(odbc_data_type, precision as u32, scale as u16)
49+
},
50+
DataType::Numeric { precision, scale } => {
51+
OdbcTypeInfo::with_precision_and_scale(odbc_data_type, precision as u32, scale as u16)
52+
},
53+
DataType::Char { length } | DataType::Varchar { length } | DataType::WChar { length } | DataType::WVarchar { length } => {
54+
if let Some(len) = length {
55+
OdbcTypeInfo::with_length(odbc_data_type, len.get() as u32)
56+
} else {
57+
OdbcTypeInfo::new(odbc_data_type)
58+
}
59+
},
60+
DataType::Binary { length } | DataType::Varbinary { length } => {
61+
if let Some(len) = length {
62+
OdbcTypeInfo::with_length(odbc_data_type, len.get() as u32)
63+
} else {
64+
OdbcTypeInfo::new(odbc_data_type)
65+
}
66+
},
67+
DataType::Float { precision } => {
68+
OdbcTypeInfo::with_precision(odbc_data_type, precision as u32)
69+
},
70+
DataType::Time { precision } | DataType::Timestamp { precision } => {
71+
OdbcTypeInfo::with_precision(odbc_data_type, precision as u32)
72+
},
73+
_ => OdbcTypeInfo::new(odbc_data_type),
74+
}
75+
}
1576

1677
#[derive(Debug)]
1778
pub(crate) struct ConnectionWorker {
@@ -323,10 +384,7 @@ where
323384
let name = String::from_utf8(cd.name).unwrap_or_else(|_| format!("col{}", i - 1));
324385
columns.push(OdbcColumn {
325386
name,
326-
type_info: OdbcTypeInfo {
327-
name: format!("{:?}", cd.data_type),
328-
is_null: false,
329-
},
387+
type_info: map_odbc_data_type(cd.data_type),
330388
ordinal: (i - 1) as usize,
331389
});
332390
}
@@ -367,34 +425,22 @@ fn collect_row_values(
367425
let mut buf = Vec::new();
368426
match row.get_text(i as u16, &mut buf) {
369427
Ok(true) => values.push((
370-
OdbcTypeInfo {
371-
name: "TEXT".into(),
372-
is_null: false,
373-
},
428+
OdbcTypeInfo::VARCHAR,
374429
Some(buf),
375430
)),
376431
Ok(false) => values.push((
377-
OdbcTypeInfo {
378-
name: "TEXT".into(),
379-
is_null: true,
380-
},
432+
OdbcTypeInfo::VARCHAR,
381433
None,
382434
)),
383435
Err(_) => {
384436
let mut bin = Vec::new();
385437
match row.get_binary(i as u16, &mut bin) {
386438
Ok(true) => values.push((
387-
OdbcTypeInfo {
388-
name: "BLOB".into(),
389-
is_null: false,
390-
},
439+
OdbcTypeInfo::VARBINARY,
391440
Some(bin),
392441
)),
393442
Ok(false) => values.push((
394-
OdbcTypeInfo {
395-
name: "BLOB".into(),
396-
is_null: true,
397-
},
443+
OdbcTypeInfo::VARBINARY,
398444
None,
399445
)),
400446
Err(e) => return Err(Error::from(e)),

sqlx-core/src/odbc/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ pub use query_result::OdbcQueryResult;
2525
pub use row::OdbcRow;
2626
pub use statement::OdbcStatement;
2727
pub use transaction::OdbcTransactionManager;
28-
pub use type_info::OdbcTypeInfo;
28+
pub use type_info::{OdbcTypeInfo, OdbcDataType};
2929
pub use value::{OdbcValue, OdbcValueRef};
3030

3131
/// An alias for [`Pool`][crate::pool::Pool], specialized for ODBC.

sqlx-core/src/odbc/type.rs

Lines changed: 50 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,89 +1,95 @@
1-
use crate::odbc::Odbc;
2-
use crate::odbc::OdbcTypeInfo;
1+
use crate::odbc::{Odbc, OdbcTypeInfo, OdbcDataType};
32
use crate::types::Type;
43

54
impl Type<Odbc> for i32 {
65
fn type_info() -> OdbcTypeInfo {
7-
OdbcTypeInfo {
8-
name: "INT".into(),
9-
is_null: false,
10-
}
6+
OdbcTypeInfo::INTEGER
117
}
12-
fn compatible(_ty: &OdbcTypeInfo) -> bool {
13-
true
8+
fn compatible(ty: &OdbcTypeInfo) -> bool {
9+
matches!(ty.data_type(), OdbcDataType::Integer | OdbcDataType::SmallInt | OdbcDataType::TinyInt)
1410
}
1511
}
1612

1713
impl Type<Odbc> for i64 {
1814
fn type_info() -> OdbcTypeInfo {
19-
OdbcTypeInfo {
20-
name: "BIGINT".into(),
21-
is_null: false,
22-
}
15+
OdbcTypeInfo::BIGINT
2316
}
24-
fn compatible(_ty: &OdbcTypeInfo) -> bool {
25-
true
17+
fn compatible(ty: &OdbcTypeInfo) -> bool {
18+
matches!(ty.data_type(), OdbcDataType::BigInt | OdbcDataType::Integer)
2619
}
2720
}
2821

2922
impl Type<Odbc> for f64 {
3023
fn type_info() -> OdbcTypeInfo {
31-
OdbcTypeInfo {
32-
name: "DOUBLE".into(),
33-
is_null: false,
34-
}
24+
OdbcTypeInfo::DOUBLE
3525
}
36-
fn compatible(_ty: &OdbcTypeInfo) -> bool {
37-
true
26+
fn compatible(ty: &OdbcTypeInfo) -> bool {
27+
matches!(ty.data_type(), OdbcDataType::Double | OdbcDataType::Float | OdbcDataType::Real)
3828
}
3929
}
4030

4131
impl Type<Odbc> for f32 {
4232
fn type_info() -> OdbcTypeInfo {
43-
OdbcTypeInfo {
44-
name: "FLOAT".into(),
45-
is_null: false,
46-
}
33+
OdbcTypeInfo::FLOAT
4734
}
48-
fn compatible(_ty: &OdbcTypeInfo) -> bool {
49-
true
35+
fn compatible(ty: &OdbcTypeInfo) -> bool {
36+
matches!(ty.data_type(), OdbcDataType::Float | OdbcDataType::Real)
5037
}
5138
}
5239

5340
impl Type<Odbc> for String {
5441
fn type_info() -> OdbcTypeInfo {
55-
OdbcTypeInfo {
56-
name: "TEXT".into(),
57-
is_null: false,
58-
}
42+
OdbcTypeInfo::VARCHAR
5943
}
60-
fn compatible(_ty: &OdbcTypeInfo) -> bool {
61-
true
44+
fn compatible(ty: &OdbcTypeInfo) -> bool {
45+
ty.data_type().is_character_type()
6246
}
6347
}
6448

6549
impl Type<Odbc> for &str {
6650
fn type_info() -> OdbcTypeInfo {
67-
OdbcTypeInfo {
68-
name: "TEXT".into(),
69-
is_null: false,
70-
}
51+
OdbcTypeInfo::VARCHAR
7152
}
72-
fn compatible(_ty: &OdbcTypeInfo) -> bool {
73-
true
53+
fn compatible(ty: &OdbcTypeInfo) -> bool {
54+
ty.data_type().is_character_type()
7455
}
7556
}
7657

7758
impl Type<Odbc> for Vec<u8> {
7859
fn type_info() -> OdbcTypeInfo {
79-
OdbcTypeInfo {
80-
name: "BLOB".into(),
81-
is_null: false,
82-
}
60+
OdbcTypeInfo::VARBINARY
8361
}
84-
fn compatible(_ty: &OdbcTypeInfo) -> bool {
85-
true
62+
fn compatible(ty: &OdbcTypeInfo) -> bool {
63+
ty.data_type().is_binary_type()
64+
}
65+
}
66+
67+
impl Type<Odbc> for i16 {
68+
fn type_info() -> OdbcTypeInfo {
69+
OdbcTypeInfo::SMALLINT
70+
}
71+
fn compatible(ty: &OdbcTypeInfo) -> bool {
72+
matches!(ty.data_type(), OdbcDataType::SmallInt | OdbcDataType::TinyInt)
73+
}
74+
}
75+
76+
impl Type<Odbc> for i8 {
77+
fn type_info() -> OdbcTypeInfo {
78+
OdbcTypeInfo::TINYINT
79+
}
80+
fn compatible(ty: &OdbcTypeInfo) -> bool {
81+
matches!(ty.data_type(), OdbcDataType::TinyInt)
82+
}
83+
}
84+
85+
impl Type<Odbc> for bool {
86+
fn type_info() -> OdbcTypeInfo {
87+
OdbcTypeInfo::BIT
88+
}
89+
fn compatible(ty: &OdbcTypeInfo) -> bool {
90+
matches!(ty.data_type(), OdbcDataType::Bit | OdbcDataType::TinyInt)
8691
}
8792
}
8893

8994
// Option<T> blanket impl is provided in core types; do not re-implement here.
95+

0 commit comments

Comments
 (0)