• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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