@@ -8,7 +8,10 @@ use std::{
88
99use super :: { ffi, Appender , Config , Connection , Result } ;
1010use crate :: {
11- error:: { result_from_duckdb_appender, result_from_duckdb_arrow, result_from_duckdb_prepare, Error } ,
11+ error:: {
12+ result_from_duckdb_appender, result_from_duckdb_arrow, result_from_duckdb_extract, result_from_duckdb_prepare,
13+ Error ,
14+ } ,
1215 raw_statement:: RawStatement ,
1316 statement:: Statement ,
1417} ;
@@ -93,11 +96,68 @@ impl InnerConnection {
9396 }
9497
9598 pub fn prepare < ' a > ( & mut self , conn : & ' a Connection , sql : & str ) -> Result < Statement < ' a > > {
96- let mut c_stmt: ffi:: duckdb_prepared_statement = ptr:: null_mut ( ) ;
9799 let c_str = CString :: new ( sql) . unwrap ( ) ;
98- let r = unsafe { ffi:: duckdb_prepare ( self . con , c_str. as_ptr ( ) as * const c_char , & mut c_stmt) } ;
99- result_from_duckdb_prepare ( r, c_stmt) ?;
100- Ok ( Statement :: new ( conn, unsafe { RawStatement :: new ( c_stmt) } ) )
100+
101+ // Extract statements (handles both single and multi-statement queries)
102+ let mut extracted = ptr:: null_mut ( ) ;
103+ let num_stmts =
104+ unsafe { ffi:: duckdb_extract_statements ( self . con , c_str. as_ptr ( ) as * const c_char , & mut extracted) } ;
105+ result_from_duckdb_extract ( num_stmts, extracted) ?;
106+
107+ // Auto-cleanup on drop
108+ let _guard = ExtractedStatementsGuard ( extracted) ;
109+
110+ // Execute all intermediate statements
111+ for i in 0 ..num_stmts - 1 {
112+ self . execute_extracted_statement ( extracted, i) ?;
113+ }
114+
115+ // Prepare and return final statement
116+ let final_stmt = self . prepare_extracted_statement ( extracted, num_stmts - 1 ) ?;
117+ Ok ( Statement :: new ( conn, unsafe { RawStatement :: new ( final_stmt) } ) )
118+ }
119+
120+ fn prepare_extracted_statement (
121+ & self ,
122+ extracted : ffi:: duckdb_extracted_statements ,
123+ index : ffi:: idx_t ,
124+ ) -> Result < ffi:: duckdb_prepared_statement > {
125+ let mut stmt = ptr:: null_mut ( ) ;
126+ let res = unsafe { ffi:: duckdb_prepare_extracted_statement ( self . con , extracted, index, & mut stmt) } ;
127+ result_from_duckdb_prepare ( res, stmt) ?;
128+ Ok ( stmt)
129+ }
130+
131+ fn execute_extracted_statement (
132+ & self ,
133+ extracted : ffi:: duckdb_extracted_statements ,
134+ index : ffi:: idx_t ,
135+ ) -> Result < ( ) > {
136+ let mut stmt = self . prepare_extracted_statement ( extracted, index) ?;
137+
138+ let mut result = unsafe { mem:: zeroed ( ) } ;
139+ let rc = unsafe { ffi:: duckdb_execute_prepared ( stmt, & mut result) } ;
140+
141+ let error = if rc != ffi:: DuckDBSuccess {
142+ unsafe {
143+ let c_err = ffi:: duckdb_result_error ( & mut result as * mut _ ) ;
144+ let msg = if c_err. is_null ( ) {
145+ None
146+ } else {
147+ Some ( CStr :: from_ptr ( c_err) . to_string_lossy ( ) . to_string ( ) )
148+ } ;
149+ Some ( Error :: DuckDBFailure ( ffi:: Error :: new ( rc) , msg) )
150+ }
151+ } else {
152+ None
153+ } ;
154+
155+ unsafe {
156+ ffi:: duckdb_destroy_prepare ( & mut stmt) ;
157+ ffi:: duckdb_destroy_result ( & mut result) ;
158+ }
159+
160+ error. map_or ( Ok ( ( ) ) , Err )
101161 }
102162
103163 pub fn appender < ' a > ( & mut self , conn : & ' a Connection , table : & str , schema : & str ) -> Result < Appender < ' a > > {
@@ -126,6 +186,14 @@ impl InnerConnection {
126186 }
127187}
128188
189+ struct ExtractedStatementsGuard ( ffi:: duckdb_extracted_statements ) ;
190+
191+ impl Drop for ExtractedStatementsGuard {
192+ fn drop ( & mut self ) {
193+ unsafe { ffi:: duckdb_destroy_extracted ( & mut self . 0 ) }
194+ }
195+ }
196+
129197impl Drop for InnerConnection {
130198 #[ allow( unused_must_use) ]
131199 #[ inline]
0 commit comments