1# pysqlite2/test/transactions.py: tests transactions 2# 3# Copyright (C) 2005-2007 Gerhard Häring <gh@ghaering.de> 4# 5# This file is part of pysqlite. 6# 7# This software is provided 'as-is', without any express or implied 8# warranty. In no event will the authors be held liable for any damages 9# arising from the use of this software. 10# 11# Permission is granted to anyone to use this software for any purpose, 12# including commercial applications, and to alter it and redistribute it 13# freely, subject to the following restrictions: 14# 15# 1. The origin of this software must not be misrepresented; you must not 16# claim that you wrote the original software. If you use this software 17# in a product, an acknowledgment in the product documentation would be 18# appreciated but is not required. 19# 2. Altered source versions must be plainly marked as such, and must not be 20# misrepresented as being the original software. 21# 3. This notice may not be removed or altered from any source distribution. 22 23import os, unittest 24import sqlite3 as sqlite 25 26def get_db_path(): 27 return "sqlite_testdb" 28 29class TransactionTests(unittest.TestCase): 30 def setUp(self): 31 try: 32 os.remove(get_db_path()) 33 except OSError: 34 pass 35 36 self.con1 = sqlite.connect(get_db_path(), timeout=0.1) 37 self.cur1 = self.con1.cursor() 38 39 self.con2 = sqlite.connect(get_db_path(), timeout=0.1) 40 self.cur2 = self.con2.cursor() 41 42 def tearDown(self): 43 self.cur1.close() 44 self.con1.close() 45 46 self.cur2.close() 47 self.con2.close() 48 49 try: 50 os.unlink(get_db_path()) 51 except OSError: 52 pass 53 54 def test_dml_does_not_auto_commit_before(self): 55 self.cur1.execute("create table test(i)") 56 self.cur1.execute("insert into test(i) values (5)") 57 self.cur1.execute("create table test2(j)") 58 self.cur2.execute("select i from test") 59 res = self.cur2.fetchall() 60 self.assertEqual(len(res), 0) 61 62 def test_insert_starts_transaction(self): 63 self.cur1.execute("create table test(i)") 64 self.cur1.execute("insert into test(i) values (5)") 65 self.cur2.execute("select i from test") 66 res = self.cur2.fetchall() 67 self.assertEqual(len(res), 0) 68 69 def test_update_starts_transaction(self): 70 self.cur1.execute("create table test(i)") 71 self.cur1.execute("insert into test(i) values (5)") 72 self.con1.commit() 73 self.cur1.execute("update test set i=6") 74 self.cur2.execute("select i from test") 75 res = self.cur2.fetchone()[0] 76 self.assertEqual(res, 5) 77 78 def test_delete_starts_transaction(self): 79 self.cur1.execute("create table test(i)") 80 self.cur1.execute("insert into test(i) values (5)") 81 self.con1.commit() 82 self.cur1.execute("delete from test") 83 self.cur2.execute("select i from test") 84 res = self.cur2.fetchall() 85 self.assertEqual(len(res), 1) 86 87 def test_replace_starts_transaction(self): 88 self.cur1.execute("create table test(i)") 89 self.cur1.execute("insert into test(i) values (5)") 90 self.con1.commit() 91 self.cur1.execute("replace into test(i) values (6)") 92 self.cur2.execute("select i from test") 93 res = self.cur2.fetchall() 94 self.assertEqual(len(res), 1) 95 self.assertEqual(res[0][0], 5) 96 97 def test_toggle_auto_commit(self): 98 self.cur1.execute("create table test(i)") 99 self.cur1.execute("insert into test(i) values (5)") 100 self.con1.isolation_level = None 101 self.assertEqual(self.con1.isolation_level, None) 102 self.cur2.execute("select i from test") 103 res = self.cur2.fetchall() 104 self.assertEqual(len(res), 1) 105 106 self.con1.isolation_level = "DEFERRED" 107 self.assertEqual(self.con1.isolation_level , "DEFERRED") 108 self.cur1.execute("insert into test(i) values (5)") 109 self.cur2.execute("select i from test") 110 res = self.cur2.fetchall() 111 self.assertEqual(len(res), 1) 112 113 def test_raise_timeout(self): 114 self.cur1.execute("create table test(i)") 115 self.cur1.execute("insert into test(i) values (5)") 116 with self.assertRaises(sqlite.OperationalError): 117 self.cur2.execute("insert into test(i) values (5)") 118 119 def test_locking(self): 120 """ 121 This tests the improved concurrency with pysqlite 2.3.4. You needed 122 to roll back con2 before you could commit con1. 123 """ 124 self.cur1.execute("create table test(i)") 125 self.cur1.execute("insert into test(i) values (5)") 126 with self.assertRaises(sqlite.OperationalError): 127 self.cur2.execute("insert into test(i) values (5)") 128 # NO self.con2.rollback() HERE!!! 129 self.con1.commit() 130 131 def test_rollback_cursor_consistency(self): 132 """ 133 Checks if cursors on the connection are set into a "reset" state 134 when a rollback is done on the connection. 135 """ 136 con = sqlite.connect(":memory:") 137 cur = con.cursor() 138 cur.execute("create table test(x)") 139 cur.execute("insert into test(x) values (5)") 140 cur.execute("select 1 union select 2 union select 3") 141 142 con.rollback() 143 with self.assertRaises(sqlite.InterfaceError): 144 cur.fetchall() 145 146class SpecialCommandTests(unittest.TestCase): 147 def setUp(self): 148 self.con = sqlite.connect(":memory:") 149 self.cur = self.con.cursor() 150 151 def test_drop_table(self): 152 self.cur.execute("create table test(i)") 153 self.cur.execute("insert into test(i) values (5)") 154 self.cur.execute("drop table test") 155 156 def test_pragma(self): 157 self.cur.execute("create table test(i)") 158 self.cur.execute("insert into test(i) values (5)") 159 self.cur.execute("pragma count_changes=1") 160 161 def tearDown(self): 162 self.cur.close() 163 self.con.close() 164 165class TransactionalDDL(unittest.TestCase): 166 def setUp(self): 167 self.con = sqlite.connect(":memory:") 168 169 def test_ddl_does_not_autostart_transaction(self): 170 # For backwards compatibility reasons, DDL statements should not 171 # implicitly start a transaction. 172 self.con.execute("create table test(i)") 173 self.con.rollback() 174 result = self.con.execute("select * from test").fetchall() 175 self.assertEqual(result, []) 176 177 def test_immediate_transactional_ddl(self): 178 # You can achieve transactional DDL by issuing a BEGIN 179 # statement manually. 180 self.con.execute("begin immediate") 181 self.con.execute("create table test(i)") 182 self.con.rollback() 183 with self.assertRaises(sqlite.OperationalError): 184 self.con.execute("select * from test") 185 186 def test_transactional_ddl(self): 187 # You can achieve transactional DDL by issuing a BEGIN 188 # statement manually. 189 self.con.execute("begin") 190 self.con.execute("create table test(i)") 191 self.con.rollback() 192 with self.assertRaises(sqlite.OperationalError): 193 self.con.execute("select * from test") 194 195 def tearDown(self): 196 self.con.close() 197 198def suite(): 199 tests = [ 200 SpecialCommandTests, 201 TransactionTests, 202 TransactionalDDL, 203 ] 204 return unittest.TestSuite( 205 [unittest.TestLoader().loadTestsFromTestCase(t) for t in tests] 206 ) 207 208def test(): 209 runner = unittest.TextTestRunner() 210 runner.run(suite()) 211 212if __name__ == "__main__": 213 test() 214