diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c --- a/Modules/_sqlite/connection.c +++ b/Modules/_sqlite/connection.c @@ -160,17 +160,16 @@ int pysqlite_connection_init(pysqlite_Co /* By default, the Cache class INCREFs the factory in its initializer, and * decrefs it in its deallocator method. Since this would create a circular * reference here, we're breaking it by decrementing self, and telling the * cache class to not decref the factory (self) in its deallocator. */ self->statement_cache->decref_factory = 0; Py_DECREF(self); - self->inTransaction = 0; self->detect_types = detect_types; self->timeout = timeout; (void)sqlite3_busy_timeout(self->db, (int)(timeout*1000)); #ifdef WITH_THREAD self->thread_ident = PyThread_get_thread_ident(); #endif if (!check_same_thread && sqlite3_libversion_number() < 3003001) { PyErr_SetString(pysqlite_NotSupportedError, "shared connections not available"); @@ -400,19 +399,17 @@ PyObject* _pysqlite_connection_begin(pys Py_END_ALLOW_THREADS if (rc != SQLITE_OK) { _pysqlite_seterror(self->db, statement); goto error; } rc = pysqlite_step(statement, self); - if (rc == SQLITE_DONE) { - self->inTransaction = 1; - } else { + if (rc != SQLITE_DONE) { _pysqlite_seterror(self->db, statement); } Py_BEGIN_ALLOW_THREADS rc = sqlite3_finalize(statement); Py_END_ALLOW_THREADS if (rc != SQLITE_OK && !PyErr_Occurred()) { @@ -433,30 +430,28 @@ PyObject* pysqlite_connection_commit(pys int rc; const char* tail; sqlite3_stmt* statement; if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { return NULL; } - if (self->inTransaction) { + if (!sqlite3_get_autocommit(self->db)) { Py_BEGIN_ALLOW_THREADS rc = sqlite3_prepare(self->db, "COMMIT", -1, &statement, &tail); Py_END_ALLOW_THREADS if (rc != SQLITE_OK) { _pysqlite_seterror(self->db, NULL); goto error; } rc = pysqlite_step(statement, self); - if (rc == SQLITE_DONE) { - self->inTransaction = 0; - } else { + if (rc != SQLITE_DONE) { _pysqlite_seterror(self->db, statement); } Py_BEGIN_ALLOW_THREADS rc = sqlite3_finalize(statement); Py_END_ALLOW_THREADS if (rc != SQLITE_OK && !PyErr_Occurred()) { _pysqlite_seterror(self->db, NULL); @@ -478,31 +473,29 @@ PyObject* pysqlite_connection_rollback(p int rc; const char* tail; sqlite3_stmt* statement; if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { return NULL; } - if (self->inTransaction) { + if (!sqlite3_get_autocommit(self->db)) { pysqlite_do_all_statements(self, ACTION_RESET, 1); Py_BEGIN_ALLOW_THREADS rc = sqlite3_prepare(self->db, "ROLLBACK", -1, &statement, &tail); Py_END_ALLOW_THREADS if (rc != SQLITE_OK) { _pysqlite_seterror(self->db, NULL); goto error; } rc = pysqlite_step(statement, self); - if (rc == SQLITE_DONE) { - self->inTransaction = 0; - } else { + if (rc != SQLITE_DONE) { _pysqlite_seterror(self->db, statement); } Py_BEGIN_ALLOW_THREADS rc = sqlite3_finalize(statement); Py_END_ALLOW_THREADS if (rc != SQLITE_OK && !PyErr_Occurred()) { _pysqlite_seterror(self->db, NULL); @@ -1173,27 +1166,38 @@ static PyObject* pysqlite_connection_get { if (!pysqlite_check_connection(self)) { return NULL; } else { return Py_BuildValue("i", sqlite3_total_changes(self->db)); } } +static PyObject * +pysqlite_connection_in_transaction(pysqlite_Connection* self, void* unused) +{ + if (!pysqlite_check_connection(self)) { + return NULL; + } + if (!sqlite3_get_autocommit(self->db)) { + Py_RETURN_TRUE; + } + Py_RETURN_FALSE; +} + static int pysqlite_connection_set_isolation_level(pysqlite_Connection* self, PyObject* isolation_level) { if (isolation_level == Py_None) { PyObject *res = pysqlite_connection_commit(self, NULL); if (!res) { return -1; } Py_DECREF(res); self->begin_statement = NULL; - self->inTransaction = 0; } else { const char * const *candidate; PyObject *uppercase_level; _Py_IDENTIFIER(upper); if (!PyUnicode_Check(isolation_level)) { PyErr_Format(PyExc_TypeError, "isolation_level must be a string or None, not %.100s", @@ -1621,16 +1625,17 @@ pysqlite_connection_exit(pysqlite_Connec } static const char connection_doc[] = PyDoc_STR("SQLite database connection object."); static PyGetSetDef connection_getset[] = { {"isolation_level", (getter)pysqlite_connection_get_isolation_level, (setter)pysqlite_connection_set_isolation_level}, {"total_changes", (getter)pysqlite_connection_get_total_changes, (setter)0}, + {"in_transaction", (getter)pysqlite_connection_in_transaction, (setter)0}, {NULL} }; static PyMethodDef connection_methods[] = { {"cursor", (PyCFunction)pysqlite_connection_cursor, METH_VARARGS|METH_KEYWORDS, PyDoc_STR("Return a cursor for the connection.")}, {"close", (PyCFunction)pysqlite_connection_close, METH_NOARGS, PyDoc_STR("Closes the connection.")}, @@ -1682,17 +1687,16 @@ static struct PyMemberDef connection_mem {"DataError", T_OBJECT, offsetof(pysqlite_Connection, DataError), READONLY}, {"OperationalError", T_OBJECT, offsetof(pysqlite_Connection, OperationalError), READONLY}, {"IntegrityError", T_OBJECT, offsetof(pysqlite_Connection, IntegrityError), READONLY}, {"InternalError", T_OBJECT, offsetof(pysqlite_Connection, InternalError), READONLY}, {"ProgrammingError", T_OBJECT, offsetof(pysqlite_Connection, ProgrammingError), READONLY}, {"NotSupportedError", T_OBJECT, offsetof(pysqlite_Connection, NotSupportedError), READONLY}, {"row_factory", T_OBJECT, offsetof(pysqlite_Connection, row_factory)}, {"text_factory", T_OBJECT, offsetof(pysqlite_Connection, text_factory)}, - {"in_transaction", T_BOOL, offsetof(pysqlite_Connection, inTransaction), READONLY}, {NULL} }; PyTypeObject pysqlite_ConnectionType = { PyVarObject_HEAD_INIT(NULL, 0) MODULE_NAME ".Connection", /* tp_name */ sizeof(pysqlite_Connection), /* tp_basicsize */ 0, /* tp_itemsize */ diff --git a/Modules/_sqlite/connection.h b/Modules/_sqlite/connection.h --- a/Modules/_sqlite/connection.h +++ b/Modules/_sqlite/connection.h @@ -32,20 +32,16 @@ #include "sqlite3.h" typedef struct { PyObject_HEAD sqlite3* db; - /* 1 if we are currently within a transaction, i. e. if a BEGIN has been - * issued */ - char inTransaction; - /* the type detection mode. Only 0, PARSE_DECLTYPES, PARSE_COLNAMES or a * bitwise combination thereof makes sense */ int detect_types; /* the timeout value in seconds for database locks */ double timeout; /* for internal use in the timeout handler: when did the timeout handler diff --git a/Modules/_sqlite/cursor.c b/Modules/_sqlite/cursor.c --- a/Modules/_sqlite/cursor.c +++ b/Modules/_sqlite/cursor.c @@ -551,28 +551,28 @@ PyObject* _pysqlite_query_execute(pysqli 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) { + if (sqlite3_get_autocommit(self->connection->db)) { 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) { + if (!sqlite3_get_autocommit(self->connection->db)) { result = pysqlite_connection_commit(self->connection, NULL); if (!result) { goto error; } Py_DECREF(result); } break; case STATEMENT_SELECT: @@ -712,25 +712,16 @@ PyObject* _pysqlite_query_execute(pysqli if (multiple) { pysqlite_statement_reset(self->statement); } Py_XDECREF(parameters); } error: - /* just to be sure (implicit ROLLBACKs with ON CONFLICT ROLLBACK/OR - * ROLLBACK could have happened */ - #ifdef SQLITE_VERSION_NUMBER - #if SQLITE_VERSION_NUMBER >= 3002002 - if (self->connection && self->connection->db) - self->connection->inTransaction = !sqlite3_get_autocommit(self->connection->db); - #endif - #endif - Py_XDECREF(parameters); Py_XDECREF(parameters_iter); Py_XDECREF(parameters_list); self->locked = 0; if (PyErr_Occurred()) { self->rowcount = -1L;