On Sep 19, 2010, at 9:54 AM, Randall Nortman wrote: > > Unfortunately, the isolation_level parameter to pysqlite2 only > controls the type of BEGIN issued, not when it is issued (I just > tested to be sure). It still waits until there is an INSERT/UPDATE/ > DELETE to begin the transaction. I expect the semantics of > serializable transactions to mean the transaction begins also with a > SELECT. The vast majority of database operations, I'd wager, begin > with a SELECT.
certainly. The pysqlite connection should be in a transaction immediately. this is what all the other DBAPIs do. > > Call this a bug in pysqlite2 if you like, I think this is a bug in Pysqlite2. I can reproduce it with sqlite3 directly. > though the DBAPI spec seems > to be silent on when transactions are started, so I think the > developers will defend their choice. I think you should give it a try, the Pysqlite folks are very on top of things and really want to do things correctly, and this is a case of them doing plainly the wrong thing for serializable isolation. SQLA really, really doesn't want to get into correcting DBAPI behavior. I've attached a test case for you to post on their tracker at http://code.google.com/p/pysqlite/issues/list .
> (I don't see where the spec says > that a DBAPI connection is always in a transaction.) Well, that you can't/shouldn't call "BEGIN" is implied by this paragraph, though weakly, but isn't specific about isolation. I also bet if you emailed the DB-SIG list, they'd be interested in this detail. .commit() Commit any pending transaction to the database. Note that if the database supports an auto-commit feature, this must be initially off. An interface method may be provided to turn it back on. > SA can provide > the behavior I want simply by implementing do_begin in SQLiteDialect > as a one-liner: connection.execute("BEGIN"). I'd much rather hear the rationale from the Pysqlite folks why they have specifically chosen not to do this, and get their advice on what we should be doing. Your above sentence can be restated as "pysqlite2 can provide the behavior I want simply by moving auto-begin after any non-DML statement, not just INSERT/UPDATE/DELETE, a [probable] one-liner". Why SQLA's issue and not pysqlite's? SQLAlchemy is heavily constructed around the "implicit BEGIN" paradigm of DBAPI and I'm not too comfortable making an exception in the case of one DBAPI that doesn't work like all the others. I tried setting isolation_level=None and calling "BEGIN", commit(), rollback() explicitly, we get seven failures. Caling "COMMIT", "ROLLBACK" instead of the connection provided version and virtually all tests error out, so already strange that conn.commit() is doing something we don't see - even when isolation_level=None. Without the isolation_level change, and just calling "BEGIN", things are "fine", but then again we don't have in depth testing of SQLite's transactional quirks...because ....its one of the very few things DBAPI allows us not to worry about ! If pysqilte could document, "hey its OK to call 'BEGIN' to delineate when the trans should be begin if pysqlite's auto-trans is too late", or if they could add a "begin()" call, or an option to just call BEGIN as soon as SELECT is issued, then we are good. If they tell us to call "BEGIN" I'd probably add this as an option to the engine just to make sure the overall userbase isn't exposed to surprises (and also that I don't have to write a crapload of new tests). > At the very least, I beg you, don't have the echo code output BEGIN if > no BEGIN is being issued. That had me barking up the wrong tree for > many hours yesterday. The echo feature is great for troubleshooting, > but only if it doesn't lie! Well we like that people are familiar with DBAPI and that it has no begin(), so with that knowledge it should be clear that SQLA's log message of "BEGIN" only represents when SQLA first starts using a DBAPI connection that has no existing transactional state, and that the DBAPI is expected to have done what it needs to ensure that a BEGIN has occurred. The "BEGIN" message can say something like "BEGIN (implicit)" or "BEGIN (virtual)", "BEGIN (assumed that the DBAPI is doing this!)" but you can be sure most people aren't going to know what the heck that means and you'll just have more people complaining. I will gladly add documentation verbiage clarifying this where you think its appropriate. Most likely on this page http://www.sqlalchemy.org/docs/core/connections.html . If we are adding options to pysqlite then that's more verbiage that will be present in any case.
import sqlite3 import os if os.path.exists("file.db"): os.unlink("file.db") conn1 = sqlite3.connect("file.db") c1 = conn1.cursor() c1.execute("PRAGMA read_uncommitted=SERIALIZABLE") c1.execute("""create table foo (id integer primary key, data varchar(30))""") c1.execute("insert into foo(id, data) values (1, 'data1')") c1.close() conn1.commit() c1 = conn1.cursor() c1.execute("select * from foo where id=1") row1 = c1.fetchone() c1.close() conn2 = sqlite3.connect("file.db") c2 = conn2.cursor() c2.execute("PRAGMA read_uncommitted=SERIALIZABLE") # sqlite3 should be doing this automatically. # when called, conn1's commit blocks #c2.execute("BEGIN") c2.execute("select * from foo where id=1") row2 = c2.fetchone() c2.close() c1 = conn1.cursor() c1.execute("update foo set data='data2'") print "About to commit conn1..." conn1.commit()
-- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To post to this group, send email to sqlalch...@googlegroups.com. To unsubscribe from this group, send email to sqlalchemy+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en.