bpo-28518: Start a transaction implicitly before a DML statement (#245)
Patch by Aviv Palivoda.
This commit is contained in:
parent
46ce7599af
commit
4a926caf8e
|
@ -179,6 +179,15 @@ class TransactionalDDL(unittest.TestCase):
|
||||||
result = self.con.execute("select * from test").fetchall()
|
result = self.con.execute("select * from test").fetchall()
|
||||||
self.assertEqual(result, [])
|
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):
|
def CheckTransactionalDDL(self):
|
||||||
# You can achieve transactional DDL by issuing a BEGIN
|
# You can achieve transactional DDL by issuing a BEGIN
|
||||||
# statement manually.
|
# statement manually.
|
||||||
|
|
|
@ -249,6 +249,9 @@ Extension Modules
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- bpo-28518: Start a transaction implicitly before a DML statement.
|
||||||
|
Patch by Aviv Palivoda.
|
||||||
|
|
||||||
- Issue #16285: urrlib.parse.quote is now based on RFC 3986 and hence includes
|
- Issue #16285: urrlib.parse.quote is now based on RFC 3986 and hence includes
|
||||||
'~' in the set of characters that is not quoted by default. Patch by
|
'~' in the set of characters that is not quoted by default. Patch by
|
||||||
Christian Theune and Ratnadeep Debnath.
|
Christian Theune and Ratnadeep Debnath.
|
||||||
|
|
|
@ -511,10 +511,9 @@ PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject*
|
||||||
pysqlite_statement_reset(self->statement);
|
pysqlite_statement_reset(self->statement);
|
||||||
pysqlite_statement_mark_dirty(self->statement);
|
pysqlite_statement_mark_dirty(self->statement);
|
||||||
|
|
||||||
/* For backwards compatibility reasons, do not start a transaction if a
|
/* We start a transaction implicitly before a DML statement.
|
||||||
DDL statement is encountered. If anybody wants transactional DDL,
|
SELECT is the only exception. See #9924. */
|
||||||
they can issue a BEGIN statement manually. */
|
if (self->connection->begin_statement && self->statement->is_dml) {
|
||||||
if (self->connection->begin_statement && !sqlite3_stmt_readonly(self->statement->st) && !self->statement->is_ddl) {
|
|
||||||
if (sqlite3_get_autocommit(self->connection->db)) {
|
if (sqlite3_get_autocommit(self->connection->db)) {
|
||||||
result = _pysqlite_connection_begin(self->connection);
|
result = _pysqlite_connection_begin(self->connection);
|
||||||
if (!result) {
|
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);
|
self->rowcount += (long)sqlite3_changes(self->connection->db);
|
||||||
} else {
|
} else {
|
||||||
self->rowcount= -1L;
|
self->rowcount= -1L;
|
||||||
|
|
|
@ -73,8 +73,9 @@ int pysqlite_statement_create(pysqlite_Statement* self, pysqlite_Connection* con
|
||||||
Py_INCREF(sql);
|
Py_INCREF(sql);
|
||||||
self->sql = sql;
|
self->sql = sql;
|
||||||
|
|
||||||
/* determine if the statement is a DDL statement */
|
/* Determine if the statement is a DML statement.
|
||||||
self->is_ddl = 0;
|
SELECT is the only exception. See #9924. */
|
||||||
|
self->is_dml = 0;
|
||||||
for (p = sql_cstr; *p != 0; p++) {
|
for (p = sql_cstr; *p != 0; p++) {
|
||||||
switch (*p) {
|
switch (*p) {
|
||||||
case ' ':
|
case ' ':
|
||||||
|
@ -84,9 +85,10 @@ int pysqlite_statement_create(pysqlite_Statement* self, pysqlite_Connection* con
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
self->is_ddl = (PyOS_strnicmp(p, "create ", 7) == 0)
|
self->is_dml = (PyOS_strnicmp(p, "insert ", 7) == 0)
|
||||||
|| (PyOS_strnicmp(p, "drop ", 5) == 0)
|
|| (PyOS_strnicmp(p, "update ", 7) == 0)
|
||||||
|| (PyOS_strnicmp(p, "reindex ", 8) == 0);
|
|| (PyOS_strnicmp(p, "delete ", 7) == 0)
|
||||||
|
|| (PyOS_strnicmp(p, "replace ", 8) == 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ typedef struct
|
||||||
sqlite3_stmt* st;
|
sqlite3_stmt* st;
|
||||||
PyObject* sql;
|
PyObject* sql;
|
||||||
int in_use;
|
int in_use;
|
||||||
int is_ddl;
|
int is_dml;
|
||||||
PyObject* in_weakreflist; /* List of weak references */
|
PyObject* in_weakreflist; /* List of weak references */
|
||||||
} pysqlite_Statement;
|
} pysqlite_Statement;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue