~ubuntu-branches/ubuntu/lucid/python-apsw/lucid

« back to all changes in this revision

Viewing changes to tests.py

  • Committer: Bazaar Package Importer
  • Author(s): Joel Rosdahl
  • Date: 2008-07-07 20:24:11 UTC
  • mfrom: (1.1.5 upstream) (3.1.1 lenny)
  • Revision ID: james.westby@ubuntu.com-20080707202411-612ylo5p89y9ilvi
Tags: 3.5.9-r2-1
* New upstream release.
* Build dependency on libsqlite3-dev 3.5.9.
* Updated Standards-Version to 3.8.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
#!/usr/bin/env python
2
2
 
3
 
# APSW test suite
 
3
# APSW test suite - runs under both Python 2 and Python 3 hence a lot
 
4
# of wierd constructs to be simultaneously compatible with both.
 
5
# (2to3 is not used).
4
6
 
5
7
import apsw
6
 
 
7
 
print "Testing with APSW file",apsw.__file__
8
 
print "          APSW version",apsw.apswversion()
9
 
print "    SQLite lib version",apsw.sqlitelibversion()
10
 
print "SQLite headers version",apsw.SQLITE_VERSION_NUMBER
11
 
 
12
 
if [int(x) for x in apsw.sqlitelibversion().split(".")]<[3,3,7]:
13
 
    print "You are using an earlier version of SQLite than recommended"
 
8
import sys
 
9
 
 
10
write=sys.stdout.write
 
11
write("                Python "+sys.executable+" "+str(sys.version_info)+"\n")
 
12
write("Testing with APSW file "+apsw.__file__+"\n")
 
13
write("          APSW version "+apsw.apswversion()+"\n")
 
14
write("    SQLite lib version "+apsw.sqlitelibversion()+"\n")
 
15
write("SQLite headers version "+str(apsw.SQLITE_VERSION_NUMBER)+"\n")
 
16
 
 
17
if [int(x) for x in apsw.sqlitelibversion().split(".")]<[3,5,9]:
 
18
    write("You are using an earlier version of SQLite than recommended\n")
 
19
 
 
20
sys.stdout.flush()
 
21
 
 
22
py3=sys.version_info>=(3,0)
14
23
 
15
24
# unittest stuff from here on
16
25
 
17
26
import unittest
18
27
import os
19
 
import sys
20
28
import math
21
29
import random
22
30
import time
23
31
import threading
24
 
import Queue
 
32
if py3:
 
33
    import queue as Queue
 
34
else:
 
35
    import Queue
25
36
import traceback
26
 
import StringIO
 
37
import re
 
38
import gc
 
39
 
 
40
# Unicode string/bytes prefix
 
41
if py3:
 
42
    UPREFIX=""
 
43
    BPREFIX="b"
 
44
else:
 
45
    UPREFIX="u"
 
46
    BPREFIX=""
 
47
# Return a unicode string - x should have been raw
 
48
def u(x):
 
49
    return eval(UPREFIX+"'''"+x+"'''")
 
50
 
 
51
# Return a bytes (py3)/buffer (py2) - x should have been raw
 
52
def b(x):
 
53
    if py3:
 
54
        return eval(BPREFIX+"'''"+x+"'''")
 
55
    return eval("buffer('''"+x+"''')")
 
56
 
 
57
# return bytes (py3)/string (py2) - x should have been raw
 
58
# Use this instead of b for file i/o data as py2 uses str
 
59
def BYTES(x):
 
60
    if py3: return b(x)
 
61
    return eval("'''"+x+"'''")
 
62
 
 
63
def l(x):
 
64
    if py3: return eval(x)
 
65
    return eval(x+"L")
 
66
 
 
67
# Various py3 things
 
68
if py3:
 
69
    long=int
 
70
 
 
71
if not py3:
 
72
    # emulation of py3 next built-in.  In py2 the iternext method is exposed
 
73
    # as object.next() but in py3 it is object.__next__().
 
74
    def next(iterator, *args):
 
75
        if len(args)>1:
 
76
            raise TypeError("bad args")
 
77
        try:
 
78
            return iterator.next()
 
79
        except StopIteration:
 
80
            if len(args):
 
81
                return args[0]
 
82
            raise
 
83
            
27
84
 
28
85
# helper functions
29
86
def randomintegers(howmany):
30
 
    for i in xrange(howmany):
 
87
    for i in range(howmany):
31
88
        yield (random.randint(0,9999999999),)
32
89
 
 
90
# An instance of this class is used to get the -1 return value to the
 
91
# C api PyObject_IsTrue
 
92
class BadIsTrue(int):
 
93
    # py2 does this
 
94
    def __nonzero__(self):
 
95
        1/0
 
96
    # py3 does this
 
97
    def __bool__(self):
 
98
        1/0
 
99
 
33
100
# helper class - runs code in a seperate thread
34
101
class ThreadRunner(threading.Thread):
35
102
 
36
103
    def __init__(self, callable, *args, **kwargs):
37
104
        threading.Thread.__init__(self)
38
 
        self.setDaemon(True)
 
105
        if py3:
 
106
            self.set_daemon(True)
 
107
        else:
 
108
            self.setDaemon(True)
39
109
        self.callable=callable
40
110
        self.args=args
41
111
        self.kwargs=kwargs
42
112
        self.q=Queue.Queue()
 
113
        self.started=False
 
114
 
 
115
    def start(self):
 
116
        if not self.started:
 
117
            self.started=True
 
118
            threading.Thread.start(self)
43
119
 
44
120
    def go(self):
45
121
        self.start()
47
123
        if t: # result
48
124
            return res
49
125
        else: # exception
50
 
            raise res[0], res[1], res[2]
 
126
            if py3:
 
127
                exec("raise res[1].with_traceback(res[2])")
 
128
            else:
 
129
                exec("raise res[0], res[1], res[2]")
51
130
 
52
131
    def run(self):
53
132
        try:
55
134
        except:
56
135
            self.q.put( (False, sys.exc_info()) )
57
136
 
58
 
 
59
137
# main test class/code
60
138
class APSW(unittest.TestCase):
61
139
 
65
143
        'complete': 1,
66
144
        'createcollation': 2,
67
145
        'createscalarfunction': 2,
 
146
        'collationneeded': 1,
68
147
        'setauthorizer': 1,
69
148
        'setbusyhandler': 1,
70
149
        'setbusytimeout': 1,
78
157
        }
79
158
 
80
159
    cursor_nargs={
81
 
            'execute': 1,
82
 
            'executemany': 2,
83
 
            'setexectrace': 1,
84
 
            'setrowtrace': 1,
85
 
            }
 
160
        'execute': 1,
 
161
        'executemany': 2,
 
162
        'setexectrace': 1,
 
163
        'setrowtrace': 1,
 
164
        }
 
165
 
 
166
    blob_nargs={
 
167
        'write': 1,
 
168
        'read': 1,
 
169
        'seek': 2
 
170
        }
86
171
 
87
172
    
88
173
    def setUp(self, dbname="testdb"):
99
184
        self.db.close(True)
100
185
        del self.db
101
186
        apsw.connection_hooks=[] # back to default value
 
187
        gc.collect()
102
188
 
103
189
    def assertTableExists(self, tablename):
104
 
        self.failUnlessEqual(self.db.cursor().execute("select count(*) from ["+tablename+"]").next()[0], 0)
 
190
        self.failUnlessEqual(next(self.db.cursor().execute("select count(*) from ["+tablename+"]"))[0], 0)
105
191
 
106
192
    def assertTableNotExists(self, tablename):
107
193
        # you get SQLError if the table doesn't exist!
118
204
        apsw.ExecTraceAbort
119
205
 
120
206
    def testConnection(self):
121
 
        "Test connection basics"
122
 
        # keyword args are not allowed
 
207
        "Test connection opening"
 
208
        # bad keyword arg
123
209
        self.assertRaises(TypeError, apsw.Connection, ":memory:", user="nobody")
124
 
        # too many arguments
125
 
        self.assertRaises(TypeError, apsw.Connection, ":memory:", 7)
126
210
        # wrong types
127
211
        self.assertRaises(TypeError, apsw.Connection, 3)
128
212
        # non-unicode
129
 
        self.assertRaises(UnicodeDecodeError, apsw.Connection, "\xef\x22\xd3\x9e")
 
213
        if not py3:
 
214
            self.assertRaises(UnicodeDecodeError, apsw.Connection, "\xef\x22\xd3\x9e")
130
215
        # bad file (cwd)
131
216
        self.assertRaises(apsw.CantOpenError, apsw.Connection, ".")
 
217
        # bad open flags can't be tested as sqlite accepts them all - ticket #3037
 
218
        # self.assertRaises(apsw.CantOpenError, apsw.Connection, "<non-existent-file>", flags=65535)
 
219
 
 
220
        # bad vfs
 
221
        self.assertRaises(TypeError, apsw.Connection, "foo", vfs=3, flags=-1)
 
222
        self.assertRaises(apsw.SQLError, apsw.Connection, "foo", vfs="jhjkds", flags=-1)
132
223
 
133
224
    def testMemoryLeaks(self):
134
225
        "MemoryLeaks: Run with a memory profiler such as valgrind and debug Python"
136
227
        # simple memory leaks will show up
137
228
        c=self.db.cursor()
138
229
        c.execute("create table foo(x)")
139
 
        c.executemany("insert into foo values(?)", ( [1], [None], [math.pi], ["jkhfkjshdf"], [u"\u1234\u345432432423423kjgjklhdfgkjhsdfjkghdfjskh"],
140
 
                                                     [buffer("78696ghgjhgjhkgjkhgjhg\xfe\xdf")]))
141
 
        for i in xrange(MEMLEAKITERATIONS):
 
230
        vals=[ [1], [None], [math.pi], ["kjkljkljl"], [u(r"\u1234\u345432432423423kjgjklhdfgkjhsdfjkghdfjskh")],
 
231
               [b(r"78696ghgjhgjhkgjkhgjhg\xfe\xdf")] ]
 
232
        c.executemany("insert into foo values(?)", vals)
 
233
        for i in range(MEMLEAKITERATIONS):
142
234
            db=apsw.Connection("testdb")
143
235
            db.createaggregatefunction("aggfunc", lambda x: x)
144
236
            db.createscalarfunction("scalarfunc", lambda x: x)
147
239
            db.setcommithook(lambda x=1: 0)
148
240
            db.setrollbackhook(lambda x=2: 1)
149
241
            db.setupdatehook(lambda x=3: 2)
150
 
            for i in xrange(100):
 
242
            db.collationneeded(lambda x: 4)
 
243
            for i in range(100):
151
244
                c2=db.cursor()
152
245
                c2.setrowtrace(lambda x: (x,))
153
246
                c2.setexectrace(lambda x,y: True)
169
262
            ("(1,?,3)", (2,)),
170
263
            ("(1,$a,$c)", {'a': 2, 'b': 99, 'c': 3}),
171
264
            # some unicode fun
172
 
            (u"($\N{LATIN SMALL LETTER E WITH CIRCUMFLEX},:\N{LATIN SMALL LETTER A WITH TILDE},$\N{LATIN SMALL LETTER O WITH DIAERESIS})", (1,2,3)),
173
 
            (u"($\N{LATIN SMALL LETTER E WITH CIRCUMFLEX},:\N{LATIN SMALL LETTER A WITH TILDE},$\N{LATIN SMALL LETTER O WITH DIAERESIS})",
174
 
             {u"\N{LATIN SMALL LETTER E WITH CIRCUMFLEX}": 1,
175
 
              u"\N{LATIN SMALL LETTER A WITH TILDE}": 2,
176
 
              u"\N{LATIN SMALL LETTER O WITH DIAERESIS}": 3,
177
 
              }),
 
265
            (u(r"($\N{LATIN SMALL LETTER E WITH CIRCUMFLEX},:\N{LATIN SMALL LETTER A WITH TILDE},$\N{LATIN SMALL LETTER O WITH DIAERESIS})"), (1,2,3)),
 
266
            (u(r"($\N{LATIN SMALL LETTER E WITH CIRCUMFLEX},:\N{LATIN SMALL LETTER A WITH TILDE},$\N{LATIN SMALL LETTER O WITH DIAERESIS})"),
 
267
             {u(r"\N{LATIN SMALL LETTER E WITH CIRCUMFLEX}"): 1,
 
268
              u(r"\N{LATIN SMALL LETTER A WITH TILDE}"): 2,
 
269
              u(r"\N{LATIN SMALL LETTER O WITH DIAERESIS}"): 3,})
 
270
            )
178
271
              
179
 
            )
180
272
        for str,bindings in vals:
181
273
            c.execute("insert into foo values"+str, bindings)
182
 
            self.failUnlessEqual(c.execute("select * from foo").next(), (1,2,3))
 
274
            self.failUnlessEqual(next(c.execute("select * from foo")), (1,2,3))
183
275
            c.execute("delete from foo")
184
276
            
185
277
        # currently missing dict keys come out as null
186
278
        c.execute("insert into foo values(:a,:b,$c)", {'a': 1, 'c':3}) # 'b' deliberately missing
187
 
        self.failUnlessEqual((1,None,3), c.execute("select * from foo").next())
 
279
        self.failUnlessEqual((1,None,3), next(c.execute("select * from foo")))
188
280
        c.execute("delete from foo")
189
281
 
190
282
        # these ones should cause errors
207
299
        self.assertRaises(apsw.BindingsError, c.execute, "insert into foo values(?,?,?); insert into foo values(?,?,?)",
208
300
                          (101,100,101,1000,103,104,105)) # too many
209
301
        # check the relevant statements did or didn't execute as appropriate
210
 
        self.failUnlessEqual(self.db.cursor().execute("select count(*) from foo where x=99").next()[0], 1)
211
 
        self.failUnlessEqual(self.db.cursor().execute("select count(*) from foo where x=102").next()[0], 1)
212
 
        self.failUnlessEqual(self.db.cursor().execute("select count(*) from foo where x=100").next()[0], 1)
213
 
        self.failUnlessEqual(self.db.cursor().execute("select count(*) from foo where x=1000").next()[0], 0)
214
 
        self.failUnlessEqual(self.db.cursor().execute("select count(*) from foo where x=101").next()[0], 1)
215
 
        self.failUnlessEqual(self.db.cursor().execute("select count(*) from foo where x=105").next()[0], 0)
 
302
        self.failUnlessEqual(next(self.db.cursor().execute("select count(*) from foo where x=99"))[0], 1)
 
303
        self.failUnlessEqual(next(self.db.cursor().execute("select count(*) from foo where x=102"))[0], 1)
 
304
        self.failUnlessEqual(next(self.db.cursor().execute("select count(*) from foo where x=100"))[0], 1)
 
305
        self.failUnlessEqual(next(self.db.cursor().execute("select count(*) from foo where x=1000"))[0], 0)
 
306
        self.failUnlessEqual(next(self.db.cursor().execute("select count(*) from foo where x=101"))[0], 1)
 
307
        self.failUnlessEqual(next(self.db.cursor().execute("select count(*) from foo where x=105"))[0], 0)
216
308
 
217
309
        # check there are some bindings!
218
310
        self.assertRaises(apsw.BindingsError, c.execute, "create table bar(x,y,z);insert into bar values(?,?,?)")
221
313
        vals=( (1,2,3), (4,5,6), (7,8,9) )
222
314
        c.executemany("insert into foo values(?,?,?);", vals)
223
315
        for x,y,z in vals:
224
 
            self.failUnlessEqual(c.execute("select * from foo where x=?",(x,)).next(), (x,y,z))
 
316
            self.failUnlessEqual(next(c.execute("select * from foo where x=?",(x,))), (x,y,z))
225
317
 
226
318
        # with an iterator
227
319
        def myvals():
250
342
                yield {'a': i, 'b': i*10, 'c': i*100}
251
343
            1/0
252
344
        self.assertRaises(ZeroDivisionError, c.executemany, "insert into foo values($a,:b,$c)", myvals())
253
 
        self.failUnlessEqual(c.execute("select count(*) from foo").next()[0], 2)
 
345
        self.failUnlessEqual(next(c.execute("select count(*) from foo"))[0], 2)
254
346
        c.execute("delete from foo")
255
347
 
256
348
        # return bad type from iterator after a while
260
352
            yield self
261
353
 
262
354
        self.assertRaises(TypeError, c.executemany, "insert into foo values($a,:b,$c)", myvals())
263
 
        self.failUnlessEqual(c.execute("select count(*) from foo").next()[0], 2)
 
355
        self.failUnlessEqual(next(c.execute("select count(*) from foo"))[0], 2)
264
356
        c.execute("delete from foo")
265
357
 
266
358
        # some errors in executemany
283
375
    def testCursor(self):
284
376
        "Check functionality of the cursor"
285
377
        c=self.db.cursor()
 
378
        # shouldn't be able to manually create
 
379
        self.assertRaises(TypeError, type(c))
 
380
        
286
381
        # give bad params
287
382
        self.assertRaises(TypeError, c.execute)
288
383
        self.assertRaises(TypeError, "foo", "bar", "bam")
292
387
        c.execute(" ;\n\t\r;;")
293
388
        
294
389
        # unicode
295
 
        self.failUnlessEqual(3, c.execute(u"select 3").next()[0])
296
 
        self.assertRaises(UnicodeDecodeError, c.execute, "\x99\xaa\xbb\xcc")
 
390
        self.failUnlessEqual(3, next(c.execute(u("select 3")))[0])
 
391
        if not py3:
 
392
            self.assertRaises(UnicodeDecodeError, c.execute, "\x99\xaa\xbb\xcc")
297
393
        
298
394
        # does it work?
299
395
        c.execute("create table foo(x,y,z)")
317
413
            ("y", "text"),
318
414
            ("z", "foo"),
319
415
            ("a", "char"),
320
 
            (u"\N{LATIN SMALL LETTER E WITH CIRCUMFLEX}\N{LATIN SMALL LETTER A WITH TILDE}", u"\N{LATIN SMALL LETTER O WITH DIAERESIS}\N{LATIN SMALL LETTER U WITH CIRCUMFLEX}"),
 
416
            (u(r"\N{LATIN SMALL LETTER E WITH CIRCUMFLEX}\N{LATIN SMALL LETTER A WITH TILDE}"),
 
417
             u(r"\N{LATIN SMALL LETTER O WITH DIAERESIS}\N{LATIN SMALL LETTER U WITH CIRCUMFLEX}")),
321
418
            )
322
419
        c.execute("drop table foo; create table foo (%s)" % (", ".join(["[%s] %s" % (n,t) for n,t in cols]),))
323
420
        c.execute("insert into foo([x a space]) values(1)")
325
422
            self.failUnlessEqual(cols, c.getdescription())
326
423
        # execution is complete ...
327
424
        self.assertRaises(apsw.ExecutionCompleteError, c.getdescription)
328
 
        self.assertRaises(StopIteration, c.next)
329
 
        self.assertRaises(StopIteration, c.next)
 
425
        self.assertRaises(StopIteration, lambda xx=0: next(c))
 
426
        self.assertRaises(StopIteration, lambda xx=0: next(c))
330
427
        # nulls for getdescription
331
428
        for row in c.execute("pragma user_version"):
332
429
            self.assertEqual(c.getdescription(), ( ('user_version', None), ))
352
449
        c.execute("create table foo(row,x)")
353
450
        vals=("a simple string",  # "ascii" string
354
451
              "0123456789"*200000, # a longer string
355
 
              u"a \u1234 unicode \ufe54 string \u0089",  # simple unicode string
356
 
              u"\N{BLACK STAR} \N{WHITE STAR} \N{LIGHTNING} \N{COMET} ", # funky unicode
 
452
              u(r"a \u1234 unicode \ufe54 string \u0089"),  # simple unicode string
 
453
              u(r"\N{BLACK STAR} \N{WHITE STAR} \N{LIGHTNING} \N{COMET} "), # funky unicode
 
454
              u(r"\N{MUSICAL SYMBOL G CLEF}"), # http://www.cmlenz.net/archives/2008/07/the-truth-about-unicode-in-python
357
455
              97, # integer
358
456
              2147483647,   # numbers on 31 bit boundary (32nd bit used for integer sign), and then
359
457
              -2147483647,  # start using 32nd bit (must be represented by 64bit to avoid losing
360
 
              2147483648L,  # detail)
361
 
              -2147483648L,
362
 
              2147483999L,
363
 
              -2147483999L,
364
 
              sys.maxint,
365
 
              992147483999L,
366
 
              -992147483999L,
367
 
              9223372036854775807L,
368
 
              -9223372036854775808L,
369
 
              buffer("a set of bytes"),      # bag of bytes initialised from a string, but don't confuse it with a
370
 
              buffer("".join([chr(x) for x in range(256)])), # string
371
 
              buffer("".join([chr(x) for x in range(256)])*20000),  # non-trivial size
 
458
              long(2147483648),  # detail)
 
459
              long(-2147483648),
 
460
              long(2147483999),
 
461
              long(-2147483999),
 
462
              992147483999,
 
463
              -992147483999,
 
464
              9223372036854775807,
 
465
              -9223372036854775808,
 
466
              b("a set of bytes"),      # bag of bytes initialised from a string, but don't confuse it with a
 
467
              b("".join(["\\x%02x" % (x,) for x in range(256)])), # string
 
468
              b("".join(["\\x%02x" % (x,) for x in range(256)])*20000),  # non-trivial size
372
469
              None,  # our good friend NULL/None
373
470
              1.1,  # floating point can't be compared exactly - failUnlessAlmostEqual is used to check
374
471
              10.2, # see Appendix B in the Python Tutorial 
401
498
 
402
499
        # check some out of bounds conditions
403
500
        # integer greater than signed 64 quantity (SQLite only supports up to that)
404
 
        self.assertRaises(OverflowError, c.execute, "insert into foo values(9999,?)", (922337203685477580799L,))
405
 
        self.assertRaises(OverflowError, c.execute, "insert into foo values(9999,?)", (-922337203685477580799L,))
 
501
        self.assertRaises(OverflowError, c.execute, "insert into foo values(9999,?)", (922337203685477580799,))
 
502
        self.assertRaises(OverflowError, c.execute, "insert into foo values(9999,?)", (-922337203685477580799,))
406
503
 
407
504
        # invalid character data - non-ascii data must be provided in unicode
408
 
        self.assertRaises(UnicodeDecodeError, c.execute, "insert into foo values(9999,?)", ("\xfe\xfb\x80\x92",))
 
505
        if not py3: # py3 - all strings are unicode so not a problem
 
506
            self.assertRaises(UnicodeDecodeError, c.execute, "insert into foo values(9999,?)", ("\xfe\xfb\x80\x92",))
409
507
 
410
508
        # not valid types for SQLite
411
509
        self.assertRaises(TypeError, c.execute, "insert into foo values(9999,?)", (apsw,)) # a module
413
511
        self.assertRaises(TypeError, c.execute, "insert into foo values(9999,?)", (dir,))  # function
414
512
 
415
513
        # check nothing got inserted
416
 
        self.failUnlessEqual(0, c.execute("select count(*) from foo where row=9999").next()[0])
 
514
        self.failUnlessEqual(0, next(c.execute("select count(*) from foo where row=9999"))[0])
 
515
 
 
516
        # playing with default encoding and non-ascii strings - py2 only
 
517
        if py3: return
 
518
        enc=sys.getdefaultencoding()
 
519
        reload(sys) # gets setdefaultencoding function back
 
520
        try:
 
521
            for v in vals:
 
522
                if type(v)!=unicode:
 
523
                    continue
 
524
                def encoding(*args):
 
525
                    return v.encode("utf8") # returns as str not unicode
 
526
                self.db.createscalarfunction("encoding", encoding)
 
527
                sys.setdefaultencoding("utf8")
 
528
                for row in c.execute("select encoding(3)"):
 
529
                    self.failUnlessEqual(v, row[0])
 
530
                c.execute("insert into foo values(1234,?)", (v.encode("utf8"),))
 
531
                for row in c.execute("select x from foo where rowid="+str(self.db.last_insert_rowid())):
 
532
                    self.failUnlessEqual(v, row[0])
 
533
        finally:
 
534
            sys.setdefaultencoding(enc)
417
535
        
418
536
    def testAuthorizer(self):
419
537
        "Verify the authorizer works"
 
538
        retval=apsw.SQLITE_DENY
420
539
        def authorizer(operation, paramone, paramtwo, databasename, triggerorview):
421
540
            # we fail creates of tables starting with "private"
422
541
            if operation==apsw.SQLITE_CREATE_TABLE and paramone.startswith("private"):
423
 
                return apsw.SQLITE_DENY
 
542
                return retval
424
543
            return apsw.SQLITE_OK
425
544
        c=self.db.cursor()
426
545
        # this should succeed
428
547
        # this should fail
429
548
        self.assertRaises(TypeError, self.db.setauthorizer, 12) # must be callable
430
549
        self.db.setauthorizer(authorizer)
431
 
        self.assertRaises(apsw.AuthError, c.execute, "create table privatetwo(x)")
 
550
        for val in apsw.SQLITE_DENY, long(apsw.SQLITE_DENY), 0x800276889000212112:
 
551
            retval=val
 
552
            if val<100:
 
553
                self.assertRaises(apsw.AuthError, c.execute, "create table privatetwo(x)")
 
554
            else:
 
555
                self.assertRaises(OverflowError, c.execute, "create table privatetwo(x)")
432
556
        # this should succeed
433
557
        self.db.setauthorizer(None)
434
558
        c.execute("create table privatethree(x)")
484
608
        # cmds should be unchanged
485
609
        self.failUnlessEqual(cmds, statements)
486
610
        # tracefunc can abort execution
487
 
        count=c.execute("select count(*) from one").next()[0]
 
611
        count=next(c.execute("select count(*) from one"))[0]
488
612
        def tracefunc(cmd, bindings):
489
613
            return False # abort
490
614
        c.setexectrace(tracefunc)
491
615
        self.assertRaises(apsw.ExecTraceAbort, c.execute, "insert into one values(1,2,3)")
492
616
        # table should not have been modified
493
617
        c.setexectrace(None)
494
 
        self.failUnlessEqual(count, c.execute("select count(*) from one").next()[0])
 
618
        self.failUnlessEqual(count, next(c.execute("select count(*) from one"))[0])
495
619
        # error in tracefunc
496
620
        def tracefunc(cmd, bindings):
497
621
            1/0
498
622
        c.setexectrace(tracefunc)
499
623
        self.assertRaises(ZeroDivisionError, c.execute, "insert into one values(1,2,3)")
500
624
        c.setexectrace(None)
501
 
        self.failUnlessEqual(count, c.execute("select count(*) from one").next()[0])
 
625
        self.failUnlessEqual(count, next(c.execute("select count(*) from one"))[0])
502
626
        # test across executemany and multiple statments
503
627
        counter=[0]
504
628
        def tracefunc(cmd, bindings):
526
650
        self.failUnlessEqual(counter[0], 4)
527
651
        c.setexectrace(None)
528
652
        # check the first statements got executed
529
 
        self.failUnlessEqual(3, c.execute("select max(x) from two").next()[0])
 
653
        self.failUnlessEqual(3, next(c.execute("select max(x) from two"))[0])
530
654
        # executemany
531
655
        def tracefunc(cmd, bindings):
532
656
            1/0
538
662
            1/0
539
663
        c.setexectrace(tracefunc)
540
664
        self.assertRaises(TypeError, c.execute, "select max(x) from two")
 
665
        def tracefunc(*args):
 
666
            return BadIsTrue()
 
667
        c.setexectrace(tracefunc)
 
668
        self.assertRaises(ZeroDivisionError, c.execute, "select max(x) from two")
541
669
 
542
670
    def testRowTracing(self):
543
671
        "Verify row tracing"
548
676
        def tracefunc(*result):
549
677
            return tuple([7 for i in result])
550
678
        # should get original row back
551
 
        self.failUnlessEqual(c.execute("select * from foo").next(), vals)
 
679
        self.failUnlessEqual(next(c.execute("select * from foo")), vals)
552
680
        self.assertRaises(TypeError, c.setrowtrace, 12) # must be callable
553
681
        c.setrowtrace(tracefunc)
554
682
        self.failUnless(c.getrowtrace() is tracefunc)
555
683
        # all values replaced with 7
556
 
        self.failUnlessEqual(c.execute("select * from foo").next(), tuple([7]*len(vals)))
 
684
        self.failUnlessEqual(next(c.execute("select * from foo")), tuple([7]*len(vals)))
557
685
        def tracefunc(*result):
558
686
            return (7,)
559
687
        # a single 7
560
688
        c.setrowtrace(tracefunc)
561
 
        self.failUnlessEqual(c.execute("select * from foo").next(), (7,))
 
689
        self.failUnlessEqual(next(c.execute("select * from foo")), (7,))
562
690
        # no alteration again
563
691
        c.setrowtrace(None)
564
 
        self.failUnlessEqual(c.execute("select * from foo").next(), vals)
 
692
        self.failUnlessEqual(next(c.execute("select * from foo")), vals)
565
693
        # error in function
566
694
        def tracefunc(*result):
567
695
            1/0
573
701
        except ZeroDivisionError:
574
702
            pass
575
703
        c.setrowtrace(None)
576
 
        self.failUnlessEqual(c.execute("select * from foo").next(), vals)
 
704
        self.failUnlessEqual(next(c.execute("select * from foo")), vals)
577
705
        # returning null
578
706
        c.execute("create table bar(x)")
579
707
        c.executemany("insert into bar values(?)", [[x] for x in range(10)])
598
726
        self.assertRaises(TypeError, self.db.createscalarfunction, "twelve", 12) # must be callable
599
727
        self.assertRaises(TypeError, self.db.createscalarfunction, "twelve", 12, 27, 28) # too many params
600
728
        self.assertRaises(apsw.SQLError, self.db.createscalarfunction, "twelve", ilove7, 900) # too many args
601
 
        self.assertRaises(TypeError, self.db.createscalarfunction, u"twelve\N{BLACK STAR}", ilove7) # must be ascii
 
729
        self.assertRaises(TypeError, self.db.createscalarfunction, u(r"twelve\N{BLACK STAR}"), ilove7) # must be ascii
602
730
        self.db.createscalarfunction("seven", ilove7)
603
731
        c.execute("create table foo(x,y,z)")
604
732
        for i in range(10):
605
733
            c.execute("insert into foo values(?,?,?)", (i,i,i))
606
734
        for i in range(10):
607
 
            self.failUnlessEqual( (7,), c.execute("select seven(x,y,z) from foo where x=?", (i,)).next())
 
735
            self.failUnlessEqual( (7,), next(c.execute("select seven(x,y,z) from foo where x=?", (i,))))
608
736
        # clear func
609
737
        self.assertRaises(apsw.BusyError, self.db.createscalarfunction,"seven", None) # active select above so no funcs can be changed
610
738
        for row in c.execute("select null"): pass # no active sql now
627
755
            return "\x99\xaa\xbb\xcc"
628
756
        
629
757
        self.db.createscalarfunction("ilove8bit", ilove8bit)
630
 
        self.assertRaises(UnicodeDecodeError, c.execute, "select ilove8bit(*) from foo")
631
 
            
 
758
        if not py3:
 
759
            self.assertRaises(UnicodeDecodeError, c.execute, "select ilove8bit(*) from foo")
 
760
        # coverage
 
761
        def bad(*args): 1/0
 
762
        self.db.createscalarfunction("bad", bad)
 
763
        self.assertRaises(ZeroDivisionError, c.execute, "select bad(3)+bad(4)")
 
764
        # turn a blob into a string to fail python utf8 conversion
 
765
        self.assertRaises(UnicodeDecodeError, c.execute, "select bad(cast (x'fffffcfb9208' as TEXT))")
 
766
        
632
767
 
633
768
    def testAggregateFunctions(self):
634
769
        "Verify aggregate functions"
655
790
        self.assertRaises(TypeError, self.db.createaggregatefunction,True, True, True, True) # wrong number/type of params
656
791
        self.assertRaises(TypeError, self.db.createaggregatefunction,"twelve", 12) # must be callable
657
792
        self.assertRaises(apsw.SQLError, self.db.createaggregatefunction, "twelve", longest.factory, 923) # max args is 127
658
 
        self.assertRaises(TypeError, self.db.createaggregatefunction,u"twelve\N{BLACK STAR}", 12) # must be ascii
 
793
        self.assertRaises(TypeError, self.db.createaggregatefunction, u(r"twelve\N{BLACK STAR}"), 12) # must be ascii
659
794
        self.db.createaggregatefunction("twelve", None)
660
795
        self.db.createaggregatefunction("longest", longest.factory)
661
796
 
669
804
        for v in vals:
670
805
            c.execute("insert into foo values(?,?,?)", v)
671
806
 
672
 
        v=c.execute("select longest(x,y,z) from foo").next()[0]
 
807
        v=next(c.execute("select longest(x,y,z) from foo"))[0]
673
808
        self.failUnlessEqual(v, vals[0][2])
674
809
 
675
810
        # SQLite doesn't allow step functions to return an error, so we have to defer to the final
749
884
            1/0
750
885
        self.db.createaggregatefunction("badfunc", badfactory)
751
886
        self.assertRaises(ZeroDivisionError, c.execute, "select badfunc(x) from foo")
752
 
        
 
887
 
753
888
        
754
889
    def testCollation(self):
755
890
        "Verify collations"
 
891
        # create a whole bunch to check they are freed
 
892
        for i in range(1024):
 
893
            self.db.createcollation("x"*i, lambda x,y: i)
 
894
        for ii in range(1024):
 
895
            self.db.createcollation("x"*ii, lambda x,y: ii)
 
896
 
756
897
        c=self.db.cursor()
757
898
        def strnumcollate(s1, s2):
758
899
            "return -1 if s1<s2, +1 if s1>s2 else 0.  Items are string head and numeric tail"
769
910
                values[vn]=v
770
911
            # compare
771
912
            if values[0]<values[1]:
772
 
                return -1
773
 
            if values[0]>values[1]:
774
 
                return 1
 
913
                return -1 # return an int
 
914
            if values[0]>values[1]: 
 
915
                return long(1) # and a long
775
916
            return 0
776
917
 
777
918
        self.assertRaises(TypeError, self.db.createcollation, "twelve", strnumcollate, 12) # wrong # params
778
919
        self.assertRaises(TypeError, self.db.createcollation, "twelve", 12) # must be callable
779
 
        self.assertRaises(TypeError, self.db.createcollation,u"twelve\N{BLACK STAR}", strnumcollate) # must be ascii
780
920
        self.db.createcollation("strnum", strnumcollate)
781
921
        c.execute("create table foo(x)")
782
922
        # adding this unicode in front improves coverage
783
 
        uni=u"\N{LATIN SMALL LETTER E WITH CIRCUMFLEX}"
 
923
        uni=u(r"\N{LATIN SMALL LETTER E WITH CIRCUMFLEX}")
784
924
        vals=(uni+"file1", uni+"file7", uni+"file9", uni+"file17", uni+"file20")
785
925
        valsrev=list(vals)
786
926
        valsrev.reverse() # put them into table in reverse order
 
927
        valsrev=valsrev[1:]+valsrev[:1] # except one out of order
787
928
        c.executemany("insert into foo values(?)", [(x,) for x in valsrev])
788
929
        for i,row in enumerate(c.execute("select x from foo order by x collate strnum")):
789
930
            self.failUnlessEqual(vals[i], row[0])
808
949
        for row in c: pass
809
950
        self.db.createcollation("strnum", None)
810
951
        # check it really has gone
811
 
        self.assertRaises(apsw.SQLError, c.execute, "select x from foo order by x collate strnum")
 
952
        try:
 
953
            c.execute("select x from foo order by x collate strnum")
 
954
        except (apsw.SQLError,apsw.SchemaChangeError):
 
955
            # exception returned could be either depending on if
 
956
            # statementcache is used.  See SQLite ticket 2158
 
957
            pass
812
958
        # check statement still works
813
959
        for _ in c.execute("select x from foo"): pass
 
960
 
 
961
        # collation needed testing
 
962
        self.assertRaises(TypeError, self.db.collationneeded, 12)
 
963
        def cn1(): pass
 
964
        def cn2(x, y): 1/0
 
965
        def cn3(x, y):
 
966
            self.assert_(x is self.db)
 
967
            self.failUnlessEqual(y, "strnum")
 
968
            self.db.createcollation("strnum", strnumcollate)
 
969
 
 
970
        self.db.collationneeded(cn1)
 
971
        try:
 
972
            for _ in c.execute("select x from foo order by x collate strnum"): pass
 
973
        except TypeError:
 
974
            pass
 
975
        self.db.collationneeded(cn2)
 
976
        try:
 
977
            for _ in c.execute("select x from foo order by x collate strnum"): pass
 
978
        except ZeroDivisionError:
 
979
            pass
 
980
        self.db.collationneeded(cn3)
 
981
        for _ in c.execute("select x from foo order by x collate strnum"): pass
 
982
        self.db.collationneeded(None)
 
983
        self.db.createcollation("strnum", None)
 
984
        
 
985
        # check it really has gone
 
986
        try:
 
987
            c.execute("select x from foo order by x collate strnum")
 
988
        except (apsw.SQLError,apsw.SchemaChangeError):
 
989
            # exception returned could be either depending on if
 
990
            # statementcache is used.  See SQLite ticket 2158
 
991
            pass
 
992
        
814
993
        
815
994
    def testProgressHandler(self):
816
995
        "Verify progress handler"
829
1008
        self.assertRaises(TypeError, self.db.setprogresshandler, ph, "foo") # second param is steps
830
1009
        self.db.setprogresshandler(ph, -17) # SQLite doesn't complain about negative numbers
831
1010
        self.db.setprogresshandler(ph, 20)
832
 
        c.execute("select max(x) from foo").next()
 
1011
        next(c.execute("select max(x) from foo"))
833
1012
 
834
1013
        self.assertNotEqual(phcalledcount[0], 0)
835
1014
        saved=phcalledcount[0]
840
1019
        self.assertRaises(ZeroDivisionError, c.execute, "update foo set x=-10")
841
1020
        self.db.setprogresshandler(None) # clear ph so next line runs
842
1021
        # none should have taken
843
 
        self.failUnlessEqual(0, c.execute("select count(*) from foo where x=-10").next()[0])
 
1022
        self.failUnlessEqual(0, next(c.execute("select count(*) from foo where x=-10"))[0])
844
1023
        # and previous ph should not have been called
845
1024
        self.failUnlessEqual(saved, phcalledcount[0])
846
 
                             
 
1025
        def ph():
 
1026
            return BadIsTrue()
 
1027
        self.db.setprogresshandler(ph, 1)
 
1028
        self.assertRaises(ZeroDivisionError, c.execute, "update foo set x=-10")
847
1029
 
848
1030
    def testChanges(self):
849
1031
        "Verify reporting of changes"
850
1032
        c=self.db.cursor()
851
1033
        c.execute("create table foo (x);begin")
852
 
        for i in xrange(100):
 
1034
        for i in range(100):
853
1035
            c.execute("insert into foo values(?)", (i+1000,))
854
1036
        c.execute("commit")
855
1037
        c.execute("update foo set x=0 where x>=1000")
856
1038
        self.failUnlessEqual(100, self.db.changes())
857
1039
        c.execute("begin")
858
 
        for i in xrange(100):
 
1040
        for i in range(100):
859
1041
            c.execute("insert into foo values(?)", (i+1000,))
860
1042
        c.execute("commit")
861
1043
        self.failUnlessEqual(300, self.db.totalchanges())
882
1064
        self.failUnlessEqual(True, self.db.complete("select * from foo; select *;"))
883
1065
        self.failUnlessEqual(False, self.db.complete("select * from foo where x=1"))
884
1066
        self.failUnlessEqual(True, self.db.complete("select * from foo;"))
 
1067
        self.failUnlessEqual(True, self.db.complete(u(r"select '\u9494\ua7a7';")))
 
1068
        if not py3:
 
1069
            self.assertRaises(UnicodeDecodeError, self.db.complete, "select '\x94\xa7';")
885
1070
        self.assertRaises(TypeError, self.db.complete, 12) # wrong type
886
1071
        self.assertRaises(TypeError, self.db.complete)     # not enough args
887
1072
        self.assertRaises(TypeError, self.db.complete, "foo", "bar") # too many args
928
1113
        
929
1114
        try:
930
1115
            for row in c.execute("begin immediate ; select * from foo"):
931
 
                print row
 
1116
                self.fail("Transaction wasn't exclusive")
932
1117
        except apsw.BusyError:
933
1118
            pass
934
1119
        self.failUnlessEqual(bhcalled[0], 4)
946
1131
        c2=db2.cursor()
947
1132
        
948
1133
        # Put in busy timeout
949
 
        TIMEOUT=3.5 # seconds
 
1134
        TIMEOUT=3 # seconds, must be integer as sqlite can round down to nearest second anyway
950
1135
        c2.execute("begin exclusive")
951
1136
        self.assertRaises(TypeError, self.db.setbusyhandler, "foo")
952
1137
        self.db.setbusytimeout(int(TIMEOUT*1000))
992
1177
        del c2
993
1178
        db2.close()
994
1179
 
 
1180
        def bh(*args):
 
1181
            return BadIsTrue()
 
1182
        db2=apsw.Connection("testdb")
 
1183
        c=self.db.cursor()
 
1184
        c2=db2.cursor()
 
1185
        c2.execute("begin exclusive")
 
1186
        self.db.setbusyhandler(bh)
 
1187
        self.assertRaises(ZeroDivisionError, c.execute, "begin immediate ; select * from foo")
 
1188
        del c
 
1189
        del c2
 
1190
        db2.close()        
 
1191
 
995
1192
    def testBusyHandling2(self):
996
1193
        "Another busy handling test"
997
1194
 
1004
1201
        cur.execute("insert into test values(123,'abc')")
1005
1202
        self.assertRaises(apsw.BusyError, cur2.execute, "insert into test values(456, 'def')")
1006
1203
        cur.execute("commit")
1007
 
        self.assertEqual(1, cur2.execute("select count(*) from test where x=123").next()[0])
 
1204
        self.assertEqual(1, next(cur2.execute("select count(*) from test where x=123"))[0])
1008
1205
        con2.close()
1009
1206
 
1010
1207
    def testInterruptHandling(self):
1052
1249
            return 1/0
1053
1250
        self.db.setcommithook(ch)
1054
1251
        self.assertRaises(ZeroDivisionError, c.execute, "insert into foo values(?)", (1,))
 
1252
        def ch():
 
1253
            return BadIsTrue()
 
1254
        self.db.setcommithook(ch)
 
1255
        self.assertRaises(ZeroDivisionError, c.execute, "insert into foo values(?)", (1,))
 
1256
        
1055
1257
 
1056
1258
    def testRollbackHook(self):
1057
1259
        "Verify rollback hooks"
1105
1307
        self.db.setupdatehook(uh)
1106
1308
        self.assertRaises(ZeroDivisionError, c.execute, "insert into foo values(100,100)")
1107
1309
        self.db.setupdatehook(None)
 
1310
        # improve code coverage
 
1311
        c.execute("create table bar(x,y); insert into bar values(1,2); insert into bar values(3,4)")
 
1312
        def uh(*args):
 
1313
            1/0
 
1314
        self.db.setupdatehook(uh)
 
1315
        self.assertRaises(ZeroDivisionError, c.execute, "insert into foo select * from bar")
 
1316
        self.db.setupdatehook(None)
 
1317
        
1108
1318
        # check cursor still works
1109
1319
        c.execute("insert into foo values(1000,1000)")
1110
 
        self.assertEqual(1, c.execute("select count(*) from foo where x=1000").next()[0])
 
1320
        self.assertEqual(1, next(c.execute("select count(*) from foo where x=1000"))[0])
1111
1321
 
1112
1322
    def testProfile(self):
1113
1323
        "Verify profiling"
1139
1349
            1/0
1140
1350
        self.db.setprofile(profile)
1141
1351
        self.assertRaises(ZeroDivisionError, c.execute, "create table bar(y)")
 
1352
        # coverage
 
1353
        wasrun=[False]
 
1354
        def profile(*args):
 
1355
            wasrun[0]=True
 
1356
        def uh(*args): 1/0
 
1357
        self.db.setprofile(profile)
 
1358
        self.db.setupdatehook(uh)
 
1359
        self.assertRaises(ZeroDivisionError, c.execute, "insert into foo values(3)")
 
1360
        self.failUnlessEqual(wasrun[0], False)
 
1361
        self.db.setprofile(None)
 
1362
        self.db.setupdatehook(None)
1142
1363
 
1143
1364
    def testThreading(self):
1144
1365
        "Verify threading behaviour"
 
1366
        # We used to require all operations on a connection happen in
 
1367
        # the same thread.  Now they can happen in any thread, so we
 
1368
        # ensure that inuse errors are detected by doing a long
 
1369
        # running operation in one thread.
1145
1370
        c=self.db.cursor()
1146
 
        c.execute("create table foo(x,y); insert into foo values(99,100); insert into foo values(101,102)")
1147
 
        ### Check operations on Connection cause error if executed in seperate thread
1148
 
        # these should execute fine in any thread
1149
 
        ThreadRunner(apsw.sqlitelibversion).go()
1150
 
        ThreadRunner(apsw.apswversion).go()
1151
 
        # these should generate errors
1152
 
        nargs=self.connection_nargs
1153
 
        for func in [x for x in dir(self.db) if not x.startswith("__")]:
1154
 
            args=("one", "two", "three")[:nargs.get(func,0)]
1155
 
            try:
1156
 
                tr=ThreadRunner(getattr(self.db, func), *args)
1157
 
                tr.go()
1158
 
                self.fail("connection method "+func+" didn't do thread safety check")
1159
 
            except apsw.ThreadingViolationError:
1160
 
                pass
1161
 
 
1162
 
        # do the same thing, but for cursor
1163
 
        nargs=self.cursor_nargs
1164
 
        for func in [x for x in dir(c) if not x.startswith("__")]:
1165
 
            args=("one", "two", "three")[:nargs.get(func,0)]
1166
 
            try:
1167
 
                tr=ThreadRunner(getattr(c, func), *args)
1168
 
                tr.go()
1169
 
                self.fail("cursor method "+func+" didn't do thread safety check")
1170
 
            except apsw.ThreadingViolationError:
1171
 
                pass
1172
 
 
1173
 
        # check cursor still works
1174
 
        for row in c.execute("select * from foo"):
1175
 
            pass
1176
 
        del c
1177
 
        # Do another query in a different thread
1178
 
        def threadcheck():
1179
 
            db=apsw.Connection("testdb")
1180
 
            c=db.cursor()
1181
 
            v=c.execute("select count(*) from foo").next()[0]
1182
 
            for _ in c: pass
1183
 
            db.close()
1184
 
            return v
1185
 
        
1186
 
        tr=ThreadRunner(threadcheck)
1187
 
        self.failUnlessEqual(2, tr.go())
 
1371
        c.execute("create table foo(x);begin;")
 
1372
        c.executemany("insert into foo values(?)", randomintegers(100000))
 
1373
        c.execute("commit")
 
1374
 
 
1375
        vals={"stop": False,
 
1376
              "raised": False}
 
1377
        def wt():
 
1378
            try:
 
1379
                while not vals["stop"]:
 
1380
                    c.execute("select min(max(x-1+x),min(x-1+x)) from foo")
 
1381
            except apsw.ThreadingViolationError:
 
1382
                vals["raised"]=True
 
1383
                vals["stop"]=True
 
1384
                
 
1385
        t=ThreadRunner(wt)
 
1386
        t.start()
 
1387
        # ensure thread t has started
 
1388
        time.sleep(0.1)
 
1389
        b4=time.time()
 
1390
        # try to get a threadingviolation for 30 seconds
 
1391
        try:
 
1392
            try:
 
1393
                while not vals["stop"] and time.time()-b4<30:
 
1394
                    c.execute("select * from foo")
 
1395
            except apsw.ThreadingViolationError:
 
1396
                vals["stop"]=True
 
1397
                vals["raised"]=True
 
1398
        finally:
 
1399
            vals["stop"]=True
 
1400
        t.go()
 
1401
        self.assertEqual(vals["raised"], True)
1188
1402
 
1189
1403
    def testStringsWithNulls(self):
1190
1404
        "Verify that strings with nulls in them are handled correctly"
1192
1406
        c=self.db.cursor()
1193
1407
        c.execute("create table foo(row,str)")
1194
1408
        vals=("a simple string",
1195
 
              "a simple string\0",
1196
1409
              "a simple string\0with a null",
1197
1410
              "a string\0with two\0nulls",
1198
1411
              "or even a \0\0\0\0\0\0sequence\0\0\0\0\of them",
1199
 
              u"a \u1234 unicode \ufe54 string \u0089",
1200
 
              u"a \u1234 unicode \ufe54 string \u0089\0",
1201
 
              u"a \u1234 unicode \ufe54 string \u0089\0and some text",
1202
 
              u"\N{BLACK STAR} \N{WHITE STAR} \N{LIGHTNING} \N{COMET}\0more\0than you\0can handle",
1203
 
              u"\N{BLACK STAR} \N{WHITE STAR} \N{LIGHTNING} \N{COMET}\0\0\0\0\0sequences\0\0\0of them")
 
1412
              u(r"a \u1234 unicode \ufe54 string \u0089"),
 
1413
              u(r"a \u1234 unicode \ufe54 string \u0089\0and some text"),
 
1414
              u(r"\N{BLACK STAR} \N{WHITE STAR} \N{LIGHTNING} \N{COMET}\0more\0than you\0can handle"),
 
1415
              u(r"\N{BLACK STAR} \N{WHITE STAR} \N{LIGHTNING} \N{COMET}\0\0\0\0\0sequences\0\0\0of them"))
 
1416
 
 
1417
        # See http://www.sqlite.org/cvstrac/tktview?tn=3056
 
1418
        if True: # [int(x) for x in apsw.sqlitelibversion().split(".")]<[3,5,8]:
 
1419
            vals=vals+(
 
1420
              "a simple string\0",
 
1421
              u(r"a \u1234 unicode \ufe54 string \u0089\0"),
 
1422
              )
1204
1423
 
1205
1424
        for i,v in enumerate(vals):
1206
1425
            c.execute("insert into foo values(?,?)", (i, v))
1207
1426
 
1208
 
        self.assertRaises(UnicodeDecodeError, c.execute, "insert into foo values(9000,?)", ("a simple string\0with a null and \xfe\xfb\x80\x92",))
 
1427
        if not py3:
 
1428
            self.assertRaises(UnicodeDecodeError, c.execute, "insert into foo values(9000,?)", ("a simple string\0with a null and \xfe\xfb\x80\x92",))
1209
1429
            
1210
1430
        # add function to test conversion back as well
1211
1431
        def snap(*args):
1220
1440
            self.failUnlessEqual(vals[row], fv)
1221
1441
        self.failUnlessEqual(count, len(vals))
1222
1442
 
 
1443
        # check execute
 
1444
        for v in vals:
 
1445
            self.failUnlessEqual(v, next(c.execute("select ?", (v,)))[0])
 
1446
            # nulls not allowed in main query string, so lets check the other bits (unicode etc)
 
1447
            v2=v.replace("\0", " zero ")
 
1448
            self.failUnlessEqual(v2, next(c.execute("select '%s'" % (v2,)))[0])
 
1449
 
1223
1450
        # ::TODO:: check collations
1224
1451
 
1225
1452
    def testSharedCache(self):
1253
1480
 
1254
1481
    def testLoadExtension(self):
1255
1482
        "Check loading of extensions"
1256
 
        # ::TODO:: I don't have checking of unicode filenames and entrypoint names here yet
1257
 
        # need to examine SQLite code to verify expected semantics
1258
 
        
1259
 
        # they need to be enable first
 
1483
        # unicode issues
 
1484
        if not py3:
 
1485
            self.assertRaises(UnicodeDecodeError, self.db.loadextension, "\xa7\x94")
 
1486
        # they need to be enabled first (off by default)
1260
1487
        self.assertRaises(apsw.ExtensionLoadingError, self.db.loadextension, LOADEXTENSIONFILENAME)
1261
1488
        self.db.enableloadextension(False)
 
1489
        self.assertRaises(ZeroDivisionError, self.db.enableloadextension, BadIsTrue())
1262
1490
        # should still be disabled
1263
1491
        self.assertRaises(apsw.ExtensionLoadingError, self.db.loadextension, LOADEXTENSIONFILENAME)
1264
1492
        self.db.enableloadextension(True)
1269
1497
        self.assertRaises(TypeError, self.db.loadextension, "foo", "bar", 12)
1270
1498
        self.db.loadextension(LOADEXTENSIONFILENAME)
1271
1499
        c=self.db.cursor()
1272
 
        self.failUnlessEqual(1, c.execute("select half(2)").next()[0])
 
1500
        self.failUnlessEqual(1, next(c.execute("select half(2)"))[0])
1273
1501
        # second entry point hasn't been called yet
1274
1502
        self.assertRaises(apsw.SQLError, c.execute, "select doubleup(2)")
1275
1503
        # load using other entry point
1276
1504
        self.assertRaises(apsw.ExtensionLoadingError, self.db.loadextension, LOADEXTENSIONFILENAME, "doesntexist")
1277
1505
        self.db.loadextension(LOADEXTENSIONFILENAME, "alternate_sqlite3_extension_init")
1278
 
        self.failUnlessEqual(4, c.execute("select doubleup(2)").next()[0])
 
1506
        self.failUnlessEqual(4, next(c.execute("select doubleup(2)"))[0])
 
1507
        
 
1508
 
 
1509
    def testMakeSqliteMsgFromException(self):
 
1510
        "Test C function that converts exception into SQLite error code"
 
1511
        class Source:
 
1512
            def Create1(self, *args):
 
1513
                e=apsw.IOError()
 
1514
                e.extendedresult=apsw.SQLITE_IOERR_BLOCKED
 
1515
                raise e
 
1516
 
 
1517
            def Create2(self, *args):
 
1518
                e=apsw.IOError()
 
1519
                e.extendedresult=long(apsw.SQLITE_IOERR_BLOCKED)
 
1520
                raise e
 
1521
 
 
1522
            def Create3(self, *args):
 
1523
                e=apsw.IOError()
 
1524
                e.extendedresult=(long("0x80")<<32)+apsw.SQLITE_IOERR_BLOCKED # bigger than 32 bits
 
1525
                raise e
 
1526
 
 
1527
            
 
1528
        self.db.createmodule("foo", Source())
 
1529
        for i in "1", "2", "3":
 
1530
            Source.Create=getattr(Source, "Create"+i)
 
1531
            try:
 
1532
                self.db.cursor().execute("create virtual table vt using foo()")
 
1533
                1/0
 
1534
            except:
 
1535
                klass,value,tb=sys.exc_info()
 
1536
            # check types and values
 
1537
            if i=="3":
 
1538
                self.failUnlessEqual(klass, ValueError)
 
1539
                continue
 
1540
            self.failUnlessEqual(klass, apsw.IOError)
 
1541
            self.assert_(isinstance(value, apsw.IOError))
 
1542
            # python 2.3 totally messes up on long<->int and signed conversions causing the test to fail
 
1543
            # but the code is fine - so just ignore rest of test for py2.3
 
1544
            if sys.version_info<(2,4):
 
1545
                return
 
1546
 
 
1547
            self.failUnlessEqual(value.extendedresult& ((long(0xffff)<<16)|long(0xffff)), apsw.SQLITE_IOERR_BLOCKED)
 
1548
            # walk the stack to verify that C level value is correct
 
1549
            found=False
 
1550
            while tb:
 
1551
                frame=tb.tb_frame
 
1552
                if frame.f_code.co_name=="resetcursor":
 
1553
                    self.failUnlessEqual(frame.f_locals["res"], apsw.SQLITE_IOERR_BLOCKED|apsw.SQLITE_IOERR)
 
1554
                    found=True
 
1555
                    break
 
1556
                tb=tb.tb_next
 
1557
            self.assertEqual(found, True)
1279
1558
 
1280
1559
    def testVtables(self):
1281
1560
        "Test virtual table functionality"
1282
1561
 
1283
1562
        data=( # row 0 is headers, column 0 is rowid
1284
1563
            ( "rowid",     "name",    "number", "item",          "description"),
1285
 
            ( 1,           "Joe Smith",    1.1, u"\u00f6\u1234", "foo"),
1286
 
            ( 6000000000L, "Road Runner", -7.3, u"\u00f6\u1235", "foo"),
1287
 
            ( 77,          "Fred",           0, u"\u00f6\u1236", "foo"),
 
1564
            ( 1,           "Joe Smith",    1.1, u(r"\u00f6\u1234"), "foo"),
 
1565
            ( 6000000000,  "Road Runner", -7.3, u(r"\u00f6\u1235"), "foo"),
 
1566
            ( 77,          "Fred",           0, u(r"\u00f6\u1236"), "foo"),
1288
1567
            )
1289
1568
 
1290
 
        dataschema="create table this_should_be_ignored"+`data[0][1:]`
 
1569
        dataschema="create table this_should_be_ignored"+str(data[0][1:])
1291
1570
        # a query that will get constraints on every column
1292
1571
        allconstraints="select rowid,* from foo where rowid>-1000 and name>='A' and number<=12.4 and item>'A' and description=='foo' order by item"
1293
1572
        allconstraintsl=[(-1, apsw.SQLITE_INDEX_CONSTRAINT_GT), # rowid >
1298
1577
                         ]
1299
1578
        
1300
1579
 
 
1580
        for i in range(20):
 
1581
            self.db.createmodule("x"*i, lambda x: i)
 
1582
        for ii in range(20):
 
1583
            self.db.createmodule("x"*ii, lambda x: ii)
 
1584
 
 
1585
        # If shared cache is enabled then vtable creation is supposed to fail
 
1586
        # See http://www.sqlite.org/cvstrac/tktview?tn=3144
 
1587
        try:
 
1588
            apsw.enablesharedcache(True)
 
1589
            db=apsw.Connection("testdb2")
 
1590
            db.createmodule("y", lambda x: 2)
 
1591
        finally:
 
1592
            apsw.enablesharedcache(False)
 
1593
 
1301
1594
        # The testing uses a different module name each time.  SQLite
1302
1595
        # doc doesn't define the semantics if a 2nd module is
1303
1596
        # registered with the same name as an existing one and I was
1318
1611
                
1319
1612
            def Create(self, *args): # db, modname, dbname, tablename, args
1320
1613
                if self.expectargs!=args[1:]:
1321
 
                    raise ValueError("Create arguments are not correct.  Expected "+`self.expectargs`+" but got "+`args[1:]`)
 
1614
                    raise ValueError("Create arguments are not correct.  Expected "+str(self.expectargs)+" but got "+str(args[1:]))
1322
1615
                1/0
1323
1616
 
1324
1617
            def CreateErrorCode(self, *args):
1327
1620
                raise apsw.BusyError("foo")
1328
1621
 
1329
1622
            def CreateUnicodeException(self, *args):
1330
 
                raise Exception(u"\N{LATIN SMALL LETTER E WITH CIRCUMFLEX}\N{LATIN SMALL LETTER A WITH TILDE}\N{LATIN SMALL LETTER O WITH DIAERESIS}")
 
1623
                raise Exception(u(r"\N{LATIN SMALL LETTER E WITH CIRCUMFLEX}\N{LATIN SMALL LETTER A WITH TILDE}\N{LATIN SMALL LETTER O WITH DIAERESIS}"))
1331
1624
 
1332
1625
            def CreateBadSchemaType(self, *args):
1333
1626
                return 12, None
1353
1646
        self.db.createmodule("testmod1", Source("testmod1", "main", "xyzzy", "1", '"one"'))
1354
1647
        self.assertRaises(ZeroDivisionError, cur.execute, 'create virtual table xyzzy using testmod1(1,"one")')
1355
1648
        # unicode
1356
 
        uni=u"\N{LATIN SMALL LETTER E WITH CIRCUMFLEX}\N{LATIN SMALL LETTER A WITH TILDE}\N{LATIN SMALL LETTER O WITH DIAERESIS}"
1357
 
        self.db.createmodule("testmod1dash1", Source("testmod1dash1", "main", uni, "1", u'"'+uni+u'"'))
1358
 
        self.assertRaises(ZeroDivisionError, cur.execute, u'create virtual table %s using testmod1dash1(1,"%s")' % (uni, uni))
 
1649
        uni=u(r"\N{LATIN SMALL LETTER E WITH CIRCUMFLEX}\N{LATIN SMALL LETTER A WITH TILDE}\N{LATIN SMALL LETTER O WITH DIAERESIS}")
 
1650
        self.db.createmodule("testmod1dash1", Source("testmod1dash1", "main", uni, "1", '"'+uni+'"'))
 
1651
        self.assertRaises(ZeroDivisionError, cur.execute, u('create virtual table %s using testmod1dash1(1,"%s")') % (uni, uni))
1359
1652
        Source.Create=Source.CreateErrorCode
1360
1653
        self.assertRaises(apsw.BusyError, cur.execute, 'create virtual table xyzzz using testmod1(2, "two")')
1361
1654
        Source.Create=Source.CreateUnicodeException
1413
1706
 
1414
1707
            def BestIndex4(self, constraints, orderbys):
1415
1708
                # this gives ValueError ("bad" is not a float)
1416
 
                return (None,12,u"\N{LATIN SMALL LETTER E WITH CIRCUMFLEX}", "anything", "bad")
 
1709
                return (None,12,u(r"\N{LATIN SMALL LETTER E WITH CIRCUMFLEX}"), "anything", "bad")
 
1710
 
 
1711
            def BestIndex5(self, constraints, orderbys):
 
1712
                # unicode error
 
1713
                return (None, None, "\xde\xad\xbe\xef")
 
1714
 
 
1715
            def BestIndex6(self, constraints, orderbys):
 
1716
                return ( (0, 1, (2, BadIsTrue()), 3, 4), )
 
1717
 
 
1718
            def BestIndex7(self, constraints, orderbys):
 
1719
                return (None, long(77), "foo", BadIsTrue(), 99)
1417
1720
 
1418
1721
            _bestindexreturn=99
1419
1722
                
1422
1725
                cl.sort()
1423
1726
                assert allconstraintsl == cl
1424
1727
                assert orderbys == ( (2, False), )
1425
 
                retval=( [4,(3,True),[2,False],1, (0, False)], 997, u"\N{LATIN SMALL LETTER E WITH CIRCUMFLEX}", False, 99)[:self._bestindexreturn]
 
1728
                retval=( [long(4),(3,True),[long(2),False],1, (0, False)], 997, u(r"\N{LATIN SMALL LETTER E WITH CIRCUMFLEX}"), False, 99)[:self._bestindexreturn]
1426
1729
                return retval
1427
1730
 
1428
1731
            def BestIndexGood(self, constraints, orderbys):
1464
1767
 
1465
1768
            def UpdateInsertRow6(self, rowid, fields):
1466
1769
                assert rowid is None
1467
 
                return -922337203685477580799L # too big
 
1770
                return -922337203685477580799 # too big
1468
1771
 
1469
1772
            def UpdateInsertRow7(self, rowid, fields):
1470
1773
                assert rowid is None
1471
 
                return 9223372036854775807L # ok
 
1774
                return 9223372036854775807 # ok
1472
1775
 
1473
1776
            def UpdateInsertRow8(self, rowid, fields):
1474
1777
                assert rowid is not None
1532
1835
            def Rollback(self):
1533
1836
                pass
1534
1837
 
 
1838
            def Rename1(self, too, many, args):
 
1839
                1/0
 
1840
 
 
1841
            def Rename2(self, x):
 
1842
                1/0
 
1843
 
 
1844
            def Rename3(self, x):
 
1845
                return ["thisshouldbeignored"*25, [1]]
 
1846
 
1535
1847
        class Cursor:
1536
1848
 
1537
1849
            _bestindexreturn=99
1564
1876
                    return 
1565
1877
                # 3 or more
1566
1878
                assert idxnum==997
1567
 
                assert idxstr==u"\N{LATIN SMALL LETTER E WITH CIRCUMFLEX}"
 
1879
                assert idxstr==u(r"\N{LATIN SMALL LETTER E WITH CIRCUMFLEX}")
1568
1880
                assert constraintargs==('A', 12.4, 'A', -1000)
1569
1881
 
1570
1882
            def Filter(self,  *args):
1580
1892
            def Eof2(self):
1581
1893
                1/0
1582
1894
 
 
1895
            def Eof3(self):
 
1896
                return BadIsTrue()
 
1897
 
1583
1898
            def Eof99(self):
1584
1899
                return not ( self.pos<len(self.table.data) )
1585
1900
 
1643
1958
            self.assertRaises(TypeError, cur.execute, allconstraints)
1644
1959
        VTable.BestIndex=VTable.BestIndex4
1645
1960
        self.assertRaises(ValueError, cur.execute, allconstraints)
 
1961
        if not py3:
 
1962
            VTable.BestIndex=VTable.BestIndex5
 
1963
            self.assertRaises(UnicodeDecodeError, cur.execute, allconstraints)
 
1964
        VTable.BestIndex=VTable.BestIndex6
 
1965
        self.assertRaises(ZeroDivisionError, cur.execute, allconstraints)
 
1966
        VTable.BestIndex=VTable.BestIndex7
 
1967
        self.assertRaises(ZeroDivisionError, cur.execute, allconstraints)
1646
1968
 
1647
1969
        # check varying number of return args from bestindex
1648
1970
        VTable.BestIndex=VTable.BestIndex99
1677
1999
        self.assertRaises(TypeError, cur.execute, allconstraints)
1678
2000
        Cursor.Eof=Cursor.Eof2
1679
2001
        self.assertRaises(ZeroDivisionError,cur.execute, allconstraints)
 
2002
        Cursor.Eof=Cursor.Eof3
 
2003
        self.assertRaises(ZeroDivisionError,cur.execute, allconstraints)
1680
2004
        Cursor.Eof=Cursor.Eof99
1681
2005
        self.assertRaises(AttributeError, cur.execute, allconstraints)
1682
2006
        # now onto to rowid
1743
2067
        self.assertRaises(OverflowError, cur.execute, sql)
1744
2068
        VTable.UpdateInsertRow=VTable.UpdateInsertRow7
1745
2069
        cur.execute(sql)
1746
 
        self.failUnlessEqual(self.db.last_insert_rowid(), 9223372036854775807L)
 
2070
        self.failUnlessEqual(self.db.last_insert_rowid(), 9223372036854775807)
1747
2071
        VTable.UpdateInsertRow=VTable.UpdateInsertRow8
1748
2072
        cur.execute("insert into foo (rowid,name, description) values(-12,'gunk', 'foo')")
1749
2073
        
1772
2096
        VTable.UpdateDeleteRow=VTable.UpdateDeleteRow3
1773
2097
        cur.execute(sql)
1774
2098
 
 
2099
        # rename
 
2100
        sql="alter table foo rename to bar"
 
2101
        VTable.Rename=VTable.Rename1
 
2102
        self.assertRaises(TypeError, cur.execute, sql)
 
2103
        VTable.Rename=VTable.Rename2
 
2104
        self.assertRaises(ZeroDivisionError, cur.execute, sql)
 
2105
        VTable.Rename=VTable.Rename3
 
2106
        # this is to catch memory leaks
 
2107
        cur.execute(sql)
 
2108
        del VTable.Rename # method is optional
 
2109
        cur.execute("alter table bar rename to foo") # put things back
 
2110
 
1775
2111
        # transaction control
1776
2112
        # Begin, Sync, Commit and rollback all use the same underlying code
 
2113
        sql="delete from foo where name=='Fred'"
1777
2114
        VTable.Begin=VTable.Begin1
1778
2115
        self.assertRaises(TypeError, cur.execute, sql)
1779
2116
        VTable.Begin=VTable.Begin2
1838
2175
        
1839
2176
        class Source:
1840
2177
            def Create(self, db, modulename, dbname, tablename, *args):
1841
 
                columns,data=getfiledata([eval(a) for a in args]) # eval strips off layer of quotes
 
2178
                columns,data=getfiledata([eval(UPREFIX+a) for a in args]) # eval strips off layer of quotes
1842
2179
                schema="create table foo("+','.join(["'%s'" % (x,) for x in columns[1:]])+")"
1843
2180
                return schema,Table(columns,data)
1844
2181
            Connect=Create
1905
2242
            pass
1906
2243
        # Find the oldest (manually)
1907
2244
        colnum=cols.index("st_ctime")
1908
 
        oldestmanual=(99999999999999999L,"","")
 
2245
        oldestmanual=(99999999999999999,"","")
1909
2246
        for file in data:
1910
2247
            if file[colnum]<oldestmanual[0]:
1911
2248
                oldestmanual=file[colnum], file[1], file[2]
1916
2253
    def testClosingChecks(self):
1917
2254
        "Check closed connection is correctly detected"
1918
2255
        cur=self.db.cursor()
 
2256
        rowid=next(cur.execute("create table foo(x blob); insert into foo values(zeroblob(98765)); select rowid from foo"))[0]
 
2257
        blob=self.db.blobopen("main", "foo", "x", rowid, True)
 
2258
        blob.close()
 
2259
        nargs=self.blob_nargs
 
2260
        for func in [x for x in dir(blob) if not x.startswith("__") and not x in ("close",)]:
 
2261
            args=("one", "two", "three")[:nargs.get(func,0)]
 
2262
            try:
 
2263
                getattr(blob, func)(*args)
 
2264
                self.fail("blob method "+func+" didn't notice that the connection is closed")
 
2265
            except ValueError: # we issue ValueError to be consistent with file objects
 
2266
                pass
 
2267
        
1919
2268
        self.db.close()
1920
2269
        nargs=self.connection_nargs
1921
2270
        for func in [x for x in dir(self.db) if not x.startswith("__") and not x in ("close",)]:
1968
2317
        import ctypes
1969
2318
        if ctypes.sizeof(ctypes.c_size_t)<8:
1970
2319
            return
1971
 
        # I use an anonymous area slightly larger than 2GB chunk of memory, but don't touch any of it
 
2320
        # For binary/blobs I use an anonymous area slightly larger than 2GB chunk of memory, but don't touch any of it
1972
2321
        import mmap
1973
2322
        f=mmap.mmap(-1, 2*1024*1024*1024+25000)
1974
2323
        c=self.db.cursor()
1975
2324
        c.execute("create table foo(theblob)")
1976
 
        self.assertRaises(apsw.TooBigError,  c.execute, "insert into foo values(?)", (buffer(f),))
1977
 
        # I can't find an easy way of making mmap fake being a string (the mmap module doc implies you can)
 
2325
        self.assertRaises(apsw.TooBigError,  c.execute, "insert into foo values(?)", (f,))
 
2326
        c.execute("insert into foo values(?)", ("jkghjk"*1024,))
 
2327
        b=self.db.blobopen("main", "foo", "theblob", self.db.last_insert_rowid(), True)
 
2328
        b.read(1)
 
2329
        self.assertRaises(ValueError, b.write, f)
 
2330
        def func(): return f
 
2331
        self.db.createscalarfunction("toobig", func)
 
2332
        self.assertRaises(apsw.TooBigError, c.execute, "select toobig()")
1978
2333
        f.close()
 
2334
        # Other testing by fault injection
 
2335
        if not hasattr(apsw, "faultdict"):
 
2336
            return
 
2337
 
 
2338
        ## SetContextResultLargeUnicode
 
2339
        apsw.faultdict["SetContextResultLargeUnicode"]=True
 
2340
        try:
 
2341
            db=apsw.Connection(":memory:")
 
2342
            db.createscalarfunction("foo", lambda x: u("a unicode string"))
 
2343
            for row in db.cursor().execute("select foo(3)"):
 
2344
                pass
 
2345
            1/0
 
2346
        except:
 
2347
            klass, value, tb=sys.exc_info()
 
2348
            self.assert_(klass is apsw.TooBigError)
 
2349
 
 
2350
        ## SetContextResultLargeString
 
2351
        if sys.version_info<(3,0):
 
2352
            apsw.faultdict["SetContextResultLargeString"]=True
 
2353
            try:
 
2354
                db=apsw.Connection(":memory:")
 
2355
                def func(x):
 
2356
                    return "an ordinary string"*10000
 
2357
                db.createscalarfunction("foo", func)
 
2358
                for row in db.cursor().execute("select foo(3)"):
 
2359
                    pass
 
2360
                1/0
 
2361
            except:
 
2362
                klass, value, tb=sys.exc_info()
 
2363
                self.assert_(klass is apsw.TooBigError)
 
2364
 
1979
2365
 
1980
2366
    def testErrorCodes(self):
1981
2367
        "Verify setting of result codes on error/exception"
1982
2368
        fname="gunk-errcode-test"
1983
 
        open(fname, "wb").write("A"*8192)
 
2369
        open(fname, "wb").write(b("A")*8192)
1984
2370
        db=apsw.Connection(fname)
1985
2371
        cur=db.cursor()
1986
2372
        try:
1987
2373
            cur.execute("select * from sqlite_master")
1988
 
        except apsw.NotADBError,e:
 
2374
        except:
 
2375
            klass,e,tb=sys.exc_info()
 
2376
            self.failUnless(isinstance(e, apsw.NotADBError))
1989
2377
            self.failUnlessEqual(e.result, apsw.SQLITE_NOTADB);
1990
2378
            self.failUnlessEqual(e.extendedresult&0xff, apsw.SQLITE_NOTADB)
1991
2379
        db.close(True)
1995
2383
        except:
1996
2384
            pass
1997
2385
 
 
2386
    def testLimits(self):
 
2387
        "Verify setting and getting limits"
 
2388
        self.assertRaises(TypeError, self.db.limit, "apollo", 11)
 
2389
        c=self.db.cursor()
 
2390
        c.execute("create table foo(x)")
 
2391
        c.execute("insert into foo values(?)", ("x"*1024,))
 
2392
        old=self.db.limit(apsw.SQLITE_LIMIT_LENGTH)
 
2393
        self.db.limit(apsw.SQLITE_LIMIT_LENGTH, 1023)
 
2394
        self.assertRaises(apsw.TooBigError, c.execute, "insert into foo values(?)", ("y"*1024,))
 
2395
        self.failUnlessEqual(1023, self.db.limit(apsw.SQLITE_LIMIT_LENGTH, 0))
 
2396
        # bug in sqlite - see http://www.sqlite.org/cvstrac/tktview?tn=3085
 
2397
        if False:
 
2398
            c.execute("insert into foo values(?)", ("x"*1024,))
 
2399
            self.failUnlessEqual(apsw.SQLITE_MAX_LENGTH, self.db.limit(apsw.SQLITE_LIMIT_LENGTH))
 
2400
 
1998
2401
    def testConnectionHooks(self):
1999
2402
        "Verify connection hooks"
2000
2403
        del apsw.connection_hooks
2023
2426
        db=apsw.Connection(":memory:")
2024
2427
        db.close()
2025
2428
 
 
2429
    def testIssue4(self):
 
2430
        # http://code.google.com/p/apsw/issues/detail?id=4
 
2431
        connection = apsw.Connection(":memory:")
 
2432
        cursor = connection.cursor()
 
2433
 
 
2434
        cursor.execute("CREATE TABLE A_TABLE (ID ABC PRIMARY KEY NOT NULL)")
 
2435
        try:
 
2436
            cursor.execute("INSERT INTO A_TABLE VALUES (NULL)")
 
2437
        except:
 
2438
            klass,e,tb=sys.exc_info()
 
2439
            assert "A_TABLE.ID" in str(e)
 
2440
    
 
2441
        try:
 
2442
            cursor.execute("INSERT INTO A_TABLE VALUES (?)", (None,))
 
2443
        except:
 
2444
            klass,e,tb=sys.exc_info()
 
2445
            assert "A_TABLE.ID" in str(e)
 
2446
 
 
2447
    def testIssue15(self):
 
2448
        # http://code.google.com/p/apsw/issues/detail?id=15
 
2449
        self.db.cursor().execute("create table foo(x)")
 
2450
        self.db.cursor().execute("begin exclusive")
 
2451
        db2=apsw.Connection("testdb")
 
2452
        db2.setbusytimeout(30000)
 
2453
        t=ThreadRunner(db2.cursor().execute, "select * from foo")
 
2454
        t.start()
 
2455
        time.sleep(1)
 
2456
        self.db.cursor().execute("commit")
 
2457
        t.go()
 
2458
        
 
2459
 
2026
2460
    def testWriteUnraiseable(self):
2027
2461
        "Verify writeunraiseable replacement function"
2028
 
        # This will deliberately leak memory for the connection (the db object)
2029
 
 
 
2462
        def unraise():
 
2463
            # We cause an unraiseable error to happen by writing to a
 
2464
            # blob open for reading.  The close method called in the
 
2465
            # destructor will then also give the error
 
2466
            db=apsw.Connection(":memory:")
 
2467
            rowid=next(db.cursor().execute("create table foo(x); insert into foo values(x'aabbccdd'); select rowid from foo"))[0]
 
2468
            blob=db.blobopen("main", "foo", "x", rowid, False)
 
2469
            try:
 
2470
                blob.write(b("badd"))
 
2471
            except apsw.ReadOnlyError:
 
2472
                pass
 
2473
            del db
 
2474
            del blob
 
2475
            gc.collect()
 
2476
            
2030
2477
        xx=sys.excepthook
2031
2478
        called=[0]
2032
2479
        def ehook(t,v,tb, called=called):
2033
2480
            called[0]=1
2034
2481
        sys.excepthook=ehook
2035
 
        db2=apsw.Connection(":memory:")
2036
 
        del db2
 
2482
        unraise()
2037
2483
        self.failUnlessEqual(called[0], 1)
2038
2484
        yy=sys.stderr
2039
2485
        sys.stderr=open("errout.txt", "wt")
2040
2486
        def ehook(blah):
2041
2487
            1/0
2042
2488
        sys.excepthook=ehook
2043
 
        db2=apsw.Connection(":memory:")
2044
 
        del db2
 
2489
        unraise()
2045
2490
        sys.stderr.close()
2046
2491
        v=open("errout.txt", "rt").read()
2047
2492
        os.remove("errout.txt")
2049
2494
        sys.excepthook=xx
2050
2495
        sys.stderr=yy
2051
2496
 
2052
 
    def testStatementCache(self):
 
2497
    def testStatementCache(self, scsize=100):
 
2498
        "Verify statement cache integrity"
2053
2499
        cur=self.db.cursor()
2054
2500
        cur.execute("create table foo(x,y)")
2055
2501
        cur.execute("create index foo_x on foo(x)")
2060
2506
        #cur.execute("insert into foo values(1,2)") # cache hit, but invalid sql
2061
2507
        cur.executemany("insert into foo values(?)", [[1],[2]])
2062
2508
        # overflow the statement cache
2063
 
        l=[self.db.cursor().execute("select x from foo") for i in xrange(40)]
 
2509
        l=[self.db.cursor().execute("select x from foo") for i in range(scsize+200)]
2064
2510
        del l
2065
2511
        for _ in cur.execute("select * from foo"): pass
2066
 
        db2=apsw.Connection("testdb")
 
2512
        db2=apsw.Connection("testdb", statementcachesize=scsize)
2067
2513
        cur2=db2.cursor()
2068
2514
        cur2.execute("create table bar(x,y)")
2069
2515
        for _ in cur.execute("select * from foo"): pass
2070
2516
        db2.close()
2071
 
        
2072
 
 
2073
 
 
2074
 
# note that a directory must be specified otherwise $LD_LIBRARY_PATH is used
2075
 
LOADEXTENSIONFILENAME="./testextension.sqlext"
2076
 
            
 
2517
 
 
2518
    def testStatementCacheZeroSize(self):
 
2519
        self.db=apsw.Connection("testdb", statementcachesize=-1)
 
2520
        self.testStatementCache(-1)
 
2521
 
 
2522
    def testWikipedia(self):
 
2523
        "Use front page of wikipedia to check unicode handling"
 
2524
        # the text also includes characters that can't be represented in 16 bits
 
2525
        text=u(r"""WIKIPEDIA\nEnglish\nThe Free Encyclopedia\n2 386 000+ articles\nDeutsch\nDie freie Enzyklop\\u00e4die\n753 000+ Artikel\nFran\\u00e7ais\nL\\u2019encyclop\\u00e9die libre\n662 000+ articles\nPolski\nWolna encyklopedia\n503 000+ hase\\u0142\n\\u65e5\\u672c\\u8a9e\n\\u30d5\\u30ea\\u30fc\\u767e\\u79d1\\u4e8b\\u5178\n492 000+ \\u8a18\\u4e8b\nItaliano\nL\\u2019enciclopedia libera\n456 000+ voci\nNederlands\nDe vrije encyclopedie\n440 000+ artikelen\nPortugu\\u00eas\nA enciclop\\u00e9dia livre\n380 000+ artigos\nEspa\\u00f1ol\nLa enciclopedia libre\n363 000+ art\\u00edculos\n\\u0420\\u0443\\u0441\\u0441\\u043a\\u0438\\u0439\n\\u0421\\u0432\\u043e\\u0431\\u043e\\u0434\\u043d\\u0430\\u044f \\u044d\\u043d\\u0446\\u0438\\u043a\\u043b\\u043e\\u043f\\u0435\\u0434\\u0438\\u044f\n285 000+ \\u0441\\u0442\\u0430\\u0442\\u0435\\u0439\nSearch \\u00b7 Suche \\u00b7 Rechercher \\u00b7 Szukaj \\u00b7 \\u691c\\u7d22 \\u00b7 Ricerca \\u00b7 Zoeken \\u00b7 Busca \\u00b7 Buscar\n\\u041f\\u043e\\u0438\\u0441\\u043a \\u00b7 S\\u00f6k \\u00b7 \\u641c\\u7d22 \\u00b7 S\\u00f8k \\u00b7 Haku \\u00b7 Cerca \\u00b7 Suk \\u00b7 \\u041f\\u043e\\u0448\\u0443\\u043a \\u00b7 C\\u0103utare \\u00b7 Ara\n 100 000+ \nCatal\\u00e0 \\u00b7 Deutsch \\u00b7 English \\u00b7 Espa\\u00f1ol \\u00b7 Fran\\u00e7ais \\u00b7 Italiano \\u00b7 Nederlands \\u00b7 \\u65e5\\u672c\\u8a9e \\u00b7 Norsk (bokm\\u00e5l) \\u00b7 Polski \\u00b7 Portugu\\u00eas \\u00b7 \\u0420\\u0443\\u0441\\u0441\\u043a\\u0438\\u0439 \\u00b7 Rom\\u00e2n\\u0103 \\u00b7 Suomi \\u00b7 Svenska \\u00b7 T\\u00fcrk\\u00e7e \\u00b7 \\u0423\\u043a\\u0440\\u0430\\u0457\\u043d\\u0441\\u044c\\u043a\\u0430 \\u00b7 Volap\\u00fck \\u00b7 \\u4e2d\\u6587\n 10 000+ \n\\u0627\\u0644\\u0639\\u0631\\u0628\\u064a\\u0629 \\u00b7 Asturianu \\u00b7 Krey\\u00f2l Ayisyen \\u00b7 Az\\u0259rbaycan / \\u0622\\u0630\\u0631\\u0628\\u0627\\u064a\\u062c\\u0627\\u0646 \\u062f\\u064a\\u0644\\u06cc \\u00b7 \\u09ac\\u09be\\u0982\\u09b2\\u09be \\u00b7 \\u0411\\u0435\\u043b\\u0430\\u0440\\u0443\\u0441\\u043a\\u0430\\u044f (\\u0410\\u043a\\u0430\\u0434\\u044d\\u043c\\u0456\\u0447\\u043d\\u0430\\u044f) \\u00b7 \\u09ac\\u09bf\\u09b7\\u09cd\\u09a3\\u09c1\\u09aa\\u09cd\\u09b0\\u09bf\\u09af\\u09bc\\u09be \\u09ae\\u09a3\\u09bf\\u09aa\\u09c1\\u09b0\\u09c0 \\u00b7 Bosanski \\u00b7 Brezhoneg \\u00b7 \\u0411\\u044a\\u043b\\u0433\\u0430\\u0440\\u0441\\u043a\\u0438 \\u00b7 \\u010cesky \\u00b7 Cymraeg \\u00b7 Dansk \\u00b7 Eesti \\u00b7 \\u0395\\u03bb\\u03bb\\u03b7\\u03bd\\u03b9\\u03ba\\u03ac \\u00b7 Esperanto \\u00b7 Euskara \\u00b7 \\u0641\\u0627\\u0631\\u0633\\u06cc \\u00b7 Galego \\u00b7 \\ud55c\\uad6d\\uc5b4 \\u00b7 \\u0939\\u093f\\u0928\\u094d\\u0926\\u0940 \\u00b7 Hrvatski \\u00b7 Ido \\u00b7 Bahasa Indonesia \\u00b7 \\u00cdslenska \\u00b7 \\u05e2\\u05d1\\u05e8\\u05d9\\u05ea \\u00b7 Basa Jawa \\u00b7 \\u10e5\\u10d0\\u10e0\\u10d7\\u10e3\\u10da\\u10d8 \\u00b7 Kurd\\u00ee / \\u0643\\u0648\\u0631\\u062f\\u06cc \\u00b7 Latina \\u00b7 Lumbaart \\u00b7 Latvie\\u0161u \\u00b7 L\\u00ebtzebuergesch \\u00b7 Lietuvi\\u0173 \\u00b7 Magyar \\u00b7 \\u041c\\u0430\\u043a\\u0435\\u0434\\u043e\\u043d\\u0441\\u043a\\u0438 \\u00b7 \\u092e\\u0930\\u093e\\u0920\\u0940 \\u00b7 Bahasa Melayu \\u00b7 \\u0928\\u0947\\u092a\\u093e\\u0932 \\u092d\\u093e\\u0937\\u093e \\u00b7 Norsk (nynorsk) \\u00b7 Nnapulitano \\u00b7 Occitan \\u00b7 Piemont\\u00e8is \\u00b7 Plattd\\u00fc\\u00fctsch \\u00b7 Shqip \\u00b7 Sicilianu \\u00b7 Simple English \\u00b7 Sinugboanon \\u00b7 Sloven\\u010dina \\u00b7 Sloven\\u0161\\u010dina \\u00b7 \\u0421\\u0440\\u043f\\u0441\\u043a\\u0438 \\u00b7 Srpskohrvatski / \\u0421\\u0440\\u043f\\u0441\\u043a\\u043e\\u0445\\u0440\\u0432\\u0430\\u0442\\u0441\\u043a\\u0438 \\u00b7 Basa Sunda \\u00b7 Tagalog \\u00b7 \\u0ba4\\u0bae\\u0bbf\\u0bb4\\u0bcd \\u00b7 \\u0c24\\u0c46\\u0c32\\u0c41\\u0c17\\u0c41 \\u00b7 \\u0e44\\u0e17\\u0e22 \\u00b7 Ti\\u1ebfng Vi\\u1ec7t \\u00b7 Walon\n 1 000+ \nAfrikaans \\u00b7 Alemannisch \\u00b7 \\u12a0\\u121b\\u122d\\u129b \\u00b7 Aragon\\u00e9s \\u00b7 Arm\\u00e3neashce \\u00b7 Arpitan \\u00b7 B\\u00e2n-l\\u00e2m-g\\u00fa \\u00b7 Basa Banyumasan \\u00b7 \\u0411\\u0435\\u043b\\u0430\\u0440\\u0443\\u0441\\u043a\\u0430\\u044f (\\u0422\\u0430\\u0440\\u0430\\u0448\\u043a\\u0435\\u0432i\\u0446\\u0430) \\u00b7 \\u092d\\u094b\\u091c\\u092a\\u0941\\u0930\\u0940 \\u00b7 Boarisch \\u00b7 Corsu \\u00b7 \\u0427\\u0103\\u0432\\u0430\\u0448 \\u00b7 Deitsch \\u00b7 \\u078b\\u07a8\\u0788\\u07ac\\u0780\\u07a8 \\u00b7 Eald Englisc \\u00b7 F\\u00f8royskt \\u00b7 Frysk \\u00b7 Furlan \\u00b7 Gaeilge \\u00b7 Gaelg \\u00b7 G\\u00e0idhlig \\u00b7 \\u53e4\\u6587 / \\u6587\\u8a00\\u6587 \\u00b7 \\u02bb\\u014clelo Hawai\\u02bbi \\u00b7 \\u0540\\u0561\\u0575\\u0565\\u0580\\u0565\\u0576 \\u00b7 Hornjoserbsce \\u00b7 Ilokano \\u00b7 Interlingua \\u00b7 \\u0418\\u0440\\u043e\\u043d \\u00e6\\u0432\\u0437\\u0430\\u0433 \\u00b7 \\u0c95\\u0ca8\\u0ccd\\u0ca8\\u0ca1 \\u00b7 Kapampangan \\u00b7 Kasz\\u00ebbsczi \\u00b7 Kernewek \\u00b7 \\u1797\\u17b6\\u179f\\u17b6\\u1781\\u17d2\\u1798\\u17c2\\u179a \\u00b7 Ladino / \\u05dc\\u05d0\\u05d3\\u05d9\\u05e0\\u05d5 \\u00b7 Ligure \\u00b7 Limburgs \\u00b7 Ling\\u00e1la \\u00b7 \\u0d2e\\u0d32\\u0d2f\\u0d3e\\u0d33\\u0d02 \\u00b7 Malti \\u00b7 M\\u0101ori \\u00b7 \\u041c\\u043e\\u043d\\u0433\\u043e\\u043b \\u00b7 N\\u0101huatlaht\\u014dlli \\u00b7 Nedersaksisch \\u00b7 \\u0928\\u0947\\u092a\\u093e\\u0932\\u0940 \\u00b7 Nouormand \\u00b7 Novial \\u00b7 O\\u2018zbek \\u00b7 \\u092a\\u093e\\u0934\\u093f \\u00b7 Pangasin\\u00e1n \\u00b7 \\u067e\\u069a\\u062a\\u0648 \\u00b7 \\u049a\\u0430\\u0437\\u0430\\u049b\\u0448\\u0430 \\u00b7 Ripoarisch \\u00b7 Rumantsch \\u00b7 Runa Simi \\u00b7 \\u0938\\u0902\\u0938\\u094d\\u0915\\u0943\\u0924\\u092e\\u094d \\u00b7 S\\u00e1megiella \\u00b7 Scots \\u00b7 Kiswahili \\u00b7 Tarand\\u00edne \\u00b7 Tatar\\u00e7a \\u00b7 \\u0422\\u043e\\u04b7\\u0438\\u043a\\u04e3 \\u00b7 Lea faka-Tonga \\u00b7 T\\u00fcrkmen \\u00b7 \\u0627\\u0631\\u062f\\u0648 \\u00b7 V\\u00e8neto \\u00b7 V\\u00f5ro \\u00b7 West-Vlams \\u00b7 Winaray \\u00b7 \\u5434\\u8bed \\u00b7 \\u05d9\\u05d9\\u05b4\\u05d3\\u05d9\\u05e9 \\u00b7 \\u7cb5\\u8a9e \\u00b7 Yor\\u00f9b\\u00e1 \\u00b7 Zazaki \\u00b7 \\u017demait\\u0117\\u0161ka\n 100+ \n\\u0710\\u072a\\u0721\\u071d\\u0710 \\u00b7 Ava\\u00f1e\\u2019\\u1ebd \\u00b7 \\u0410\\u0432\\u0430\\u0440 \\u00b7 Aymara \\u00b7 Bamanankan \\u00b7 \\u0411\\u0430\\u0448\\u04a1\\u043e\\u0440\\u0442 \\u00b7 Bikol Central \\u00b7 \\u0f56\\u0f7c\\u0f51\\u0f0b\\u0f61\\u0f72\\u0f42 \\u00b7 Chamoru \\u00b7 Chavacano de Zamboanga \\u00b7 Bislama \\u00b7 Din\\u00e9 Bizaad \\u00b7 Dolnoserbski \\u00b7 Emigli\\u00e0n-Rumagn\\u00f2l \\u00b7 E\\u028begbe \\u00b7 \\u06af\\u06cc\\u0644\\u06a9\\u06cc \\u00b7 \\u0a97\\u0ac1\\u0a9c\\u0ab0\\u0abe\\u0aa4\\u0ac0 \\u00b7 \\U00010332\\U0001033f\\U00010344\\U00010339\\U00010343\\U0001033a \\u00b7 Hak-k\\u00e2-fa / \\u5ba2\\u5bb6\\u8a71 \\u00b7 Igbo \\u00b7 \\u1403\\u14c4\\u1483\\u144e\\u1450\\u1466 / Inuktitut \\u00b7 Interlingue \\u00b7 \\u0915\\u0936\\u094d\\u092e\\u0940\\u0930\\u0940 / \\u0643\\u0634\\u0645\\u064a\\u0631\\u064a \\u00b7 Kongo \\u00b7 \\u041a\\u044b\\u0440\\u0433\\u044b\\u0437\\u0447\\u0430 \\u00b7 \\u0e9e\\u0eb2\\u0eaa\\u0eb2\\u0ea5\\u0eb2\\u0ea7 \\u00b7 lojban \\u00b7 Malagasy \\u00b7 M\\u0101z\\u0259r\\u016bni / \\u0645\\u0627\\u0632\\u0650\\u0631\\u0648\\u0646\\u06cc \\u00b7 M\\u00ecng-d\\u0115\\u0324ng-ng\\u1e73\\u0304 \\u00b7 \\u041c\\u043e\\u043b\\u0434\\u043e\\u0432\\u0435\\u043d\\u044f\\u0441\\u043a\\u044d \\u00b7 \\u1017\\u1019\\u102c\\u1005\\u102c \\u00b7 Ekakair\\u0169 Naoero \\u00b7 N\\u0113hiyaw\\u0113win / \\u14c0\\u1426\\u1403\\u152d\\u140d\\u140f\\u1423 \\u00b7 Norfuk / Pitkern \\u00b7 \\u041d\\u043e\\u0445\\u0447\\u0438\\u0439\\u043d \\u00b7 \\u0b13\\u0b21\\u0b3c\\u0b3f\\u0b06 \\u00b7 Afaan Oromoo \\u00b7 \\u0985\\u09b8\\u09ae\\u09c0\\u09af\\u09bc\\u09be \\u00b7 \\u0a2a\\u0a70\\u0a1c\\u0a3e\\u0a2c\\u0a40 / \\u067e\\u0646\\u062c\\u0627\\u0628\\u06cc \\u00b7 Papiamentu \\u00b7 Q\\u0131r\\u0131mtatarca \\u00b7 Romani / \\u0930\\u094b\\u092e\\u093e\\u0928\\u0940 \\u00b7 Kinyarwanda \\u00b7 Gagana S\\u0101moa \\u00b7 Sardu \\u00b7 Seeltersk \\u00b7 \\u0dc3\\u0dd2\\u0d82\\u0dc4\\u0dbd \\u00b7 \\u0633\\u0646\\u068c\\u064a \\u00b7 \\u0421\\u043b\\u043e\\u0432\\u0463\\u043d\\u044c\\u0441\\u043a\\u044a \\u00b7 Af Soomaali \\u00b7 SiSwati \\u00b7 Reo Tahiti \\u00b7 Taqbaylit \\u00b7 Tetun \\u00b7 \\u1275\\u130d\\u122d\\u129b \\u00b7 Tok Pisin \\u00b7 \\u13e3\\u13b3\\u13a9 \\u00b7 \\u0423\\u0434\\u043c\\u0443\\u0440\\u0442 \\u00b7 Uyghur / \\u0626\\u06c7\\u064a\\u063a\\u06c7\\u0631\\u0686\\u0647 \\u00b7 Tshiven\\u1e13a \\u00b7 Wollof \\u00b7 isiXhosa \\u00b7 Ze\\u00eauws \\u00b7 isiZulu\nOther languages \\u00b7 Weitere Sprachen \\u00b7 \\u4ed6\\u306e\\u8a00\\u8a9e \\u00b7 Kompletna lista j\\u0119zyk\\u00f3w \\u00b7 \\u5176\\u4ed6\\u8bed\\u8a00 \\u00b7 \\u0414\\u0440\\u0443\\u0433\\u0438\\u0435 \\u044f\\u0437\\u044b\\u043a\\u0438 \\u00b7 Aliaj lingvoj \\u00b7 \\ub2e4\\ub978 \\uc5b8\\uc5b4 \\u00b7 Ng\\u00f4n ng\\u1eef kh\\u00e1c""")
 
2526
 
 
2527
        self.db.close()
 
2528
 
 
2529
        for encoding in "UTF-16", "UTF-16le", "UTF-16be", "UTF-8":
 
2530
            if os.path.exists("testdb"):
 
2531
                os.remove("testdb")
 
2532
            db=apsw.Connection("testdb")
 
2533
            c=db.cursor()
 
2534
            c.execute("pragma encoding=\"%s\"" % (encoding,))
 
2535
            for row in c.execute("pragma encoding"):
 
2536
                # we use startswith as UTF-16 will be returned with le/be suffix
 
2537
                self.assert_(row[0].startswith(encoding))
 
2538
            c.execute("create table foo(x); insert into foo values(?)", (text,))
 
2539
            for row in c.execute("select * from foo"):
 
2540
                self.failUnlessEqual(row[0], text)
 
2541
            db.close()
 
2542
 
 
2543
 
 
2544
    def sourceCheckFunction(self, name, lines):
 
2545
        # Checks an individual function does things right
 
2546
        if name.startswith("ZeroBlobBind_"):
 
2547
                return
 
2548
 
 
2549
        if name.startswith("APSWCursor_"):
 
2550
            # these methods aren't publically exported so the checks
 
2551
            # will already have been done by their callers
 
2552
            if name[len("APSWCursor_"):] in ("dealloc", "init", "dobinding", "dobindings", "doexectrace", "dorowtrace", "step", "close"):
 
2553
                return
 
2554
            use=None
 
2555
            closed=None
 
2556
            for i,line in enumerate(lines):
 
2557
                if "CHECK_USE" in line and use is None:
 
2558
                    use=i
 
2559
                if "CHECK_CLOSED" in line and closed is None:
 
2560
                    closed=i
 
2561
            if use is None:
 
2562
                self.fail("CHECK_USE missing in "+name)
 
2563
            if closed is None:
 
2564
                self.fail("CHECK_CLOSED missing in "+name)
 
2565
            if closed<use:
 
2566
                self.fail("CHECK_CLOSED should be after CHECK_USE in "+name)
 
2567
            return
 
2568
 
 
2569
        if name.startswith("Connection_"):
 
2570
            # these methods aren't publically exported so the checks
 
2571
            # will already have been done by their callers
 
2572
            if name[len("Connection_"):] in ("internal_cleanup", "dealloc", "init", "close", "interrupt"):
 
2573
                return
 
2574
            use=None
 
2575
            closed=None
 
2576
            for i,line in enumerate(lines):
 
2577
                if "CHECK_USE" in line and use is None:
 
2578
                    use=i
 
2579
                if "CHECK_CLOSED" in line and closed is None:
 
2580
                    closed=i
 
2581
            if use is None:
 
2582
                self.fail("CHECK_USE missing in "+name)
 
2583
            if closed is None:
 
2584
                self.fail("CHECK_CLOSED missing in "+name)
 
2585
            if closed<use:
 
2586
                self.fail("CHECK_CLOSED should be after CHECK_USE in "+name)
 
2587
            return
 
2588
 
 
2589
        if name.startswith("APSWBlob_"):
 
2590
            # these methods aren't publically exported so the checks
 
2591
            # will already have been done by their callers
 
2592
            if name[len("APSWBlob_"):] in ("dealloc", "init", "close"):
 
2593
                return
 
2594
            use=None
 
2595
            closed=None
 
2596
            for i,line in enumerate(lines):
 
2597
                if "CHECK_USE" in line and use is None:
 
2598
                    use=i
 
2599
                if "CHECK_BLOB_CLOSED" in line and closed is None:
 
2600
                    closed=i
 
2601
            if use is None:
 
2602
                self.fail("CHECK_USE missing in "+name)
 
2603
            if closed is None:
 
2604
                self.fail("CHECK_BLOB_CLOSED missing in "+name)
 
2605
            if closed<use:
 
2606
                self.fail("CHECK_BLOB_CLOSED should be after CHECK_USE in "+name)
 
2607
            return
 
2608
 
 
2609
        self.fail(name+" doesn't have source check")
 
2610
 
 
2611
    def testSourceChecks(self):
 
2612
        "Check various source code issues"
 
2613
        # We expect a coding style where the functions are named
 
2614
        # Object_method, are at the start of the line and have a first
 
2615
        # parameter named self.
 
2616
        if not os.path.exists("apsw.c"): return
 
2617
        funcpat=re.compile(r"^(\w+_\w+)\s*\(\s*\w+\s*\*\s*self")
 
2618
        name=None
 
2619
        lines=[]
 
2620
        infunc=False
 
2621
        for line in open("apsw.c", "rtU"):
 
2622
            if line.startswith("}") and infunc:
 
2623
                infunc=False
 
2624
                self.sourceCheckFunction(name, lines)
 
2625
                lines=[]
 
2626
                name=None
 
2627
                continue
 
2628
            if name and line.startswith("{"):
 
2629
                infunc=True
 
2630
                continue
 
2631
            if infunc:
 
2632
                lines.append(line)
 
2633
                continue
 
2634
            m=funcpat.match(line)
 
2635
            if m:
 
2636
                name=m.group(1)
 
2637
            
 
2638
 
 
2639
    def testZeroBlob(self):
 
2640
        "Verify handling of zero blobs"
 
2641
        self.assertRaises(TypeError, apsw.zeroblob)
 
2642
        self.assertRaises(TypeError, apsw.zeroblob, "foo")
 
2643
        self.assertRaises(TypeError, apsw.zeroblob, -7)
 
2644
        self.assertRaises(TypeError, apsw.zeroblob, size=27)
 
2645
        self.assertRaises(OverflowError, apsw.zeroblob, 4000000000)
 
2646
        cur=self.db.cursor()
 
2647
        cur.execute("create table foo(x)")
 
2648
        cur.execute("insert into foo values(?)", (apsw.zeroblob(27),))
 
2649
        v=next(cur.execute("select * from foo"))[0]
 
2650
        self.assertEqual(v, b(r"\x00"*27))
 
2651
        # Make sure inheritance works
 
2652
        class multi:
 
2653
            def __init__(self, *args):
 
2654
                self.foo=3
 
2655
        class derived(apsw.zeroblob):
 
2656
            def __init__(self, num):
 
2657
                #multi.__init__(self)
 
2658
                apsw.zeroblob.__init__(self, num)
 
2659
        cur.execute("delete from foo; insert into foo values(?)", (derived(28),))
 
2660
        v=next(cur.execute("select * from foo"))[0]
 
2661
        self.assertEqual(v, b(r"\x00"*28))
 
2662
 
 
2663
    def testBlobIO(self):
 
2664
        "Verify Blob input/output"
 
2665
        cur=self.db.cursor()
 
2666
        rowid=next(cur.execute("create table foo(x blob); insert into foo values(zeroblob(98765)); select rowid from foo"))[0]
 
2667
        self.assertRaises(TypeError, self.db.blobopen, 1)
 
2668
        self.assertRaises(TypeError, self.db.blobopen, u("main"), "foo\xf3")
 
2669
        if sys.version_info>=(2,4):
 
2670
            # Bug in python 2.3 gives internal error when complex is
 
2671
            # passed to PyArg_ParseTuple for Long instead of raising
 
2672
            # TypeError.  Corrected in 2.4
 
2673
            self.assertRaises(TypeError, self.db.blobopen, u("main"), "foo", "x", complex(-1,-1), True)
 
2674
        self.assertRaises(TypeError, self.db.blobopen, u("main"), "foo", "x", rowid, True, False)
 
2675
        self.assertRaises(apsw.SQLError, self.db.blobopen, "main", "foo", "x", rowid+27, False)
 
2676
        self.assertRaises(apsw.SQLError, self.db.blobopen, "foo", "foo" , "x", rowid, False)
 
2677
        self.assertRaises(apsw.SQLError, self.db.blobopen, "main", "x" , "x", rowid, False)
 
2678
        self.assertRaises(apsw.SQLError, self.db.blobopen, "main", "foo" , "y", rowid, False)
 
2679
        blobro=self.db.blobopen("main", "foo", "x", rowid, False)
 
2680
        # sidebar: check they can't be manually created
 
2681
        self.assertRaises(TypeError, type(blobro))
 
2682
        # check vals
 
2683
        self.assertEqual(blobro.length(), 98765)
 
2684
        self.assertEqual(blobro.length(), 98765)
 
2685
        self.failUnlessEqual(blobro.read(0), BYTES(""))
 
2686
        for i in range(98765):
 
2687
            x=blobro.read(1)
 
2688
            self.assertEqual(BYTES(r"\x00"), x)
 
2689
        x=blobro.read(10)
 
2690
        self.assertEqual(x, None)
 
2691
        blobro.seek(0,1)
 
2692
        self.assertEqual(blobro.tell(), 98765)
 
2693
        blobro.seek(0)
 
2694
        self.assertEqual(blobro.tell(), 0)
 
2695
        self.failUnlessEqual(len(blobro.read(11119999)), 98765)
 
2696
        blobro.seek(2222)
 
2697
        self.assertEqual(blobro.tell(), 2222)
 
2698
        blobro.seek(0,0)
 
2699
        self.assertEqual(blobro.tell(), 0)
 
2700
        self.assertEqual(blobro.read(), BYTES(r"\x00"*98765))
 
2701
        blobro.seek(-3,2)
 
2702
        self.assertEqual(blobro.read(), BYTES(r"\x00"*3))
 
2703
        # check types
 
2704
        self.assertRaises(TypeError, blobro.read, "foo")
 
2705
        self.assertRaises(TypeError, blobro.tell, "foo")
 
2706
        self.assertRaises(TypeError, blobro.seek)
 
2707
        self.assertRaises(TypeError, blobro.seek, "foo", 1)
 
2708
        self.assertRaises(TypeError, blobro.seek, 0, 1, 2)
 
2709
        self.assertRaises(ValueError, blobro.seek, 0, -3)
 
2710
        self.assertRaises(ValueError, blobro.seek, 0, 3)
 
2711
        # can't seek before begining or after end of file
 
2712
        self.assertRaises(ValueError, blobro.seek, -1, 0)
 
2713
        self.assertRaises(ValueError, blobro.seek, 25, 1)
 
2714
        self.assertRaises(ValueError, blobro.seek, 25, 2)
 
2715
        self.assertRaises(ValueError, blobro.seek, 100000, 0)
 
2716
        self.assertRaises(ValueError, blobro.seek, -100000, 1)
 
2717
        self.assertRaises(ValueError, blobro.seek, -100000, 2)
 
2718
        blobro.seek(0,0)
 
2719
        self.assertRaises(apsw.ReadOnlyError, blobro.write, b("kermit was here"))
 
2720
        # you get the error on the close too, and blob is always closed - sqlite ticket #2815
 
2721
        self.assertRaises(apsw.ReadOnlyError, blobro.close) 
 
2722
        # check can't work on closed blob
 
2723
        self.assertRaises(ValueError, blobro.read)
 
2724
        self.assertRaises(ValueError, blobro.seek, 0, 0)
 
2725
        self.assertRaises(ValueError, blobro.tell)
 
2726
        self.assertRaises(ValueError, blobro.write, "abc")
 
2727
        # write tests
 
2728
        blobrw=self.db.blobopen("main", "foo", "x", rowid, True)
 
2729
        self.assertEqual(blobrw.length(), 98765)
 
2730
        blobrw.write(b("abcd"))
 
2731
        blobrw.seek(0, 0)
 
2732
        self.assertEqual(blobrw.read(4), BYTES("abcd"))
 
2733
        blobrw.write(b("efg"))
 
2734
        blobrw.seek(0, 0)
 
2735
        self.assertEqual(blobrw.read(7), BYTES("abcdefg"))
 
2736
        blobrw.seek(50, 0)
 
2737
        blobrw.write(b("hijkl"))
 
2738
        blobrw.seek(-98765, 2)
 
2739
        self.assertEqual(blobrw.read(55), BYTES("abcdefg"+r"\x00"*43+"hijkl"))
 
2740
        self.assertRaises(TypeError, blobrw.write, 12)
 
2741
        self.assertRaises(TypeError, blobrw.write)
 
2742
        # try to go beyond end
 
2743
        self.assertRaises(ValueError, blobrw.write, b(" "*100000))
 
2744
        self.assertRaises(TypeError, blobrw.close, "elephant")
 
2745
 
 
2746
    def testBlobReadError(self):
 
2747
        "Ensure blob read errors are handled well"
 
2748
        cur=self.db.cursor()
 
2749
        cur.execute("create table ioerror (x, blob)")
 
2750
        cur.execute("insert into ioerror (rowid,x,blob) values (2,3,x'deadbeef')")
 
2751
        blob=self.db.blobopen("main", "ioerror", "blob", 2, False)
 
2752
        blob.read(1)
 
2753
        cur.execute("update ioerror set blob='fsdfdsfasd' where x=3")
 
2754
        try:
 
2755
            blob.read(1)
 
2756
            1/0
 
2757
        except:
 
2758
            klass,value=sys.exc_info()[:2]
 
2759
            self.assert_(klass is apsw.AbortError)
 
2760
 
 
2761
    # Note that faults fire only once, so there is no need to reset
 
2762
    # them.  The testing for objects bigger than 2GB is done in
 
2763
    # testLargeObjects
 
2764
    def testzzFaultInjection(self):
 
2765
        if not hasattr(apsw, "faultdict"):
 
2766
            return
 
2767
 
 
2768
        def dummy(*args):
 
2769
            1/0
 
2770
 
 
2771
        def dummy2(*args):
 
2772
            return 7
 
2773
 
 
2774
        # The 1/0 in these tests is to cause a ZeroDivisionError so
 
2775
        # that an exception is always thrown.  If we catch that then
 
2776
        # it means earlier expected exceptions were not thrown.
 
2777
 
 
2778
        ## UnknownSQLiteErrorCode
 
2779
        apsw.faultdict["UnknownSQLiteErrorCode"]=True
 
2780
        try:
 
2781
            self.db.cursor().execute("select '")
 
2782
            1/0
 
2783
        except:
 
2784
            klass,value=sys.exc_info()[:2]
 
2785
            self.assert_(klass is apsw.Error)
 
2786
            self.assert_("254" in str(value))
 
2787
 
 
2788
        ## AsWriteBufferFails
 
2789
        if not py3:
 
2790
            apsw.faultdict["AsWriteBufferFails"]=True
 
2791
            try:
 
2792
                for row in self.db.cursor().execute("select x'1234ccddeeff'"):
 
2793
                    pass
 
2794
                1/0
 
2795
            except:
 
2796
                klass,value=sys.exc_info()[:2]
 
2797
                self.assert_(klass is MemoryError)
 
2798
 
 
2799
        ## ConnectionCloseFail
 
2800
        apsw.faultdict["ConnectionCloseFail"]=True
 
2801
        try:
 
2802
            db=apsw.Connection(":memory:")
 
2803
            db.cursor().execute("select 3")
 
2804
            db.close(True)
 
2805
            1/0
 
2806
        except:
 
2807
            klass,value=sys.exc_info()[:2]
 
2808
            self.assert_(klass is apsw.IOError)
 
2809
 
 
2810
        ## DestructorCloseFail
 
2811
        if not os.getenv("APSW_NO_MEMLEAK"):
 
2812
            # save existing excepthook
 
2813
            xx=sys.excepthook
 
2814
            # put in our own
 
2815
            called=[0]
 
2816
            def ehook(t,v,tb, called=called):
 
2817
                called[0]=1
 
2818
            sys.excepthook=ehook
 
2819
            # test
 
2820
            apsw.faultdict["DestructorCloseFail"]=True
 
2821
            db=apsw.Connection(":memory:")
 
2822
            db.cursor().execute("select 3")
 
2823
            del db
 
2824
            gc.collect()
 
2825
            # check there was an unraiseable
 
2826
            self.failUnlessEqual(called[0], 1)
 
2827
            # restore
 
2828
            sys.excepthook=xx
 
2829
 
 
2830
        ## BlobAllocFails
 
2831
        apsw.faultdict["BlobAllocFails"]=True
 
2832
        try:
 
2833
            db=apsw.Connection(":memory:")
 
2834
            db.cursor().execute("create table foo(ablob); insert into foo (ROWID, ablob) values (1,x'aabbccddeeff')")
 
2835
            blob=db.blobopen("main", "foo", "ablob", 1, False)
 
2836
            1/0
 
2837
        except:
 
2838
            klass,value=sys.exc_info()[:2]
 
2839
            self.assert_(klass is MemoryError)
 
2840
 
 
2841
        ## CursorAllocFails
 
2842
        apsw.faultdict["CursorAllocFails"]=True
 
2843
        try:
 
2844
            db=apsw.Connection(":memory:")
 
2845
            db.cursor().execute("select 3")
 
2846
            1/0
 
2847
        except:
 
2848
            klass,value=sys.exc_info()[:2]
 
2849
            self.assert_(klass is MemoryError)
 
2850
 
 
2851
        ## RollbackHookExistingError
 
2852
        apsw.faultdict["RollbackHookExistingError"]=True
 
2853
        try:
 
2854
            db=apsw.Connection(":memory:")
 
2855
            db.setrollbackhook(dummy)
 
2856
            db.cursor().execute("create table foo(a); begin ; insert into foo values(3); rollback")
 
2857
            1/0
 
2858
        except:
 
2859
            klass,value=sys.exc_info()[:2]
 
2860
            self.assert_(klass is MemoryError)
 
2861
 
 
2862
        ## CommitHookExceptionAlready
 
2863
        apsw.faultdict["CommitHookExistingError"]=True
 
2864
        try:
 
2865
            db=apsw.Connection(":memory:")
 
2866
            db.setcommithook(dummy)
 
2867
            db.cursor().execute("begin; create table foo(a); insert into foo values(3); commit")
 
2868
            1/0
 
2869
        except:
 
2870
            klass,value=sys.exc_info()[:2]
 
2871
            self.assert_(klass is MemoryError)
 
2872
 
 
2873
        ## AuthorizerExistingError
 
2874
        apsw.faultdict["AuthorizerExistingError"]=True
 
2875
        try:
 
2876
            db=apsw.Connection(":memory:")
 
2877
            db.setauthorizer(dummy)
 
2878
            db.cursor().execute("create table foo(a)")
 
2879
            1/0
 
2880
        except:
 
2881
            klass,value=sys.exc_info()[:2]
 
2882
            self.assert_(klass is MemoryError)
 
2883
 
 
2884
        ## SetAuthorizerNullFail
 
2885
        apsw.faultdict["SetAuthorizerNullFail"]=True
 
2886
        try:
 
2887
            db=apsw.Connection(":memory:")
 
2888
            db.setauthorizer(None)
 
2889
            1/0
 
2890
        except:
 
2891
            klass,value=sys.exc_info()[:2]
 
2892
            self.assert_(klass is apsw.IOError)
 
2893
 
 
2894
        ## SetAuthorizerFail
 
2895
        apsw.faultdict["SetAuthorizerFail"]=True
 
2896
        try:
 
2897
            db=apsw.Connection(":memory:")
 
2898
            db.setauthorizer(dummy)
 
2899
            1/0
 
2900
        except:
 
2901
            klass,value=sys.exc_info()[:2]
 
2902
            self.assert_(klass is apsw.IOError)
 
2903
 
 
2904
        ## CollationNeededNullFail
 
2905
        apsw.faultdict["CollationNeededNullFail"]=True
 
2906
        try:
 
2907
            db=apsw.Connection(":memory:")
 
2908
            db.collationneeded(None)
 
2909
            1/0
 
2910
        except:
 
2911
            klass,value=sys.exc_info()[:2]
 
2912
            self.assert_(klass is apsw.IOError)
 
2913
            
 
2914
        ## CollationNeededFail
 
2915
        apsw.faultdict["CollationNeededFail"]=True
 
2916
        try:
 
2917
            db=apsw.Connection(":memory:")
 
2918
            db.collationneeded(dummy)
 
2919
            1/0
 
2920
        except:
 
2921
            klass,value=sys.exc_info()[:2]
 
2922
            self.assert_(klass is apsw.IOError)
 
2923
 
 
2924
        ##EnableLoadExtensionFail
 
2925
        apsw.faultdict["EnableLoadExtensionFail"]=True
 
2926
        try:
 
2927
            db=apsw.Connection(":memory:")
 
2928
            db.enableloadextension(True)
 
2929
            1/0
 
2930
        except:
 
2931
            klass,value=sys.exc_info()[:2]
 
2932
            self.assert_(klass is apsw.IOError)
 
2933
 
 
2934
        ## SetBusyHandlerNullFail
 
2935
        apsw.faultdict["SetBusyHandlerNullFail"]=True
 
2936
        try:
 
2937
            db=apsw.Connection(":memory:")
 
2938
            db.setbusyhandler(None)
 
2939
            1/0
 
2940
        except:
 
2941
            klass,value=sys.exc_info()[:2]
 
2942
            self.assert_(klass is apsw.IOError)
 
2943
            
 
2944
        ## SetBusyHandlerFail
 
2945
        apsw.faultdict["SetBusyHandlerFail"]=True
 
2946
        try:
 
2947
            db=apsw.Connection(":memory:")
 
2948
            db.setbusyhandler(dummy)
 
2949
            1/0
 
2950
        except:
 
2951
            klass,value=sys.exc_info()[:2]
 
2952
            self.assert_(klass is apsw.IOError)
 
2953
 
 
2954
        ## UnknownValueType
 
2955
        apsw.faultdict["UnknownValueType"]=True
 
2956
        try:
 
2957
            db=apsw.Connection(":memory:")
 
2958
            db.createscalarfunction("dummy", dummy)
 
2959
            db.cursor().execute("select dummy(4)")
 
2960
            1/0
 
2961
        except:
 
2962
            klass,value=sys.exc_info()[:2]
 
2963
            self.assert_(klass is apsw.Error)
 
2964
            self.assert_("123456" in str(value))
 
2965
 
 
2966
        ## UnknownColumnType
 
2967
        apsw.faultdict["UnknownColumnType"]=True
 
2968
        try:
 
2969
            db=apsw.Connection(":memory:")
 
2970
            for row in db.cursor().execute("select 3"):
 
2971
                pass
 
2972
            1/0
 
2973
        except:
 
2974
            klass,value=sys.exc_info()[:2]
 
2975
            self.assert_(klass is apsw.Error)
 
2976
            self.assert_("12348" in str(value))
 
2977
        
 
2978
        ## SetContextResultUnicodeConversionFails
 
2979
        apsw.faultdict["SetContextResultUnicodeConversionFails"]=True
 
2980
        try:
 
2981
            db=apsw.Connection(":memory:")
 
2982
            db.createscalarfunction("foo", lambda x: u("another unicode string"))
 
2983
            for row in db.cursor().execute("select foo(3)"):
 
2984
                pass
 
2985
            1/0
 
2986
        except:
 
2987
            klass,value=sys.exc_info()[:2]
 
2988
            self.assert_(klass is MemoryError)
 
2989
 
 
2990
        ## SetContextResultStringUnicodeConversionFails
 
2991
        if sys.version_info<(3,0):
 
2992
            apsw.faultdict["SetContextResultStringUnicodeConversionFails"]=True
 
2993
            try:
 
2994
                db=apsw.Connection(":memory:")
 
2995
                db.createscalarfunction("foo", lambda x: "another string"*10000)
 
2996
                for row in db.cursor().execute("select foo(3)"):
 
2997
                    pass
 
2998
                1/0
 
2999
            except:
 
3000
                klass,value=sys.exc_info()[:2]
 
3001
                self.assert_(klass is MemoryError)
 
3002
 
 
3003
        ## SetContextResultAsReadBufferFail
 
3004
        apsw.faultdict["SetContextResultAsReadBufferFail"]=True
 
3005
        try:
 
3006
            db=apsw.Connection(":memory:")
 
3007
            db.createscalarfunction("foo", lambda x: b("another string"))
 
3008
            for row in db.cursor().execute("select foo(3)"):
 
3009
                pass
 
3010
            1/0
 
3011
        except:
 
3012
            klass,value=sys.exc_info()[:2]
 
3013
            self.assert_(klass is MemoryError)
 
3014
 
 
3015
        ## GFAPyTuple_NewFail
 
3016
        apsw.faultdict["GFAPyTuple_NewFail"]=True
 
3017
        try:
 
3018
            db=apsw.Connection(":memory:")
 
3019
            db.createscalarfunction("foo", dummy)
 
3020
            for row in db.cursor().execute("select foo(3)"):
 
3021
                pass
 
3022
            1/0
 
3023
        except:
 
3024
            klass,value=sys.exc_info()[:2]
 
3025
            self.assert_(klass is MemoryError)
 
3026
 
 
3027
        ## Same again
 
3028
        apsw.faultdict["GFAPyTuple_NewFail"]=True
 
3029
        try:
 
3030
            db=apsw.Connection(":memory:")
 
3031
            def foo():
 
3032
                return None, dummy2, dummy2
 
3033
            db.createaggregatefunction("foo", foo)
 
3034
            for row in db.cursor().execute("create table bar(x);insert into bar values(3); select foo(x) from bar"):
 
3035
                pass
 
3036
            1/0
 
3037
        except:
 
3038
            klass,value=sys.exc_info()[:2]
 
3039
            self.assert_(klass is MemoryError)
 
3040
 
 
3041
        ## CBDispatchExistingError
 
3042
        apsw.faultdict["CBDispatchExistingError"]=True
 
3043
        try:
 
3044
            db=apsw.Connection(":memory:")
 
3045
            db.createscalarfunction("foo", dummy)
 
3046
            db.cursor().execute("select foo(3)")
 
3047
            1/0
 
3048
        except:
 
3049
            klass,value=sys.exc_info()[:2]
 
3050
            self.assert_(klass is MemoryError)
 
3051
 
 
3052
        ## CBDispatchFinalError
 
3053
        apsw.faultdict["CBDispatchFinalError"]=True
 
3054
        try:
 
3055
            # save existing excepthook
 
3056
            xx=sys.excepthook
 
3057
            # put in our own
 
3058
            called=[0]
 
3059
            def ehook(t,v,tb, called=called):
 
3060
                called[0]=1
 
3061
            sys.excepthook=ehook
 
3062
 
 
3063
            db=apsw.Connection(":memory:")
 
3064
            def foo():
 
3065
                return None, dummy, dummy2
 
3066
            db.createaggregatefunction("foo", foo)
 
3067
            for row in db.cursor().execute("create table bar(x);insert into bar values(3); select foo(x) from bar"):
 
3068
                pass
 
3069
            1/0
 
3070
        except:
 
3071
            klass,value=sys.exc_info()[:2]
 
3072
            self.assert_(klass is ZeroDivisionError)
 
3073
            # restore
 
3074
            sys.excepthook=xx
 
3075
            # check there was an unraiseable
 
3076
            self.failUnlessEqual(called[0], 1)
 
3077
 
 
3078
        ## Virtual table code
 
3079
        class Source:
 
3080
            def Create(self, *args):
 
3081
                return "create table foo(x,y)", Table()
 
3082
            Connect=Create
 
3083
        class Table:
 
3084
            def __init__(self):
 
3085
                self.data=[ #("rowid", "x", "y"),
 
3086
                            [0, 1, 2],
 
3087
                            [3, 4, 5]]
 
3088
            def Open(self):
 
3089
                return Cursor(self)
 
3090
 
 
3091
            def BestIndex(self, *args): return None
 
3092
 
 
3093
            def UpdateChangeRow(self, rowid, newrowid, fields):
 
3094
                for i, row in enumerate(self.data):
 
3095
                    if row[0]==rowid:
 
3096
                        self.data[i]=[newrowid]+list(fields)
 
3097
        class Cursor:
 
3098
            def __init__(self, table):
 
3099
                self.table=table
 
3100
                self.row=0
 
3101
            def Eof(self):
 
3102
                return self.row>=len(self.table.data)
 
3103
            def Rowid(self):
 
3104
                return self.table.data[self.row][0]
 
3105
            def Column(self, col):
 
3106
                return self.table.data[self.row][1+col]
 
3107
            def Filter(self, *args):
 
3108
                self.row=0
 
3109
            def Next(self):
 
3110
                self.row+=1
 
3111
                def Close(self): pass
 
3112
 
 
3113
        ## VtabCreateBadString
 
3114
        apsw.faultdict["VtabCreateBadString"]=True
 
3115
        try:
 
3116
            db=apsw.Connection(":memory:")
 
3117
            db.createmodule("nonsense", None)
 
3118
            db.cursor().execute("create virtual table foo using nonsense(3,4)")
 
3119
            1/0
 
3120
        except:
 
3121
            klass,value=sys.exc_info()[:2]
 
3122
            self.assert_(klass is MemoryError)
 
3123
 
 
3124
        ## VtabUpdateChangeRowFail
 
3125
        apsw.faultdict["VtabUpdateChangeRowFail"]=True
 
3126
        try:
 
3127
            db=apsw.Connection(":memory:")
 
3128
            db.createmodule("foo", Source())
 
3129
            db.cursor().execute("create virtual table foo using foo();update foo set x=3 where y=2")
 
3130
            1/0
 
3131
        except:
 
3132
            klass,value=sys.exc_info()[:2]
 
3133
            self.assert_(klass is MemoryError)
 
3134
 
 
3135
        ## VtabUpdateBadField
 
3136
        apsw.faultdict["VtabUpdateBadField"]=True
 
3137
        try:
 
3138
            db=apsw.Connection(":memory:")
 
3139
            db.createmodule("foo", Source())
 
3140
            db.cursor().execute("create virtual table foo using foo();update foo set x=3 where y=2")
 
3141
            1/0
 
3142
        except:
 
3143
            klass,value=sys.exc_info()[:2]
 
3144
            self.assert_(klass is MemoryError)
 
3145
            
 
3146
        ## VtabRenameBadName
 
3147
        apsw.faultdict["VtabRenameBadName"]=True
 
3148
        try:
 
3149
            db=apsw.Connection(":memory:")
 
3150
            db.createmodule("foo", Source())
 
3151
            db.cursor().execute("create virtual table foo using foo(); alter table foo rename to bar")
 
3152
            1/0
 
3153
        except:
 
3154
            klass,value=sys.exc_info()[:2]
 
3155
            self.assert_(klass is MemoryError)
 
3156
 
 
3157
        ## VtabRenameBadName
 
3158
        apsw.faultdict["CreateModuleFail"]=True
 
3159
        try:
 
3160
            db=apsw.Connection(":memory:")
 
3161
            db.createmodule("foo", Source())
 
3162
            1/0
 
3163
        except:
 
3164
            klass,value=sys.exc_info()[:2]
 
3165
            self.assert_(klass is apsw.IOError)        
 
3166
 
 
3167
        
 
3168
if sys.platform!="win32":
 
3169
    # note that a directory must be specified otherwise $LD_LIBRARY_PATH is used
 
3170
    LOADEXTENSIONFILENAME="./testextension.sqlext"
 
3171
else:
 
3172
    LOADEXTENSIONFILENAME="testextension.sqlext"
 
3173
 
2077
3174
MEMLEAKITERATIONS=1000
2078
3175
PROFILESTEPS=100000
2079
3176
 
2080
3177
if __name__=='__main__':
2081
3178
 
2082
 
    if not getattr(apsw, "enableloadextension", None):
 
3179
    memdb=apsw.Connection(":memory:")
 
3180
    if not getattr(memdb, "enableloadextension", None):
2083
3181
        del APSW.testLoadExtension
2084
3182
 
2085
 
    if getattr(apsw, "enableloadextension", None) and not os.path.exists(LOADEXTENSIONFILENAME):
2086
 
        print "Not doing LoadExtension test.  You need to compile the extension first"
 
3183
    # We can do extension loading but no extension present ...
 
3184
    if getattr(memdb, "enableloadextension", None) and not os.path.exists(LOADEXTENSIONFILENAME):
 
3185
        write("Not doing LoadExtension test.  You need to compile the extension first\n")
2087
3186
        if sys.platform.startswith("darwin"):
2088
 
            print "  gcc -fPIC -bundle -o "+LOADEXTENSIONFILENAME+" -Isqlite3 testextension.c"
 
3187
            write("  gcc -fPIC -bundle -o "+LOADEXTENSIONFILENAME+" -Isqlite3 testextension.c\n")
2089
3188
        else:
2090
 
            print "  gcc -fPIC -shared -o "+LOADEXTENSIONFILENAME+" -Isqlite3 testextension.c"
 
3189
            write("  gcc -fPIC -shared -o "+LOADEXTENSIONFILENAME+" -Isqlite3 testextension.c\n")
2091
3190
        del APSW.testLoadExtension
2092
 
 
2093
 
    # This test has to deliberately leak memory
 
3191
        sys.stdout.flush()
 
3192
 
 
3193
    del memdb
 
3194
 
2094
3195
    if os.getenv("APSW_NO_MEMLEAK"):
2095
 
        del APSW.testWriteUnraiseable
2096
 
    
 
3196
        # Delete tests that have to deliberately leak memory
 
3197
        # del APSW.testWriteUnraiseable  (used to but no more)
 
3198
        pass
 
3199
        
2097
3200
    v=os.getenv("APSW_TEST_ITERATIONS")
2098
3201
    if v is None:
2099
3202
        unittest.main()
2103
3206
        MEMLEAKITERATIONS=5
2104
3207
        PROFILESTEPS=1000
2105
3208
        v=int(v)
2106
 
        for i in xrange(v):
2107
 
            print "Iteration",i+1,"of",v
 
3209
        for i in range(v):
 
3210
            write("Iteration "+str(i+1)+" of "+str(v)+"\n")
2108
3211
            try:
2109
3212
                unittest.main()
2110
3213
            except SystemExit:
2126
3229
    del threading
2127
3230
    del Queue
2128
3231
    del traceback
 
3232
    del re
 
3233
 
 
3234
    gc.collect()
 
3235
    del gc