diff -r 2ccdf2b3819d Lib/sqlite3/test/transactions.py --- a/Lib/sqlite3/test/transactions.py Mon Jan 16 17:18:53 2017 +0100 +++ b/Lib/sqlite3/test/transactions.py Tue Jan 24 00:24:10 2017 +0200 @@ -179,6 +179,15 @@ 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. diff -r 2ccdf2b3819d Modules/_sqlite/cursor.c --- a/Modules/_sqlite/cursor.c Mon Jan 16 17:18:53 2017 +0100 +++ b/Modules/_sqlite/cursor.c Tue Jan 24 00:24:10 2017 +0200 @@ -511,10 +511,8 @@ 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 statment (except SELECT) */ + if (self->connection->begin_statement && self->statement->is_dml) { if (sqlite3_get_autocommit(self->connection->db)) { result = _pysqlite_connection_begin(self->connection); if (!result) { diff -r 2ccdf2b3819d Modules/_sqlite/statement.c --- a/Modules/_sqlite/statement.c Mon Jan 16 17:18:53 2017 +0100 +++ b/Modules/_sqlite/statement.c Tue Jan 24 00:24:10 2017 +0200 @@ -73,8 +73,8 @@ 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 (except SELECT) */ + self->is_dml = 0; for (p = sql_cstr; *p != 0; p++) { switch (*p) { case ' ': @@ -84,9 +84,10 @@ 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 -r 2ccdf2b3819d Modules/_sqlite/statement.h --- a/Modules/_sqlite/statement.h Mon Jan 16 17:18:53 2017 +0100 +++ b/Modules/_sqlite/statement.h Tue Jan 24 00:24:10 2017 +0200 @@ -38,7 +38,7 @@ sqlite3_stmt* st; PyObject* sql; int in_use; - int is_ddl; + int is_dml; PyObject* in_weakreflist; /* List of weak references */ } pysqlite_Statement;