@@ -149,7 +149,7 @@ static void _pysqlite_drop_unused_cursor_references(pysqlite_Connection* self);
149
149
static void free_callback_context (callback_context * ctx );
150
150
static void set_callback_context (callback_context * * ctx_pp ,
151
151
callback_context * ctx );
152
- static void connection_close (pysqlite_Connection * self );
152
+ static int connection_close (pysqlite_Connection * self );
153
153
PyObject * _pysqlite_query_execute (pysqlite_Cursor * , int , PyObject * , PyObject * );
154
154
155
155
static PyObject *
@@ -247,10 +247,13 @@ pysqlite_connection_init_impl(pysqlite_Connection *self, PyObject *database,
247
247
}
248
248
249
249
if (self -> initialized ) {
250
+ self -> initialized = 0 ;
251
+
250
252
PyTypeObject * tp = Py_TYPE(self );
251
253
tp -> tp_clear ((PyObject * )self );
252
- connection_close (self );
253
- self -> initialized = 0 ;
254
+ if (connection_close (self ) < 0 ) {
255
+ return -1 ;
256
+ }
254
257
}
255
258
256
259
// Create and configure SQLite database object.
@@ -334,7 +337,9 @@ pysqlite_connection_init_impl(pysqlite_Connection *self, PyObject *database,
334
337
self -> initialized = 1 ;
335
338
336
339
if (autocommit == AUTOCOMMIT_DISABLED ) {
337
- (void )connection_exec_stmt (self , "BEGIN" );
340
+ if (connection_exec_stmt (self , "BEGIN" ) < 0 ) {
341
+ return -1 ;
342
+ }
338
343
}
339
344
return 0 ;
340
345
@@ -432,48 +437,83 @@ free_callback_contexts(pysqlite_Connection *self)
432
437
static void
433
438
remove_callbacks (sqlite3 * db )
434
439
{
435
- sqlite3_trace_v2 (db , SQLITE_TRACE_STMT , 0 , 0 );
440
+ /* None of these APIs can fail, as long as they are given a valid
441
+ * database pointer. */
442
+ assert (db != NULL );
443
+ int rc = sqlite3_trace_v2 (db , SQLITE_TRACE_STMT , 0 , 0 );
444
+ assert (rc == SQLITE_OK ), (void )rc ;
445
+
436
446
sqlite3_progress_handler (db , 0 , 0 , (void * )0 );
437
- (void )sqlite3_set_authorizer (db , NULL , NULL );
447
+
448
+ rc = sqlite3_set_authorizer (db , NULL , NULL );
449
+ assert (rc == SQLITE_OK ), (void )rc ;
438
450
}
439
451
440
- static void
452
+ static int
441
453
connection_close (pysqlite_Connection * self )
442
454
{
443
- if (self -> db ) {
444
- if ( self -> autocommit == AUTOCOMMIT_DISABLED &&
445
- ! sqlite3_get_autocommit ( self -> db ))
446
- {
447
- /* If close is implicitly called as a result of interpreter
448
- * tear-down, we must not call back into Python. */
449
- if ( _Py_IsInterpreterFinalizing ( PyInterpreterState_Get ())) {
450
- remove_callbacks ( self -> db );
451
- }
452
- ( void ) connection_exec_stmt ( self , "ROLLBACK" ) ;
455
+ if (self -> db == NULL ) {
456
+ return 0 ;
457
+ }
458
+
459
+ int rc = 0 ;
460
+ if ( self -> autocommit == AUTOCOMMIT_DISABLED &&
461
+ ! sqlite3_get_autocommit ( self -> db ))
462
+ {
463
+ if ( connection_exec_stmt ( self , "ROLLBACK" ) < 0 ) {
464
+ rc = -1 ;
453
465
}
466
+ }
454
467
455
- free_callback_contexts (self );
468
+ sqlite3 * db = self -> db ;
469
+ self -> db = NULL ;
456
470
457
- sqlite3 * db = self -> db ;
458
- self -> db = NULL ;
471
+ Py_BEGIN_ALLOW_THREADS
472
+ /* The v2 close call always returns SQLITE_OK if given a valid database
473
+ * pointer (which we do), so we can safely ignore the return value */
474
+ (void )sqlite3_close_v2 (db );
475
+ Py_END_ALLOW_THREADS
459
476
460
- Py_BEGIN_ALLOW_THREADS
461
- int rc = sqlite3_close_v2 (db );
462
- assert (rc == SQLITE_OK ), (void )rc ;
463
- Py_END_ALLOW_THREADS
464
- }
477
+ free_callback_contexts (self );
478
+ return rc ;
465
479
}
466
480
467
481
static void
468
- connection_dealloc ( pysqlite_Connection * self )
482
+ connection_finalize ( PyObject * self )
469
483
{
470
- PyTypeObject * tp = Py_TYPE (self );
471
- PyObject_GC_UnTrack (self );
472
- tp -> tp_clear ((PyObject * )self );
484
+ pysqlite_Connection * con = (pysqlite_Connection * )self ;
485
+ PyObject * exc = PyErr_GetRaisedException ();
486
+
487
+ /* If close is implicitly called as a result of interpreter
488
+ * tear-down, we must not call back into Python. */
489
+ PyInterpreterState * interp = PyInterpreterState_Get ();
490
+ int teardown = _Py_IsInterpreterFinalizing (interp );
491
+ if (teardown && con -> db ) {
492
+ remove_callbacks (con -> db );
493
+ }
473
494
474
495
/* Clean up if user has not called .close() explicitly. */
475
- connection_close (self );
496
+ if (connection_close (con ) < 0 ) {
497
+ if (teardown ) {
498
+ PyErr_Clear ();
499
+ }
500
+ else {
501
+ PyErr_WriteUnraisable ((PyObject * )self );
502
+ }
503
+ }
504
+
505
+ PyErr_SetRaisedException (exc );
506
+ }
476
507
508
+ static void
509
+ connection_dealloc (PyObject * self )
510
+ {
511
+ if (PyObject_CallFinalizerFromDealloc (self ) < 0 ) {
512
+ return ;
513
+ }
514
+ PyTypeObject * tp = Py_TYPE (self );
515
+ PyObject_GC_UnTrack (self );
516
+ tp -> tp_clear (self );
477
517
tp -> tp_free (self );
478
518
Py_DECREF (tp );
479
519
}
@@ -621,7 +661,9 @@ pysqlite_connection_close_impl(pysqlite_Connection *self)
621
661
622
662
pysqlite_close_all_blobs (self );
623
663
Py_CLEAR (self -> statement_cache );
624
- connection_close (self );
664
+ if (connection_close (self ) < 0 ) {
665
+ return NULL ;
666
+ }
625
667
626
668
Py_RETURN_NONE ;
627
669
}
@@ -2555,6 +2597,7 @@ static struct PyMemberDef connection_members[] =
2555
2597
};
2556
2598
2557
2599
static PyType_Slot connection_slots [] = {
2600
+ {Py_tp_finalize , connection_finalize },
2558
2601
{Py_tp_dealloc , connection_dealloc },
2559
2602
{Py_tp_doc , (void * )connection_doc },
2560
2603
{Py_tp_methods , connection_methods },
0 commit comments