mirror of
https://github.com/python/cpython.git
synced 2025-08-04 17:08:35 +00:00
[3.10] gh-93421: Update sqlite3 cursor.rowcount only after SQLITE_DONE (GH-93526) (GH-93599)
(cherry picked from commit 875de61
)
This commit is contained in:
parent
6b9122483f
commit
9cc0afcb87
3 changed files with 25 additions and 9 deletions
|
@ -381,6 +381,14 @@ class CursorTests(unittest.TestCase):
|
|||
self.cu.executemany("insert into test(name) values (?)", [(1,), (2,), (3,)])
|
||||
self.assertEqual(self.cu.rowcount, 3)
|
||||
|
||||
@unittest.skipIf(sqlite.sqlite_version_info < (3, 35, 0),
|
||||
"Requires SQLite 3.35.0 or newer")
|
||||
def test_rowcount_update_returning(self):
|
||||
# gh-93421: rowcount is updated correctly for UPDATE...RETURNING queries
|
||||
self.cu.execute("update test set name='bar' where name='foo' returning 1")
|
||||
self.assertEqual(self.cu.fetchone()[0], 1)
|
||||
self.assertEqual(self.cu.rowcount, 1)
|
||||
|
||||
def test_total_changes(self):
|
||||
self.cu.execute("insert into test(name) values ('foo')")
|
||||
self.cu.execute("insert into test(name) values ('foo')")
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
Update :data:`sqlite3.Cursor.rowcount` when a DML statement has run to
|
||||
completion. This fixes the row count for SQL queries like
|
||||
``UPDATE ... RETURNING``. Patch by Erlend E. Aasland.
|
|
@ -492,10 +492,9 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation
|
|||
pysqlite_statement_reset(self->statement);
|
||||
}
|
||||
|
||||
/* reset description and rowcount */
|
||||
/* reset description */
|
||||
Py_INCREF(Py_None);
|
||||
Py_SETREF(self->description, Py_None);
|
||||
self->rowcount = 0L;
|
||||
|
||||
func_args = PyTuple_New(1);
|
||||
if (!func_args) {
|
||||
|
@ -527,6 +526,7 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation
|
|||
|
||||
pysqlite_statement_reset(self->statement);
|
||||
pysqlite_statement_mark_dirty(self->statement);
|
||||
self->rowcount = self->statement->is_dml ? 0L : -1L;
|
||||
|
||||
/* We start a transaction implicitly before a DML statement.
|
||||
SELECT is the only exception. See #9924. */
|
||||
|
@ -604,12 +604,6 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation
|
|||
}
|
||||
}
|
||||
|
||||
if (self->statement->is_dml) {
|
||||
self->rowcount += (long)sqlite3_changes(self->connection->db);
|
||||
} else {
|
||||
self->rowcount= -1L;
|
||||
}
|
||||
|
||||
if (!multiple) {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
lastrowid = sqlite3_last_insert_rowid(self->connection->db);
|
||||
|
@ -630,11 +624,17 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation
|
|||
if (self->next_row == NULL)
|
||||
goto error;
|
||||
} else if (rc == SQLITE_DONE && !multiple) {
|
||||
if (self->statement->is_dml) {
|
||||
self->rowcount = (long)sqlite3_changes(self->connection->db);
|
||||
}
|
||||
pysqlite_statement_reset(self->statement);
|
||||
Py_CLEAR(self->statement);
|
||||
}
|
||||
|
||||
if (multiple) {
|
||||
if (self->statement->is_dml && rc == SQLITE_DONE) {
|
||||
self->rowcount += (long)sqlite3_changes(self->connection->db);
|
||||
}
|
||||
pysqlite_statement_reset(self->statement);
|
||||
}
|
||||
Py_XDECREF(parameters);
|
||||
|
@ -824,7 +824,12 @@ pysqlite_cursor_iternext(pysqlite_Cursor *self)
|
|||
if (PyErr_Occurred()) {
|
||||
goto error;
|
||||
}
|
||||
if (rc != SQLITE_DONE && rc != SQLITE_ROW) {
|
||||
if (rc == SQLITE_DONE) {
|
||||
if (self->statement->is_dml) {
|
||||
self->rowcount = (long)sqlite3_changes(self->connection->db);
|
||||
}
|
||||
}
|
||||
else if (rc != SQLITE_ROW) {
|
||||
_pysqlite_seterror(self->connection->db, NULL);
|
||||
goto error;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue