@@ -79,6 +79,7 @@ pub use crate::{
79
79
config:: { AccessMode , Config , DefaultNullOrder , DefaultOrder } ,
80
80
error:: Error ,
81
81
ffi:: ErrorCode ,
82
+ inner_connection:: InterruptHandle ,
82
83
params:: { params_from_iter, Params , ParamsFromIter } ,
83
84
row:: { AndThenRows , Map , MappedRows , Row , RowIndex , Rows } ,
84
85
statement:: Statement ,
@@ -532,6 +533,30 @@ impl Connection {
532
533
self . db . borrow_mut ( ) . appender ( self , table, schema)
533
534
}
534
535
536
+ /// Get a handle to interrupt long-running queries.
537
+ ///
538
+ /// ## Example
539
+ ///
540
+ /// ```rust,no_run
541
+ /// # use duckdb::{Connection, Result};
542
+ /// fn run_query(conn: Connection) -> Result<()> {
543
+ /// let interrupt_handle = conn.interrupt_handle();
544
+ /// let join_handle = std::thread::spawn(move || { conn.execute("expensive query", []) });
545
+ ///
546
+ /// // Arbitrary wait for query to start
547
+ /// std::thread::sleep(std::time::Duration::from_millis(100));
548
+ ///
549
+ /// interrupt_handle.interrupt();
550
+ ///
551
+ /// let query_result = join_handle.join().unwrap();
552
+ /// assert!(query_result.is_err());
553
+ ///
554
+ /// Ok(())
555
+ /// }
556
+ pub fn interrupt_handle ( & self ) -> std:: sync:: Arc < InterruptHandle > {
557
+ self . db . borrow ( ) . get_interrupt_handle ( )
558
+ }
559
+
535
560
/// Close the DuckDB connection.
536
561
///
537
562
/// This is functionally equivalent to the `Drop` implementation for
@@ -1337,6 +1362,36 @@ mod test {
1337
1362
Ok ( ( ) )
1338
1363
}
1339
1364
1365
+ #[ test]
1366
+ fn test_interrupt ( ) -> Result < ( ) > {
1367
+ let db = checked_memory_handle ( ) ;
1368
+ let db_interrupt = db. interrupt_handle ( ) ;
1369
+
1370
+ let ( tx, rx) = std:: sync:: mpsc:: channel ( ) ;
1371
+ std:: thread:: spawn ( move || {
1372
+ let mut stmt = db
1373
+ . prepare ( "select count(*) from range(10000000) t1, range(1000000) t2" )
1374
+ . unwrap ( ) ;
1375
+ tx. send ( stmt. execute ( [ ] ) ) . unwrap ( ) ;
1376
+ } ) ;
1377
+
1378
+ std:: thread:: sleep ( std:: time:: Duration :: from_millis ( 100 ) ) ;
1379
+ db_interrupt. interrupt ( ) ;
1380
+
1381
+ let result = rx. recv_timeout ( std:: time:: Duration :: from_secs ( 5 ) ) . unwrap ( ) ;
1382
+ assert ! ( result. is_err_and( |err| err. to_string( ) . contains( "INTERRUPT" ) ) ) ;
1383
+ Ok ( ( ) )
1384
+ }
1385
+
1386
+ #[ test]
1387
+ fn test_interrupt_on_dropped_db ( ) {
1388
+ let db = checked_memory_handle ( ) ;
1389
+ let db_interrupt = db. interrupt_handle ( ) ;
1390
+
1391
+ drop ( db) ;
1392
+ db_interrupt. interrupt ( ) ;
1393
+ }
1394
+
1340
1395
#[ cfg( feature = "bundled" ) ]
1341
1396
#[ test]
1342
1397
fn test_version ( ) -> Result < ( ) > {
0 commit comments