@@ -360,6 +360,12 @@ _pysqlite_fetch_one_row(pysqlite_Cursor* self)
360360 return NULL ;
361361
362362 sqlite3 * db = self -> connection -> db ;
363+ if (db == NULL ) {
364+ pysqlite_state * state = self -> connection -> state ;
365+ PyErr_SetString (state -> ProgrammingError ,
366+ "Cannot operate on a closed database." );
367+ goto error ;
368+ }
363369 for (i = 0 ; i < numcols ; i ++ ) {
364370 if (self -> connection -> detect_types
365371 && self -> row_cast_map != NULL
@@ -530,10 +536,16 @@ begin_transaction(pysqlite_Connection *self)
530536static PyObject *
531537get_statement_from_cache (pysqlite_Cursor * self , PyObject * operation )
532538{
533- PyObject * args [] = { NULL , operation , }; // Borrowed ref.
534- PyObject * cache = self -> connection -> statement_cache ;
539+ PyObject * args [] = { NULL , operation , };
540+
541+ /* Hold a strong reference: a Python callback invoked during statement
542+ * preparation (e.g. an authorizer) may close the connection, which calls
543+ * Py_CLEAR(connection->statement_cache). */
544+ PyObject * cache = Py_NewRef (self -> connection -> statement_cache );
535545 size_t nargsf = 1 | PY_VECTORCALL_ARGUMENTS_OFFSET ;
536- return PyObject_Vectorcall (cache , args + 1 , nargsf , NULL );
546+ PyObject * result = PyObject_Vectorcall (cache , args + 1 , nargsf , NULL );
547+ Py_DECREF (cache );
548+ return result ;
537549}
538550
539551static inline int
@@ -957,7 +969,7 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation
957969 }
958970
959971 if (rc == SQLITE_DONE ) {
960- if (self -> statement -> is_dml ) {
972+ if (self -> statement -> is_dml && self -> connection -> db ) {
961973 self -> rowcount += (long )sqlite3_changes (self -> connection -> db );
962974 }
963975 if (stmt_reset (self -> statement ) != SQLITE_OK ) {
@@ -967,7 +979,7 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation
967979 Py_XDECREF (parameters );
968980 }
969981
970- if (!multiple ) {
982+ if (!multiple && self -> connection -> db ) {
971983 sqlite_int64 lastrowid ;
972984
973985 Py_BEGIN_ALLOW_THREADS
@@ -1157,7 +1169,7 @@ pysqlite_cursor_iternext(PyObject *op)
11571169 }
11581170 int rc = stmt_step (stmt );
11591171 if (rc == SQLITE_DONE ) {
1160- if (self -> statement -> is_dml ) {
1172+ if (self -> statement -> is_dml && self -> connection -> db ) {
11611173 self -> rowcount = (long )sqlite3_changes (self -> connection -> db );
11621174 }
11631175 rc = stmt_reset (self -> statement );
0 commit comments