1+ use std:: sync:: OnceLock ;
12use std:: thread;
23
34use futures_channel:: oneshot;
@@ -21,6 +22,9 @@ type ExecuteSender = flume::Sender<ExecuteResult>;
2122type PrepareResult = Result < ( u64 , Vec < OdbcColumn > , usize ) , Error > ;
2223type 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 ) ]
2529pub ( crate ) struct ConnectionWorker {
2630 command_tx : flume:: Sender < Command > ,
@@ -160,12 +164,13 @@ fn worker_thread_main(
160164}
161165
162166fn 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