Skip to content

Commit 3a3e0fe

Browse files
committed
feat: Add ODBC support to the Any database driver
This commit introduces comprehensive support for ODBC in the sqlx-core library. It includes the addition of ODBC-specific types, connection options, and implementations for encoding and decoding various data types. New tests have been added to ensure robust functionality and compatibility with ODBC interactions. The Cargo.toml file has also been updated to include the new ODBC test suite, enhancing overall test coverage.
1 parent 89130fc commit 3a3e0fe

34 files changed

+1429
-645
lines changed

Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,11 @@ name = "any-pool"
192192
path = "tests/any/pool.rs"
193193
required-features = ["any"]
194194

195+
[[test]]
196+
name = "any-odbc"
197+
path = "tests/any/odbc.rs"
198+
required-features = ["any", "odbc"]
199+
195200
#
196201
# Migrations
197202
#

sqlx-core/src/any/arguments.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@ pub(crate) enum AnyArgumentBufferKind<'q> {
4646
crate::mssql::MssqlArguments,
4747
std::marker::PhantomData<&'q ()>,
4848
),
49+
50+
#[cfg(feature = "odbc")]
51+
Odbc(
52+
crate::odbc::OdbcArguments<'q>,
53+
std::marker::PhantomData<&'q ()>,
54+
),
4955
}
5056

5157
// control flow inferred type bounds would be fun
@@ -131,3 +137,24 @@ impl<'q> From<AnyArguments<'q>> for crate::postgres::PgArguments {
131137
}
132138
}
133139
}
140+
141+
#[cfg(feature = "odbc")]
142+
#[allow(irrefutable_let_patterns)]
143+
impl<'q> From<AnyArguments<'q>> for crate::odbc::OdbcArguments<'q> {
144+
fn from(args: AnyArguments<'q>) -> Self {
145+
let mut buf = AnyArgumentBuffer(AnyArgumentBufferKind::Odbc(
146+
Default::default(),
147+
std::marker::PhantomData,
148+
));
149+
150+
for value in args.values {
151+
let _ = value.encode_by_ref(&mut buf);
152+
}
153+
154+
if let AnyArgumentBufferKind::Odbc(args, _) = buf.0 {
155+
args
156+
} else {
157+
unreachable!()
158+
}
159+
}
160+
}

sqlx-core/src/any/column.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ use crate::sqlite::{SqliteColumn, SqliteRow, SqliteStatement};
1313
#[cfg(feature = "mssql")]
1414
use crate::mssql::{MssqlColumn, MssqlRow, MssqlStatement};
1515

16+
#[cfg(feature = "odbc")]
17+
use crate::odbc::{OdbcColumn, OdbcRow, OdbcStatement};
18+
1619
#[derive(Debug, Clone)]
1720
pub struct AnyColumn {
1821
pub(crate) kind: AnyColumnKind,
@@ -34,6 +37,9 @@ pub(crate) enum AnyColumnKind {
3437

3538
#[cfg(feature = "mssql")]
3639
Mssql(MssqlColumn),
40+
41+
#[cfg(feature = "odbc")]
42+
Odbc(OdbcColumn),
3743
}
3844

3945
impl Column for AnyColumn {
@@ -52,6 +58,9 @@ impl Column for AnyColumn {
5258

5359
#[cfg(feature = "mssql")]
5460
AnyColumnKind::Mssql(row) => row.ordinal(),
61+
62+
#[cfg(feature = "odbc")]
63+
AnyColumnKind::Odbc(row) => row.ordinal(),
5564
}
5665
}
5766

@@ -68,6 +77,9 @@ impl Column for AnyColumn {
6877

6978
#[cfg(feature = "mssql")]
7079
AnyColumnKind::Mssql(row) => row.name(),
80+
81+
#[cfg(feature = "odbc")]
82+
AnyColumnKind::Odbc(row) => row.name(),
7183
}
7284
}
7385

@@ -441,3 +453,28 @@ impl<I: ?Sized> AnyColumnIndex for I where
441453
I: ColumnIndex<SqliteRow> + for<'q> ColumnIndex<SqliteStatement<'q>>
442454
{
443455
}
456+
457+
#[cfg(all(
458+
not(any(
459+
feature = "mysql",
460+
feature = "mssql",
461+
feature = "postgres",
462+
feature = "sqlite"
463+
)),
464+
feature = "odbc"
465+
))]
466+
pub trait AnyColumnIndex: ColumnIndex<OdbcRow> + for<'q> ColumnIndex<OdbcStatement<'q>> {}
467+
468+
#[cfg(all(
469+
not(any(
470+
feature = "mysql",
471+
feature = "mssql",
472+
feature = "postgres",
473+
feature = "sqlite"
474+
)),
475+
feature = "odbc"
476+
))]
477+
impl<I: ?Sized> AnyColumnIndex for I where
478+
I: ColumnIndex<OdbcRow> + for<'q> ColumnIndex<OdbcStatement<'q>>
479+
{
480+
}

sqlx-core/src/any/connection/establish.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ impl AnyConnection {
3434
.await
3535
.map(AnyConnectionKind::Mssql)
3636
}
37+
38+
#[cfg(feature = "odbc")]
39+
AnyConnectOptionsKind::Odbc(options) => {
40+
crate::odbc::OdbcConnection::connect_with(options)
41+
.await
42+
.map(AnyConnectionKind::Odbc)
43+
}
3744
}
3845
.map(AnyConnection)
3946
}

sqlx-core/src/any/connection/executor.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ impl<'c> Executor<'c> for &'c mut AnyConnection {
4949
.fetch_many((query, arguments.map(Into::into)))
5050
.map_ok(|v| v.map_right(Into::into).map_left(Into::into))
5151
.boxed(),
52+
53+
#[cfg(feature = "odbc")]
54+
AnyConnectionKind::Odbc(conn) => conn
55+
.fetch_many((query, arguments.map(Into::into)))
56+
.map_ok(|v| v.map_right(Into::into).map_left(Into::into))
57+
.boxed(),
5258
}
5359
}
5460

@@ -88,6 +94,12 @@ impl<'c> Executor<'c> for &'c mut AnyConnection {
8894
.fetch_optional((query, arguments.map(Into::into)))
8995
.await?
9096
.map(Into::into),
97+
98+
#[cfg(feature = "odbc")]
99+
AnyConnectionKind::Odbc(conn) => conn
100+
.fetch_optional((query, arguments.map(Into::into)))
101+
.await?
102+
.map(Into::into),
91103
})
92104
})
93105
}
@@ -114,6 +126,9 @@ impl<'c> Executor<'c> for &'c mut AnyConnection {
114126

115127
#[cfg(feature = "mssql")]
116128
AnyConnectionKind::Mssql(conn) => conn.prepare(sql).await.map(Into::into)?,
129+
130+
#[cfg(feature = "odbc")]
131+
AnyConnectionKind::Odbc(conn) => conn.prepare(sql).await.map(Into::into)?,
117132
})
118133
})
119134
}
@@ -138,6 +153,9 @@ impl<'c> Executor<'c> for &'c mut AnyConnection {
138153

139154
#[cfg(feature = "mssql")]
140155
AnyConnectionKind::Mssql(conn) => conn.describe(sql).await.map(map_describe)?,
156+
157+
#[cfg(feature = "odbc")]
158+
AnyConnectionKind::Odbc(conn) => conn.describe(sql).await.map(map_describe)?,
141159
})
142160
})
143161
}

sqlx-core/src/any/connection/mod.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ use crate::mssql;
1515

1616
#[cfg(feature = "mysql")]
1717
use crate::mysql;
18+
19+
#[cfg(feature = "odbc")]
20+
use crate::odbc;
1821
use crate::transaction::Transaction;
1922

2023
mod establish;
@@ -48,6 +51,9 @@ pub enum AnyConnectionKind {
4851

4952
#[cfg(feature = "sqlite")]
5053
Sqlite(sqlite::SqliteConnection),
54+
55+
#[cfg(feature = "odbc")]
56+
Odbc(odbc::OdbcConnection),
5157
}
5258

5359
impl AnyConnectionKind {
@@ -64,6 +70,9 @@ impl AnyConnectionKind {
6470

6571
#[cfg(feature = "mssql")]
6672
AnyConnectionKind::Mssql(_) => AnyKind::Mssql,
73+
74+
#[cfg(feature = "odbc")]
75+
AnyConnectionKind::Odbc(_) => AnyKind::Odbc,
6776
}
6877
}
6978
}
@@ -94,6 +103,9 @@ macro_rules! delegate_to {
94103

95104
#[cfg(feature = "mssql")]
96105
AnyConnectionKind::Mssql(conn) => conn.$method($($arg),*),
106+
107+
#[cfg(feature = "odbc")]
108+
AnyConnectionKind::Odbc(conn) => conn.$method($($arg),*),
97109
}
98110
};
99111
}
@@ -112,6 +124,9 @@ macro_rules! delegate_to_mut {
112124

113125
#[cfg(feature = "mssql")]
114126
AnyConnectionKind::Mssql(conn) => conn.$method($($arg),*),
127+
128+
#[cfg(feature = "odbc")]
129+
AnyConnectionKind::Odbc(conn) => conn.$method($($arg),*),
115130
}
116131
};
117132
}
@@ -134,6 +149,9 @@ impl Connection for AnyConnection {
134149

135150
#[cfg(feature = "mssql")]
136151
AnyConnectionKind::Mssql(conn) => conn.close(),
152+
153+
#[cfg(feature = "odbc")]
154+
AnyConnectionKind::Odbc(conn) => conn.close(),
137155
}
138156
}
139157

@@ -150,6 +168,9 @@ impl Connection for AnyConnection {
150168

151169
#[cfg(feature = "mssql")]
152170
AnyConnectionKind::Mssql(conn) => conn.close_hard(),
171+
172+
#[cfg(feature = "odbc")]
173+
AnyConnectionKind::Odbc(conn) => conn.close_hard(),
153174
}
154175
}
155176

@@ -178,6 +199,10 @@ impl Connection for AnyConnection {
178199
// no cache
179200
#[cfg(feature = "mssql")]
180201
AnyConnectionKind::Mssql(_) => 0,
202+
203+
// no cache
204+
#[cfg(feature = "odbc")]
205+
AnyConnectionKind::Odbc(_) => 0,
181206
}
182207
}
183208

@@ -195,6 +220,10 @@ impl Connection for AnyConnection {
195220
// no cache
196221
#[cfg(feature = "mssql")]
197222
AnyConnectionKind::Mssql(_) => Box::pin(futures_util::future::ok(())),
223+
224+
// no cache
225+
#[cfg(feature = "odbc")]
226+
AnyConnectionKind::Odbc(_) => Box::pin(futures_util::future::ok(())),
198227
}
199228
}
200229

@@ -236,3 +265,10 @@ impl From<sqlite::SqliteConnection> for AnyConnection {
236265
AnyConnection(AnyConnectionKind::Sqlite(conn))
237266
}
238267
}
268+
269+
#[cfg(feature = "odbc")]
270+
impl From<odbc::OdbcConnection> for AnyConnection {
271+
fn from(conn: odbc::OdbcConnection) -> Self {
272+
AnyConnection(AnyConnectionKind::Odbc(conn))
273+
}
274+
}

0 commit comments

Comments
 (0)