Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
cosmetic fixes
  • Loading branch information
berkerpeksag authored and Erlend E. Aasland committed Mar 2, 2021
commit 6e1cf0669400420c3b7db393e3534e689b4654c1
42 changes: 23 additions & 19 deletions Lib/sqlite3/test/regression.py
Original file line number Diff line number Diff line change
Expand Up @@ -416,61 +416,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