Repository navigation
SQLite rowcount is corrupted when combining UPDATE RETURNING w/ table that is dropped and recreated #93421
Description
Activity
- addedtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
on Jun 1, 2022 - added3.11only security fixesonly security fixes3.10 (EOL)end of lifeend of life3.12only security fixesonly security fixes
on Jun 1, 2022 cc: @erlend-aasland
A
Reacted by Erlend E. AaslandThanks for the report!
Internally, we simply use the function
sqlite3_changesto setrowcount1, implying that we do not calculaterowcountourself; the value comes straight from the underlying SQLite library. Ifsqlite3_changesreturns zero,rowcountwill be zero.I've verified that this only happens with
UPDATE ... RETURNINGstatements, which also implies that the behaviour we are observing comes from the underlying SQLite library. I suggest to report this on the SQLite forum (they do not have a bug tracker).Note: I did some tests where I used
sqlite3_total_changes()in addition tosqlite3_changes(), and they revealed that the number of total changes on the database connection did not increase whithUPDATE ... RETURNINGstatements, only with normalUPDATEstatements.Closing this as not-a-bug.
See also:
- https://www.sqlite.org/c3ref/changes.html
- https://www.sqlite.org/c3ref/total_changes.html
- https://www.sqlite.org/lang_returning.html
- https://www.sqlite.org/lang_corefunc.html#changes
Footnotes
-
Assuming that you've supplied a valid statement, and that no database errors were raised by SQLite. In case of errors,
rowcountwill normally be set to-1. ↩
- removedtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error3.11only security fixesonly security fixes3.10 (EOL)end of lifeend of life
on Jun 2, 2022 25 remaining items
Thanks for the report, and for pushing this through, Mike. Thanks for reviewing, Ma Lin!
- added a commit that references this issue
on Jun 8, 2022 Just thought, if the next row is cached (like pre 3df0fc8), the .rowcount will be more correct?
We'd still only update
.rowcountafter SQLITE_DONE, so when the statement is stepped through, you'll have the correct row count, caching or not.For example, in these conditions: [...]
That is a separate issue (and it has always been). It is not very large or complex fix; we just need to step through a statement for each loop iteration in
_pysqlite_query_executeifmultipleis true, kinda like we do inexecutescript. It is a bug, though, so it would be quite ok to backport it through 3.10.However, as you point out, such code is probably rare; it does not make sense with
UPDATE ... RETURNINGinexecutemany.- added a commit that references this issue
on Jun 26, 2022 As a data point, I have a MacOS user who is using 3.10.8, and getting the
rowcount0 problem. From what I understand the 3.10 backport was merged in June and 3.10.8 was tagged as of October, so should have the fix from what I understand.This is an
UPDATE ... RETURNINGexecute that assertsrowcount == 1, which fails because it is unexpectedly 0.As a data point, I have a MacOS user who is using 3.10.8, and getting the
rowcount0 problem. From what I understand the 3.10 backport was merged in June and 3.10.8 was tagged as of October, so should have the fix from what I understand.This is an
UPDATE ... RETURNINGexecute that assertsrowcount == 1, which fails because it is unexpectedly 0.Would you mind posting a minimal reproducer?
Python 3.10.8 should have the fix, yes.
The reproducer from the top does not work for him. It'll happen in the course of operation of the larger application repeatedly however. No idea how to reproduce it outside of that.
Finally had the problem happen myself. It appears to be a different problem than tables being dropped or recreated. Repro on the above linked issue.
Metadata
Metadata
Assignees
Labels
Projects
- StatusShow more project fieldsDone
version info:
we have a test suite that creates a table, runs some SQL, then drops it. if multiple tests run that each perform this task, if the same SQLite connection is used, rowcount starts returning "0". Seems to also require RETURNING to be used. Full demonstration:
on the third run, where we ran the "test" on the same connection twice, it fails:
it would appear there's some internal caching of table state that needs to be cleared.