Skip to content
Prev Previous commit
Next Next commit
cosmetic fixes
  • Loading branch information
berkerpeksag committed May 9, 2019
commit cc49a97449ad7fb6475e5af2da5681690e5b619f
42 changes: 23 additions & 19 deletions Lib/sqlite3/test/regression.py
Original file line number Diff line number Diff line change
Expand Up @@ -449,61 +449,65 @@ class DMLStatementDetectionTestCase(unittest.TestCase):
Test behavior of sqlite3_stmt_readonly() in determining if a statement is
DML or not.
"""
@unittest.skipIf(sqlite.sqlite_version_info < (3, 8, 3),
'needs sqlite 3.8.3 or newer')
@unittest.skipIf(sqlite.sqlite_version_info < (3, 8, 3), 'needs sqlite 3.8.3 or newer')
def test_dml_detection_cte(self):
conn = sqlite.connect(':memory:')
conn.execute('create table kv ("key" text, "val" integer)')
conn.execute('CREATE TABLE kv ("key" TEXT, "val" INTEGER)')
self.assertFalse(conn.in_transaction)
conn.execute('insert into kv (key, val) values (?, ?), (?, ?)',
conn.execute('INSERT INTO kv (key, val) VALUES (?, ?), (?, ?)',
('k1', 1, 'k2', 2))
self.assertTrue(conn.in_transaction)

conn.commit()
self.assertFalse(conn.in_transaction)

rc = conn.execute('update kv set val=val + ?', (10,))
rc = conn.execute('UPDATE kv SET val=val + ?', (10,))
self.assertEqual(rc.rowcount, 2)
self.assertTrue(conn.in_transaction)
conn.commit()
self.assertFalse(conn.in_transaction)

rc = conn.execute('with c(k, v) as (select key, val + ? from kv) '
'update kv set val=(select v from c where k=kv.key)',
(100,))
rc = conn.execute(
'WITH c(k, v) AS (SELECT key, val + ? FROM kv) '
'UPDATE kv SET val=(SELECT v FROM c WHERE k=kv.key)',
(100,)
)
self.assertEqual(rc.rowcount, 2)
self.assertTrue(conn.in_transaction)

curs = conn.execute('select key, val from kv order by key')
curs = conn.execute('SELECT key, val FROM kv ORDER BY key')
self.assertEqual(curs.fetchall(), [('k1', 111), ('k2', 112)])

@unittest.skipIf(sqlite.sqlite_version_info < (3, 7, 11),
'needs sqlite 3.7.11 or newer')
@unittest.skipIf(sqlite.sqlite_version_info < (3, 7, 11), 'needs sqlite 3.7.11 or newer')
def test_dml_detection_sql_comment(self):
conn = sqlite.connect(':memory:')
conn.execute('create table kv ("key" text, "val" integer)')
conn.execute('insert into kv (key, val) values (?, ?), (?, ?)',
conn.execute('CREATE TABLE kv ("key" TEXT, "val" INTEGER)')
self.assertFalse(conn.in_transaction)
conn.execute('INSERT INTO kv (key, val) VALUES (?, ?), (?, ?)',
('k1', 1, 'k2', 2))
conn.commit()

self.assertFalse(conn.in_transaction)
rc = conn.execute('-- a comment\nupdate kv set val=val + ?', (10,))

rc = conn.execute('-- a comment\nUPDATE kv SET val=val + ?', (10,))
self.assertEqual(rc.rowcount, 2)
self.assertTrue(conn.in_transaction)

curs = conn.execute('select key, val from kv order by key')
curs = conn.execute('SELECT key, val FROM kv ORDER BY key')
self.assertEqual(curs.fetchall(), [('k1', 11), ('k2', 12)])
conn.rollback()
self.assertFalse(conn.in_transaction)
# Fetch again after rollback.
curs = conn.execute('SELECT key, val FROM kv ORDER BY key')
self.assertEqual(curs.fetchall(), [('k1', 1), ('k2', 2)])

def test_dml_detection_begin_exclusive(self):
# sqlite3_stmt_readonly() reports BEGIN EXCLUSIVE as being a
# non-read-only statement. To retain compatibility with the
# transactional behavior, we add a special exclusion for these
# statements.
conn = sqlite.connect(':memory:')
conn.execute('begin exclusive')
conn.execute('BEGIN EXCLUSIVE')
self.assertTrue(conn.in_transaction)
conn.execute('rollback')
conn.execute('ROLLBACK')
self.assertFalse(conn.in_transaction)


Expand Down
10 changes: 4 additions & 6 deletions Modules/_sqlite/statement.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,16 @@ typedef enum {
TYPE_UNKNOWN
} parameter_type;

int pysqlite_statement_is_dml(sqlite3_stmt *st, const char *sql)
static int pysqlite_statement_is_dml(sqlite3_stmt *statement, const char *sql)
{
const char* p;
int is_dml = 0;

#ifdef HAVE_SQLITE3_STMT_READONLY
is_dml = !sqlite3_stmt_readonly(st);
is_dml = !sqlite3_stmt_readonly(statement);
if (is_dml) {
/* Retain backwards-compatibility, as sqlite3_stmt_readonly will return
* false for BEGIN [IMMEDIATE|EXCLUSIVE] or DDL statements.
*/
* false for BEGIN [IMMEDIATE|EXCLUSIVE] or DDL statements. */
for (p = sql; *p != 0; p++) {
switch (*p) {
case ' ':
Expand All @@ -81,8 +80,7 @@ int pysqlite_statement_is_dml(sqlite3_stmt *st, const char *sql)
#else
/* Determine if the statement is a DML statement. SELECT is the only
* exception. This is a fallback for older versions of SQLite which do not
* support the sqlite3_stmt_readonly() API.
*/
* support the sqlite3_stmt_readonly() API. */
for (p = sql; *p != 0; p++) {
switch (*p) {
case ' ':
Expand Down