[pysqlite] repeatable reads with pysqlite?
Phil Budne <phil-kXB7xIAHHG1Wk0Htik3J/[email protected]> Tue, 21 Oct 2008 19:06:51 -0400 (EDT)
| Newsgroups | gmane.comp.python.db.pysqlite.user |
|---|---|
| Message-ID | <[email protected]> |
I started a project using apsw, since I hadn't known about lastrowid
in DB-API (or it's support in pysqlite). Since "sqlite3" is now part
of the base Python distribution (and installation of apsw under both
FreeBSD "ports" and Mac "MacPorts" failed, requiring me to to a hand
install), I was looking at porting my code to it, with an eye to
making it database neutral.
When working with apsw, I wrapped series of queries that need to
return consistent results in BEGIN/END pairs (to ensure "repeatable
reads" / avoid "phantom reads"), as well as when deleting and
inserting groups of rows. However, I've found that sqlite3 has it's
own ideas about issuing BEGIN statements, which can cause execute()
calls to fail.
It doesn't seem like DB-API implementations are consistent on this
subject. From what I can see MySQL-python-1.2.2 doesn't EVER start
transactions on it's own, and psycopg2 does (depending on isolation
level) on EVERY execute.
Here is the logic in pysqlite-2.5.0/src/cursor.c's
_pysqlite_query_execute() function:
statement_type = detect_statement_type(operation_cstr);
if (self->connection->begin_statement) {
switch (statement_type) {
case STATEMENT_UPDATE:
case STATEMENT_DELETE:
case STATEMENT_INSERT:
case STATEMENT_REPLACE:
if (!self->connection->inTransaction) {
result = _pysqlite_connection_begin(self->connection);
if (!result) {
goto error;
}
Py_DECREF(result);
}
break;
case STATEMENT_OTHER:
/* it's a DDL statement or something similar
- we better COMMIT first so it works for all cases */
if (self->connection->inTransaction) {
result = pysqlite_connection_commit(self->connection, NULL);
if (!result) {
goto error;
}
Py_DECREF(result);
}
break;
case STATEMENT_SELECT:
if (multiple) {
PyErr_SetString(pysqlite_ProgrammingError,
"You cannot execute SELECT statements in executemany().");
goto error;
}
break;
}
It seems to me that if you want to execute a series of SELECTs inside
a transaction under pysqlite, you need to issue an UPDATE, DELETE,
INSERT or UPDATE first!