@@ -44,22 +44,6 @@ def func_returnlonglong():
44
44
def func_raiseexception ():
45
45
5 / 0
46
46
47
- def func_isstring (v ):
48
- return type (v ) is str
49
- def func_isint (v ):
50
- return type (v ) is int
51
- def func_isfloat (v ):
52
- return type (v ) is float
53
- def func_isnone (v ):
54
- return type (v ) is type (None )
55
- def func_isblob (v ):
56
- return isinstance (v , (bytes , memoryview ))
57
- def func_islonglong (v ):
58
- return isinstance (v , int ) and v >= 1 << 31
59
-
60
- def func (* args ):
61
- return len (args )
62
-
63
47
class AggrNoStep :
64
48
def __init__ (self ):
65
49
pass
@@ -160,15 +144,13 @@ def setUp(self):
160
144
self .con .create_function ("returnnull" , 0 , func_returnnull )
161
145
self .con .create_function ("returnblob" , 0 , func_returnblob )
162
146
self .con .create_function ("returnlonglong" , 0 , func_returnlonglong )
147
+ self .con .create_function ("returnnan" , 0 , lambda : float ("nan" ))
148
+ self .con .create_function ("returntoolargeint" , 0 , lambda : 1 << 65 )
163
149
self .con .create_function ("raiseexception" , 0 , func_raiseexception )
164
150
165
- self .con .create_function ("isstring" , 1 , func_isstring )
166
- self .con .create_function ("isint" , 1 , func_isint )
167
- self .con .create_function ("isfloat" , 1 , func_isfloat )
168
- self .con .create_function ("isnone" , 1 , func_isnone )
169
- self .con .create_function ("isblob" , 1 , func_isblob )
170
- self .con .create_function ("islonglong" , 1 , func_islonglong )
171
- self .con .create_function ("spam" , - 1 , func )
151
+ self .con .create_function ("isblob" , 1 , lambda x : isinstance (x , bytes ))
152
+ self .con .create_function ("isnone" , 1 , lambda x : x is None )
153
+ self .con .create_function ("spam" , - 1 , lambda * x : len (x ))
172
154
self .con .execute ("create table test(t text)" )
173
155
174
156
def tearDown (self ):
@@ -245,57 +227,79 @@ def CheckFuncReturnLongLong(self):
245
227
val = cur .fetchone ()[0 ]
246
228
self .assertEqual (val , 1 << 31 )
247
229
230
+ def CheckFuncReturnNaN (self ):
231
+ cur = self .con .cursor ()
232
+ cur .execute ("select returnnan()" )
233
+ self .assertIsNone (cur .fetchone ()[0 ])
234
+
235
+ def CheckFuncReturnTooLargeInt (self ):
236
+ cur = self .con .cursor ()
237
+ with self .assertRaises (sqlite .OperationalError ):
238
+ self .con .execute ("select returntoolargeint()" )
239
+
248
240
def CheckFuncException (self ):
249
241
cur = self .con .cursor ()
250
242
with self .assertRaises (sqlite .OperationalError ) as cm :
251
243
cur .execute ("select raiseexception()" )
252
244
cur .fetchone ()
253
245
self .assertEqual (str (cm .exception ), 'user-defined function raised exception' )
254
246
255
- def CheckParamString (self ):
256
- cur = self .con .cursor ()
257
- for text in ["foo" , str ()]:
258
- with self .subTest (text = text ):
259
- cur .execute ("select isstring(?)" , (text ,))
260
- val = cur .fetchone ()[0 ]
261
- self .assertEqual (val , 1 )
262
-
263
- def CheckParamInt (self ):
264
- cur = self .con .cursor ()
265
- cur .execute ("select isint(?)" , (42 ,))
266
- val = cur .fetchone ()[0 ]
267
- self .assertEqual (val , 1 )
268
-
269
- def CheckParamFloat (self ):
270
- cur = self .con .cursor ()
271
- cur .execute ("select isfloat(?)" , (3.14 ,))
272
- val = cur .fetchone ()[0 ]
273
- self .assertEqual (val , 1 )
274
-
275
- def CheckParamNone (self ):
276
- cur = self .con .cursor ()
277
- cur .execute ("select isnone(?)" , (None ,))
278
- val = cur .fetchone ()[0 ]
279
- self .assertEqual (val , 1 )
280
-
281
- def CheckParamBlob (self ):
282
- cur = self .con .cursor ()
283
- cur .execute ("select isblob(?)" , (memoryview (b"blob" ),))
284
- val = cur .fetchone ()[0 ]
285
- self .assertEqual (val , 1 )
286
-
287
- def CheckParamLongLong (self ):
288
- cur = self .con .cursor ()
289
- cur .execute ("select islonglong(?)" , (1 << 42 ,))
290
- val = cur .fetchone ()[0 ]
291
- self .assertEqual (val , 1 )
292
-
293
247
def CheckAnyArguments (self ):
294
248
cur = self .con .cursor ()
295
249
cur .execute ("select spam(?, ?)" , (1 , 2 ))
296
250
val = cur .fetchone ()[0 ]
297
251
self .assertEqual (val , 2 )
298
252
253
+ def CheckEmptyBlob (self ):
254
+ cur = self .con .execute ("select isblob(x'')" )
255
+ self .assertTrue (cur .fetchone ()[0 ])
256
+
257
+ def CheckNaNFloat (self ):
258
+ cur = self .con .execute ("select isnone(?)" , (float ("nan" ),))
259
+ # SQLite has no concept of nan; it is converted to NULL
260
+ self .assertTrue (cur .fetchone ()[0 ])
261
+
262
+ def CheckTooLargeInt (self ):
263
+ err = "Python int too large to convert to SQLite INTEGER"
264
+ self .assertRaisesRegex (OverflowError , err , self .con .execute ,
265
+ "select spam(?)" , (1 << 65 ,))
266
+
267
+ def CheckNonContiguousBlob (self ):
268
+ self .assertRaisesRegex (ValueError , "could not convert BLOB to buffer" ,
269
+ self .con .execute , "select spam(?)" ,
270
+ (memoryview (b"blob" )[::2 ],))
271
+
272
+ def CheckParamSurrogates (self ):
273
+ self .assertRaisesRegex (UnicodeEncodeError , "surrogates not allowed" ,
274
+ self .con .execute , "select spam(?)" ,
275
+ ("\ud803 \ude6d " ,))
276
+
277
+ def CheckFuncParams (self ):
278
+ results = []
279
+ def append_result (arg ):
280
+ results .append ((arg , type (arg )))
281
+ self .con .create_function ("test_params" , 1 , append_result )
282
+
283
+ dataset = [
284
+ (42 , int ),
285
+ (- 1 , int ),
286
+ (1234567890123456789 , int ),
287
+ (4611686018427387905 , int ), # 63-bit int with non-zero low bits
288
+ (3.14 , float ),
289
+ (float ('inf' ), float ),
290
+ ("text" , str ),
291
+ ("1\x00 2" , str ),
292
+ ("\u02e2 q\u02e1 \u2071 \u1d57 \u1d49 " , str ),
293
+ (b"blob" , bytes ),
294
+ (bytearray (range (2 )), bytes ),
295
+ (memoryview (b"blob" ), bytes ),
296
+ (None , type (None )),
297
+ ]
298
+ for val , _ in dataset :
299
+ cur = self .con .execute ("select test_params(?)" , (val ,))
300
+ cur .fetchone ()
301
+ self .assertEqual (dataset , results )
302
+
299
303
# Regarding deterministic functions:
300
304
#
301
305
# Between 3.8.3 and 3.15.0, deterministic functions were only used to
0 commit comments