Skip to content

Commit bb4062a

Browse files
Update rowcount after SQLITE_DONE
1 parent 4082c8e commit bb4062a

File tree

3 files changed

+19
-5
lines changed

3 files changed

+19
-5
lines changed

Lib/test/test_sqlite3/test_dbapi.py

+8
Original file line numberDiff line numberDiff line change
@@ -887,6 +887,14 @@ def test_rowcount_executemany(self):
887887
self.cu.executemany("insert into test(name) values (?)", [(1,), (2,), (3,)])
888888
self.assertEqual(self.cu.rowcount, 3)
889889

890+
@unittest.skipIf(sqlite.sqlite_version_info < (3, 35, 0),
891+
"Requires SQLite 3.35.0 or newer")
892+
def test_rowcount_update_returning(self):
893+
# gh-93421: rowcount is updated correctly for UPDATE...RETURNING queries
894+
self.cu.execute("update test set name='bar' where name='foo' returning 1")
895+
self.assertEqual(self.cu.fetchone()[0], 1)
896+
self.assertEqual(self.cu.rowcount, 1)
897+
890898
def test_total_changes(self):
891899
self.cu.execute("insert into test(name) values ('foo')")
892900
self.cu.execute("insert into test(name) values ('foo')")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix :data:`sqlite3.Cursor.rowcount` for ``UPDATE ... RETURNING``` SQL
2+
queries. Patch by Erlend E. Aasland.

Modules/_sqlite/cursor.c

+9-5
Original file line numberDiff line numberDiff line change
@@ -835,10 +835,9 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation
835835
stmt_reset(self->statement);
836836
}
837837

838-
/* reset description and rowcount */
838+
/* reset description */
839839
Py_INCREF(Py_None);
840840
Py_SETREF(self->description, Py_None);
841-
self->rowcount = 0L;
842841

843842
if (self->statement) {
844843
(void)stmt_reset(self->statement);
@@ -867,6 +866,7 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation
867866

868867
stmt_reset(self->statement);
869868
stmt_mark_dirty(self->statement);
869+
self->rowcount = self->statement->is_dml ? 0L : -1L;
870870

871871
/* We start a transaction implicitly before a DML statement.
872872
SELECT is the only exception. See #9924. */
@@ -944,13 +944,14 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation
944944
}
945945
}
946946

947-
if (self->statement->is_dml) {
947+
if (self->statement->is_dml && multiple) {
948948
self->rowcount += (long)sqlite3_changes(self->connection->db);
949-
} else {
950-
self->rowcount= -1L;
951949
}
952950

953951
if (rc == SQLITE_DONE && !multiple) {
952+
if (self->statement->is_dml) {
953+
self->rowcount = (long)sqlite3_changes(self->connection->db);
954+
}
954955
stmt_reset(self->statement);
955956
Py_CLEAR(self->statement);
956957
}
@@ -1125,6 +1126,9 @@ pysqlite_cursor_iternext(pysqlite_Cursor *self)
11251126
}
11261127
int rc = stmt_step(stmt);
11271128
if (rc == SQLITE_DONE) {
1129+
if (self->statement->is_dml) {
1130+
self->rowcount = (long)sqlite3_changes(self->connection->db);
1131+
}
11281132
(void)stmt_reset(self->statement);
11291133
}
11301134
else if (rc != SQLITE_ROW) {

0 commit comments

Comments
 (0)