blob: 429089072496edc4927e4ea56bf6eb23a38aa35e [file] [log] [blame]
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001# pysqlite2/test/userfunctions.py: tests for user-defined functions and
2# aggregates.
3#
Erlend Egeberg Aaslandc610d972020-05-29 01:27:31 +02004# Copyright (C) 2005-2007 Gerhard Häring <gh@ghaering.de>
Thomas Wouters49fd7fa2006-04-21 10:40:58 +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
24import unittest
Sergey Fedoseev08308582018-07-08 12:09:20 +050025import unittest.mock
Miss Islington (bot)ad2f3b72021-06-04 20:09:40 -070026import gc
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000027import sqlite3 as sqlite
28
29def func_returntext():
30 return "foo"
31def func_returnunicode():
Guido van Rossumef87d6e2007-05-02 19:09:54 +000032 return "bar"
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000033def func_returnint():
34 return 42
35def func_returnfloat():
36 return 3.14
37def func_returnnull():
38 return None
39def func_returnblob():
Guido van Rossumbae07c92007-10-08 02:46:15 +000040 return b"blob"
Petri Lehtinen4fe85ab2012-02-19 21:38:00 +020041def func_returnlonglong():
42 return 1<<31
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000043def func_raiseexception():
44 5/0
45
46def func_isstring(v):
Guido van Rossumef87d6e2007-05-02 19:09:54 +000047 return type(v) is str
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000048def func_isint(v):
49 return type(v) is int
50def func_isfloat(v):
51 return type(v) is float
52def func_isnone(v):
53 return type(v) is type(None)
54def func_isblob(v):
Guido van Rossumbae07c92007-10-08 02:46:15 +000055 return isinstance(v, (bytes, memoryview))
Petri Lehtinen4fe85ab2012-02-19 21:38:00 +020056def func_islonglong(v):
57 return isinstance(v, int) and v >= 1<<31
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000058
Berker Peksagfa0f62d2016-03-27 22:39:14 +030059def func(*args):
60 return len(args)
61
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000062class AggrNoStep:
63 def __init__(self):
64 pass
65
Thomas Wouters0e3f5912006-08-11 14:57:12 +000066 def finalize(self):
67 return 1
68
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000069class AggrNoFinalize:
70 def __init__(self):
71 pass
72
73 def step(self, x):
74 pass
75
76class AggrExceptionInInit:
77 def __init__(self):
78 5/0
79
80 def step(self, x):
81 pass
82
83 def finalize(self):
84 pass
85
86class AggrExceptionInStep:
87 def __init__(self):
88 pass
89
90 def step(self, x):
91 5/0
92
93 def finalize(self):
94 return 42
95
96class AggrExceptionInFinalize:
97 def __init__(self):
98 pass
99
100 def step(self, x):
101 pass
102
103 def finalize(self):
104 5/0
105
106class AggrCheckType:
107 def __init__(self):
108 self.val = None
109
110 def step(self, whichType, val):
Guido van Rossumbae07c92007-10-08 02:46:15 +0000111 theType = {"str": str, "int": int, "float": float, "None": type(None),
112 "blob": bytes}
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000113 self.val = int(theType[whichType] is type(val))
114
115 def finalize(self):
116 return self.val
117
Berker Peksagfa0f62d2016-03-27 22:39:14 +0300118class AggrCheckTypes:
119 def __init__(self):
120 self.val = 0
121
122 def step(self, whichType, *vals):
123 theType = {"str": str, "int": int, "float": float, "None": type(None),
124 "blob": bytes}
125 for val in vals:
126 self.val += int(theType[whichType] is type(val))
127
128 def finalize(self):
129 return self.val
130
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000131class AggrSum:
132 def __init__(self):
133 self.val = 0.0
134
135 def step(self, val):
136 self.val += val
137
138 def finalize(self):
139 return self.val
140
141class FunctionTests(unittest.TestCase):
142 def setUp(self):
143 self.con = sqlite.connect(":memory:")
144
145 self.con.create_function("returntext", 0, func_returntext)
146 self.con.create_function("returnunicode", 0, func_returnunicode)
147 self.con.create_function("returnint", 0, func_returnint)
148 self.con.create_function("returnfloat", 0, func_returnfloat)
149 self.con.create_function("returnnull", 0, func_returnnull)
150 self.con.create_function("returnblob", 0, func_returnblob)
Petri Lehtinen4fe85ab2012-02-19 21:38:00 +0200151 self.con.create_function("returnlonglong", 0, func_returnlonglong)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000152 self.con.create_function("raiseexception", 0, func_raiseexception)
153
154 self.con.create_function("isstring", 1, func_isstring)
155 self.con.create_function("isint", 1, func_isint)
156 self.con.create_function("isfloat", 1, func_isfloat)
157 self.con.create_function("isnone", 1, func_isnone)
158 self.con.create_function("isblob", 1, func_isblob)
Petri Lehtinen4fe85ab2012-02-19 21:38:00 +0200159 self.con.create_function("islonglong", 1, func_islonglong)
Berker Peksagfa0f62d2016-03-27 22:39:14 +0300160 self.con.create_function("spam", -1, func)
Erlend Egeberg Aaslandc610d972020-05-29 01:27:31 +0200161 self.con.execute("create table test(t text)")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000162
163 def tearDown(self):
164 self.con.close()
165
Erlend Egeberg Aasland849e3392021-01-07 01:05:07 +0100166 def test_func_error_on_create(self):
Berker Peksag1003b342016-06-12 22:34:49 +0300167 with self.assertRaises(sqlite.OperationalError):
Thomas Wouters477c8d52006-05-27 19:21:47 +0000168 self.con.create_function("bla", -100, lambda x: 2*x)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000169
Erlend Egeberg Aasland849e3392021-01-07 01:05:07 +0100170 def test_func_ref_count(self):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000171 def getfunc():
172 def f():
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000173 return 1
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000174 return f
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000175 f = getfunc()
176 globals()["foo"] = f
177 # self.con.create_function("reftest", 0, getfunc())
178 self.con.create_function("reftest", 0, f)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000179 cur = self.con.cursor()
180 cur.execute("select reftest()")
181
Erlend Egeberg Aasland849e3392021-01-07 01:05:07 +0100182 def test_func_return_text(self):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000183 cur = self.con.cursor()
184 cur.execute("select returntext()")
185 val = cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000186 self.assertEqual(type(val), str)
187 self.assertEqual(val, "foo")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000188
Erlend Egeberg Aasland849e3392021-01-07 01:05:07 +0100189 def test_func_return_unicode(self):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000190 cur = self.con.cursor()
191 cur.execute("select returnunicode()")
192 val = cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000193 self.assertEqual(type(val), str)
194 self.assertEqual(val, "bar")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000195
Erlend Egeberg Aasland849e3392021-01-07 01:05:07 +0100196 def test_func_return_int(self):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000197 cur = self.con.cursor()
198 cur.execute("select returnint()")
199 val = cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000200 self.assertEqual(type(val), int)
201 self.assertEqual(val, 42)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000202
Erlend Egeberg Aasland849e3392021-01-07 01:05:07 +0100203 def test_func_return_float(self):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000204 cur = self.con.cursor()
205 cur.execute("select returnfloat()")
206 val = cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000207 self.assertEqual(type(val), float)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000208 if val < 3.139 or val > 3.141:
209 self.fail("wrong value")
210
Erlend Egeberg Aasland849e3392021-01-07 01:05:07 +0100211 def test_func_return_null(self):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000212 cur = self.con.cursor()
213 cur.execute("select returnnull()")
214 val = cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000215 self.assertEqual(type(val), type(None))
216 self.assertEqual(val, None)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000217
Erlend Egeberg Aasland849e3392021-01-07 01:05:07 +0100218 def test_func_return_blob(self):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000219 cur = self.con.cursor()
220 cur.execute("select returnblob()")
221 val = cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000222 self.assertEqual(type(val), bytes)
223 self.assertEqual(val, b"blob")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000224
Erlend Egeberg Aasland849e3392021-01-07 01:05:07 +0100225 def test_func_return_long_long(self):
Petri Lehtinen4fe85ab2012-02-19 21:38:00 +0200226 cur = self.con.cursor()
227 cur.execute("select returnlonglong()")
228 val = cur.fetchone()[0]
229 self.assertEqual(val, 1<<31)
230
Erlend Egeberg Aasland849e3392021-01-07 01:05:07 +0100231 def test_func_exception(self):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000232 cur = self.con.cursor()
Berker Peksag1003b342016-06-12 22:34:49 +0300233 with self.assertRaises(sqlite.OperationalError) as cm:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000234 cur.execute("select raiseexception()")
235 cur.fetchone()
Berker Peksag1003b342016-06-12 22:34:49 +0300236 self.assertEqual(str(cm.exception), 'user-defined function raised exception')
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000237
Erlend Egeberg Aasland849e3392021-01-07 01:05:07 +0100238 def test_param_string(self):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000239 cur = self.con.cursor()
Miss Islington (bot)067d6d42021-06-04 11:54:39 -0700240 for text in ["foo", str()]:
241 with self.subTest(text=text):
242 cur.execute("select isstring(?)", (text,))
243 val = cur.fetchone()[0]
244 self.assertEqual(val, 1)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000245
Erlend Egeberg Aasland849e3392021-01-07 01:05:07 +0100246 def test_param_int(self):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000247 cur = self.con.cursor()
248 cur.execute("select isint(?)", (42,))
249 val = cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000250 self.assertEqual(val, 1)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000251
Erlend Egeberg Aasland849e3392021-01-07 01:05:07 +0100252 def test_param_float(self):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000253 cur = self.con.cursor()
254 cur.execute("select isfloat(?)", (3.14,))
255 val = cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000256 self.assertEqual(val, 1)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000257
Erlend Egeberg Aasland849e3392021-01-07 01:05:07 +0100258 def test_param_none(self):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000259 cur = self.con.cursor()
260 cur.execute("select isnone(?)", (None,))
261 val = cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000262 self.assertEqual(val, 1)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000263
Erlend Egeberg Aasland849e3392021-01-07 01:05:07 +0100264 def test_param_blob(self):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000265 cur = self.con.cursor()
Guido van Rossumbae07c92007-10-08 02:46:15 +0000266 cur.execute("select isblob(?)", (memoryview(b"blob"),))
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000267 val = cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000268 self.assertEqual(val, 1)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000269
Erlend Egeberg Aasland849e3392021-01-07 01:05:07 +0100270 def test_param_long_long(self):
Petri Lehtinen4fe85ab2012-02-19 21:38:00 +0200271 cur = self.con.cursor()
272 cur.execute("select islonglong(?)", (1<<42,))
273 val = cur.fetchone()[0]
274 self.assertEqual(val, 1)
275
Erlend Egeberg Aasland849e3392021-01-07 01:05:07 +0100276 def test_any_arguments(self):
Berker Peksagfa0f62d2016-03-27 22:39:14 +0300277 cur = self.con.cursor()
278 cur.execute("select spam(?, ?)", (1, 2))
279 val = cur.fetchone()[0]
280 self.assertEqual(val, 2)
281
Erlend Egeberg Aasland5cb601f2021-04-14 23:09:11 +0200282 def test_empty_blob(self):
283 cur = self.con.execute("select isblob(x'')")
284 self.assertTrue(cur.fetchone()[0])
285
Erlend Egeberg Aaslandc610d972020-05-29 01:27:31 +0200286 # Regarding deterministic functions:
287 #
288 # Between 3.8.3 and 3.15.0, deterministic functions were only used to
289 # optimize inner loops, so for those versions we can only test if the
290 # sqlite machinery has factored out a call or not. From 3.15.0 and onward,
291 # deterministic functions were permitted in WHERE clauses of partial
292 # indices, which allows testing based on syntax, iso. the query optimizer.
293 @unittest.skipIf(sqlite.sqlite_version_info < (3, 8, 3), "Requires SQLite 3.8.3 or higher")
Erlend Egeberg Aasland849e3392021-01-07 01:05:07 +0100294 def test_func_non_deterministic(self):
Sergey Fedoseev08308582018-07-08 12:09:20 +0500295 mock = unittest.mock.Mock(return_value=None)
Erlend Egeberg Aaslandc610d972020-05-29 01:27:31 +0200296 self.con.create_function("nondeterministic", 0, mock, deterministic=False)
297 if sqlite.sqlite_version_info < (3, 15, 0):
298 self.con.execute("select nondeterministic() = nondeterministic()")
299 self.assertEqual(mock.call_count, 2)
300 else:
301 with self.assertRaises(sqlite.OperationalError):
302 self.con.execute("create index t on test(t) where nondeterministic() is not null")
Sergey Fedoseev08308582018-07-08 12:09:20 +0500303
Erlend Egeberg Aaslandc610d972020-05-29 01:27:31 +0200304 @unittest.skipIf(sqlite.sqlite_version_info < (3, 8, 3), "Requires SQLite 3.8.3 or higher")
Erlend Egeberg Aasland849e3392021-01-07 01:05:07 +0100305 def test_func_deterministic(self):
Sergey Fedoseev08308582018-07-08 12:09:20 +0500306 mock = unittest.mock.Mock(return_value=None)
307 self.con.create_function("deterministic", 0, mock, deterministic=True)
Erlend Egeberg Aaslandc610d972020-05-29 01:27:31 +0200308 if sqlite.sqlite_version_info < (3, 15, 0):
309 self.con.execute("select deterministic() = deterministic()")
310 self.assertEqual(mock.call_count, 1)
311 else:
312 try:
313 self.con.execute("create index t on test(t) where deterministic() is not null")
314 except sqlite.OperationalError:
315 self.fail("Unexpected failure while creating partial index")
Sergey Fedoseev08308582018-07-08 12:09:20 +0500316
317 @unittest.skipIf(sqlite.sqlite_version_info >= (3, 8, 3), "SQLite < 3.8.3 needed")
Erlend Egeberg Aasland849e3392021-01-07 01:05:07 +0100318 def test_func_deterministic_not_supported(self):
Sergey Fedoseev08308582018-07-08 12:09:20 +0500319 with self.assertRaises(sqlite.NotSupportedError):
320 self.con.create_function("deterministic", 0, int, deterministic=True)
321
Erlend Egeberg Aasland849e3392021-01-07 01:05:07 +0100322 def test_func_deterministic_keyword_only(self):
Sergey Fedoseev08308582018-07-08 12:09:20 +0500323 with self.assertRaises(TypeError):
324 self.con.create_function("deterministic", 0, int, True)
325
Miss Islington (bot)ad2f3b72021-06-04 20:09:40 -0700326 def test_function_destructor_via_gc(self):
327 # See bpo-44304: The destructor of the user function can
328 # crash if is called without the GIL from the gc functions
329 dest = sqlite.connect(':memory:')
330 def md5sum(t):
331 return
332
333 dest.create_function("md5", 1, md5sum)
334 x = dest("create table lang (name, first_appeared)")
335 del md5sum, dest
336
337 y = [x]
338 y.append(y)
339
340 del x,y
341 gc.collect()
Berker Peksagfa0f62d2016-03-27 22:39:14 +0300342
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000343class AggregateTests(unittest.TestCase):
344 def setUp(self):
345 self.con = sqlite.connect(":memory:")
346 cur = self.con.cursor()
347 cur.execute("""
348 create table test(
349 t text,
350 i integer,
351 f float,
352 n,
353 b blob
354 )
355 """)
356 cur.execute("insert into test(t, i, f, n, b) values (?, ?, ?, ?, ?)",
Guido van Rossumbae07c92007-10-08 02:46:15 +0000357 ("foo", 5, 3.14, None, memoryview(b"blob"),))
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000358
359 self.con.create_aggregate("nostep", 1, AggrNoStep)
360 self.con.create_aggregate("nofinalize", 1, AggrNoFinalize)
361 self.con.create_aggregate("excInit", 1, AggrExceptionInInit)
362 self.con.create_aggregate("excStep", 1, AggrExceptionInStep)
363 self.con.create_aggregate("excFinalize", 1, AggrExceptionInFinalize)
364 self.con.create_aggregate("checkType", 2, AggrCheckType)
Berker Peksagfa0f62d2016-03-27 22:39:14 +0300365 self.con.create_aggregate("checkTypes", -1, AggrCheckTypes)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000366 self.con.create_aggregate("mysum", 1, AggrSum)
367
368 def tearDown(self):
369 #self.cur.close()
370 #self.con.close()
371 pass
372
Erlend Egeberg Aasland849e3392021-01-07 01:05:07 +0100373 def test_aggr_error_on_create(self):
Berker Peksag1003b342016-06-12 22:34:49 +0300374 with self.assertRaises(sqlite.OperationalError):
Thomas Wouters477c8d52006-05-27 19:21:47 +0000375 self.con.create_function("bla", -100, AggrSum)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000376
Erlend Egeberg Aasland849e3392021-01-07 01:05:07 +0100377 def test_aggr_no_step(self):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000378 cur = self.con.cursor()
Berker Peksag1003b342016-06-12 22:34:49 +0300379 with self.assertRaises(AttributeError) as cm:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000380 cur.execute("select nostep(t) from test")
Berker Peksag1003b342016-06-12 22:34:49 +0300381 self.assertEqual(str(cm.exception), "'AggrNoStep' object has no attribute 'step'")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000382
Erlend Egeberg Aasland849e3392021-01-07 01:05:07 +0100383 def test_aggr_no_finalize(self):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000384 cur = self.con.cursor()
Berker Peksag1003b342016-06-12 22:34:49 +0300385 with self.assertRaises(sqlite.OperationalError) as cm:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000386 cur.execute("select nofinalize(t) from test")
387 val = cur.fetchone()[0]
Berker Peksag1003b342016-06-12 22:34:49 +0300388 self.assertEqual(str(cm.exception), "user-defined aggregate's 'finalize' method raised error")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000389
Erlend Egeberg Aasland849e3392021-01-07 01:05:07 +0100390 def test_aggr_exception_in_init(self):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000391 cur = self.con.cursor()
Berker Peksag1003b342016-06-12 22:34:49 +0300392 with self.assertRaises(sqlite.OperationalError) as cm:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000393 cur.execute("select excInit(t) from test")
394 val = cur.fetchone()[0]
Berker Peksag1003b342016-06-12 22:34:49 +0300395 self.assertEqual(str(cm.exception), "user-defined aggregate's '__init__' method raised error")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000396
Erlend Egeberg Aasland849e3392021-01-07 01:05:07 +0100397 def test_aggr_exception_in_step(self):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000398 cur = self.con.cursor()
Berker Peksag1003b342016-06-12 22:34:49 +0300399 with self.assertRaises(sqlite.OperationalError) as cm:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000400 cur.execute("select excStep(t) from test")
401 val = cur.fetchone()[0]
Berker Peksag1003b342016-06-12 22:34:49 +0300402 self.assertEqual(str(cm.exception), "user-defined aggregate's 'step' method raised error")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000403
Erlend Egeberg Aasland849e3392021-01-07 01:05:07 +0100404 def test_aggr_exception_in_finalize(self):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000405 cur = self.con.cursor()
Berker Peksag1003b342016-06-12 22:34:49 +0300406 with self.assertRaises(sqlite.OperationalError) as cm:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000407 cur.execute("select excFinalize(t) from test")
408 val = cur.fetchone()[0]
Berker Peksag1003b342016-06-12 22:34:49 +0300409 self.assertEqual(str(cm.exception), "user-defined aggregate's 'finalize' method raised error")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000410
Erlend Egeberg Aasland849e3392021-01-07 01:05:07 +0100411 def test_aggr_check_param_str(self):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000412 cur = self.con.cursor()
Miss Islington (bot)067d6d42021-06-04 11:54:39 -0700413 cur.execute("select checkTypes('str', ?, ?)", ("foo", str()))
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000414 val = cur.fetchone()[0]
Miss Islington (bot)067d6d42021-06-04 11:54:39 -0700415 self.assertEqual(val, 2)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000416
Erlend Egeberg Aasland849e3392021-01-07 01:05:07 +0100417 def test_aggr_check_param_int(self):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000418 cur = self.con.cursor()
419 cur.execute("select checkType('int', ?)", (42,))
420 val = cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000421 self.assertEqual(val, 1)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000422
Erlend Egeberg Aasland849e3392021-01-07 01:05:07 +0100423 def test_aggr_check_params_int(self):
Berker Peksagfa0f62d2016-03-27 22:39:14 +0300424 cur = self.con.cursor()
425 cur.execute("select checkTypes('int', ?, ?)", (42, 24))
426 val = cur.fetchone()[0]
427 self.assertEqual(val, 2)
428
Erlend Egeberg Aasland849e3392021-01-07 01:05:07 +0100429 def test_aggr_check_param_float(self):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000430 cur = self.con.cursor()
431 cur.execute("select checkType('float', ?)", (3.14,))
432 val = cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000433 self.assertEqual(val, 1)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000434
Erlend Egeberg Aasland849e3392021-01-07 01:05:07 +0100435 def test_aggr_check_param_none(self):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000436 cur = self.con.cursor()
437 cur.execute("select checkType('None', ?)", (None,))
438 val = cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000439 self.assertEqual(val, 1)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000440
Erlend Egeberg Aasland849e3392021-01-07 01:05:07 +0100441 def test_aggr_check_param_blob(self):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000442 cur = self.con.cursor()
Guido van Rossumbae07c92007-10-08 02:46:15 +0000443 cur.execute("select checkType('blob', ?)", (memoryview(b"blob"),))
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000444 val = cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000445 self.assertEqual(val, 1)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000446
Erlend Egeberg Aasland849e3392021-01-07 01:05:07 +0100447 def test_aggr_check_aggr_sum(self):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000448 cur = self.con.cursor()
449 cur.execute("delete from test")
450 cur.executemany("insert into test(i) values (?)", [(10,), (20,), (30,)])
451 cur.execute("select mysum(i) from test")
452 val = cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000453 self.assertEqual(val, 60)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000454
Erlend Egeberg Aasland979b23c2021-02-19 12:20:32 +0100455 def test_aggr_no_match(self):
456 cur = self.con.execute("select mysum(i) from (select 1 as i) where i == 0")
457 val = cur.fetchone()[0]
458 self.assertIsNone(val)
459
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000460class AuthorizerTests(unittest.TestCase):
Serhiy Storchaka3cf96ac2013-02-07 17:01:47 +0200461 @staticmethod
462 def authorizer_cb(action, arg1, arg2, dbname, source):
463 if action != sqlite.SQLITE_SELECT:
464 return sqlite.SQLITE_DENY
465 if arg2 == 'c2' or arg1 == 't2':
466 return sqlite.SQLITE_DENY
467 return sqlite.SQLITE_OK
468
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000469 def setUp(self):
470 self.con = sqlite.connect(":memory:")
471 self.con.executescript("""
472 create table t1 (c1, c2);
473 create table t2 (c1, c2);
474 insert into t1 (c1, c2) values (1, 2);
475 insert into t2 (c1, c2) values (4, 5);
476 """)
477
478 # For our security test:
479 self.con.execute("select c2 from t2")
480
Serhiy Storchaka3cf96ac2013-02-07 17:01:47 +0200481 self.con.set_authorizer(self.authorizer_cb)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000482
483 def tearDown(self):
484 pass
485
Serhiy Storchaka3cf96ac2013-02-07 17:01:47 +0200486 def test_table_access(self):
Berker Peksag1003b342016-06-12 22:34:49 +0300487 with self.assertRaises(sqlite.DatabaseError) as cm:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000488 self.con.execute("select * from t2")
Berker Peksag1003b342016-06-12 22:34:49 +0300489 self.assertIn('prohibited', str(cm.exception))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000490
Serhiy Storchaka3cf96ac2013-02-07 17:01:47 +0200491 def test_column_access(self):
Berker Peksag1003b342016-06-12 22:34:49 +0300492 with self.assertRaises(sqlite.DatabaseError) as cm:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000493 self.con.execute("select c2 from t1")
Berker Peksag1003b342016-06-12 22:34:49 +0300494 self.assertIn('prohibited', str(cm.exception))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000495
Serhiy Storchaka3cf96ac2013-02-07 17:01:47 +0200496class AuthorizerRaiseExceptionTests(AuthorizerTests):
497 @staticmethod
498 def authorizer_cb(action, arg1, arg2, dbname, source):
499 if action != sqlite.SQLITE_SELECT:
500 raise ValueError
501 if arg2 == 'c2' or arg1 == 't2':
502 raise ValueError
503 return sqlite.SQLITE_OK
504
505class AuthorizerIllegalTypeTests(AuthorizerTests):
506 @staticmethod
507 def authorizer_cb(action, arg1, arg2, dbname, source):
508 if action != sqlite.SQLITE_SELECT:
509 return 0.0
510 if arg2 == 'c2' or arg1 == 't2':
511 return 0.0
512 return sqlite.SQLITE_OK
513
514class AuthorizerLargeIntegerTests(AuthorizerTests):
515 @staticmethod
516 def authorizer_cb(action, arg1, arg2, dbname, source):
517 if action != sqlite.SQLITE_SELECT:
518 return 2**32
519 if arg2 == 'c2' or arg1 == 't2':
520 return 2**32
521 return sqlite.SQLITE_OK
522
523
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000524def suite():
Erlend Egeberg Aasland849e3392021-01-07 01:05:07 +0100525 tests = [
526 AggregateTests,
527 AuthorizerIllegalTypeTests,
528 AuthorizerLargeIntegerTests,
529 AuthorizerRaiseExceptionTests,
530 AuthorizerTests,
531 FunctionTests,
532 ]
533 return unittest.TestSuite(
534 [unittest.TestLoader().loadTestsFromTestCase(t) for t in tests]
535 )
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000536
537def test():
538 runner = unittest.TextTestRunner()
539 runner.run(suite())
540
541if __name__ == "__main__":
542 test()