Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 34k
bpo-36859: Use sqlite3_stmt_readonly API when possible to determine if statement is DML.K#13216
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Conversation
coleifer commented May 9, 2019 • edited by bedevere-bot
Loading Uh oh!
There was an error while loading. Please reload this page.
edited by bedevere-bot
Uh oh!
There was an error while loading. Please reload this page.
the-knights-who-say-ni commented May 9, 2019
Hello, and thanks for your contribution! I'm a bot set up to make sure that the project can legally accept your contribution by verifying you have signed the PSF contributor agreement (CLA). Our records indicate we have not received your CLA. For legal reasons we need you to sign this before we can look at your contribution. Please follow the steps outlined in the CPython devguide to rectify this issue. If you have recently signed the CLA, please wait at least one business day You can check yourself to see if the CLA has been received. Thanks again for your contribution, we look forward to reviewing it! |
Uh oh!
There was an error while loading. Please reload this page.
berkerpeksag left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a great improvement, thank you for your PR!
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Misc/NEWS.d/next/Library/2019-05-09-09-54-00.bpo-36859.CuCkEd.rst Outdated Show resolvedHide resolved
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
bedevere-bot commented May 9, 2019
A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated. Once you have made the requested changes, please leave a comment on this pull request containing the phrase |
coleifer commented May 9, 2019
I have made the requested changes; please review again. |
bedevere-bot commented May 9, 2019
Thanks for making the requested changes! @berkerpeksag: please review the changes made to this pull request. |
coleifer commented May 9, 2019
Oh thanks for pushing the markup fix, my bad! So what happens now? :) |
berkerpeksag commented May 9, 2019
I'm testing it locally now. Hopefully, I'm going to merge it tonight :) |
coleifer commented May 9, 2019
Apologies for the new commit, but I was just thinking and realized that sqlite supports a limited subset of ALTER TABLE. So ALTER, plus VACUUM/ANALYZE/REINDEX have been added to the list. These are queries that may write to the database (so |
berkerpeksag commented May 9, 2019
Good catch! We had a test for Also, looking at old commits and issues, it seems to me that we can move new tests into the existing test case cpython/Lib/sqlite3/test/transactions.py Line 170 in 137be34
What do you think? |
Also add additional assertion covering ALTER statements.
coleifer commented May 10, 2019
I agree, and have moved the tests into the transactions module. I also added an assertion covering the ALTER statement to an existing transactional DDL case. |
ghost commented May 11, 2019
Hi, I have two worries. 1, Fallback when sqlite doesn't have 2, using BTW, |
ghost commented May 11, 2019 • edited by ghost
Loading Uh oh!
There was an error while loading. Please reload this page.
edited by ghost
Uh oh!
There was an error while loading. Please reload this page.
How about this proposal. Don't change the determine logic of rc=conn.execute( 'with c(k, v) as (select key, value + 10 from kv) ''update kv set value=(select v from c where k=kv.key)')We encourage the user to set Add a new parameter /* in file \Modules\_sqlite\cursor.c */-if (self->statement->is_dml){+if (self->statement->is_dml||count_row){self->rowcount+= (long)sqlite3_changes(self->connection->db)} else{self->rowcount=-1L}The idea is to let user manipulate complex statement manually, in order to round the historical issues. |
coleifer commented May 11, 2019
As long as you aren't using a 9 year old sqlite, the behavior will be correct. The behavior is currently buggy.
That patch is a much worse implementation of what this patch fixes. That patch was not merged. The use of strncmp is sketchy, I agree, but please let's not throw the baby out with the bathwater. Currently there are some real issues with the logic. The crux of the issue is that the sqlite lib needs to enter a txn if the user issues a data modifying statement... except ddl is not included in this. My sense is that this patch is a real improvement. But is it perfect? No. Nice catch I somehow misread the version. |
coleifer commented May 11, 2019
Ultimately it's up to the core team. This feels cheesey to me, tho. Regarding isolation level: yes! For myself, I always always always set to none, because pysqlites implementation is so problematic. This patch isn't trying to change the existing behavior, though. Simply make it more reliable. Again,it's just a patch, it's up to the core devs to decide. I've already got a standalone pysqlite3 package and have merged these changes over there. |
berkerpeksag commented May 11, 2019
I'm thinking about introducing a This is similar to what we do in email package: https://docs.python.org/3/library/email.policy.html#module-email.policy It would also help us to fix other quirks of sqlite3 module without breaking backwards compatibility. |
coleifer commented May 11, 2019
Rethinking the whole transaction handling is great, but obviously not something I had been trying to undertake. If such a plan moves forward then this patch is not needed. |
coleifer commented May 11, 2019 • edited
Loading Uh oh!
There was an error while loading. Please reload this page.
edited
Uh oh!
There was an error while loading. Please reload this page.
So thinking about this some more, and also looking at the interest and motivation for #10913 -- I do think there's sufficient interest in solving this particular bug, which I summarize as:
Ramifications: transaction controls may not reliably cover certain queries (CTEs, preceding comments), which also leads to the cursor not exposing the rowcount attribute. This patch certainly fixes this, and fixes it much better than the linked patch. Reasons why this patch is not perfect:
Options, as I see them:
|
berkerpeksag commented May 11, 2019
I'm definitely going to merge this PR. The |
Feature added in sqlite 3.7.4, not .11.
ghost commented May 12, 2019
It would be nice to remove sqlite3's warts by adding a new mode. I'm not strongly against this patch, because my proposal is not very beautiful. For this patch, issue35398's problem is more serious, some statements that begin with a comment may abort the program: >>>conn.execute('/* comment */ vacuum') # this will start a transactionTraceback (mostrecentcalllast): File"<stdin>", line1, in<module>sqlite3.OperationalError: cannotVACUUMfromwithinatransactionIt seems we should detect leading comments like PR #10913. RHEL6 (Product retirement at November 30, 2020) is still alive, it's shipped with SQLite 3.6.x. How about emit a RuntimeWarning when importing sqlite3 module if |
coleifer commented May 12, 2019 • edited
Loading Uh oh!
There was an error while loading. Please reload this page.
edited
Uh oh!
There was an error while loading. Please reload this page.
Why don't you grep the pysqlite for ifdefs. You'll find that there are a number of differences that are dependant on the sqlite version. In the case of an old version the original behavior is retained, so I don't understand why raising a runtime error makes sense. Similarly, this patch is intended to do away with the necessity to parse comments. This patch fixes the issue you referenced. |
ghost commented May 14, 2019
Search
The first two don't introduce different behaviors. The third one is documented clearly, and if run a code on old SQLite, the program will abort. While with this patch, please imagine this scene: the same program, under the same version Python, can get different results silently. If this happened, it's very hard to find where the bug is, the programmer may get insane. Even worse, no one noticed the difference at all, but polluted results may break things (at that time or in the future) like a specter. Moreover, IMO
With this patch, this statement can't be executed:
You still have to detect leading comments. |
coleifer commented May 14, 2019
Do you? I don't know. The error message is clear, the solution simple? |
coleifer commented May 14, 2019
These are all good points. I don't see a good way forward that is both backward-compatible and can maintain compatibility across potentially different libsqlite3 installs. Edge-cases with current implementation:
Edge-cases with this patch:
|
ghost commented May 14, 2019
Due to the leading comment, this simple code will abort with this patch: importsqlite3conn=sqlite3.connect(':memory:') conn.execute('/* comment */ vacuum')
It's a troublesome issue. If must pick a solution, I vote for this order: IMO
Hard to decide for me, let the core developers choose. :) |
coleifer commented Jun 4, 2019
What's the status on this? |
erlend-aasland commented Jan 10, 2021
After #24106, this PR can be greatly simplified. Its not for me to decide, but I think this is an improvement, and I'm in favour of merging it (after a rebase onto current master). |
Implements fix for https://bugs.python.org/issue36859
The stdlib sqlite3 module attempts to detect if a statement is data-modifying, which it currently does by stripping whitespace and looking at the start of the SQL string. There are numerous issues with this approach:
In sqlite 3.7.11, the
sqlite3_stmt_readonlyAPI was added which implements this logic correctly.pysqlite has weeeird quirks with how it handles DDL (create/drop), which the above api correctly identifies as writing to the db, but for our purposes should not be considered DML. Same for
begin exclusiveandbegin immediatetransaction controls.So this patch:
Sqlite docs for sqlite3_stmt_readonly.
https://bugs.python.org/issue36859