blob: 323b25dbb21af02b5c18570b4bd8b7c30668efb6 [file] [log] [blame]
Petri Lehtinen9e147552013-02-23 19:05:09 +01001#-*- coding: iso-8859-1 -*-
Anthony Baxter72289a62006-04-04 06:29:05 +00002# pysqlite2/test/regression.py: pysqlite regression tests
3#
Gerhard Häring1cc60ed2008-02-29 22:08:41 +00004# Copyright (C) 2006-2007 Gerhard Häring <gh@ghaering.de>
Anthony Baxter72289a62006-04-04 06:29:05 +00005#
6# This file is part of pysqlite.
7#
8# This software is provided 'as-is', without any express or implied
9# warranty. In no event will the authors be held liable for any damages
10# arising from the use of this software.
11#
12# Permission is granted to anyone to use this software for any purpose,
13# including commercial applications, and to alter it and redistribute it
14# freely, subject to the following restrictions:
15#
16# 1. The origin of this software must not be misrepresented; you must not
17# claim that you wrote the original software. If you use this software
18# in a product, an acknowledgment in the product documentation would be
19# appreciated but is not required.
20# 2. Altered source versions must be plainly marked as such, and must not be
21# misrepresented as being the original software.
22# 3. This notice may not be removed or altered from any source distribution.
23
Gerhard Häring1cc60ed2008-02-29 22:08:41 +000024import datetime
Anthony Baxter72289a62006-04-04 06:29:05 +000025import unittest
Gerhard Häring3e99c0a2006-04-23 15:24:26 +000026import sqlite3 as sqlite
Miss Islington (bot)4b544aa2017-11-06 16:44:19 -080027import weakref
28from test import support
Anthony Baxter72289a62006-04-04 06:29:05 +000029
30class RegressionTests(unittest.TestCase):
31 def setUp(self):
32 self.con = sqlite.connect(":memory:")
33
34 def tearDown(self):
35 self.con.close()
36
37 def CheckPragmaUserVersion(self):
38 # This used to crash pysqlite because this pragma command returns NULL for the column name
39 cur = self.con.cursor()
40 cur.execute("pragma user_version")
41
Gerhard Häring3e99c0a2006-04-23 15:24:26 +000042 def CheckPragmaSchemaVersion(self):
43 # This still crashed pysqlite <= 2.2.1
44 con = sqlite.connect(":memory:", detect_types=sqlite.PARSE_COLNAMES)
45 try:
46 cur = self.con.cursor()
47 cur.execute("pragma schema_version")
48 finally:
49 cur.close()
50 con.close()
51
52 def CheckStatementReset(self):
53 # pysqlite 2.1.0 to 2.2.0 have the problem that not all statements are
54 # reset before a rollback, but only those that are still in the
55 # statement cache. The others are not accessible from the connection object.
56 con = sqlite.connect(":memory:", cached_statements=5)
57 cursors = [con.cursor() for x in xrange(5)]
58 cursors[0].execute("create table test(x)")
59 for i in range(10):
60 cursors[0].executemany("insert into test(x) values (?)", [(x,) for x in xrange(10)])
61
62 for i in range(5):
63 cursors[i].execute(" " * i + "select x from test")
64
65 con.rollback()
66
Gerhard Häring1541ef02006-06-13 22:24:47 +000067 def CheckColumnNameWithSpaces(self):
68 cur = self.con.cursor()
69 cur.execute('select 1 as "foo bar [datetime]"')
Gregory P. Smith1844b0d2009-07-04 08:42:10 +000070 self.assertEqual(cur.description[0][0], "foo bar")
Gerhard Häring1541ef02006-06-13 22:24:47 +000071
72 cur.execute('select 1 as "foo baz"')
Gregory P. Smith1844b0d2009-07-04 08:42:10 +000073 self.assertEqual(cur.description[0][0], "foo baz")
Gerhard Häring1541ef02006-06-13 22:24:47 +000074
Gerhard Häring1cc60ed2008-02-29 22:08:41 +000075 def CheckStatementFinalizationOnCloseDb(self):
76 # pysqlite versions <= 2.3.3 only finalized statements in the statement
77 # cache when closing the database. statements that were still
Serhiy Storchaka9a118f12016-04-17 09:37:36 +030078 # referenced in cursors weren't closed and could provoke "
Gerhard Häring1cc60ed2008-02-29 22:08:41 +000079 # "OperationalError: Unable to close due to unfinalised statements".
80 con = sqlite.connect(":memory:")
81 cursors = []
82 # default statement cache size is 100
83 for i in range(105):
84 cur = con.cursor()
85 cursors.append(cur)
86 cur.execute("select 1 x union select " + str(i))
87 con.close()
88
89 def CheckOnConflictRollback(self):
90 if sqlite.sqlite_version_info < (3, 2, 2):
91 return
92 con = sqlite.connect(":memory:")
93 con.execute("create table foo(x, unique(x) on conflict rollback)")
94 con.execute("insert into foo(x) values (1)")
95 try:
96 con.execute("insert into foo(x) values (1)")
97 except sqlite.DatabaseError:
98 pass
99 con.execute("insert into foo(x) values (2)")
100 try:
101 con.commit()
102 except sqlite.OperationalError:
103 self.fail("pysqlite knew nothing about the implicit ROLLBACK")
104
105 def CheckWorkaroundForBuggySqliteTransferBindings(self):
106 """
107 pysqlite would crash with older SQLite versions unless
108 a workaround is implemented.
109 """
Gerhard Häringf40f6842008-03-02 13:08:03 +0000110 self.con.execute("create table foo(bar)")
111 self.con.execute("drop table foo")
112 self.con.execute("create table foo(bar)")
Gerhard Häring1cc60ed2008-02-29 22:08:41 +0000113
114 def CheckEmptyStatement(self):
115 """
116 pysqlite used to segfault with SQLite versions 3.5.x. These return NULL
117 for "no-operation" statements
118 """
119 self.con.execute("")
120
121 def CheckUnicodeConnect(self):
122 """
Martin Panterbf2dca92016-07-11 07:51:37 +0000123 With pysqlite 2.4.0 you needed to use a string or an APSW connection
Gerhard Häring1cc60ed2008-02-29 22:08:41 +0000124 object for opening database connections.
125
126 Formerly, both bytestrings and unicode strings used to work.
127
128 Let's make sure unicode strings work in the future.
129 """
130 con = sqlite.connect(u":memory:")
131 con.close()
132
133 def CheckTypeMapUsage(self):
134 """
135 pysqlite until 2.4.1 did not rebuild the row_cast_map when recompiling
136 a statement. This test exhibits the problem.
137 """
138 SELECT = "select * from foo"
139 con = sqlite.connect(":memory:",detect_types=sqlite.PARSE_DECLTYPES)
140 con.execute("create table foo(bar timestamp)")
141 con.execute("insert into foo(bar) values (?)", (datetime.datetime.now(),))
142 con.execute(SELECT)
143 con.execute("drop table foo")
144 con.execute("create table foo(bar integer)")
145 con.execute("insert into foo(bar) values (5)")
146 con.execute(SELECT)
147
Georg Brandla24869a2008-07-16 22:33:18 +0000148 def CheckRegisterAdapter(self):
149 """
150 See issue 3312.
151 """
152 self.assertRaises(TypeError, sqlite.register_adapter, {}, None)
153
154 def CheckSetIsolationLevel(self):
155 """
156 See issue 3312.
157 """
158 con = sqlite.connect(":memory:")
159 self.assertRaises(UnicodeEncodeError, setattr, con,
160 "isolation_level", u"\xe9")
161
Gerhard Häring3bbb6722010-03-05 09:12:37 +0000162 def CheckCursorConstructorCallCheck(self):
163 """
Ezio Melotti5dd99eb2013-08-17 16:07:38 +0300164 Verifies that cursor methods check whether base class __init__ was
165 called.
Gerhard Häring3bbb6722010-03-05 09:12:37 +0000166 """
167 class Cursor(sqlite.Cursor):
168 def __init__(self, con):
169 pass
170
171 con = sqlite.connect(":memory:")
172 cur = Cursor(con)
173 try:
174 cur.execute("select 4+5").fetchall()
175 self.fail("should have raised ProgrammingError")
176 except sqlite.ProgrammingError:
177 pass
178 except:
179 self.fail("should have raised ProgrammingError")
180
181 def CheckConnectionConstructorCallCheck(self):
182 """
Ezio Melotti5dd99eb2013-08-17 16:07:38 +0300183 Verifies that connection methods check whether base class __init__ was
184 called.
Gerhard Häring3bbb6722010-03-05 09:12:37 +0000185 """
186 class Connection(sqlite.Connection):
187 def __init__(self, name):
188 pass
189
190 con = Connection(":memory:")
191 try:
192 cur = con.cursor()
193 self.fail("should have raised ProgrammingError")
194 except sqlite.ProgrammingError:
195 pass
196 except:
197 self.fail("should have raised ProgrammingError")
198
199 def CheckCursorRegistration(self):
200 """
201 Verifies that subclassed cursor classes are correctly registered with
202 the connection object, too. (fetch-across-rollback problem)
203 """
204 class Connection(sqlite.Connection):
205 def cursor(self):
206 return Cursor(self)
207
208 class Cursor(sqlite.Cursor):
209 def __init__(self, con):
210 sqlite.Cursor.__init__(self, con)
211
212 con = Connection(":memory:")
213 cur = con.cursor()
214 cur.execute("create table foo(x)")
215 cur.executemany("insert into foo(x) values (?)", [(3,), (4,), (5,)])
216 cur.execute("select x from foo")
217 con.rollback()
218 try:
219 cur.fetchall()
220 self.fail("should have raised InterfaceError")
221 except sqlite.InterfaceError:
222 pass
223 except:
224 self.fail("should have raised InterfaceError")
225
226 def CheckAutoCommit(self):
227 """
228 Verifies that creating a connection in autocommit mode works.
229 2.5.3 introduced a regression so that these could no longer
230 be created.
231 """
232 con = sqlite.connect(":memory:", isolation_level=None)
233
234 def CheckPragmaAutocommit(self):
235 """
236 Verifies that running a PRAGMA statement that does an autocommit does
237 work. This did not work in 2.5.3/2.5.4.
238 """
Victor Stinner6e055d72010-03-13 03:27:07 +0000239 cur = self.con.cursor()
Gerhard Häring3bbb6722010-03-05 09:12:37 +0000240 cur.execute("create table foo(bar)")
241 cur.execute("insert into foo(bar) values (5)")
242
243 cur.execute("pragma page_size")
244 row = cur.fetchone()
245
246 def CheckSetDict(self):
247 """
248 See http://bugs.python.org/issue7478
249
250 It was possible to successfully register callbacks that could not be
251 hashed. Return codes of PyDict_SetItem were not checked properly.
252 """
253 class NotHashable:
254 def __call__(self, *args, **kw):
255 pass
256 def __hash__(self):
257 raise TypeError()
258 var = NotHashable()
Victor Stinner6e055d72010-03-13 03:27:07 +0000259 self.assertRaises(TypeError, self.con.create_function, var)
260 self.assertRaises(TypeError, self.con.create_aggregate, var)
261 self.assertRaises(TypeError, self.con.set_authorizer, var)
262 self.assertRaises(TypeError, self.con.set_progress_handler, var)
263
264 def CheckConnectionCall(self):
265 """
266 Call a connection with a non-string SQL request: check error handling
267 of the statement constructor.
268 """
269 self.assertRaises(sqlite.Warning, self.con, 1)
Gerhard Häring1cc60ed2008-02-29 22:08:41 +0000270
Petri Lehtinenc7fd5232011-05-09 12:24:09 +0200271 def CheckRecursiveCursorUse(self):
272 """
273 http://bugs.python.org/issue10811
274
275 Recursively using a cursor, such as when reusing it from a generator led to segfaults.
276 Now we catch recursive cursor usage and raise a ProgrammingError.
277 """
278 con = sqlite.connect(":memory:")
279
280 cur = con.cursor()
281 cur.execute("create table a (bar)")
282 cur.execute("create table b (baz)")
283
284 def foo():
285 cur.execute("insert into a (bar) values (?)", (1,))
286 yield 1
287
288 with self.assertRaises(sqlite.ProgrammingError):
289 cur.executemany("insert into b (baz) values (?)",
290 ((i,) for i in foo()))
291
Petri Lehtinen9e147552013-02-23 19:05:09 +0100292 def CheckConvertTimestampMicrosecondPadding(self):
293 """
294 http://bugs.python.org/issue14720
295
296 The microsecond parsing of convert_timestamp() should pad with zeros,
297 since the microsecond string "456" actually represents "456000".
298 """
299
300 con = sqlite.connect(":memory:", detect_types=sqlite.PARSE_DECLTYPES)
301 cur = con.cursor()
302 cur.execute("CREATE TABLE t (x TIMESTAMP)")
Petri Lehtinen9e147552013-02-23 19:05:09 +0100303
Petri Lehtinene41a4632013-02-26 21:32:02 +0200304 # Microseconds should be 456000
305 cur.execute("INSERT INTO t (x) VALUES ('2012-04-04 15:06:00.456')")
306
307 # Microseconds should be truncated to 123456
308 cur.execute("INSERT INTO t (x) VALUES ('2012-04-04 15:06:00.123456789')")
309
310 cur.execute("SELECT * FROM t")
311 values = [x[0] for x in cur.fetchall()]
312
313 self.assertEqual(values, [
314 datetime.datetime(2012, 4, 4, 15, 6, 0, 456000),
315 datetime.datetime(2012, 4, 4, 15, 6, 0, 123456),
316 ])
Petri Lehtinen9e147552013-02-23 19:05:09 +0100317
Victor Stinner94502192013-12-19 16:44:48 +0100318 def CheckInvalidIsolationLevelType(self):
319 # isolation level is a string, not an integer
320 self.assertRaises(TypeError,
321 sqlite.connect, ":memory:", isolation_level=123)
322
Petri Lehtinenc7fd5232011-05-09 12:24:09 +0200323
Serhiy Storchaka0aa65622014-09-11 13:27:19 +0300324 def CheckNullCharacter(self):
325 # Issue #21147
326 con = sqlite.connect(":memory:")
327 self.assertRaises(ValueError, con, "\0select 1")
328 self.assertRaises(ValueError, con, "select 1\0")
329 cur = con.cursor()
330 self.assertRaises(ValueError, cur.execute, " \0select 2")
331 self.assertRaises(ValueError, cur.execute, "select 2\0")
332
Benjamin Peterson9ce15642017-01-16 00:07:27 -0800333 def CheckCommitCursorReset(self):
334 """
335 Connection.commit() did reset cursors, which made sqlite3
336 to return rows multiple times when fetched from cursors
337 after commit. See issues 10513 and 23129 for details.
338 """
339 con = sqlite.connect(":memory:")
340 con.executescript("""
341 create table t(c);
342 create table t2(c);
343 insert into t values(0);
344 insert into t values(1);
345 insert into t values(2);
346 """)
347
348 self.assertEqual(con.isolation_level, "")
349
350 counter = 0
351 for i, row in enumerate(con.execute("select c from t")):
352 con.execute("insert into t2(c) values (?)", (i,))
353 con.commit()
354 if counter == 0:
355 self.assertEqual(row[0], 0)
356 elif counter == 1:
357 self.assertEqual(row[0], 1)
358 elif counter == 2:
359 self.assertEqual(row[0], 2)
360 counter += 1
361 self.assertEqual(counter, 3, "should have returned exactly three rows")
362
Miss Islington (bot)4b544aa2017-11-06 16:44:19 -0800363 def CheckBpo31770(self):
364 """
365 The interpreter shouldn't crash in case Cursor.__init__() is called
366 more than once.
367 """
368 def callback(*args):
369 pass
370 con = sqlite.connect(":memory:")
371 cur = sqlite.Cursor(con)
372 ref = weakref.ref(cur, callback)
373 cur.__init__(con)
374 del cur
375 # The interpreter shouldn't crash when ref is collected.
376 del ref
377 support.gc_collect()
378
Serhiy Storchaka0aa65622014-09-11 13:27:19 +0300379
Anthony Baxter72289a62006-04-04 06:29:05 +0000380def suite():
381 regression_suite = unittest.makeSuite(RegressionTests, "Check")
382 return unittest.TestSuite((regression_suite,))
383
384def test():
385 runner = unittest.TextTestRunner()
386 runner.run(suite())
387
388if __name__ == "__main__":
389 test()