@@ -9,27 +9,27 @@ use either::Either;
99mod odbc_bridge;
1010use futures_core:: future:: BoxFuture ;
1111use futures_util:: future;
12+ use odbc_api:: ConnectionTransitions ;
1213use odbc_bridge:: { establish_connection, execute_sql} ;
1314// no direct spawn_blocking here; use run_blocking helper
1415use crate :: odbc:: { OdbcStatement , OdbcStatementMetadata } ;
15- use odbc_api:: ResultSetMetadata ;
16+ use odbc_api:: { handles :: StatementConnection , Prepared , ResultSetMetadata , SharedConnection } ;
1617use std:: borrow:: Cow ;
1718use std:: collections:: HashMap ;
1819use std:: sync:: Arc ;
1920
20- fn collect_columns (
21- prepared : & mut odbc_api:: Prepared < odbc_api:: handles:: StatementImpl < ' _ > > ,
22- ) -> Vec < OdbcColumn > {
21+ mod executor;
22+
23+ type PreparedStatement = Prepared < StatementConnection < SharedConnection < ' static > > > ;
24+
25+ fn collect_columns ( prepared : & mut PreparedStatement ) -> Vec < OdbcColumn > {
2326 let count = prepared. num_result_cols ( ) . unwrap_or ( 0 ) ;
2427 ( 1 ..=count)
2528 . map ( |i| create_column ( prepared, i as u16 ) )
2629 . collect ( )
2730}
2831
29- fn create_column (
30- stmt : & mut odbc_api:: Prepared < odbc_api:: handles:: StatementImpl < ' _ > > ,
31- index : u16 ,
32- ) -> OdbcColumn {
32+ fn create_column ( stmt : & mut PreparedStatement , index : u16 ) -> OdbcColumn {
3333 let mut cd = odbc_api:: ColumnDescription :: default ( ) ;
3434 let _ = stmt. describe_col ( index, & mut cd) ;
3535
@@ -44,16 +44,21 @@ fn decode_column_name(name_bytes: Vec<u8>, index: u16) -> String {
4444 String :: from_utf8 ( name_bytes) . unwrap_or_else ( |_| format ! ( "col{}" , index - 1 ) )
4545}
4646
47- mod executor;
48-
4947/// A connection to an ODBC-accessible database.
5048///
5149/// ODBC uses a blocking C API, so we offload blocking calls to the runtime's blocking
5250/// thread-pool via `spawn_blocking` and synchronize access with a mutex.
53- #[ derive( Debug ) ]
5451pub struct OdbcConnection {
55- pub ( crate ) conn : odbc_api:: SharedConnection < ' static > ,
56- pub ( crate ) stmt_cache : HashMap < u64 , crate :: odbc:: statement:: OdbcStatementMetadata > ,
52+ pub ( crate ) conn : SharedConnection < ' static > ,
53+ pub ( crate ) stmt_cache : HashMap < Arc < str > , PreparedStatement > ,
54+ }
55+
56+ impl std:: fmt:: Debug for OdbcConnection {
57+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
58+ f. debug_struct ( "OdbcConnection" )
59+ . field ( "conn" , & self . conn )
60+ . finish ( )
61+ }
5762}
5863
5964impl OdbcConnection {
@@ -139,11 +144,16 @@ impl OdbcConnection {
139144 args : Option < OdbcArguments > ,
140145 ) -> Result < flume:: Receiver < Result < Either < OdbcQueryResult , OdbcRow > , Error > > , Error > {
141146 let ( tx, rx) = flume:: bounded ( 64 ) ;
142- let sql = sql. to_string ( ) ;
143- let args_move = args;
147+
148+ // !!TODO!!!: Put back the prepared statement after usage
149+ let maybe_prepared = if let Some ( prepared) = self . stmt_cache . remove ( sql) {
150+ MaybePrepared :: Prepared ( prepared)
151+ } else {
152+ MaybePrepared :: NotPrepared ( sql. to_string ( ) )
153+ } ;
144154
145155 self . with_conn ( "execute_stream" , move |conn| {
146- if let Err ( e) = execute_sql ( conn, & sql , args_move , & tx) {
156+ if let Err ( e) = execute_sql ( conn, maybe_prepared , args , & tx) {
147157 let _ = tx. send ( Err ( e) ) ;
148158 }
149159 Ok ( ( ) )
@@ -153,61 +163,38 @@ impl OdbcConnection {
153163 Ok ( rx)
154164 }
155165
156- pub ( crate ) async fn prepare_metadata (
157- & mut self ,
158- sql : & str ,
159- ) -> Result < ( u64 , Vec < OdbcColumn > , usize ) , Error > {
160- use std:: collections:: hash_map:: DefaultHasher ;
161- use std:: hash:: { Hash , Hasher } ;
162-
163- let mut hasher = DefaultHasher :: new ( ) ;
164- sql. hash ( & mut hasher) ;
165- let key = hasher. finish ( ) ;
166-
167- // Check cache first
168- if let Some ( metadata) = self . stmt_cache . get ( & key) {
169- return Ok ( ( key, metadata. columns . clone ( ) , metadata. parameters ) ) ;
170- }
171-
172- // Create new prepared statement to get metadata
173- let sql = sql. to_string ( ) ;
174- self . with_conn ( "prepare_metadata" , move |conn| {
175- let mut prepared = conn. prepare ( & sql) ?;
176- let columns = collect_columns ( & mut prepared) ;
177- let params = usize:: from ( prepared. num_params ( ) . unwrap_or ( 0 ) ) ;
178- Ok ( ( columns, params) )
179- } )
180- . await
181- . map ( |( columns, params) | {
182- // Cache the metadata
183- let metadata = crate :: odbc:: statement:: OdbcStatementMetadata {
184- columns : columns. clone ( ) ,
185- parameters : params,
186- } ;
187- self . stmt_cache . insert ( key, metadata) ;
188- ( key, columns, params)
189- } )
190- }
191-
192166 pub ( crate ) async fn clear_cached_statements ( & mut self ) -> Result < ( ) , Error > {
193167 // Clear the statement metadata cache
194168 self . stmt_cache . clear ( ) ;
195169 Ok ( ( ) )
196170 }
197171
198- pub async fn prepare ( & mut self , sql : & str ) -> Result < OdbcStatement < ' static > , Error > {
199- let ( _, columns, parameters) = self . prepare_metadata ( sql) . await ?;
200- let metadata = OdbcStatementMetadata {
201- columns,
202- parameters,
203- } ;
172+ pub async fn prepare < ' a > ( & mut self , sql : & ' a str ) -> Result < OdbcStatement < ' a > , Error > {
173+ let conn = Arc :: clone ( & self . conn ) ;
174+ let sql_arc = Arc :: from ( sql. to_string ( ) ) ;
175+ let sql_clone = Arc :: clone ( & sql_arc) ;
176+ let ( prepared, metadata) = run_blocking ( move || {
177+ let mut prepared = conn. into_prepared ( & sql_clone) ?;
178+ let metadata = OdbcStatementMetadata {
179+ columns : collect_columns ( & mut prepared) ,
180+ parameters : usize:: from ( prepared. num_params ( ) . unwrap_or ( 0 ) ) ,
181+ } ;
182+ Ok ( ( prepared, metadata) )
183+ } )
184+ . await ?;
185+ self . stmt_cache . insert ( Arc :: clone ( & sql_arc) , prepared) ;
204186 Ok ( OdbcStatement {
205- sql : Cow :: Owned ( sql. to_string ( ) ) ,
187+ sql : Cow :: Borrowed ( sql) ,
206188 metadata,
207189 } )
208190 }
209191}
210192
193+ pub ( crate ) enum MaybePrepared {
194+ Prepared ( PreparedStatement ) ,
195+ NotPrepared ( String ) ,
196+ }
197+
211198impl Connection for OdbcConnection {
212199 type Database = Odbc ;
213200
0 commit comments