blob: 14f6b656c0be77f1528a798615ce7db3659cf282 [file] [log] [blame]
Petri Lehtinenf8547992012-02-02 17:17:36 +02001#-*- coding: iso-8859-1 -*-
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002# pysqlite2/test/userfunctions.py: tests for user-defined functions and
3# aggregates.
4#
Martin v. Löwis03117362008-03-30 20:21:00 +00005# Copyright (C) 2005-2007 Gerhard Häring <gh@ghaering.de>
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00006#
7# This file is part of pysqlite.
8#
9# This software is provided 'as-is', without any express or implied
10# warranty. In no event will the authors be held liable for any damages
11# arising from the use of this software.
12#
13# Permission is granted to anyone to use this software for any purpose,
14# including commercial applications, and to alter it and redistribute it
15# freely, subject to the following restrictions:
16#
17# 1. The origin of this software must not be misrepresented; you must not
18# claim that you wrote the original software. If you use this software
19# in a product, an acknowledgment in the product documentation would be
20# appreciated but is not required.
21# 2. Altered source versions must be plainly marked as such, and must not be
22# misrepresented as being the original software.
23# 3. This notice may not be removed or altered from any source distribution.
24
25import unittest
26import sqlite3 as sqlite
27
28def func_returntext():
29 return "foo"
30def func_returnunicode():
Guido van Rossumef87d6e2007-05-02 19:09:54 +000031 return "bar"
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000032def func_returnint():
33 return 42
34def func_returnfloat():
35 return 3.14
36def func_returnnull():
37 return None
38def func_returnblob():
Guido van Rossumbae07c92007-10-08 02:46:15 +000039 return b"blob"
Petri Lehtinen4fe85ab2012-02-19 21:38:00 +020040def func_returnlonglong():
41 return 1<<31
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000042def func_raiseexception():
43 5/0
44
45def func_isstring(v):
Guido van Rossumef87d6e2007-05-02 19:09:54 +000046 return type(v) is str
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000047def func_isint(v):
48 return type(v) is int
49def func_isfloat(v):
50 return type(v) is float
51def func_isnone(v):
52 return type(v) is type(None)
53def func_isblob(v):
Guido van Rossumbae07c92007-10-08 02:46:15 +000054 return isinstance(v, (bytes, memoryview))
Petri Lehtinen4fe85ab2012-02-19 21:38:00 +020055def func_islonglong(v):
56 return isinstance(v, int) and v >= 1<<31
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000057
58class AggrNoStep:
59 def __init__(self):
60 pass
61
Thomas Wouters0e3f5912006-08-11 14:57:12 +000062 def finalize(self):
63 return 1
64
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000065class AggrNoFinalize:
66 def __init__(self):
67 pass
68
69 def step(self, x):
70 pass
71
72class AggrExceptionInInit:
73 def __init__(self):
74 5/0
75
76 def step(self, x):
77 pass
78
79 def finalize(self):
80 pass
81
82class AggrExceptionInStep:
83 def __init__(self):
84 pass
85
86 def step(self, x):
87 5/0
88
89 def finalize(self):
90 return 42
91
92class AggrExceptionInFinalize:
93 def __init__(self):
94 pass
95
96 def step(self, x):
97 pass
98
99 def finalize(self):
100 5/0
101
102class AggrCheckType:
103 def __init__(self):
104 self.val = None
105
106 def step(self, whichType, val):
Guido van Rossumbae07c92007-10-08 02:46:15 +0000107 theType = {"str": str, "int": int, "float": float, "None": type(None),
108 "blob": bytes}
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000109 self.val = int(theType[whichType] is type(val))
110
111 def finalize(self):
112 return self.val
113
114class AggrSum:
115 def __init__(self):
116 self.val = 0.0
117
118 def step(self, val):
119 self.val += val
120
121 def finalize(self):
122 return self.val
123
124class FunctionTests(unittest.TestCase):
125 def setUp(self):
126 self.con = sqlite.connect(":memory:")
127
128 self.con.create_function("returntext", 0, func_returntext)
129 self.con.create_function("returnunicode", 0, func_returnunicode)
130 self.con.create_function("returnint", 0, func_returnint)
131 self.con.create_function("returnfloat", 0, func_returnfloat)
132 self.con.create_function("returnnull", 0, func_returnnull)
133 self.con.create_function("returnblob", 0, func_returnblob)
Petri Lehtinen4fe85ab2012-02-19 21:38:00 +0200134 self.con.create_function("returnlonglong", 0, func_returnlonglong)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000135 self.con.create_function("raiseexception", 0, func_raiseexception)
136
137 self.con.create_function("isstring", 1, func_isstring)
138 self.con.create_function("isint", 1, func_isint)
139 self.con.create_function("isfloat", 1, func_isfloat)
140 self.con.create_function("isnone", 1, func_isnone)
141 self.con.create_function("isblob", 1, func_isblob)
Petri Lehtinen4fe85ab2012-02-19 21:38:00 +0200142 self.con.create_function("islonglong", 1, func_islonglong)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000143
144 def tearDown(self):
145 self.con.close()
146
Thomas Wouters477c8d52006-05-27 19:21:47 +0000147 def CheckFuncErrorOnCreate(self):
148 try:
149 self.con.create_function("bla", -100, lambda x: 2*x)
150 self.fail("should have raised an OperationalError")
151 except sqlite.OperationalError:
152 pass
153
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000154 def CheckFuncRefCount(self):
155 def getfunc():
156 def f():
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000157 return 1
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000158 return f
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000159 f = getfunc()
160 globals()["foo"] = f
161 # self.con.create_function("reftest", 0, getfunc())
162 self.con.create_function("reftest", 0, f)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000163 cur = self.con.cursor()
164 cur.execute("select reftest()")
165
166 def CheckFuncReturnText(self):
167 cur = self.con.cursor()
168 cur.execute("select returntext()")
169 val = cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000170 self.assertEqual(type(val), str)
171 self.assertEqual(val, "foo")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000172
173 def CheckFuncReturnUnicode(self):
174 cur = self.con.cursor()
175 cur.execute("select returnunicode()")
176 val = cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000177 self.assertEqual(type(val), str)
178 self.assertEqual(val, "bar")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000179
180 def CheckFuncReturnInt(self):
181 cur = self.con.cursor()
182 cur.execute("select returnint()")
183 val = cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000184 self.assertEqual(type(val), int)
185 self.assertEqual(val, 42)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000186
187 def CheckFuncReturnFloat(self):
188 cur = self.con.cursor()
189 cur.execute("select returnfloat()")
190 val = cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000191 self.assertEqual(type(val), float)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000192 if val < 3.139 or val > 3.141:
193 self.fail("wrong value")
194
195 def CheckFuncReturnNull(self):
196 cur = self.con.cursor()
197 cur.execute("select returnnull()")
198 val = cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000199 self.assertEqual(type(val), type(None))
200 self.assertEqual(val, None)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000201
202 def CheckFuncReturnBlob(self):
203 cur = self.con.cursor()
204 cur.execute("select returnblob()")
205 val = cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000206 self.assertEqual(type(val), bytes)
207 self.assertEqual(val, b"blob")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000208
Petri Lehtinen4fe85ab2012-02-19 21:38:00 +0200209 def CheckFuncReturnLongLong(self):
210 cur = self.con.cursor()
211 cur.execute("select returnlonglong()")
212 val = cur.fetchone()[0]
213 self.assertEqual(val, 1<<31)
214
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000215 def CheckFuncException(self):
216 cur = self.con.cursor()
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000217 try:
218 cur.execute("select raiseexception()")
219 cur.fetchone()
220 self.fail("should have raised OperationalError")
Guido van Rossumb940e112007-01-10 16:19:56 +0000221 except sqlite.OperationalError as e:
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000222 self.assertEqual(e.args[0], 'user-defined function raised exception')
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000223
224 def CheckParamString(self):
225 cur = self.con.cursor()
226 cur.execute("select isstring(?)", ("foo",))
227 val = cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000228 self.assertEqual(val, 1)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000229
230 def CheckParamInt(self):
231 cur = self.con.cursor()
232 cur.execute("select isint(?)", (42,))
233 val = cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000234 self.assertEqual(val, 1)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000235
236 def CheckParamFloat(self):
237 cur = self.con.cursor()
238 cur.execute("select isfloat(?)", (3.14,))
239 val = cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000240 self.assertEqual(val, 1)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000241
242 def CheckParamNone(self):
243 cur = self.con.cursor()
244 cur.execute("select isnone(?)", (None,))
245 val = cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000246 self.assertEqual(val, 1)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000247
248 def CheckParamBlob(self):
249 cur = self.con.cursor()
Guido van Rossumbae07c92007-10-08 02:46:15 +0000250 cur.execute("select isblob(?)", (memoryview(b"blob"),))
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000251 val = cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000252 self.assertEqual(val, 1)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000253
Petri Lehtinen4fe85ab2012-02-19 21:38:00 +0200254 def CheckParamLongLong(self):
255 cur = self.con.cursor()
256 cur.execute("select islonglong(?)", (1<<42,))
257 val = cur.fetchone()[0]
258 self.assertEqual(val, 1)
259
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000260class AggregateTests(unittest.TestCase):
261 def setUp(self):
262 self.con = sqlite.connect(":memory:")
263 cur = self.con.cursor()
264 cur.execute("""
265 create table test(
266 t text,
267 i integer,
268 f float,
269 n,
270 b blob
271 )
272 """)
273 cur.execute("insert into test(t, i, f, n, b) values (?, ?, ?, ?, ?)",
Guido van Rossumbae07c92007-10-08 02:46:15 +0000274 ("foo", 5, 3.14, None, memoryview(b"blob"),))
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000275
276 self.con.create_aggregate("nostep", 1, AggrNoStep)
277 self.con.create_aggregate("nofinalize", 1, AggrNoFinalize)
278 self.con.create_aggregate("excInit", 1, AggrExceptionInInit)
279 self.con.create_aggregate("excStep", 1, AggrExceptionInStep)
280 self.con.create_aggregate("excFinalize", 1, AggrExceptionInFinalize)
281 self.con.create_aggregate("checkType", 2, AggrCheckType)
282 self.con.create_aggregate("mysum", 1, AggrSum)
283
284 def tearDown(self):
285 #self.cur.close()
286 #self.con.close()
287 pass
288
Thomas Wouters477c8d52006-05-27 19:21:47 +0000289 def CheckAggrErrorOnCreate(self):
290 try:
291 self.con.create_function("bla", -100, AggrSum)
292 self.fail("should have raised an OperationalError")
293 except sqlite.OperationalError:
294 pass
295
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000296 def CheckAggrNoStep(self):
297 cur = self.con.cursor()
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000298 try:
299 cur.execute("select nostep(t) from test")
300 self.fail("should have raised an AttributeError")
Guido van Rossumb940e112007-01-10 16:19:56 +0000301 except AttributeError as e:
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000302 self.assertEqual(e.args[0], "'AggrNoStep' object has no attribute 'step'")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000303
304 def CheckAggrNoFinalize(self):
305 cur = self.con.cursor()
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000306 try:
307 cur.execute("select nofinalize(t) from test")
308 val = cur.fetchone()[0]
309 self.fail("should have raised an OperationalError")
Guido van Rossumb940e112007-01-10 16:19:56 +0000310 except sqlite.OperationalError as e:
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000311 self.assertEqual(e.args[0], "user-defined aggregate's 'finalize' method raised error")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000312
313 def CheckAggrExceptionInInit(self):
314 cur = self.con.cursor()
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000315 try:
316 cur.execute("select excInit(t) from test")
317 val = cur.fetchone()[0]
318 self.fail("should have raised an OperationalError")
Guido van Rossumb940e112007-01-10 16:19:56 +0000319 except sqlite.OperationalError as e:
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000320 self.assertEqual(e.args[0], "user-defined aggregate's '__init__' method raised error")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000321
322 def CheckAggrExceptionInStep(self):
323 cur = self.con.cursor()
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000324 try:
325 cur.execute("select excStep(t) from test")
326 val = cur.fetchone()[0]
327 self.fail("should have raised an OperationalError")
Guido van Rossumb940e112007-01-10 16:19:56 +0000328 except sqlite.OperationalError as e:
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000329 self.assertEqual(e.args[0], "user-defined aggregate's 'step' method raised error")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000330
331 def CheckAggrExceptionInFinalize(self):
332 cur = self.con.cursor()
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000333 try:
334 cur.execute("select excFinalize(t) from test")
335 val = cur.fetchone()[0]
336 self.fail("should have raised an OperationalError")
Guido van Rossumb940e112007-01-10 16:19:56 +0000337 except sqlite.OperationalError as e:
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000338 self.assertEqual(e.args[0], "user-defined aggregate's 'finalize' method raised error")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000339
340 def CheckAggrCheckParamStr(self):
341 cur = self.con.cursor()
342 cur.execute("select checkType('str', ?)", ("foo",))
343 val = cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000344 self.assertEqual(val, 1)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000345
346 def CheckAggrCheckParamInt(self):
347 cur = self.con.cursor()
348 cur.execute("select checkType('int', ?)", (42,))
349 val = cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000350 self.assertEqual(val, 1)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000351
352 def CheckAggrCheckParamFloat(self):
353 cur = self.con.cursor()
354 cur.execute("select checkType('float', ?)", (3.14,))
355 val = cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000356 self.assertEqual(val, 1)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000357
358 def CheckAggrCheckParamNone(self):
359 cur = self.con.cursor()
360 cur.execute("select checkType('None', ?)", (None,))
361 val = cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000362 self.assertEqual(val, 1)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000363
364 def CheckAggrCheckParamBlob(self):
365 cur = self.con.cursor()
Guido van Rossumbae07c92007-10-08 02:46:15 +0000366 cur.execute("select checkType('blob', ?)", (memoryview(b"blob"),))
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000367 val = cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000368 self.assertEqual(val, 1)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000369
370 def CheckAggrCheckAggrSum(self):
371 cur = self.con.cursor()
372 cur.execute("delete from test")
373 cur.executemany("insert into test(i) values (?)", [(10,), (20,), (30,)])
374 cur.execute("select mysum(i) from test")
375 val = cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000376 self.assertEqual(val, 60)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000377
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000378def authorizer_cb(action, arg1, arg2, dbname, source):
379 if action != sqlite.SQLITE_SELECT:
380 return sqlite.SQLITE_DENY
381 if arg2 == 'c2' or arg1 == 't2':
382 return sqlite.SQLITE_DENY
383 return sqlite.SQLITE_OK
384
385class AuthorizerTests(unittest.TestCase):
386 def setUp(self):
387 self.con = sqlite.connect(":memory:")
388 self.con.executescript("""
389 create table t1 (c1, c2);
390 create table t2 (c1, c2);
391 insert into t1 (c1, c2) values (1, 2);
392 insert into t2 (c1, c2) values (4, 5);
393 """)
394
395 # For our security test:
396 self.con.execute("select c2 from t2")
397
398 self.con.set_authorizer(authorizer_cb)
399
400 def tearDown(self):
401 pass
402
403 def CheckTableAccess(self):
404 try:
405 self.con.execute("select * from t2")
Guido van Rossumb940e112007-01-10 16:19:56 +0000406 except sqlite.DatabaseError as e:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000407 if not e.args[0].endswith("prohibited"):
408 self.fail("wrong exception text: %s" % e.args[0])
409 return
410 self.fail("should have raised an exception due to missing privileges")
411
412 def CheckColumnAccess(self):
413 try:
414 self.con.execute("select c2 from t1")
Guido van Rossumb940e112007-01-10 16:19:56 +0000415 except sqlite.DatabaseError as e:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000416 if not e.args[0].endswith("prohibited"):
417 self.fail("wrong exception text: %s" % e.args[0])
418 return
419 self.fail("should have raised an exception due to missing privileges")
420
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000421def suite():
422 function_suite = unittest.makeSuite(FunctionTests, "Check")
423 aggregate_suite = unittest.makeSuite(AggregateTests, "Check")
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000424 authorizer_suite = unittest.makeSuite(AuthorizerTests, "Check")
425 return unittest.TestSuite((function_suite, aggregate_suite, authorizer_suite))
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000426
427def test():
428 runner = unittest.TextTestRunner()
429 runner.run(suite())
430
431if __name__ == "__main__":
432 test()