11use  crate :: connection:: Connection ; 
22use  crate :: error:: Error ; 
33use  crate :: odbc:: blocking:: run_blocking; 
4- use  crate :: odbc:: { Odbc ,  OdbcArguments ,  OdbcColumn ,  OdbcConnectOptions ,  OdbcQueryResult ,  OdbcRow } ; 
4+ use  crate :: odbc:: { 
5+     Odbc ,  OdbcArguments ,  OdbcColumn ,  OdbcConnectOptions ,  OdbcQueryResult ,  OdbcRow ,  OdbcTypeInfo , 
6+ } ; 
57use  crate :: transaction:: Transaction ; 
68use  either:: Either ; 
79mod  odbc_bridge; 
810use  futures_core:: future:: BoxFuture ; 
911use  futures_util:: future; 
10- use  odbc_bridge:: { do_prepare ,   establish_connection,  execute_sql,   OdbcConn } ; 
12+ use  odbc_bridge:: { establish_connection,  execute_sql} ; 
1113// no direct spawn_blocking here; use run_blocking helper 
12- use  std:: sync:: { Arc ,  Mutex } ; 
14+ use  crate :: odbc:: { OdbcStatement ,  OdbcStatementMetadata } ; 
15+ use  odbc_api:: ResultSetMetadata ; 
16+ use  std:: borrow:: Cow ; 
17+ use  std:: collections:: HashMap ; 
18+ use  std:: sync:: Arc ; 
19+ 
20+ fn  collect_columns ( 
21+     prepared :  & mut  odbc_api:: Prepared < odbc_api:: handles:: StatementImpl < ' _ > > , 
22+ )  -> Vec < OdbcColumn >  { 
23+     let  count = prepared. num_result_cols ( ) . unwrap_or ( 0 ) ; 
24+     ( 1 ..=count) 
25+         . map ( |i| create_column ( prepared,  i as  u16 ) ) 
26+         . collect ( ) 
27+ } 
28+ 
29+ fn  create_column ( 
30+     stmt :  & mut  odbc_api:: Prepared < odbc_api:: handles:: StatementImpl < ' _ > > , 
31+     index :  u16 , 
32+ )  -> OdbcColumn  { 
33+     let  mut  cd = odbc_api:: ColumnDescription :: default ( ) ; 
34+     let  _ = stmt. describe_col ( index,  & mut  cd) ; 
35+ 
36+     OdbcColumn  { 
37+         name :  decode_column_name ( cd. name ,  index) , 
38+         type_info :  OdbcTypeInfo :: new ( cd. data_type ) , 
39+         ordinal :  usize:: from ( index. checked_sub ( 1 ) . unwrap ( ) ) , 
40+     } 
41+ } 
42+ 
43+ fn  decode_column_name ( name_bytes :  Vec < u8 > ,  index :  u16 )  -> String  { 
44+     String :: from_utf8 ( name_bytes) . unwrap_or_else ( |_| format ! ( "col{}" ,  index - 1 ) ) 
45+ } 
1346
1447mod  executor; 
1548
@@ -19,86 +52,88 @@ mod executor;
1952/// thread-pool via `spawn_blocking` and synchronize access with a mutex. 
2053#[ derive( Debug ) ]  
2154pub  struct  OdbcConnection  { 
22-     pub ( crate )  conn :  Arc < Mutex < OdbcConn > > , 
55+     pub ( crate )  conn :  odbc_api:: SharedConnection < ' static > , 
56+     pub ( crate )  stmt_cache :  HashMap < u64 ,  crate :: odbc:: statement:: OdbcStatementMetadata > , 
2357} 
2458
2559impl  OdbcConnection  { 
26-     #[ inline]  
27-     async  fn  with_conn < T ,  F > ( & self ,  f :  F )  -> Result < T ,  Error > 
28-     where 
29-         T :  Send  + ' static , 
30-         F :  FnOnce ( & mut  OdbcConn )  -> Result < T ,  Error >  + Send  + ' static , 
31-     { 
32-         let  inner = self . conn . clone ( ) ; 
33-         run_blocking ( move  || { 
34-             let  mut  conn = inner. lock ( ) . unwrap ( ) ; 
35-             f ( & mut  conn) 
36-         } ) 
37-         . await 
38-     } 
39- 
40-     #[ inline]  
41-     async  fn  with_conn_map < T ,  E ,  F > ( & self ,  ctx :  & ' static  str ,  f :  F )  -> Result < T ,  Error > 
42-     where 
43-         T :  Send  + ' static , 
44-         E :  std:: fmt:: Display , 
45-         F :  FnOnce ( & mut  OdbcConn )  -> Result < T ,  E >  + Send  + ' static , 
46-     { 
47-         let  inner = self . conn . clone ( ) ; 
48-         run_blocking ( move  || { 
49-             let  mut  conn = inner. lock ( ) . unwrap ( ) ; 
50-             f ( & mut  conn) . map_err ( |e| Error :: Protocol ( format ! ( "{}: {}" ,  ctx,  e) ) ) 
51-         } ) 
52-         . await 
53-     } 
54- 
5560    pub ( crate )  async  fn  establish ( options :  & OdbcConnectOptions )  -> Result < Self ,  Error >  { 
56-         let  conn  = run_blocking ( { 
61+         let  shared_conn  = run_blocking ( { 
5762            let  options = options. clone ( ) ; 
58-             move  || establish_connection ( & options) 
63+             move  || { 
64+                 let  conn = establish_connection ( & options) ?; 
65+                 let  shared_conn = odbc_api:: SharedConnection :: new ( std:: sync:: Mutex :: new ( conn) ) ; 
66+                 Ok :: < _ ,  Error > ( shared_conn) 
67+             } 
5968        } ) 
6069        . await ?; 
6170
6271        Ok ( Self  { 
63-             conn :  Arc :: new ( Mutex :: new ( conn) ) , 
72+             conn :  shared_conn, 
73+             stmt_cache :  HashMap :: new ( ) , 
6474        } ) 
6575    } 
6676
6777    /// Returns the name of the actual Database Management System (DBMS) this 
6878     /// connection is talking to as reported by the ODBC driver. 
6979     pub  async  fn  dbms_name ( & mut  self )  -> Result < String ,  Error >  { 
70-         self . with_conn_map :: < _ ,  _ ,  _ > ( "Failed to get DBMS name" ,  |conn| { 
71-             conn. conn . database_management_system_name ( ) 
80+         let  conn = Arc :: clone ( & self . conn ) ; 
81+         run_blocking ( move  || { 
82+             let  conn_guard = conn
83+                 . lock ( ) 
84+                 . map_err ( |_| Error :: Protocol ( "Failed to lock connection" . into ( ) ) ) ?; 
85+             conn_guard
86+                 . database_management_system_name ( ) 
87+                 . map_err ( Error :: from) 
7288        } ) 
7389        . await 
7490    } 
7591
7692    pub ( crate )  async  fn  ping_blocking ( & mut  self )  -> Result < ( ) ,  Error >  { 
77-         self . with_conn_map :: < _ ,  _ ,  _ > ( "Ping failed" ,  |conn| { 
78-             conn. conn . execute ( "SELECT 1" ,  ( ) ,  None ) . map ( |_| ( ) ) 
93+         let  conn = Arc :: clone ( & self . conn ) ; 
94+         run_blocking ( move  || { 
95+             let  conn_guard = conn
96+                 . lock ( ) 
97+                 . map_err ( |_| Error :: Protocol ( "Failed to lock connection" . into ( ) ) ) ?; 
98+             conn_guard
99+                 . execute ( "SELECT 1" ,  ( ) ,  None ) 
100+                 . map_err ( Error :: from) 
101+                 . map ( |_| ( ) ) 
79102        } ) 
80103        . await 
81104    } 
82105
83106    pub ( crate )  async  fn  begin_blocking ( & mut  self )  -> Result < ( ) ,  Error >  { 
84-         self . with_conn_map :: < _ ,  _ ,  _ > ( "Failed to begin transaction" ,  |conn| { 
85-             conn. conn . set_autocommit ( false ) 
107+         let  conn = Arc :: clone ( & self . conn ) ; 
108+         run_blocking ( move  || { 
109+             let  conn_guard = conn
110+                 . lock ( ) 
111+                 . map_err ( |_| Error :: Protocol ( "Failed to lock connection" . into ( ) ) ) ?; 
112+             conn_guard. set_autocommit ( false ) . map_err ( Error :: from) 
86113        } ) 
87114        . await 
88115    } 
89116
90117    pub ( crate )  async  fn  commit_blocking ( & mut  self )  -> Result < ( ) ,  Error >  { 
91-         self . with_conn_map :: < _ ,  _ ,  _ > ( "Failed to commit transaction" ,  |conn| { 
92-             conn. conn . commit ( ) ?; 
93-             conn. conn . set_autocommit ( true ) 
118+         let  conn = Arc :: clone ( & self . conn ) ; 
119+         run_blocking ( move  || { 
120+             let  conn_guard = conn
121+                 . lock ( ) 
122+                 . map_err ( |_| Error :: Protocol ( "Failed to lock connection" . into ( ) ) ) ?; 
123+             conn_guard. commit ( ) ?; 
124+             conn_guard. set_autocommit ( true ) . map_err ( Error :: from) 
94125        } ) 
95126        . await 
96127    } 
97128
98129    pub ( crate )  async  fn  rollback_blocking ( & mut  self )  -> Result < ( ) ,  Error >  { 
99-         self . with_conn_map :: < _ ,  _ ,  _ > ( "Failed to rollback transaction" ,  |conn| { 
100-             conn. conn . rollback ( ) ?; 
101-             conn. conn . set_autocommit ( true ) 
130+         let  conn = Arc :: clone ( & self . conn ) ; 
131+         run_blocking ( move  || { 
132+             let  conn_guard = conn
133+                 . lock ( ) 
134+                 . map_err ( |_| Error :: Protocol ( "Failed to lock connection" . into ( ) ) ) ?; 
135+             conn_guard. rollback ( ) ?; 
136+             conn_guard. set_autocommit ( true ) . map_err ( Error :: from) 
102137        } ) 
103138        . await 
104139    } 
@@ -111,23 +146,79 @@ impl OdbcConnection {
111146        let  ( tx,  rx)  = flume:: bounded ( 64 ) ; 
112147        let  sql = sql. to_string ( ) ; 
113148        let  args_move = args; 
114-         self . with_conn ( move  |conn| { 
115-             if  let  Err ( e)  = execute_sql ( conn,  & sql,  args_move,  & tx)  { 
149+         let  conn = Arc :: clone ( & self . conn ) ; 
150+ 
151+         run_blocking ( move  || { 
152+             let  mut  conn_guard = conn
153+                 . lock ( ) 
154+                 . map_err ( |_| Error :: Protocol ( "Failed to lock connection" . into ( ) ) ) ?; 
155+             if  let  Err ( e)  = execute_sql ( & mut  conn_guard,  & sql,  args_move,  & tx)  { 
116156                let  _ = tx. send ( Err ( e) ) ; 
117157            } 
118158            Ok ( ( ) ) 
119159        } ) 
120160        . await ?; 
161+ 
121162        Ok ( rx) 
122163    } 
123164
124165    pub ( crate )  async  fn  prepare_metadata ( 
125166        & mut  self , 
126167        sql :  & str , 
127168    )  -> Result < ( u64 ,  Vec < OdbcColumn > ,  usize ) ,  Error >  { 
169+         use  std:: collections:: hash_map:: DefaultHasher ; 
170+         use  std:: hash:: { Hash ,  Hasher } ; 
171+ 
172+         let  mut  hasher = DefaultHasher :: new ( ) ; 
173+         sql. hash ( & mut  hasher) ; 
174+         let  key = hasher. finish ( ) ; 
175+ 
176+         // Check cache first 
177+         if  let  Some ( metadata)  = self . stmt_cache . get ( & key)  { 
178+             return  Ok ( ( key,  metadata. columns . clone ( ) ,  metadata. parameters ) ) ; 
179+         } 
180+ 
181+         // Create new prepared statement to get metadata 
128182        let  sql = sql. to_string ( ) ; 
129-         self . with_conn ( move  |conn| do_prepare ( conn,  sql. into ( ) ) ) 
130-             . await 
183+         let  conn = Arc :: clone ( & self . conn ) ; 
184+ 
185+         run_blocking ( move  || { 
186+             let  conn_guard = conn
187+                 . lock ( ) 
188+                 . map_err ( |_| Error :: Protocol ( "Failed to lock connection" . into ( ) ) ) ?; 
189+             let  mut  prepared = conn_guard. prepare ( & sql) . map_err ( Error :: from) ?; 
190+             let  columns = collect_columns ( & mut  prepared) ; 
191+             let  params = usize:: from ( prepared. num_params ( ) . unwrap_or ( 0 ) ) ; 
192+             Ok :: < _ ,  Error > ( ( columns,  params) ) 
193+         } ) 
194+         . await 
195+         . map ( |( columns,  params) | { 
196+             // Cache the metadata 
197+             let  metadata = crate :: odbc:: statement:: OdbcStatementMetadata  { 
198+                 columns :  columns. clone ( ) , 
199+                 parameters :  params, 
200+             } ; 
201+             self . stmt_cache . insert ( key,  metadata) ; 
202+             ( key,  columns,  params) 
203+         } ) 
204+     } 
205+ 
206+     pub ( crate )  async  fn  clear_cached_statements ( & mut  self )  -> Result < ( ) ,  Error >  { 
207+         // Clear the statement metadata cache 
208+         self . stmt_cache . clear ( ) ; 
209+         Ok ( ( ) ) 
210+     } 
211+ 
212+     pub  async  fn  prepare ( & mut  self ,  sql :  & str )  -> Result < OdbcStatement < ' static > ,  Error >  { 
213+         let  ( _,  columns,  parameters)  = self . prepare_metadata ( sql) . await ?; 
214+         let  metadata = OdbcStatementMetadata  { 
215+             columns, 
216+             parameters, 
217+         } ; 
218+         Ok ( OdbcStatement  { 
219+             sql :  Cow :: Owned ( sql. to_string ( ) ) , 
220+             metadata, 
221+         } ) 
131222    } 
132223} 
133224
@@ -168,6 +259,10 @@ impl Connection for OdbcConnection {
168259    fn  should_flush ( & self )  -> bool  { 
169260        false 
170261    } 
262+ 
263+     fn  clear_cached_statements ( & mut  self )  -> BoxFuture < ' _ ,  Result < ( ) ,  Error > >  { 
264+         Box :: pin ( self . clear_cached_statements ( ) ) 
265+     } 
171266} 
172267
173268// moved helpers to connection/inner.rs 
0 commit comments