@@ -29,21 +29,21 @@ mod _sqlite {
2929 sqlite3_bind_null, sqlite3_bind_parameter_count, sqlite3_bind_parameter_name,
3030 sqlite3_bind_text, sqlite3_blob, sqlite3_blob_bytes, sqlite3_blob_close, sqlite3_blob_open,
3131 sqlite3_blob_read, sqlite3_blob_write, sqlite3_busy_timeout, sqlite3_changes,
32- sqlite3_close , sqlite3_column_blob, sqlite3_column_bytes, sqlite3_column_count,
33- sqlite3_column_decltype , sqlite3_column_double, sqlite3_column_int64, sqlite3_column_name,
34- sqlite3_column_text , sqlite3_column_type, sqlite3_complete, sqlite3_context,
35- sqlite3_context_db_handle , sqlite3_create_collation_v2, sqlite3_create_function_v2,
36- sqlite3_create_window_function , sqlite3_data_count, sqlite3_db_handle, sqlite3_errcode,
37- sqlite3_errmsg , sqlite3_exec , sqlite3_expanded_sql , sqlite3_extended_errcode ,
38- sqlite3_finalize , sqlite3_get_autocommit , sqlite3_interrupt , sqlite3_last_insert_rowid ,
39- sqlite3_libversion , sqlite3_limit , sqlite3_open_v2 , sqlite3_prepare_v2 ,
40- sqlite3_progress_handler , sqlite3_reset , sqlite3_result_blob, sqlite3_result_double,
41- sqlite3_result_error , sqlite3_result_error_nomem, sqlite3_result_error_toobig,
42- sqlite3_result_int64 , sqlite3_result_null, sqlite3_result_text, sqlite3_set_authorizer,
43- sqlite3_sleep , sqlite3_step, sqlite3_stmt, sqlite3_stmt_busy, sqlite3_stmt_readonly,
44- sqlite3_threadsafe , sqlite3_total_changes, sqlite3_trace_v2, sqlite3_user_data,
45- sqlite3_value , sqlite3_value_blob, sqlite3_value_bytes, sqlite3_value_double,
46- sqlite3_value_int64 , sqlite3_value_text, sqlite3_value_type,
32+ sqlite3_column_blob, sqlite3_column_bytes, sqlite3_column_count, sqlite3_column_decltype ,
33+ sqlite3_column_double, sqlite3_column_int64, sqlite3_column_name, sqlite3_column_text ,
34+ sqlite3_column_type, sqlite3_complete, sqlite3_context, sqlite3_context_db_handle ,
35+ sqlite3_create_collation_v2, sqlite3_create_function_v2, sqlite3_create_window_function ,
36+ sqlite3_data_count, sqlite3_db_handle, sqlite3_errcode, sqlite3_errmsg , sqlite3_exec ,
37+ sqlite3_expanded_sql , sqlite3_extended_errcode , sqlite3_finalize , sqlite3_get_autocommit ,
38+ sqlite3_interrupt , sqlite3_last_insert_rowid , sqlite3_libversion , sqlite3_limit ,
39+ sqlite3_open_v2 , sqlite3_prepare_v2 , sqlite3_progress_handler , sqlite3_reset ,
40+ sqlite3_result_blob, sqlite3_result_double, sqlite3_result_error ,
41+ sqlite3_result_error_nomem, sqlite3_result_error_toobig, sqlite3_result_int64 ,
42+ sqlite3_result_null, sqlite3_result_text, sqlite3_set_authorizer, sqlite3_sleep ,
43+ sqlite3_step, sqlite3_stmt, sqlite3_stmt_busy, sqlite3_stmt_readonly, sqlite3_threadsafe ,
44+ sqlite3_total_changes, sqlite3_trace_v2, sqlite3_user_data, sqlite3_value ,
45+ sqlite3_value_blob, sqlite3_value_bytes, sqlite3_value_double, sqlite3_value_int64 ,
46+ sqlite3_value_text, sqlite3_value_type,
4747 } ;
4848 use malachite_bigint:: Sign ;
4949 use rustpython_common:: {
@@ -2016,6 +2016,18 @@ mod _sqlite {
20162016 impl SelfIter for Cursor { }
20172017 impl IterNext for Cursor {
20182018 fn next ( zelf : & Py < Self > , vm : & VirtualMachine ) -> PyResult < PyIterReturn > {
2019+ // Check if connection is closed first, and if so, clear statement to release file lock
2020+ if zelf. connection . is_closed ( ) {
2021+ let mut guard = zelf. inner . lock ( ) ;
2022+ if let Some ( stmt) = guard. as_mut ( ) . and_then ( |inner| inner. statement . take ( ) ) {
2023+ stmt. lock ( ) . reset ( ) ;
2024+ }
2025+ return Err ( new_programming_error (
2026+ vm,
2027+ "Cannot operate on a closed database." . to_owned ( ) ,
2028+ ) ) ;
2029+ }
2030+
20192031 let mut inner = zelf. inner ( vm) ?;
20202032 let Some ( stmt) = & inner. statement else {
20212033 return Ok ( PyIterReturn :: StopIteration ( None ) ) ;
@@ -2720,9 +2732,17 @@ mod _sqlite {
27202732 }
27212733 }
27222734
2735+ // sqlite3_close_v2 is not exported by libsqlite3-sys, so we declare it manually.
2736+ // It handles "zombie close" - if there are still unfinalized statements,
2737+ // the database will be closed when the last statement is finalized.
2738+ unsafe extern "C" {
2739+ fn sqlite3_close_v2 ( db : * mut sqlite3 ) -> c_int ;
2740+ }
2741+
27232742 impl Drop for Sqlite {
27242743 fn drop ( & mut self ) {
2725- unsafe { sqlite3_close ( self . raw . db ) } ;
2744+ // Use sqlite3_close_v2 for safe closing even with active statements
2745+ unsafe { sqlite3_close_v2 ( self . raw . db ) } ;
27262746 }
27272747 }
27282748
0 commit comments