userfunctions.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. #-*- coding: ISO-8859-1 -*-
  2. # pysqlite2/test/userfunctions.py: tests for user-defined functions and
  3. # aggregates.
  4. #
  5. # Copyright (C) 2005-2007 Gerhard Häring <gh@ghaering.de>
  6. #
  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. import unittest
  25. import pysqlcipher.dbapi2 as sqlite
  26. def func_returntext():
  27. return "foo"
  28. def func_returnunicode():
  29. return u"bar"
  30. def func_returnint():
  31. return 42
  32. def func_returnfloat():
  33. return 3.14
  34. def func_returnnull():
  35. return None
  36. def func_returnblob():
  37. return buffer("blob")
  38. def func_raiseexception():
  39. 5 // 0
  40. def func_isstring(v):
  41. return type(v) is unicode
  42. def func_isint(v):
  43. return type(v) is int
  44. def func_isfloat(v):
  45. return type(v) is float
  46. def func_isnone(v):
  47. return type(v) is type(None)
  48. def func_isblob(v):
  49. return type(v) is buffer
  50. class AggrNoStep:
  51. def __init__(self):
  52. pass
  53. def finalize(self):
  54. return 1
  55. class AggrNoFinalize:
  56. def __init__(self):
  57. pass
  58. def step(self, x):
  59. pass
  60. class AggrExceptionInInit:
  61. def __init__(self):
  62. 5 // 0
  63. def step(self, x):
  64. pass
  65. def finalize(self):
  66. pass
  67. class AggrExceptionInStep:
  68. def __init__(self):
  69. pass
  70. def step(self, x):
  71. 5 // 0
  72. def finalize(self):
  73. return 42
  74. class AggrExceptionInFinalize:
  75. def __init__(self):
  76. pass
  77. def step(self, x):
  78. pass
  79. def finalize(self):
  80. 5 // 0
  81. class AggrCheckType:
  82. def __init__(self):
  83. self.val = None
  84. def step(self, whichType, val):
  85. theType = {"str": unicode, "int": int, "float": float, "None": type(None), "blob": buffer}
  86. self.val = int(theType[whichType] is type(val))
  87. def finalize(self):
  88. return self.val
  89. class AggrSum:
  90. def __init__(self):
  91. self.val = 0.0
  92. def step(self, val):
  93. self.val += val
  94. def finalize(self):
  95. return self.val
  96. class FunctionTests(unittest.TestCase):
  97. def setUp(self):
  98. self.con = sqlite.connect(":memory:")
  99. self.con.create_function("returntext", 0, func_returntext)
  100. self.con.create_function("returnunicode", 0, func_returnunicode)
  101. self.con.create_function("returnint", 0, func_returnint)
  102. self.con.create_function("returnfloat", 0, func_returnfloat)
  103. self.con.create_function("returnnull", 0, func_returnnull)
  104. self.con.create_function("returnblob", 0, func_returnblob)
  105. self.con.create_function("raiseexception", 0, func_raiseexception)
  106. self.con.create_function("isstring", 1, func_isstring)
  107. self.con.create_function("isint", 1, func_isint)
  108. self.con.create_function("isfloat", 1, func_isfloat)
  109. self.con.create_function("isnone", 1, func_isnone)
  110. self.con.create_function("isblob", 1, func_isblob)
  111. def tearDown(self):
  112. self.con.close()
  113. def CheckFuncErrorOnCreate(self):
  114. try:
  115. self.con.create_function("bla", -100, lambda x: 2*x)
  116. self.fail("should have raised an OperationalError")
  117. except sqlite.OperationalError:
  118. pass
  119. def CheckFuncRefCount(self):
  120. def getfunc():
  121. def f():
  122. return 1
  123. return f
  124. f = getfunc()
  125. globals()["foo"] = f
  126. # self.con.create_function("reftest", 0, getfunc())
  127. self.con.create_function("reftest", 0, f)
  128. cur = self.con.cursor()
  129. cur.execute("select reftest()")
  130. def CheckFuncReturnText(self):
  131. cur = self.con.cursor()
  132. cur.execute("select returntext()")
  133. val = cur.fetchone()[0]
  134. self.assertEqual(type(val), unicode)
  135. self.assertEqual(val, "foo")
  136. def CheckFuncReturnUnicode(self):
  137. cur = self.con.cursor()
  138. cur.execute("select returnunicode()")
  139. val = cur.fetchone()[0]
  140. self.assertEqual(type(val), unicode)
  141. self.assertEqual(val, u"bar")
  142. def CheckFuncReturnInt(self):
  143. cur = self.con.cursor()
  144. cur.execute("select returnint()")
  145. val = cur.fetchone()[0]
  146. self.assertEqual(type(val), int)
  147. self.assertEqual(val, 42)
  148. def CheckFuncReturnFloat(self):
  149. cur = self.con.cursor()
  150. cur.execute("select returnfloat()")
  151. val = cur.fetchone()[0]
  152. self.assertEqual(type(val), float)
  153. if val < 3.139 or val > 3.141:
  154. self.fail("wrong value")
  155. def CheckFuncReturnNull(self):
  156. cur = self.con.cursor()
  157. cur.execute("select returnnull()")
  158. val = cur.fetchone()[0]
  159. self.assertEqual(type(val), type(None))
  160. self.assertEqual(val, None)
  161. def CheckFuncReturnBlob(self):
  162. cur = self.con.cursor()
  163. cur.execute("select returnblob()")
  164. val = cur.fetchone()[0]
  165. self.assertEqual(type(val), buffer)
  166. self.assertEqual(val, buffer("blob"))
  167. def CheckFuncException(self):
  168. cur = self.con.cursor()
  169. try:
  170. cur.execute("select raiseexception()")
  171. cur.fetchone()
  172. self.fail("should have raised OperationalError")
  173. except sqlite.OperationalError, e:
  174. self.assertEqual(e.args[0], 'user-defined function raised exception')
  175. def CheckParamString(self):
  176. cur = self.con.cursor()
  177. cur.execute("select isstring(?)", ("foo",))
  178. val = cur.fetchone()[0]
  179. self.assertEqual(val, 1)
  180. def CheckParamInt(self):
  181. cur = self.con.cursor()
  182. cur.execute("select isint(?)", (42,))
  183. val = cur.fetchone()[0]
  184. self.assertEqual(val, 1)
  185. def CheckParamFloat(self):
  186. cur = self.con.cursor()
  187. cur.execute("select isfloat(?)", (3.14,))
  188. val = cur.fetchone()[0]
  189. self.assertEqual(val, 1)
  190. def CheckParamNone(self):
  191. cur = self.con.cursor()
  192. cur.execute("select isnone(?)", (None,))
  193. val = cur.fetchone()[0]
  194. self.assertEqual(val, 1)
  195. def CheckParamBlob(self):
  196. cur = self.con.cursor()
  197. cur.execute("select isblob(?)", (buffer("blob"),))
  198. val = cur.fetchone()[0]
  199. self.assertEqual(val, 1)
  200. class AggregateTests(unittest.TestCase):
  201. def setUp(self):
  202. self.con = sqlite.connect(":memory:")
  203. cur = self.con.cursor()
  204. cur.execute("""
  205. create table test(
  206. t text,
  207. i integer,
  208. f float,
  209. n,
  210. b blob
  211. )
  212. """)
  213. cur.execute("insert into test(t, i, f, n, b) values (?, ?, ?, ?, ?)",
  214. ("foo", 5, 3.14, None, buffer("blob"),))
  215. self.con.create_aggregate("nostep", 1, AggrNoStep)
  216. self.con.create_aggregate("nofinalize", 1, AggrNoFinalize)
  217. self.con.create_aggregate("excInit", 1, AggrExceptionInInit)
  218. self.con.create_aggregate("excStep", 1, AggrExceptionInStep)
  219. self.con.create_aggregate("excFinalize", 1, AggrExceptionInFinalize)
  220. self.con.create_aggregate("checkType", 2, AggrCheckType)
  221. self.con.create_aggregate("mysum", 1, AggrSum)
  222. def tearDown(self):
  223. #self.cur.close()
  224. #self.con.close()
  225. pass
  226. def CheckAggrErrorOnCreate(self):
  227. try:
  228. self.con.create_function("bla", -100, AggrSum)
  229. self.fail("should have raised an OperationalError")
  230. except sqlite.OperationalError:
  231. pass
  232. def CheckAggrNoStep(self):
  233. cur = self.con.cursor()
  234. try:
  235. cur.execute("select nostep(t) from test")
  236. self.fail("should have raised an AttributeError")
  237. except AttributeError, e:
  238. self.assertEqual(e.args[0], "AggrNoStep instance has no attribute 'step'")
  239. def CheckAggrNoFinalize(self):
  240. cur = self.con.cursor()
  241. try:
  242. cur.execute("select nofinalize(t) from test")
  243. val = cur.fetchone()[0]
  244. self.fail("should have raised an OperationalError")
  245. except sqlite.OperationalError, e:
  246. self.assertEqual(e.args[0], "user-defined aggregate's 'finalize' method raised error")
  247. def CheckAggrExceptionInInit(self):
  248. cur = self.con.cursor()
  249. try:
  250. cur.execute("select excInit(t) from test")
  251. val = cur.fetchone()[0]
  252. self.fail("should have raised an OperationalError")
  253. except sqlite.OperationalError, e:
  254. self.assertEqual(e.args[0], "user-defined aggregate's '__init__' method raised error")
  255. def CheckAggrExceptionInStep(self):
  256. cur = self.con.cursor()
  257. try:
  258. cur.execute("select excStep(t) from test")
  259. val = cur.fetchone()[0]
  260. self.fail("should have raised an OperationalError")
  261. except sqlite.OperationalError, e:
  262. self.assertEqual(e.args[0], "user-defined aggregate's 'step' method raised error")
  263. def CheckAggrExceptionInFinalize(self):
  264. cur = self.con.cursor()
  265. try:
  266. cur.execute("select excFinalize(t) from test")
  267. val = cur.fetchone()[0]
  268. self.fail("should have raised an OperationalError")
  269. except sqlite.OperationalError, e:
  270. self.assertEqual(e.args[0], "user-defined aggregate's 'finalize' method raised error")
  271. def CheckAggrCheckParamStr(self):
  272. cur = self.con.cursor()
  273. cur.execute("select checkType('str', ?)", ("foo",))
  274. val = cur.fetchone()[0]
  275. self.assertEqual(val, 1)
  276. def CheckAggrCheckParamInt(self):
  277. cur = self.con.cursor()
  278. cur.execute("select checkType('int', ?)", (42,))
  279. val = cur.fetchone()[0]
  280. self.assertEqual(val, 1)
  281. def CheckAggrCheckParamFloat(self):
  282. cur = self.con.cursor()
  283. cur.execute("select checkType('float', ?)", (3.14,))
  284. val = cur.fetchone()[0]
  285. self.assertEqual(val, 1)
  286. def CheckAggrCheckParamNone(self):
  287. cur = self.con.cursor()
  288. cur.execute("select checkType('None', ?)", (None,))
  289. val = cur.fetchone()[0]
  290. self.assertEqual(val, 1)
  291. def CheckAggrCheckParamBlob(self):
  292. cur = self.con.cursor()
  293. cur.execute("select checkType('blob', ?)", (buffer("blob"),))
  294. val = cur.fetchone()[0]
  295. self.assertEqual(val, 1)
  296. def CheckAggrCheckAggrSum(self):
  297. cur = self.con.cursor()
  298. cur.execute("delete from test")
  299. cur.executemany("insert into test(i) values (?)", [(10,), (20,), (30,)])
  300. cur.execute("select mysum(i) from test")
  301. val = cur.fetchone()[0]
  302. self.assertEqual(val, 60)
  303. def authorizer_cb(action, arg1, arg2, dbname, source):
  304. if action != sqlite.SQLITE_SELECT:
  305. return sqlite.SQLITE_DENY
  306. if arg2 == 'c2' or arg1 == 't2':
  307. return sqlite.SQLITE_DENY
  308. return sqlite.SQLITE_OK
  309. class AuthorizerTests(unittest.TestCase):
  310. def setUp(self):
  311. self.con = sqlite.connect(":memory:")
  312. self.con.executescript("""
  313. create table t1 (c1, c2);
  314. create table t2 (c1, c2);
  315. insert into t1 (c1, c2) values (1, 2);
  316. insert into t2 (c1, c2) values (4, 5);
  317. """)
  318. # For our security test:
  319. self.con.execute("select c2 from t2")
  320. self.con.set_authorizer(authorizer_cb)
  321. def tearDown(self):
  322. pass
  323. def CheckTableAccess(self):
  324. try:
  325. self.con.execute("select * from t2")
  326. except sqlite.DatabaseError, e:
  327. if not e.args[0].endswith("prohibited"):
  328. self.fail("wrong exception text: %s" % e.args[0])
  329. return
  330. self.fail("should have raised an exception due to missing privileges")
  331. def CheckColumnAccess(self):
  332. try:
  333. self.con.execute("select c2 from t1")
  334. except sqlite.DatabaseError, e:
  335. if not e.args[0].endswith("prohibited"):
  336. self.fail("wrong exception text: %s" % e.args[0])
  337. return
  338. self.fail("should have raised an exception due to missing privileges")
  339. def suite():
  340. function_suite = unittest.makeSuite(FunctionTests, "Check")
  341. aggregate_suite = unittest.makeSuite(AggregateTests, "Check")
  342. authorizer_suite = unittest.makeSuite(AuthorizerTests, "Check")
  343. return unittest.TestSuite((function_suite, aggregate_suite, authorizer_suite))
  344. def test():
  345. runner = unittest.TextTestRunner()
  346. runner.run(suite())
  347. if __name__ == "__main__":
  348. test()