Repository navigation
SQLite incorrect row count for UPDATE #79579
Description
Activity
SQLite driver returns an incorrect row count (-1) for UPDATE statements that begin with a comment.
Downstream Reference:
sqlalchemy/sqlalchemy#4396Test Case:
import sqlite3 conn = sqlite3.connect(":memory:") cursor = conn.cursor() cursor.execute(""" CREATE TABLE foo ( id INTEGER NOT NULL, updated_at DATETIME, PRIMARY KEY (id) ) """) cursor.execute(""" /* watermarking bug */ INSERT INTO foo (id, updated_at) VALUES (?, ?) """, [1, None]) cursor.execute(""" UPDATE foo SET updated_at=? WHERE foo.id = ? """, ('2018-12-02 14:55:57.169785', 1)) assert cursor.rowcount == 1 cursor.execute(""" /* watermarking bug */ UPDATE foo SET updated_at=? WHERE foo.id = ? """, ('2018-12-03 14:55:57.169785', 1)) assert cursor.rowcount == 1- addedstdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directory
on Dec 4, 2018 Did some debugging here. If I am understanding this correctly the rowcount is set at
. It checks for is_dml flag that is set herecpython/Modules/_sqlite/cursor.c
Line 574 in b8e689a
if (self->statement->is_dml) { cpython/Modules/_sqlite/statement.c
Line 78 in b8e689a
self->is_dml = 0; The part to set is_dml skips space, tabs and newline and checks for the first set of characters that is not skipped to be insert, update, delete or replace and in this case the first set of characters to be matched will be "/* watermarking */". Thus with comment not matching, is_dml is not set and -1 is set for the rowcount.
I took a stab at patch. It fixes the issue for me, as proven via the Test Case.
See also gh-81040.
- addedtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
on May 16, 2022 Now that we require SQLite 3.7.15, we can safely use sqlite3_stmt_readonly to determine if we should update
.rowcountor not. The API returns true for SELECT queries, which is also the case today. The API is pretty conservative, and returns false for cases where a query might modify the database. In those cases, we may end up with.rowcountbeing zero. That is perfectly fine.I see no reason not to usesqlite3_stmt_readonlyto solve this.EDIT:
sqlite3_changessupport INSERT, UPDATE, and DELETE statements only.sqlite3_stmt_readonlyencompasses a lot more than that. As long as we are usingsqlite3_changesto update.rowcount, we simply cannot usesqlite3_stmt_readonly, because SQLite does not reset the number returned bysqlite3_changes; for unsupported statements, you may end up withsqlite3_changesreturning the change count for a previous statement.If we'd used something like
sqlite3_total_changes64, we could safely usesqlite3_stmt_readonly, because in the worst cases we'd end up with a.rowcountof zero, and that is perfectly fine.I see no reason not to use sqlite3_stmt_readonly to solve this.
@animalize made me change my mind about that, so I made a competing PR: gh-93623
Thanks for pushing, Ma Lin.
- added a commit that references this issue
on Jun 13, 2022 - added a commit that references this issue
on Jun 26, 2022 - added a commit that references this issue
on Dec 2, 2024
Metadata
Metadata
Assignees
Labels
Projects
- StatusShow more project fieldsDone
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields: