diff options
author | Berker Peksag <berker.peksag@gmail.com> | 2017-02-26 16:09:10 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-02-26 16:09:10 (GMT) |
commit | 76995cab69d5ef83d31d8a5754cbad11be4038cb (patch) | |
tree | 1a3af522b463de5c31b226f7a48797f9bf687be8 | |
parent | 893e86e9d3c0caeb878ccb1120c7259e022f3b68 (diff) | |
download | cpython-76995cab69d5ef83d31d8a5754cbad11be4038cb.zip cpython-76995cab69d5ef83d31d8a5754cbad11be4038cb.tar.gz cpython-76995cab69d5ef83d31d8a5754cbad11be4038cb.tar.bz2 |
bpo-28518: Start a transaction implicitly before a DML statement (#245) (#318)
Patch by Aviv Palivoda.
(cherry picked from commit 4a926caf8e5fd8af771b2c34bfb6e91c732331fe)
-rw-r--r-- | Lib/sqlite3/test/transactions.py | 9 | ||||
-rw-r--r-- | Misc/NEWS | 3 | ||||
-rw-r--r-- | Modules/_sqlite/cursor.c | 9 | ||||
-rw-r--r-- | Modules/_sqlite/statement.c | 12 | ||||
-rw-r--r-- | Modules/_sqlite/statement.h | 2 |
5 files changed, 24 insertions, 11 deletions
diff --git a/Lib/sqlite3/test/transactions.py b/Lib/sqlite3/test/transactions.py index 45f1b04..b8a13de 100644 --- a/Lib/sqlite3/test/transactions.py +++ b/Lib/sqlite3/test/transactions.py @@ -179,6 +179,15 @@ class TransactionalDDL(unittest.TestCase): result = self.con.execute("select * from test").fetchall() self.assertEqual(result, []) + def CheckImmediateTransactionalDDL(self): + # You can achieve transactional DDL by issuing a BEGIN + # statement manually. + self.con.execute("begin immediate") + self.con.execute("create table test(i)") + self.con.rollback() + with self.assertRaises(sqlite.OperationalError): + self.con.execute("select * from test") + def CheckTransactionalDDL(self): # You can achieve transactional DDL by issuing a BEGIN # statement manually. @@ -69,6 +69,9 @@ Extension Modules Library ------- +- bpo-28518: Start a transaction implicitly before a DML statement. + Patch by Aviv Palivoda. + - bpo-29532: Altering a kwarg dictionary passed to functools.partial() no longer affects a partial object after creation. diff --git a/Modules/_sqlite/cursor.c b/Modules/_sqlite/cursor.c index 39f7a65..8341fb8 100644 --- a/Modules/_sqlite/cursor.c +++ b/Modules/_sqlite/cursor.c @@ -511,10 +511,9 @@ PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* pysqlite_statement_reset(self->statement); pysqlite_statement_mark_dirty(self->statement); - /* For backwards compatibility reasons, do not start a transaction if a - DDL statement is encountered. If anybody wants transactional DDL, - they can issue a BEGIN statement manually. */ - if (self->connection->begin_statement && !sqlite3_stmt_readonly(self->statement->st) && !self->statement->is_ddl) { + /* We start a transaction implicitly before a DML statement. + SELECT is the only exception. See #9924. */ + if (self->connection->begin_statement && self->statement->is_dml) { if (sqlite3_get_autocommit(self->connection->db)) { result = _pysqlite_connection_begin(self->connection); if (!result) { @@ -609,7 +608,7 @@ PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* } } - if (!sqlite3_stmt_readonly(self->statement->st)) { + if (self->statement->is_dml) { self->rowcount += (long)sqlite3_changes(self->connection->db); } else { self->rowcount= -1L; diff --git a/Modules/_sqlite/statement.c b/Modules/_sqlite/statement.c index 0df661b..087375b 100644 --- a/Modules/_sqlite/statement.c +++ b/Modules/_sqlite/statement.c @@ -73,8 +73,9 @@ int pysqlite_statement_create(pysqlite_Statement* self, pysqlite_Connection* con Py_INCREF(sql); self->sql = sql; - /* determine if the statement is a DDL statement */ - self->is_ddl = 0; + /* Determine if the statement is a DML statement. + SELECT is the only exception. See #9924. */ + self->is_dml = 0; for (p = sql_cstr; *p != 0; p++) { switch (*p) { case ' ': @@ -84,9 +85,10 @@ int pysqlite_statement_create(pysqlite_Statement* self, pysqlite_Connection* con continue; } - self->is_ddl = (PyOS_strnicmp(p, "create ", 7) == 0) - || (PyOS_strnicmp(p, "drop ", 5) == 0) - || (PyOS_strnicmp(p, "reindex ", 8) == 0); + self->is_dml = (PyOS_strnicmp(p, "insert ", 7) == 0) + || (PyOS_strnicmp(p, "update ", 7) == 0) + || (PyOS_strnicmp(p, "delete ", 7) == 0) + || (PyOS_strnicmp(p, "replace ", 8) == 0); break; } diff --git a/Modules/_sqlite/statement.h b/Modules/_sqlite/statement.h index 6eef168..8db10f6 100644 --- a/Modules/_sqlite/statement.h +++ b/Modules/_sqlite/statement.h @@ -38,7 +38,7 @@ typedef struct sqlite3_stmt* st; PyObject* sql; int in_use; - int is_ddl; + int is_dml; PyObject* in_weakreflist; /* List of weak references */ } pysqlite_Statement; |