blob: 26494e146f77fc016a65166de349fb9ae979a507 [file] [log] [blame]
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001#-*- coding: ISO-8859-1 -*-
2# pysqlite2/test/types.py: tests for type conversion and detection
3#
4# Copyright (C) 2005 Gerhard Häring <gh@ghaering.de>
5#
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
Ezio Melotti78ea2022009-09-12 18:41:20 +000024import datetime
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000025import unittest
26import sqlite3 as sqlite
Ezio Melotti78ea2022009-09-12 18:41:20 +000027try:
28 import zlib
29except ImportError:
30 zlib = None
31
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000032
33class SqliteTypeTests(unittest.TestCase):
34 def setUp(self):
35 self.con = sqlite.connect(":memory:")
36 self.cur = self.con.cursor()
37 self.cur.execute("create table test(i integer, s varchar, f number, b blob)")
38
39 def tearDown(self):
40 self.cur.close()
41 self.con.close()
42
43 def CheckString(self):
Guido van Rossumef87d6e2007-05-02 19:09:54 +000044 self.cur.execute("insert into test(s) values (?)", ("Österreich",))
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000045 self.cur.execute("select s from test")
46 row = self.cur.fetchone()
Gregory P. Smith04cecaf2009-07-04 08:32:15 +000047 self.assertEqual(row[0], "Österreich")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000048
49 def CheckSmallInt(self):
50 self.cur.execute("insert into test(i) values (?)", (42,))
51 self.cur.execute("select i from test")
52 row = self.cur.fetchone()
Gregory P. Smith04cecaf2009-07-04 08:32:15 +000053 self.assertEqual(row[0], 42)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000054
55 def CheckLargeInt(self):
56 num = 2**40
57 self.cur.execute("insert into test(i) values (?)", (num,))
58 self.cur.execute("select i from test")
59 row = self.cur.fetchone()
Gregory P. Smith04cecaf2009-07-04 08:32:15 +000060 self.assertEqual(row[0], num)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000061
62 def CheckFloat(self):
63 val = 3.14
64 self.cur.execute("insert into test(f) values (?)", (val,))
65 self.cur.execute("select f from test")
66 row = self.cur.fetchone()
Gregory P. Smith04cecaf2009-07-04 08:32:15 +000067 self.assertEqual(row[0], val)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000068
69 def CheckBlob(self):
Guido van Rossum98297ee2007-11-06 21:34:58 +000070 sample = b"Guglhupf"
71 val = memoryview(sample)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000072 self.cur.execute("insert into test(b) values (?)", (val,))
73 self.cur.execute("select b from test")
74 row = self.cur.fetchone()
Gregory P. Smith04cecaf2009-07-04 08:32:15 +000075 self.assertEqual(row[0], sample)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000076
77 def CheckUnicodeExecute(self):
Guido van Rossumef87d6e2007-05-02 19:09:54 +000078 self.cur.execute("select 'Österreich'")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000079 row = self.cur.fetchone()
Gregory P. Smith04cecaf2009-07-04 08:32:15 +000080 self.assertEqual(row[0], "Österreich")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000081
82class DeclTypesTests(unittest.TestCase):
83 class Foo:
84 def __init__(self, _val):
Guido van Rossum98297ee2007-11-06 21:34:58 +000085 if isinstance(_val, bytes):
86 # sqlite3 always calls __init__ with a bytes created from a
Brett Cannon40430012007-10-22 20:24:51 +000087 # UTF-8 string when __conform__ was used to store the object.
88 _val = _val.decode('utf8')
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000089 self.val = _val
90
91 def __cmp__(self, other):
92 if not isinstance(other, DeclTypesTests.Foo):
93 raise ValueError
94 if self.val == other.val:
95 return 0
96 else:
97 return 1
98
Guido van Rossum47b9ff62006-08-24 00:41:19 +000099 def __eq__(self, other):
100 c = self.__cmp__(other)
101 if c is NotImplemented:
102 return c
103 return c == 0
104
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000105 def __conform__(self, protocol):
106 if protocol is sqlite.PrepareProtocol:
107 return self.val
108 else:
109 return None
110
111 def __str__(self):
112 return "<%s>" % self.val
113
114 def setUp(self):
115 self.con = sqlite.connect(":memory:", detect_types=sqlite.PARSE_DECLTYPES)
116 self.cur = self.con.cursor()
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000117 self.cur.execute("create table test(i int, s str, f float, b bool, u unicode, foo foo, bin blob, n1 number, n2 number(5))")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000118
119 # override float, make them always return the same number
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000120 sqlite.converters["FLOAT"] = lambda x: 47.2
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000121
122 # and implement two custom ones
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000123 sqlite.converters["BOOL"] = lambda x: bool(int(x))
124 sqlite.converters["FOO"] = DeclTypesTests.Foo
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000125 sqlite.converters["WRONG"] = lambda x: "WRONG"
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000126 sqlite.converters["NUMBER"] = float
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000127
128 def tearDown(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000129 del sqlite.converters["FLOAT"]
130 del sqlite.converters["BOOL"]
131 del sqlite.converters["FOO"]
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000132 del sqlite.converters["NUMBER"]
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000133 self.cur.close()
134 self.con.close()
135
136 def CheckString(self):
137 # default
138 self.cur.execute("insert into test(s) values (?)", ("foo",))
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000139 self.cur.execute('select s as "s [WRONG]" from test')
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000140 row = self.cur.fetchone()
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000141 self.assertEqual(row[0], "foo")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000142
143 def CheckSmallInt(self):
144 # default
145 self.cur.execute("insert into test(i) values (?)", (42,))
146 self.cur.execute("select i from test")
147 row = self.cur.fetchone()
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000148 self.assertEqual(row[0], 42)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000149
150 def CheckLargeInt(self):
151 # default
152 num = 2**40
153 self.cur.execute("insert into test(i) values (?)", (num,))
154 self.cur.execute("select i from test")
155 row = self.cur.fetchone()
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000156 self.assertEqual(row[0], num)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000157
158 def CheckFloat(self):
159 # custom
160 val = 3.14
161 self.cur.execute("insert into test(f) values (?)", (val,))
162 self.cur.execute("select f from test")
163 row = self.cur.fetchone()
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000164 self.assertEqual(row[0], 47.2)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000165
166 def CheckBool(self):
167 # custom
168 self.cur.execute("insert into test(b) values (?)", (False,))
169 self.cur.execute("select b from test")
170 row = self.cur.fetchone()
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000171 self.assertEqual(row[0], False)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000172
173 self.cur.execute("delete from test")
174 self.cur.execute("insert into test(b) values (?)", (True,))
175 self.cur.execute("select b from test")
176 row = self.cur.fetchone()
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000177 self.assertEqual(row[0], True)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000178
179 def CheckUnicode(self):
180 # default
Guido van Rossumef87d6e2007-05-02 19:09:54 +0000181 val = "\xd6sterreich"
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000182 self.cur.execute("insert into test(u) values (?)", (val,))
183 self.cur.execute("select u from test")
184 row = self.cur.fetchone()
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000185 self.assertEqual(row[0], val)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000186
187 def CheckFoo(self):
188 val = DeclTypesTests.Foo("bla")
189 self.cur.execute("insert into test(foo) values (?)", (val,))
190 self.cur.execute("select foo from test")
191 row = self.cur.fetchone()
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000192 self.assertEqual(row[0], val)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000193
194 def CheckUnsupportedSeq(self):
195 class Bar: pass
196 val = Bar()
197 try:
198 self.cur.execute("insert into test(f) values (?)", (val,))
199 self.fail("should have raised an InterfaceError")
200 except sqlite.InterfaceError:
201 pass
202 except:
203 self.fail("should have raised an InterfaceError")
204
205 def CheckUnsupportedDict(self):
206 class Bar: pass
207 val = Bar()
208 try:
209 self.cur.execute("insert into test(f) values (:val)", {"val": val})
210 self.fail("should have raised an InterfaceError")
211 except sqlite.InterfaceError:
212 pass
213 except:
214 self.fail("should have raised an InterfaceError")
215
216 def CheckBlob(self):
217 # default
Guido van Rossum98297ee2007-11-06 21:34:58 +0000218 sample = b"Guglhupf"
219 val = memoryview(sample)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000220 self.cur.execute("insert into test(bin) values (?)", (val,))
221 self.cur.execute("select bin from test")
222 row = self.cur.fetchone()
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000223 self.assertEqual(row[0], sample)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000224
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000225 def CheckNumber1(self):
226 self.cur.execute("insert into test(n1) values (5)")
227 value = self.cur.execute("select n1 from test").fetchone()[0]
228 # if the converter is not used, it's an int instead of a float
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000229 self.assertEqual(type(value), float)
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000230
231 def CheckNumber2(self):
232 """Checks wether converter names are cut off at '(' characters"""
233 self.cur.execute("insert into test(n2) values (5)")
234 value = self.cur.execute("select n2 from test").fetchone()[0]
235 # if the converter is not used, it's an int instead of a float
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000236 self.assertEqual(type(value), float)
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000237
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000238class ColNamesTests(unittest.TestCase):
239 def setUp(self):
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000240 self.con = sqlite.connect(":memory:", detect_types=sqlite.PARSE_COLNAMES)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000241 self.cur = self.con.cursor()
242 self.cur.execute("create table test(x foo)")
243
Gerhard Häringe7ea7452008-03-29 00:45:29 +0000244 sqlite.converters["FOO"] = lambda x: "[%s]" % x.decode("ascii")
245 sqlite.converters["BAR"] = lambda x: "<%s>" % x.decode("ascii")
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000246 sqlite.converters["EXC"] = lambda x: 5/0
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000247 sqlite.converters["B1B1"] = lambda x: "MARKER"
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000248
249 def tearDown(self):
Gerhard Häringe7ea7452008-03-29 00:45:29 +0000250 del sqlite.converters["FOO"]
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000251 del sqlite.converters["BAR"]
252 del sqlite.converters["EXC"]
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000253 del sqlite.converters["B1B1"]
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000254 self.cur.close()
255 self.con.close()
256
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000257 def CheckDeclTypeNotUsed(self):
258 """
259 Assures that the declared type is not used when PARSE_DECLTYPES
260 is not set.
261 """
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000262 self.cur.execute("insert into test(x) values (?)", ("xxx",))
263 self.cur.execute("select x from test")
264 val = self.cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000265 self.assertEqual(val, "xxx")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000266
267 def CheckNone(self):
268 self.cur.execute("insert into test(x) values (?)", (None,))
269 self.cur.execute("select x from test")
270 val = self.cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000271 self.assertEqual(val, None)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000272
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000273 def CheckColName(self):
274 self.cur.execute("insert into test(x) values (?)", ("xxx",))
275 self.cur.execute('select x as "x [bar]" from test')
276 val = self.cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000277 self.assertEqual(val, "<xxx>")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000278
279 # Check if the stripping of colnames works. Everything after the first
280 # whitespace should be stripped.
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000281 self.assertEqual(self.cur.description[0][0], "x")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000282
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000283 def CheckCaseInConverterName(self):
Guido van Rossum98297ee2007-11-06 21:34:58 +0000284 self.cur.execute("select 'other' as \"x [b1b1]\"")
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000285 val = self.cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000286 self.assertEqual(val, "MARKER")
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000287
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000288 def CheckCursorDescriptionNoRow(self):
289 """
290 cursor.description should at least provide the column name(s), even if
291 no row returned.
292 """
293 self.cur.execute("select * from test where 0 = 1")
294 self.assert_(self.cur.description[0][0] == "x")
295
296class ObjectAdaptationTests(unittest.TestCase):
297 def cast(obj):
298 return float(obj)
299 cast = staticmethod(cast)
300
301 def setUp(self):
302 self.con = sqlite.connect(":memory:")
303 try:
304 del sqlite.adapters[int]
305 except:
306 pass
307 sqlite.register_adapter(int, ObjectAdaptationTests.cast)
308 self.cur = self.con.cursor()
309
310 def tearDown(self):
311 del sqlite.adapters[(int, sqlite.PrepareProtocol)]
312 self.cur.close()
313 self.con.close()
314
315 def CheckCasterIsUsed(self):
316 self.cur.execute("select ?", (4,))
317 val = self.cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000318 self.assertEqual(type(val), float)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000319
Ezio Melotti78ea2022009-09-12 18:41:20 +0000320@unittest.skipUnless(zlib, "requires zlib")
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000321class BinaryConverterTests(unittest.TestCase):
322 def convert(s):
Gerhard Häringe7ea7452008-03-29 00:45:29 +0000323 return zlib.decompress(s)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000324 convert = staticmethod(convert)
325
326 def setUp(self):
327 self.con = sqlite.connect(":memory:", detect_types=sqlite.PARSE_COLNAMES)
328 sqlite.register_converter("bin", BinaryConverterTests.convert)
329
330 def tearDown(self):
331 self.con.close()
332
333 def CheckBinaryInputForConverter(self):
Gerhard Häring6d214562007-08-10 18:15:11 +0000334 testdata = b"abcdefg" * 10
Gerhard Häringe7ea7452008-03-29 00:45:29 +0000335 result = self.con.execute('select ? as "x [bin]"', (memoryview(zlib.compress(testdata)),)).fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000336 self.assertEqual(testdata, result)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000337
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000338class DateTimeTests(unittest.TestCase):
339 def setUp(self):
340 self.con = sqlite.connect(":memory:", detect_types=sqlite.PARSE_DECLTYPES)
341 self.cur = self.con.cursor()
342 self.cur.execute("create table test(d date, ts timestamp)")
343
344 def tearDown(self):
345 self.cur.close()
346 self.con.close()
347
348 def CheckSqliteDate(self):
349 d = sqlite.Date(2004, 2, 14)
350 self.cur.execute("insert into test(d) values (?)", (d,))
351 self.cur.execute("select d from test")
352 d2 = self.cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000353 self.assertEqual(d, d2)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000354
355 def CheckSqliteTimestamp(self):
356 ts = sqlite.Timestamp(2004, 2, 14, 7, 15, 0)
357 self.cur.execute("insert into test(ts) values (?)", (ts,))
358 self.cur.execute("select ts from test")
359 ts2 = self.cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000360 self.assertEqual(ts, ts2)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000361
362 def CheckSqlTimestamp(self):
363 # The date functions are only available in SQLite version 3.1 or later
364 if sqlite.sqlite_version_info < (3, 1):
365 return
366
Gerhard Häringe7ea7452008-03-29 00:45:29 +0000367 # SQLite's current_timestamp uses UTC time, while datetime.datetime.now() uses local time.
368 now = datetime.datetime.now()
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000369 self.cur.execute("insert into test(ts) values (current_timestamp)")
370 self.cur.execute("select ts from test")
371 ts = self.cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000372 self.assertEqual(type(ts), datetime.datetime)
373 self.assertEqual(ts.year, now.year)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000374
375 def CheckDateTimeSubSeconds(self):
376 ts = sqlite.Timestamp(2004, 2, 14, 7, 15, 0, 500000)
377 self.cur.execute("insert into test(ts) values (?)", (ts,))
378 self.cur.execute("select ts from test")
379 ts2 = self.cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000380 self.assertEqual(ts, ts2)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000381
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000382 def CheckDateTimeSubSecondsFloatingPoint(self):
383 ts = sqlite.Timestamp(2004, 2, 14, 7, 15, 0, 510241)
384 self.cur.execute("insert into test(ts) values (?)", (ts,))
385 self.cur.execute("select ts from test")
386 ts2 = self.cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000387 self.assertEqual(ts, ts2)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000388
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000389def suite():
390 sqlite_type_suite = unittest.makeSuite(SqliteTypeTests, "Check")
391 decltypes_type_suite = unittest.makeSuite(DeclTypesTests, "Check")
392 colnames_type_suite = unittest.makeSuite(ColNamesTests, "Check")
393 adaptation_suite = unittest.makeSuite(ObjectAdaptationTests, "Check")
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000394 bin_suite = unittest.makeSuite(BinaryConverterTests, "Check")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000395 date_suite = unittest.makeSuite(DateTimeTests, "Check")
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000396 return unittest.TestSuite((sqlite_type_suite, decltypes_type_suite, colnames_type_suite, adaptation_suite, bin_suite, date_suite))
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000397
398def test():
399 runner = unittest.TextTestRunner()
400 runner.run(suite())
401
402if __name__ == "__main__":
403 test()