return 1;
}
+static pysqlite_state *
+get_module_state_by_cursor(pysqlite_Cursor *cursor)
+{
+ if (cursor->connection != NULL && cursor->connection->state != NULL) {
+ return cursor->connection->state;
+ }
+ return pysqlite_get_state_by_type(Py_TYPE(cursor));
+}
+
+static void
+cursor_sqlite3_internal_error(pysqlite_Cursor *cursor,
+ const char *error_message,
+ int chain_exceptions)
+{
+ pysqlite_state *state = get_module_state_by_cursor(cursor);
+ if (chain_exceptions) {
+ assert(PyErr_Occurred());
+ PyObject *exc = PyErr_GetRaisedException();
+ PyErr_SetString(state->InternalError, error_message);
+ _PyErr_ChainExceptions1(exc);
+ }
+ else {
+ assert(!PyErr_Occurred());
+ PyErr_SetString(state->InternalError, error_message);
+ }
+}
+
+static void
+cursor_cannot_reset_stmt_error(pysqlite_Cursor *cursor, int chain_exceptions)
+{
+ cursor_sqlite3_internal_error(cursor,
+ "cannot reset statement",
+ chain_exceptions);
+}
+
/*[clinic input]
module _sqlite3
class _sqlite3.Cursor "pysqlite_Cursor *" "clinic_state()->CursorType"
Py_CLEAR(self->row_factory);
if (self->statement) {
/* Reset the statement if the user has not closed the cursor */
- stmt_reset(self->statement);
+ int rc = stmt_reset(self->statement);
Py_CLEAR(self->statement);
+ if (rc != SQLITE_OK) {
+ cursor_cannot_reset_stmt_error(self, 0);
+ PyErr_FormatUnraisable("Exception ignored in cursor_clear()");
+ }
}
return 0;
if (self->statement) {
// Reset pending statements on this cursor.
- (void)stmt_reset(self->statement);
+ if (stmt_reset(self->statement) != SQLITE_OK) {
+ goto reset_failure;
+ }
}
PyObject *stmt = get_statement_from_cache(self, operation);
}
}
- (void)stmt_reset(self->statement);
+ if (stmt_reset(self->statement) != SQLITE_OK) {
+ goto reset_failure;
+ }
self->rowcount = self->statement->is_dml ? 0L : -1L;
/* We start a transaction implicitly before a DML statement.
if (self->statement->is_dml) {
self->rowcount += (long)sqlite3_changes(self->connection->db);
}
- stmt_reset(self->statement);
+ if (stmt_reset(self->statement) != SQLITE_OK) {
+ goto reset_failure;
+ }
}
Py_XDECREF(parameters);
}
if (PyErr_Occurred()) {
if (self->statement) {
- (void)stmt_reset(self->statement);
+ sqlite3 *db = sqlite3_db_handle(self->statement->st);
+ int sqlite3_state = sqlite3_errcode(db);
+ // stmt_reset() may return a previously set exception,
+ // either triggered because of Python or sqlite3.
+ rc = stmt_reset(self->statement);
Py_CLEAR(self->statement);
+ if (sqlite3_state == SQLITE_OK && rc != SQLITE_OK) {
+ cursor_cannot_reset_stmt_error(self, 1);
+ }
}
self->rowcount = -1L;
return NULL;
Py_CLEAR(self->statement);
}
return Py_NewRef((PyObject *)self);
+
+reset_failure:
+ /* suite to execute when stmt_reset() failed and no exception is set */
+ assert(!PyErr_Occurred());
+
+ Py_XDECREF(parameters);
+ Py_XDECREF(parameters_iter);
+ Py_XDECREF(parameters_list);
+
+ self->locked = 0;
+ self->rowcount = -1L;
+ Py_CLEAR(self->statement);
+ cursor_cannot_reset_stmt_error(self, 0);
+ return NULL;
}
/*[clinic input]
if (self->statement->is_dml) {
self->rowcount = (long)sqlite3_changes(self->connection->db);
}
- (void)stmt_reset(self->statement);
+ rc = stmt_reset(self->statement);
Py_CLEAR(self->statement);
+ if (rc != SQLITE_OK) {
+ goto reset_failure;
+ }
}
else if (rc != SQLITE_ROW) {
- set_error_from_db(self->connection->state, self->connection->db);
- (void)stmt_reset(self->statement);
+ rc = set_error_from_db(self->connection->state, self->connection->db);
+ int reset_rc = stmt_reset(self->statement);
Py_CLEAR(self->statement);
Py_DECREF(row);
+ if (rc == SQLITE_OK && reset_rc != SQLITE_OK) {
+ goto reset_failure;
+ }
return NULL;
}
if (!Py_IsNone(self->row_factory)) {
Py_SETREF(row, new_row);
}
return row;
+
+reset_failure:
+ cursor_cannot_reset_stmt_error(self, 0);
+ return NULL;
}
/*[clinic input]
}
if (self->statement) {
- (void)stmt_reset(self->statement);
+ int rc = stmt_reset(self->statement);
+ // Force self->statement to be NULL even if stmt_reset() may have
+ // failed to avoid a possible double-free if someone calls close()
+ // twice as a leak here would be better than a double-free.
Py_CLEAR(self->statement);
+ if (rc != SQLITE_OK) {
+ cursor_cannot_reset_stmt_error(self, 0);
+ return NULL;
+ }
}
self->closed = 1;