use odbc_api::{Connection, ConnectionOptions, Environment, IntoParameter, sys::{AttrConnectionPooling, AttrCpMatch}}; use std::{sync::OnceLock, time::Duration}; use std::sync::{Arc, Condvar, Mutex}; const NUM_THREADS: u32 = 10; // number of threads to spawn const CONDVAR_FLAG: bool = false; // wait for all threads to start then connect to ODBC all at the same time. const CONN_IDLE_PAUSE: u64 = 30; // seconds to stay alive connection within each thread // if CONDVAR_FLAG == true : // PoolMaxSize >= NUM_THREADS ==> OK // PoolMaxSize < NUM_THREADS ==> [[unixODBC][Driver Manager]Connection pool at capacity and the wait has timed out] // if CONDVAR_FLAG == false and (CONN_IDLE_PAUSE + CPTimeout) > PoolWaitTimeout : // PoolMaxSize >= NUM_THREADS ==> OK // PoolMaxSize < NUM_THREADS ==> [[unixODBC][Driver Manager]Connection pool at capacity and the wait has timed out] fn connection_pooling<'a>(connection_string: &str) -> Connection<'a> { // Environment initialized only once and safe to share between threads let env = { pub static ENV: OnceLock = OnceLock::new(); ENV.get_or_init(|| unsafe { println!("Environment for connection pooling"); Environment::set_connection_pooling(AttrConnectionPooling::DriverAware).unwrap(); let mut env = Environment::new().unwrap(); env.set_connection_pooling_matching(AttrCpMatch::Strict) .unwrap(); env }) }; println!("Connection MSSQL pool"); let conn: Connection<'a> = env .connect_with_connection_string( connection_string, ConnectionOptions { login_timeout_sec: Some(15), }, ) .unwrap(); conn } fn odbc_mssql() -> Result<(), Box> { let counter = Arc::new((Mutex::new(0), Condvar::new())); let mut handles = Vec::new(); for _ in 0..NUM_THREADS { let counter_clone = Arc::clone(&counter); let handle = std::thread::spawn(move || { if CONDVAR_FLAG { // Wait for all threads to start then connect to ODBC all at the same time. println!("Thread {:?} waits for all threads", std::thread::current().id()); let (lock, cvar) = &*counter_clone; let mut count = lock.lock().unwrap(); *count += 1; if *count < NUM_THREADS { count = cvar.wait(count).unwrap(); } else { cvar.notify_all(); // Notify all threads to start } } // Connection string for MSSQL let connection_string = " Driver={ODBC_Driver_18_for_SQL_Server_Pool};\ Server=0.0.0.0;\ UID=SA;\ PWD=Pepe1234;TrustServerCertificate=Yes;Database=mydatabase; "; let conn: Connection<'_> = connection_pooling(connection_string); // let conn = unsafe { conn.promote_to_send() }; let mut prepared = conn.prepare("SELECT * FROM mytable WHERE id=?;").unwrap(); match prepared.execute(&IntoParameter::into_parameter(1)) { Err(e) => println!("{}", e), Ok(None) => println!("No result set generated."), Ok(Some(_cursor)) => {} }; // Stay alive for 10 seconds std::thread::sleep(Duration::from_secs(CONN_IDLE_PAUSE)); // Check if connection is dead assert!(!conn.is_dead().unwrap()); }); handles.push(handle); } for handle in handles { println!("Thread {:?} started", handle.thread().id()); handle.join().unwrap(); } Ok(()) } fn main() { odbc_mssql().unwrap(); }