classification
Title: sqlite3 module should allow DDL statements in transactions
Type: enhancement Stage:
Components: Library (Lib) Versions: Python 3.3
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: Jeremy Banks, Mark.Bucciarelli, asvetlov, dholth, ghaering, r.david.murray, scott.urban, torsten, tshepang, zzzeek
Priority: normal Keywords: patch

Created on 2010-12-20 18:02 by scott.urban, last changed 2013-04-04 19:37 by zzzeek.

Files
File name Uploaded Description Edit
pysql-transactions.2.diff scott.urban, 2010-12-20 18:02 proposed patch
test_sqlite_ddl.py scott.urban, 2010-12-20 18:03 test script
sqlite_transaction_config_py27.diff torsten, 2011-03-27 01:34 Patch against Python 2.7
sqlite_transaction_config_py3.diff torsten, 2011-03-27 01:54 Patch for Python 3 default branch review
sqlite_transaction_config_py27.diff torsten, 2011-03-27 01:56 Patch against Python 2.7, take 2
sqlite_transaction_config_v2.diff torsten, 2011-03-30 20:32 Updated patch: Added docs review
Messages (12)
msg124392 - (view) Author: Scott Urban (scott.urban) Date: 2010-12-20 18:02
The python sqlite module automatically commits open transactions
when it encounters a DDL statement.  This is unnecessary; DDL is
transactional in my testing (see attached).

Attached patch addresses the issue. Patch is against 2.6.1, but
looking at Trunk in svn, it seems like the patch is needed and
would apply. One issue I could foresee is that this behavior might
depend on the sqlite version in use (I'm on 3.6.10).

Patch also allows pragma statement.
msg124393 - (view) Author: Scott Urban (scott.urban) Date: 2010-12-20 18:03
Here are some tests.
msg124398 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2010-12-20 18:34
See also Issue 8145.  It would be nice if someone could sort all this out, but I'm not knowledgeable enough to do so.

For this patch, it would be a significant change it behaviour.  Therefore it would have to be a new feature controlled by a flag of some sort (which is part of the reason for the reference to issue 8145).
msg124407 - (view) Author: Scott Urban (scott.urban) Date: 2010-12-20 22:08
I find the way that the sqlite3 module handles transactions pretty
surprising in general, but I agree that someone who got used
to DDL not rolling back could in theory find this patch surprising.

We will apply this patch to our python build because having DDL
covered by a transactions is convenient for certain tasks. If anyone
can think of a problem with this simple patch, I'd like to hear it.

Thanks
Scott
msg128815 - (view) Author: Daniel Holth (dholth) (Python committer) Date: 2011-02-18 21:17
I want transactional DDL too. I was tremendously surprised that I could not duplicate the way sqlite3 behaves on the command line from witin pysqlite.

Instead of this patch, I would rather be able to instruct pysqlite to always begin a transaction for any kind of statement (I hear this is a requirement for DB-API compliance) and never perform an implicit commit for any reason. For example, someone on the google code project had a complaint that 'SAVEPOINT' (create a subtransaction) automatically commits because pysqlite doesn't know about it.

I tried to trick pysqlite into doing what I wanted by prepending /* update */ to every CREATE TABLE statement but it didn't seem to quite work. Instead, I would prefer a pysqlite that does not strcmp(statement) at all.
msg132285 - (view) Author: Torsten Landschoff (torsten) Date: 2011-03-27 01:34
The attached patch is my take on this issue. I ran into the problem that during schema upgrades dropping a table was not rolled back. In another instance, renaming a table was not rolled back. This greatly increases the risk of data loss for our application.

Because I do not currently foresee which commands might need dropping out of a transaction and because of backwards compatibility woes, I added a new field to the sqlite3.Connection: operation_needs_transaction_callback

This function is called to decide if a running transaction should be implicitly committed (I'd consider this dangerous), if a transaction has to be started if not running (should normally always hold) or if the transaction state should be left alone.

For example, the "pragma foreign_keys = ..." is a no-op inside a transaction, therefore an implicit begin would be possibly harmful. In our application, we enable foreign keys when getting the connection out of the SQLAlchemy pool via a pool listener, which would be disabled if there is an implicit begin triggered.

The patch also adds a bunch of unit tests to cover the new behaviour.
msg132287 - (view) Author: Torsten Landschoff (torsten) Date: 2011-03-27 01:54
Same patch for Python 3. In fact, this also adds a missing Py_XDECREF.
msg132414 - (view) Author: Daniel Holth (dholth) (Python committer) Date: 2011-03-28 19:49
Torsten basically you are suggesting that PRAGMA would never work at all with my 'do not strcmp() the sql at all, always begin a transaction' approach?
msg132470 - (view) Author: Torsten Landschoff (torsten) Date: 2011-03-29 07:39
> Torsten basically you are suggesting that PRAGMA would never work at all with my 'do not strcmp() the sql at all, always begin a transaction' approach?

No. Most pragmas should still work and getting the current setting of a pragma should also work.

I was only referring to http://www.sqlite.org/pragma.html#pragma_foreign_keys

Quote:

> This pragma is a no-op within a transaction; foreign key constraint enforcement may only be enabled or disabled when there is no pending BEGIN or SAVEPOINT.

I did not see such a restriction for other pragmas though I admit that I did not reread the list in full.
msg132612 - (view) Author: Torsten Landschoff (torsten) Date: 2011-03-30 20:32
The attached patch is an updated version which adds a bit of documentation.
msg136362 - (view) Author: Torsten Landschoff (torsten) Date: 2011-05-20 10:28
I updated the patch for upstream pysqlite2. Available at

http://code.google.com/p/pysqlite/issues/detail?id=24

Patch over there is for Python 2 (tested with our production Python 2.6).
msg144197 - (view) Author: Mark Bucciarelli (Mark.Bucciarelli) Date: 2011-09-17 15:39
Opened http://bugs.python.org/issue12997 in case there is a way to solve the foreign_key PRAGMA issue with a less disruptive fix.
History
Date User Action Args
2013-04-04 19:37:21zzzeeksetnosy: + zzzeek
2013-01-26 17:30:57tshepangsetnosy: + tshepang
2012-10-18 18:56:16Jeremy Bankssetnosy: + Jeremy Banks
2011-09-17 15:39:45Mark.Bucciarellisetnosy: + Mark.Bucciarelli
messages: + msg144197
2011-05-20 10:28:22torstensetmessages: + msg136362
2011-03-30 20:32:44torstensetfiles: + sqlite_transaction_config_v2.diff

messages: + msg132612
2011-03-29 07:39:29torstensetmessages: + msg132470
2011-03-28 19:49:14dholthsetmessages: + msg132414
2011-03-27 01:56:07torstensetfiles: + sqlite_transaction_config_py27.diff
2011-03-27 01:54:12torstensetfiles: + sqlite_transaction_config_py3.diff

messages: + msg132287
2011-03-27 01:34:16torstensetfiles: + sqlite_transaction_config_py27.diff
nosy: + torsten
messages: + msg132285

2011-02-18 21:17:20dholthsetnosy: + dholth
messages: + msg128815
2010-12-21 00:10:59asvetlovsetnosy: + asvetlov
2010-12-20 22:08:46scott.urbansetmessages: + msg124407
2010-12-20 18:34:15r.david.murraysetversions: + Python 3.3, - Python 2.6
nosy: + ghaering, r.david.murray

messages: + msg124398

type: behavior -> enhancement
2010-12-20 18:03:40scott.urbansetfiles: + test_sqlite_ddl.py

messages: + msg124393
2010-12-20 18:02:11scott.urbancreate