Skip to content

Commit ea15e32

Browse files
cursoragentlovasoa
andcommitted
feat: Cache prepared statement metadata for ODBC
Co-authored-by: contact <[email protected]>
1 parent 9e71ab3 commit ea15e32

File tree

2 files changed

+36
-14
lines changed

2 files changed

+36
-14
lines changed

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

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,13 @@ use either::Either;
66
use flume::{SendError, Sender};
77
use odbc_api::handles::StatementImpl;
88
use odbc_api::{Cursor, CursorRow, IntoParameter, Nullable, Preallocated, ResultSetMetadata};
9+
use std::collections::HashMap;
910

10-
pub type OdbcConn = odbc_api::Connection<'static>;
11+
#[derive(Debug)]
12+
pub struct OdbcConn {
13+
pub conn: odbc_api::Connection<'static>,
14+
pub prepared_meta_cache: HashMap<u64, (Vec<OdbcColumn>, usize)>,
15+
}
1116
pub type ExecuteResult = Result<Either<OdbcQueryResult, OdbcRow>, Error>;
1217
pub type ExecuteSender = Sender<ExecuteResult>;
1318

@@ -16,17 +21,20 @@ pub fn establish_connection(options: &crate::odbc::OdbcConnectOptions) -> Result
1621
let conn = env
1722
.connect_with_connection_string(options.connection_string(), Default::default())
1823
.map_err(|e| Error::Configuration(e.to_string().into()))?;
19-
Ok(conn)
24+
Ok(OdbcConn {
25+
conn,
26+
prepared_meta_cache: HashMap::new(),
27+
})
2028
}
2129

2230
pub fn execute_sql(
23-
conn: &mut OdbcConn,
31+
inner: &mut OdbcConn,
2432
sql: &str,
2533
args: Option<OdbcArguments>,
2634
tx: &ExecuteSender,
2735
) -> Result<(), Error> {
2836
let params = prepare_parameters(args);
29-
let stmt = &mut conn.preallocate().map_err(Error::from)?;
37+
let stmt = &mut inner.conn.preallocate().map_err(Error::from)?;
3038

3139
if let Some(mut cursor) = stmt.execute(sql, &params[..])? {
3240
handle_cursor(&mut cursor, tx);
@@ -314,11 +322,25 @@ fn extract_binary(
314322
}
315323

316324
pub fn do_prepare(
317-
conn: &mut OdbcConn,
325+
inner: &mut OdbcConn,
318326
sql: Box<str>,
319327
) -> Result<(u64, Vec<OdbcColumn>, usize), Error> {
320-
let mut prepared = conn.prepare(&sql)?;
328+
use std::collections::hash_map::DefaultHasher;
329+
use std::hash::{Hash, Hasher};
330+
331+
let mut hasher = DefaultHasher::new();
332+
sql.hash(&mut hasher);
333+
let key = hasher.finish();
334+
335+
if let Some((cols, params)) = inner.prepared_meta_cache.get(&key) {
336+
return Ok((key, cols.clone(), *params));
337+
}
338+
339+
let mut prepared = inner.conn.prepare(&sql)?;
321340
let columns = collect_columns(&mut prepared);
322341
let params = usize::from(prepared.num_params().unwrap_or(0));
323-
Ok((0, columns, params))
342+
inner
343+
.prepared_meta_cache
344+
.insert(key, (columns.clone(), params));
345+
Ok((key, columns, params))
324346
}

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

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -70,37 +70,37 @@ impl OdbcConnection {
7070
/// connection is talking to as reported by the ODBC driver.
7171
pub async fn dbms_name(&mut self) -> Result<String, Error> {
7272
self.with_conn_map::<_, _, _>("Failed to get DBMS name", |conn| {
73-
conn.database_management_system_name()
73+
conn.conn.database_management_system_name()
7474
})
7575
.await
7676
}
7777

7878
pub(crate) async fn ping_blocking(&mut self) -> Result<(), Error> {
7979
self.with_conn_map::<_, _, _>("Ping failed", |conn| {
80-
conn.execute("SELECT 1", (), None).map(|_| ())
80+
conn.conn.execute("SELECT 1", (), None).map(|_| ())
8181
})
8282
.await
8383
}
8484

8585
pub(crate) async fn begin_blocking(&mut self) -> Result<(), Error> {
8686
self.with_conn_map::<_, _, _>("Failed to begin transaction", |conn| {
87-
conn.set_autocommit(false)
87+
conn.conn.set_autocommit(false)
8888
})
8989
.await
9090
}
9191

9292
pub(crate) async fn commit_blocking(&mut self) -> Result<(), Error> {
9393
self.with_conn_map::<_, _, _>("Failed to commit transaction", |conn| {
94-
conn.commit()?;
95-
conn.set_autocommit(true)
94+
conn.conn.commit()?;
95+
conn.conn.set_autocommit(true)
9696
})
9797
.await
9898
}
9999

100100
pub(crate) async fn rollback_blocking(&mut self) -> Result<(), Error> {
101101
self.with_conn_map::<_, _, _>("Failed to rollback transaction", |conn| {
102-
conn.rollback()?;
103-
conn.set_autocommit(true)
102+
conn.conn.rollback()?;
103+
conn.conn.set_autocommit(true)
104104
})
105105
.await
106106
}

0 commit comments

Comments
 (0)