Skip to content

Commit 72729b4

Browse files
committed
fix(odbc): use shared ODBC environment to prevent concurrency issues
1 parent 91b8f0e commit 72729b4

File tree

1 file changed

+11
-6
lines changed

1 file changed

+11
-6
lines changed

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

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::sync::OnceLock;
12
use std::thread;
23

34
use futures_channel::oneshot;
@@ -21,6 +22,9 @@ type ExecuteSender = flume::Sender<ExecuteResult>;
2122
type PrepareResult = Result<(u64, Vec<OdbcColumn>, usize), Error>;
2223
type PrepareSender = oneshot::Sender<PrepareResult>;
2324

25+
// Shared ODBC environment - initialized once, used by all connections
26+
static ODBC_ENV: OnceLock<&'static odbc_api::Environment> = OnceLock::new();
27+
2428
#[derive(Debug)]
2529
pub(crate) struct ConnectionWorker {
2630
command_tx: flume::Sender<Command>,
@@ -160,12 +164,13 @@ fn worker_thread_main(
160164
}
161165

162166
fn establish_connection(options: &OdbcConnectOptions) -> Result<OdbcConnection, Error> {
163-
// Create environment and connect. We leak the environment to extend its lifetime
164-
// to 'static, as ODBC connection borrows it. This is acceptable for long-lived
165-
// process and mirrors SQLite approach to background workers.
166-
let env = Box::leak(Box::new(
167-
odbc_api::Environment::new().map_err(|e| Error::Configuration(e.to_string().into()))?,
168-
));
167+
// Get or create the shared ODBC environment
168+
// This ensures thread-safe initialization and prevents concurrent environment creation issues
169+
let env = ODBC_ENV.get_or_init(|| {
170+
Box::leak(Box::new(
171+
odbc_api::Environment::new().expect("Failed to create ODBC environment"),
172+
))
173+
});
169174

170175
let conn = env
171176
.connect_with_connection_string(options.connection_string(), Default::default())

0 commit comments

Comments
 (0)