@@ -146,7 +146,7 @@ static void _pysqlite_drop_unused_cursor_references(pysqlite_Connection* self);
146146static void free_callback_context (callback_context * ctx );
147147static void set_callback_context (callback_context * * ctx_pp ,
148148 callback_context * ctx );
149- static void connection_close (pysqlite_Connection * self );
149+ static int connection_close (pysqlite_Connection * self );
150150PyObject * _pysqlite_query_execute (pysqlite_Cursor * , int , PyObject * , PyObject * );
151151
152152static PyObject *
@@ -244,10 +244,13 @@ pysqlite_connection_init_impl(pysqlite_Connection *self, PyObject *database,
244244 }
245245
246246 if (self -> initialized ) {
247+ self -> initialized = 0 ;
248+
247249 PyTypeObject * tp = Py_TYPE (self );
248250 tp -> tp_clear ((PyObject * )self );
249- connection_close (self );
250- self -> initialized = 0 ;
251+ if (connection_close (self ) < 0 ) {
252+ return -1 ;
253+ }
251254 }
252255
253256 // Create and configure SQLite database object.
@@ -331,7 +334,9 @@ pysqlite_connection_init_impl(pysqlite_Connection *self, PyObject *database,
331334 self -> initialized = 1 ;
332335
333336 if (autocommit == AUTOCOMMIT_DISABLED ) {
334- (void )connection_exec_stmt (self , "BEGIN" );
337+ if (connection_exec_stmt (self , "BEGIN" ) < 0 ) {
338+ return -1 ;
339+ }
335340 }
336341 return 0 ;
337342
@@ -401,52 +406,88 @@ free_callback_contexts(pysqlite_Connection *self)
401406static void
402407remove_callbacks (sqlite3 * db )
403408{
409+ assert (db != NULL );
410+ /* None of these APIs can fail, as long as they are given a valid
411+ * database pointer. */
412+ int rc ;
404413#ifdef HAVE_TRACE_V2
405- sqlite3_trace_v2 (db , SQLITE_TRACE_STMT , 0 , 0 );
414+ rc = sqlite3_trace_v2 (db , SQLITE_TRACE_STMT , 0 , 0 );
415+ assert (rc == SQLITE_OK ), (void )rc ;
406416#else
407417 sqlite3_trace (db , 0 , (void * )0 );
408418#endif
419+
409420 sqlite3_progress_handler (db , 0 , 0 , (void * )0 );
410- (void )sqlite3_set_authorizer (db , NULL , NULL );
421+
422+ rc = sqlite3_set_authorizer (db , NULL , NULL );
423+ assert (rc == SQLITE_OK ), (void )rc ;
411424}
412425
413- static void
426+ static int
414427connection_close (pysqlite_Connection * self )
415428{
416- if (self -> db ) {
417- if ( self -> autocommit == AUTOCOMMIT_DISABLED &&
418- ! sqlite3_get_autocommit ( self -> db ))
419- {
420- /* If close is implicitly called as a result of interpreter
421- * tear-down, we must not call back into Python. */
422- if ( _Py_IsInterpreterFinalizing ( PyInterpreterState_Get ())) {
423- remove_callbacks ( self -> db );
424- }
425- ( void ) connection_exec_stmt ( self , "ROLLBACK" ) ;
429+ if (self -> db == NULL ) {
430+ return 0 ;
431+ }
432+
433+ int rc = 0 ;
434+ if ( self -> autocommit == AUTOCOMMIT_DISABLED &&
435+ ! sqlite3_get_autocommit ( self -> db ))
436+ {
437+ if ( connection_exec_stmt ( self , "ROLLBACK" ) < 0 ) {
438+ rc = -1 ;
426439 }
440+ }
427441
428- free_callback_contexts (self );
442+ sqlite3 * db = self -> db ;
443+ self -> db = NULL ;
429444
430- sqlite3 * db = self -> db ;
431- self -> db = NULL ;
445+ Py_BEGIN_ALLOW_THREADS
446+ /* The v2 close call always returns SQLITE_OK if given a valid database
447+ * pointer (which we do), so we can safely ignore the return value */
448+ (void )sqlite3_close_v2 (db );
449+ Py_END_ALLOW_THREADS
432450
433- Py_BEGIN_ALLOW_THREADS
434- int rc = sqlite3_close_v2 (db );
435- assert (rc == SQLITE_OK ), (void )rc ;
436- Py_END_ALLOW_THREADS
437- }
451+ free_callback_contexts (self );
452+ return rc ;
438453}
439454
440455static void
441- connection_dealloc ( pysqlite_Connection * self )
456+ connection_finalize ( PyObject * self )
442457{
443- PyTypeObject * tp = Py_TYPE (self );
444- PyObject_GC_UnTrack (self );
445- tp -> tp_clear ((PyObject * )self );
458+ pysqlite_Connection * con = (pysqlite_Connection * )self ;
459+ PyObject * exc = PyErr_GetRaisedException ();
460+
461+ /* If close is implicitly called as a result of interpreter
462+ * tear-down, we must not call back into Python. */
463+ PyInterpreterState * interp = PyInterpreterState_Get ();
464+ int teardown = _Py_IsInterpreterFinalizing (interp );
465+ if (teardown && con -> db ) {
466+ remove_callbacks (con -> db );
467+ }
446468
447469 /* Clean up if user has not called .close() explicitly. */
448- connection_close (self );
470+ if (connection_close (con ) < 0 ) {
471+ if (teardown ) {
472+ PyErr_Clear ();
473+ }
474+ else {
475+ PyErr_WriteUnraisable ((PyObject * )self );
476+ }
477+ }
478+
479+ PyErr_SetRaisedException (exc );
480+ }
449481
482+ static void
483+ connection_dealloc (PyObject * self )
484+ {
485+ if (PyObject_CallFinalizerFromDealloc (self ) < 0 ) {
486+ return ;
487+ }
488+ PyTypeObject * tp = Py_TYPE (self );
489+ PyObject_GC_UnTrack (self );
490+ tp -> tp_clear (self );
450491 tp -> tp_free (self );
451492 Py_DECREF (tp );
452493}
@@ -594,7 +635,9 @@ pysqlite_connection_close_impl(pysqlite_Connection *self)
594635
595636 pysqlite_close_all_blobs (self );
596637 Py_CLEAR (self -> statement_cache );
597- connection_close (self );
638+ if (connection_close (self ) < 0 ) {
639+ return NULL ;
640+ }
598641
599642 Py_RETURN_NONE ;
600643}
@@ -2582,6 +2625,7 @@ static struct PyMemberDef connection_members[] =
25822625};
25832626
25842627static PyType_Slot connection_slots [] = {
2628+ {Py_tp_finalize , connection_finalize },
25852629 {Py_tp_dealloc , connection_dealloc },
25862630 {Py_tp_doc , (void * )connection_doc },
25872631 {Py_tp_methods , connection_methods },
0 commit comments