add perl5 support to Vx6.9 for openssl-3.1.7 (#1)
Reviewed-on: http://13.234.246.121:3000/Neominds/ossl35vx69/pulls/1 Reviewed-by: Jayesh Babu <jayesh@neominds.in> Co-authored-by: siddhant <siddhant.singh@neominds.in> Co-committed-by: siddhant <siddhant.singh@neominds.in>
This commit is contained in:
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -0,0 +1,170 @@
|
||||
import sqlite3 as sqlite
|
||||
import unittest
|
||||
|
||||
|
||||
@unittest.skipIf(sqlite.sqlite_version_info < (3, 6, 11), "Backup API not supported")
|
||||
class BackupTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
cx = self.cx = sqlite.connect(":memory:")
|
||||
cx.execute('CREATE TABLE foo (key INTEGER)')
|
||||
cx.executemany('INSERT INTO foo (key) VALUES (?)', [(3,), (4,)])
|
||||
cx.commit()
|
||||
|
||||
def tearDown(self):
|
||||
self.cx.close()
|
||||
|
||||
def verify_backup(self, bckcx):
|
||||
result = bckcx.execute("SELECT key FROM foo ORDER BY key").fetchall()
|
||||
self.assertEqual(result[0][0], 3)
|
||||
self.assertEqual(result[1][0], 4)
|
||||
|
||||
def test_bad_target_none(self):
|
||||
with self.assertRaises(TypeError):
|
||||
self.cx.backup(None)
|
||||
|
||||
def test_bad_target_filename(self):
|
||||
with self.assertRaises(TypeError):
|
||||
self.cx.backup('some_file_name.db')
|
||||
|
||||
def test_bad_target_same_connection(self):
|
||||
with self.assertRaises(ValueError):
|
||||
self.cx.backup(self.cx)
|
||||
|
||||
def test_bad_target_closed_connection(self):
|
||||
bck = sqlite.connect(':memory:')
|
||||
bck.close()
|
||||
with self.assertRaises(sqlite.ProgrammingError):
|
||||
self.cx.backup(bck)
|
||||
|
||||
def test_bad_source_closed_connection(self):
|
||||
bck = sqlite.connect(':memory:')
|
||||
source = sqlite.connect(":memory:")
|
||||
source.close()
|
||||
with self.assertRaises(sqlite.ProgrammingError):
|
||||
source.backup(bck)
|
||||
|
||||
def test_bad_target_in_transaction(self):
|
||||
bck = sqlite.connect(':memory:')
|
||||
bck.execute('CREATE TABLE bar (key INTEGER)')
|
||||
bck.executemany('INSERT INTO bar (key) VALUES (?)', [(3,), (4,)])
|
||||
with self.assertRaises(sqlite.OperationalError) as cm:
|
||||
self.cx.backup(bck)
|
||||
if sqlite.sqlite_version_info < (3, 8, 8):
|
||||
self.assertEqual(str(cm.exception), 'target is in transaction')
|
||||
|
||||
def test_keyword_only_args(self):
|
||||
with self.assertRaises(TypeError):
|
||||
with sqlite.connect(':memory:') as bck:
|
||||
self.cx.backup(bck, 1)
|
||||
|
||||
def test_simple(self):
|
||||
with sqlite.connect(':memory:') as bck:
|
||||
self.cx.backup(bck)
|
||||
self.verify_backup(bck)
|
||||
|
||||
def test_progress(self):
|
||||
journal = []
|
||||
|
||||
def progress(status, remaining, total):
|
||||
journal.append(status)
|
||||
|
||||
with sqlite.connect(':memory:') as bck:
|
||||
self.cx.backup(bck, pages=1, progress=progress)
|
||||
self.verify_backup(bck)
|
||||
|
||||
self.assertEqual(len(journal), 2)
|
||||
self.assertEqual(journal[0], sqlite.SQLITE_OK)
|
||||
self.assertEqual(journal[1], sqlite.SQLITE_DONE)
|
||||
|
||||
def test_progress_all_pages_at_once_1(self):
|
||||
journal = []
|
||||
|
||||
def progress(status, remaining, total):
|
||||
journal.append(remaining)
|
||||
|
||||
with sqlite.connect(':memory:') as bck:
|
||||
self.cx.backup(bck, progress=progress)
|
||||
self.verify_backup(bck)
|
||||
|
||||
self.assertEqual(len(journal), 1)
|
||||
self.assertEqual(journal[0], 0)
|
||||
|
||||
def test_progress_all_pages_at_once_2(self):
|
||||
journal = []
|
||||
|
||||
def progress(status, remaining, total):
|
||||
journal.append(remaining)
|
||||
|
||||
with sqlite.connect(':memory:') as bck:
|
||||
self.cx.backup(bck, pages=-1, progress=progress)
|
||||
self.verify_backup(bck)
|
||||
|
||||
self.assertEqual(len(journal), 1)
|
||||
self.assertEqual(journal[0], 0)
|
||||
|
||||
def test_non_callable_progress(self):
|
||||
with self.assertRaises(TypeError) as cm:
|
||||
with sqlite.connect(':memory:') as bck:
|
||||
self.cx.backup(bck, pages=1, progress='bar')
|
||||
self.assertEqual(str(cm.exception), 'progress argument must be a callable')
|
||||
|
||||
def test_modifying_progress(self):
|
||||
journal = []
|
||||
|
||||
def progress(status, remaining, total):
|
||||
if not journal:
|
||||
self.cx.execute('INSERT INTO foo (key) VALUES (?)', (remaining+1000,))
|
||||
self.cx.commit()
|
||||
journal.append(remaining)
|
||||
|
||||
with sqlite.connect(':memory:') as bck:
|
||||
self.cx.backup(bck, pages=1, progress=progress)
|
||||
self.verify_backup(bck)
|
||||
|
||||
result = bck.execute("SELECT key FROM foo"
|
||||
" WHERE key >= 1000"
|
||||
" ORDER BY key").fetchall()
|
||||
self.assertEqual(result[0][0], 1001)
|
||||
|
||||
self.assertEqual(len(journal), 3)
|
||||
self.assertEqual(journal[0], 1)
|
||||
self.assertEqual(journal[1], 1)
|
||||
self.assertEqual(journal[2], 0)
|
||||
|
||||
def test_failing_progress(self):
|
||||
def progress(status, remaining, total):
|
||||
raise SystemError('nearly out of space')
|
||||
|
||||
with self.assertRaises(SystemError) as err:
|
||||
with sqlite.connect(':memory:') as bck:
|
||||
self.cx.backup(bck, progress=progress)
|
||||
self.assertEqual(str(err.exception), 'nearly out of space')
|
||||
|
||||
def test_database_source_name(self):
|
||||
with sqlite.connect(':memory:') as bck:
|
||||
self.cx.backup(bck, name='main')
|
||||
with sqlite.connect(':memory:') as bck:
|
||||
self.cx.backup(bck, name='temp')
|
||||
with self.assertRaises(sqlite.OperationalError) as cm:
|
||||
with sqlite.connect(':memory:') as bck:
|
||||
self.cx.backup(bck, name='non-existing')
|
||||
self.assertIn(
|
||||
str(cm.exception),
|
||||
['SQL logic error', 'SQL logic error or missing database',
|
||||
'unknown database non-existing']
|
||||
)
|
||||
|
||||
self.cx.execute("ATTACH DATABASE ':memory:' AS attached_db")
|
||||
self.cx.execute('CREATE TABLE attached_db.foo (key INTEGER)')
|
||||
self.cx.executemany('INSERT INTO attached_db.foo (key) VALUES (?)', [(3,), (4,)])
|
||||
self.cx.commit()
|
||||
with sqlite.connect(':memory:') as bck:
|
||||
self.cx.backup(bck, name='attached_db')
|
||||
self.verify_backup(bck)
|
||||
|
||||
|
||||
def suite():
|
||||
return unittest.makeSuite(BackupTests)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,81 @@
|
||||
# Author: Paul Kippes <kippesp@gmail.com>
|
||||
|
||||
import unittest
|
||||
import sqlite3 as sqlite
|
||||
|
||||
class DumpTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.cx = sqlite.connect(":memory:")
|
||||
self.cu = self.cx.cursor()
|
||||
|
||||
def tearDown(self):
|
||||
self.cx.close()
|
||||
|
||||
def CheckTableDump(self):
|
||||
expected_sqls = [
|
||||
"""CREATE TABLE "index"("index" blob);"""
|
||||
,
|
||||
"""INSERT INTO "index" VALUES(X'01');"""
|
||||
,
|
||||
"""CREATE TABLE "quoted""table"("quoted""field" text);"""
|
||||
,
|
||||
"""INSERT INTO "quoted""table" VALUES('quoted''value');"""
|
||||
,
|
||||
"CREATE TABLE t1(id integer primary key, s1 text, " \
|
||||
"t1_i1 integer not null, i2 integer, unique (s1), " \
|
||||
"constraint t1_idx1 unique (i2));"
|
||||
,
|
||||
"INSERT INTO \"t1\" VALUES(1,'foo',10,20);"
|
||||
,
|
||||
"INSERT INTO \"t1\" VALUES(2,'foo2',30,30);"
|
||||
,
|
||||
"CREATE TABLE t2(id integer, t2_i1 integer, " \
|
||||
"t2_i2 integer, primary key (id)," \
|
||||
"foreign key(t2_i1) references t1(t1_i1));"
|
||||
,
|
||||
"CREATE TRIGGER trigger_1 update of t1_i1 on t1 " \
|
||||
"begin " \
|
||||
"update t2 set t2_i1 = new.t1_i1 where t2_i1 = old.t1_i1; " \
|
||||
"end;"
|
||||
,
|
||||
"CREATE VIEW v1 as select * from t1 left join t2 " \
|
||||
"using (id);"
|
||||
]
|
||||
[self.cu.execute(s) for s in expected_sqls]
|
||||
i = self.cx.iterdump()
|
||||
actual_sqls = [s for s in i]
|
||||
expected_sqls = ['BEGIN TRANSACTION;'] + expected_sqls + \
|
||||
['COMMIT;']
|
||||
[self.assertEqual(expected_sqls[i], actual_sqls[i])
|
||||
for i in range(len(expected_sqls))]
|
||||
|
||||
def CheckUnorderableRow(self):
|
||||
# iterdump() should be able to cope with unorderable row types (issue #15545)
|
||||
class UnorderableRow:
|
||||
def __init__(self, cursor, row):
|
||||
self.row = row
|
||||
def __getitem__(self, index):
|
||||
return self.row[index]
|
||||
self.cx.row_factory = UnorderableRow
|
||||
CREATE_ALPHA = """CREATE TABLE "alpha" ("one");"""
|
||||
CREATE_BETA = """CREATE TABLE "beta" ("two");"""
|
||||
expected = [
|
||||
"BEGIN TRANSACTION;",
|
||||
CREATE_ALPHA,
|
||||
CREATE_BETA,
|
||||
"COMMIT;"
|
||||
]
|
||||
self.cu.execute(CREATE_BETA)
|
||||
self.cu.execute(CREATE_ALPHA)
|
||||
got = list(self.cx.iterdump())
|
||||
self.assertEqual(expected, got)
|
||||
|
||||
def suite():
|
||||
return unittest.TestSuite(unittest.makeSuite(DumpTests, "Check"))
|
||||
|
||||
def test():
|
||||
runner = unittest.TextTestRunner()
|
||||
runner.run(suite())
|
||||
|
||||
if __name__ == "__main__":
|
||||
test()
|
||||
@@ -0,0 +1,318 @@
|
||||
#-*- coding: iso-8859-1 -*-
|
||||
# pysqlite2/test/factory.py: tests for the various factories in pysqlite
|
||||
#
|
||||
# Copyright (C) 2005-2007 Gerhard Häring <gh@ghaering.de>
|
||||
#
|
||||
# This file is part of pysqlite.
|
||||
#
|
||||
# This software is provided 'as-is', without any express or implied
|
||||
# warranty. In no event will the authors be held liable for any damages
|
||||
# arising from the use of this software.
|
||||
#
|
||||
# Permission is granted to anyone to use this software for any purpose,
|
||||
# including commercial applications, and to alter it and redistribute it
|
||||
# freely, subject to the following restrictions:
|
||||
#
|
||||
# 1. The origin of this software must not be misrepresented; you must not
|
||||
# claim that you wrote the original software. If you use this software
|
||||
# in a product, an acknowledgment in the product documentation would be
|
||||
# appreciated but is not required.
|
||||
# 2. Altered source versions must be plainly marked as such, and must not be
|
||||
# misrepresented as being the original software.
|
||||
# 3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
import unittest
|
||||
import sqlite3 as sqlite
|
||||
from collections.abc import Sequence
|
||||
|
||||
class MyConnection(sqlite.Connection):
|
||||
def __init__(self, *args, **kwargs):
|
||||
sqlite.Connection.__init__(self, *args, **kwargs)
|
||||
|
||||
def dict_factory(cursor, row):
|
||||
d = {}
|
||||
for idx, col in enumerate(cursor.description):
|
||||
d[col[0]] = row[idx]
|
||||
return d
|
||||
|
||||
class MyCursor(sqlite.Cursor):
|
||||
def __init__(self, *args, **kwargs):
|
||||
sqlite.Cursor.__init__(self, *args, **kwargs)
|
||||
self.row_factory = dict_factory
|
||||
|
||||
class ConnectionFactoryTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.con = sqlite.connect(":memory:", factory=MyConnection)
|
||||
|
||||
def tearDown(self):
|
||||
self.con.close()
|
||||
|
||||
def CheckIsInstance(self):
|
||||
self.assertIsInstance(self.con, MyConnection)
|
||||
|
||||
class CursorFactoryTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.con = sqlite.connect(":memory:")
|
||||
|
||||
def tearDown(self):
|
||||
self.con.close()
|
||||
|
||||
def CheckIsInstance(self):
|
||||
cur = self.con.cursor()
|
||||
self.assertIsInstance(cur, sqlite.Cursor)
|
||||
cur = self.con.cursor(MyCursor)
|
||||
self.assertIsInstance(cur, MyCursor)
|
||||
cur = self.con.cursor(factory=lambda con: MyCursor(con))
|
||||
self.assertIsInstance(cur, MyCursor)
|
||||
|
||||
def CheckInvalidFactory(self):
|
||||
# not a callable at all
|
||||
self.assertRaises(TypeError, self.con.cursor, None)
|
||||
# invalid callable with not exact one argument
|
||||
self.assertRaises(TypeError, self.con.cursor, lambda: None)
|
||||
# invalid callable returning non-cursor
|
||||
self.assertRaises(TypeError, self.con.cursor, lambda con: None)
|
||||
|
||||
class RowFactoryTestsBackwardsCompat(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.con = sqlite.connect(":memory:")
|
||||
|
||||
def CheckIsProducedByFactory(self):
|
||||
cur = self.con.cursor(factory=MyCursor)
|
||||
cur.execute("select 4+5 as foo")
|
||||
row = cur.fetchone()
|
||||
self.assertIsInstance(row, dict)
|
||||
cur.close()
|
||||
|
||||
def tearDown(self):
|
||||
self.con.close()
|
||||
|
||||
class RowFactoryTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.con = sqlite.connect(":memory:")
|
||||
|
||||
def CheckCustomFactory(self):
|
||||
self.con.row_factory = lambda cur, row: list(row)
|
||||
row = self.con.execute("select 1, 2").fetchone()
|
||||
self.assertIsInstance(row, list)
|
||||
|
||||
def CheckSqliteRowIndex(self):
|
||||
self.con.row_factory = sqlite.Row
|
||||
row = self.con.execute("select 1 as a_1, 2 as b").fetchone()
|
||||
self.assertIsInstance(row, sqlite.Row)
|
||||
|
||||
self.assertEqual(row["a_1"], 1, "by name: wrong result for column 'a_1'")
|
||||
self.assertEqual(row["b"], 2, "by name: wrong result for column 'b'")
|
||||
|
||||
self.assertEqual(row["A_1"], 1, "by name: wrong result for column 'A_1'")
|
||||
self.assertEqual(row["B"], 2, "by name: wrong result for column 'B'")
|
||||
|
||||
self.assertEqual(row[0], 1, "by index: wrong result for column 0")
|
||||
self.assertEqual(row[1], 2, "by index: wrong result for column 1")
|
||||
self.assertEqual(row[-1], 2, "by index: wrong result for column -1")
|
||||
self.assertEqual(row[-2], 1, "by index: wrong result for column -2")
|
||||
|
||||
with self.assertRaises(IndexError):
|
||||
row['c']
|
||||
with self.assertRaises(IndexError):
|
||||
row['a_\x11']
|
||||
with self.assertRaises(IndexError):
|
||||
row['a\x7f1']
|
||||
with self.assertRaises(IndexError):
|
||||
row[2]
|
||||
with self.assertRaises(IndexError):
|
||||
row[-3]
|
||||
with self.assertRaises(IndexError):
|
||||
row[2**1000]
|
||||
|
||||
def CheckSqliteRowIndexUnicode(self):
|
||||
self.con.row_factory = sqlite.Row
|
||||
row = self.con.execute("select 1 as \xff").fetchone()
|
||||
self.assertEqual(row["\xff"], 1)
|
||||
with self.assertRaises(IndexError):
|
||||
row['\u0178']
|
||||
with self.assertRaises(IndexError):
|
||||
row['\xdf']
|
||||
|
||||
def CheckSqliteRowSlice(self):
|
||||
# A sqlite.Row can be sliced like a list.
|
||||
self.con.row_factory = sqlite.Row
|
||||
row = self.con.execute("select 1, 2, 3, 4").fetchone()
|
||||
self.assertEqual(row[0:0], ())
|
||||
self.assertEqual(row[0:1], (1,))
|
||||
self.assertEqual(row[1:3], (2, 3))
|
||||
self.assertEqual(row[3:1], ())
|
||||
# Explicit bounds are optional.
|
||||
self.assertEqual(row[1:], (2, 3, 4))
|
||||
self.assertEqual(row[:3], (1, 2, 3))
|
||||
# Slices can use negative indices.
|
||||
self.assertEqual(row[-2:-1], (3,))
|
||||
self.assertEqual(row[-2:], (3, 4))
|
||||
# Slicing supports steps.
|
||||
self.assertEqual(row[0:4:2], (1, 3))
|
||||
self.assertEqual(row[3:0:-2], (4, 2))
|
||||
|
||||
def CheckSqliteRowIter(self):
|
||||
"""Checks if the row object is iterable"""
|
||||
self.con.row_factory = sqlite.Row
|
||||
row = self.con.execute("select 1 as a, 2 as b").fetchone()
|
||||
for col in row:
|
||||
pass
|
||||
|
||||
def CheckSqliteRowAsTuple(self):
|
||||
"""Checks if the row object can be converted to a tuple"""
|
||||
self.con.row_factory = sqlite.Row
|
||||
row = self.con.execute("select 1 as a, 2 as b").fetchone()
|
||||
t = tuple(row)
|
||||
self.assertEqual(t, (row['a'], row['b']))
|
||||
|
||||
def CheckSqliteRowAsDict(self):
|
||||
"""Checks if the row object can be correctly converted to a dictionary"""
|
||||
self.con.row_factory = sqlite.Row
|
||||
row = self.con.execute("select 1 as a, 2 as b").fetchone()
|
||||
d = dict(row)
|
||||
self.assertEqual(d["a"], row["a"])
|
||||
self.assertEqual(d["b"], row["b"])
|
||||
|
||||
def CheckSqliteRowHashCmp(self):
|
||||
"""Checks if the row object compares and hashes correctly"""
|
||||
self.con.row_factory = sqlite.Row
|
||||
row_1 = self.con.execute("select 1 as a, 2 as b").fetchone()
|
||||
row_2 = self.con.execute("select 1 as a, 2 as b").fetchone()
|
||||
row_3 = self.con.execute("select 1 as a, 3 as b").fetchone()
|
||||
row_4 = self.con.execute("select 1 as b, 2 as a").fetchone()
|
||||
row_5 = self.con.execute("select 2 as b, 1 as a").fetchone()
|
||||
|
||||
self.assertTrue(row_1 == row_1)
|
||||
self.assertTrue(row_1 == row_2)
|
||||
self.assertFalse(row_1 == row_3)
|
||||
self.assertFalse(row_1 == row_4)
|
||||
self.assertFalse(row_1 == row_5)
|
||||
self.assertFalse(row_1 == object())
|
||||
|
||||
self.assertFalse(row_1 != row_1)
|
||||
self.assertFalse(row_1 != row_2)
|
||||
self.assertTrue(row_1 != row_3)
|
||||
self.assertTrue(row_1 != row_4)
|
||||
self.assertTrue(row_1 != row_5)
|
||||
self.assertTrue(row_1 != object())
|
||||
|
||||
with self.assertRaises(TypeError):
|
||||
row_1 > row_2
|
||||
with self.assertRaises(TypeError):
|
||||
row_1 < row_2
|
||||
with self.assertRaises(TypeError):
|
||||
row_1 >= row_2
|
||||
with self.assertRaises(TypeError):
|
||||
row_1 <= row_2
|
||||
|
||||
self.assertEqual(hash(row_1), hash(row_2))
|
||||
|
||||
def CheckSqliteRowAsSequence(self):
|
||||
""" Checks if the row object can act like a sequence """
|
||||
self.con.row_factory = sqlite.Row
|
||||
row = self.con.execute("select 1 as a, 2 as b").fetchone()
|
||||
|
||||
as_tuple = tuple(row)
|
||||
self.assertEqual(list(reversed(row)), list(reversed(as_tuple)))
|
||||
self.assertIsInstance(row, Sequence)
|
||||
|
||||
def CheckFakeCursorClass(self):
|
||||
# Issue #24257: Incorrect use of PyObject_IsInstance() caused
|
||||
# segmentation fault.
|
||||
# Issue #27861: Also applies for cursor factory.
|
||||
class FakeCursor(str):
|
||||
__class__ = sqlite.Cursor
|
||||
self.con.row_factory = sqlite.Row
|
||||
self.assertRaises(TypeError, self.con.cursor, FakeCursor)
|
||||
self.assertRaises(TypeError, sqlite.Row, FakeCursor(), ())
|
||||
|
||||
def tearDown(self):
|
||||
self.con.close()
|
||||
|
||||
class TextFactoryTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.con = sqlite.connect(":memory:")
|
||||
|
||||
def CheckUnicode(self):
|
||||
austria = "Österreich"
|
||||
row = self.con.execute("select ?", (austria,)).fetchone()
|
||||
self.assertEqual(type(row[0]), str, "type of row[0] must be unicode")
|
||||
|
||||
def CheckString(self):
|
||||
self.con.text_factory = bytes
|
||||
austria = "Österreich"
|
||||
row = self.con.execute("select ?", (austria,)).fetchone()
|
||||
self.assertEqual(type(row[0]), bytes, "type of row[0] must be bytes")
|
||||
self.assertEqual(row[0], austria.encode("utf-8"), "column must equal original data in UTF-8")
|
||||
|
||||
def CheckCustom(self):
|
||||
self.con.text_factory = lambda x: str(x, "utf-8", "ignore")
|
||||
austria = "Österreich"
|
||||
row = self.con.execute("select ?", (austria,)).fetchone()
|
||||
self.assertEqual(type(row[0]), str, "type of row[0] must be unicode")
|
||||
self.assertTrue(row[0].endswith("reich"), "column must contain original data")
|
||||
|
||||
def CheckOptimizedUnicode(self):
|
||||
# In py3k, str objects are always returned when text_factory
|
||||
# is OptimizedUnicode
|
||||
self.con.text_factory = sqlite.OptimizedUnicode
|
||||
austria = "Österreich"
|
||||
germany = "Deutchland"
|
||||
a_row = self.con.execute("select ?", (austria,)).fetchone()
|
||||
d_row = self.con.execute("select ?", (germany,)).fetchone()
|
||||
self.assertEqual(type(a_row[0]), str, "type of non-ASCII row must be str")
|
||||
self.assertEqual(type(d_row[0]), str, "type of ASCII-only row must be str")
|
||||
|
||||
def tearDown(self):
|
||||
self.con.close()
|
||||
|
||||
class TextFactoryTestsWithEmbeddedZeroBytes(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.con = sqlite.connect(":memory:")
|
||||
self.con.execute("create table test (value text)")
|
||||
self.con.execute("insert into test (value) values (?)", ("a\x00b",))
|
||||
|
||||
def CheckString(self):
|
||||
# text_factory defaults to str
|
||||
row = self.con.execute("select value from test").fetchone()
|
||||
self.assertIs(type(row[0]), str)
|
||||
self.assertEqual(row[0], "a\x00b")
|
||||
|
||||
def CheckBytes(self):
|
||||
self.con.text_factory = bytes
|
||||
row = self.con.execute("select value from test").fetchone()
|
||||
self.assertIs(type(row[0]), bytes)
|
||||
self.assertEqual(row[0], b"a\x00b")
|
||||
|
||||
def CheckBytearray(self):
|
||||
self.con.text_factory = bytearray
|
||||
row = self.con.execute("select value from test").fetchone()
|
||||
self.assertIs(type(row[0]), bytearray)
|
||||
self.assertEqual(row[0], b"a\x00b")
|
||||
|
||||
def CheckCustom(self):
|
||||
# A custom factory should receive a bytes argument
|
||||
self.con.text_factory = lambda x: x
|
||||
row = self.con.execute("select value from test").fetchone()
|
||||
self.assertIs(type(row[0]), bytes)
|
||||
self.assertEqual(row[0], b"a\x00b")
|
||||
|
||||
def tearDown(self):
|
||||
self.con.close()
|
||||
|
||||
def suite():
|
||||
connection_suite = unittest.makeSuite(ConnectionFactoryTests, "Check")
|
||||
cursor_suite = unittest.makeSuite(CursorFactoryTests, "Check")
|
||||
row_suite_compat = unittest.makeSuite(RowFactoryTestsBackwardsCompat, "Check")
|
||||
row_suite = unittest.makeSuite(RowFactoryTests, "Check")
|
||||
text_suite = unittest.makeSuite(TextFactoryTests, "Check")
|
||||
text_zero_bytes_suite = unittest.makeSuite(TextFactoryTestsWithEmbeddedZeroBytes, "Check")
|
||||
return unittest.TestSuite((connection_suite, cursor_suite, row_suite_compat, row_suite, text_suite, text_zero_bytes_suite))
|
||||
|
||||
def test():
|
||||
runner = unittest.TextTestRunner()
|
||||
runner.run(suite())
|
||||
|
||||
if __name__ == "__main__":
|
||||
test()
|
||||
@@ -0,0 +1,290 @@
|
||||
#-*- coding: iso-8859-1 -*-
|
||||
# pysqlite2/test/hooks.py: tests for various SQLite-specific hooks
|
||||
#
|
||||
# Copyright (C) 2006-2007 Gerhard Häring <gh@ghaering.de>
|
||||
#
|
||||
# This file is part of pysqlite.
|
||||
#
|
||||
# This software is provided 'as-is', without any express or implied
|
||||
# warranty. In no event will the authors be held liable for any damages
|
||||
# arising from the use of this software.
|
||||
#
|
||||
# Permission is granted to anyone to use this software for any purpose,
|
||||
# including commercial applications, and to alter it and redistribute it
|
||||
# freely, subject to the following restrictions:
|
||||
#
|
||||
# 1. The origin of this software must not be misrepresented; you must not
|
||||
# claim that you wrote the original software. If you use this software
|
||||
# in a product, an acknowledgment in the product documentation would be
|
||||
# appreciated but is not required.
|
||||
# 2. Altered source versions must be plainly marked as such, and must not be
|
||||
# misrepresented as being the original software.
|
||||
# 3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
import unittest
|
||||
import sqlite3 as sqlite
|
||||
|
||||
from test.support import TESTFN, unlink
|
||||
|
||||
class CollationTests(unittest.TestCase):
|
||||
def CheckCreateCollationNotString(self):
|
||||
con = sqlite.connect(":memory:")
|
||||
with self.assertRaises(TypeError):
|
||||
con.create_collation(None, lambda x, y: (x > y) - (x < y))
|
||||
|
||||
def CheckCreateCollationNotCallable(self):
|
||||
con = sqlite.connect(":memory:")
|
||||
with self.assertRaises(TypeError) as cm:
|
||||
con.create_collation("X", 42)
|
||||
self.assertEqual(str(cm.exception), 'parameter must be callable')
|
||||
|
||||
def CheckCreateCollationNotAscii(self):
|
||||
con = sqlite.connect(":memory:")
|
||||
with self.assertRaises(sqlite.ProgrammingError):
|
||||
con.create_collation("collä", lambda x, y: (x > y) - (x < y))
|
||||
|
||||
def CheckCreateCollationBadUpper(self):
|
||||
class BadUpperStr(str):
|
||||
def upper(self):
|
||||
return None
|
||||
con = sqlite.connect(":memory:")
|
||||
mycoll = lambda x, y: -((x > y) - (x < y))
|
||||
con.create_collation(BadUpperStr("mycoll"), mycoll)
|
||||
result = con.execute("""
|
||||
select x from (
|
||||
select 'a' as x
|
||||
union
|
||||
select 'b' as x
|
||||
) order by x collate mycoll
|
||||
""").fetchall()
|
||||
self.assertEqual(result[0][0], 'b')
|
||||
self.assertEqual(result[1][0], 'a')
|
||||
|
||||
@unittest.skipIf(sqlite.sqlite_version_info < (3, 2, 1),
|
||||
'old SQLite versions crash on this test')
|
||||
def CheckCollationIsUsed(self):
|
||||
def mycoll(x, y):
|
||||
# reverse order
|
||||
return -((x > y) - (x < y))
|
||||
|
||||
con = sqlite.connect(":memory:")
|
||||
con.create_collation("mycoll", mycoll)
|
||||
sql = """
|
||||
select x from (
|
||||
select 'a' as x
|
||||
union
|
||||
select 'b' as x
|
||||
union
|
||||
select 'c' as x
|
||||
) order by x collate mycoll
|
||||
"""
|
||||
result = con.execute(sql).fetchall()
|
||||
self.assertEqual(result, [('c',), ('b',), ('a',)],
|
||||
msg='the expected order was not returned')
|
||||
|
||||
con.create_collation("mycoll", None)
|
||||
with self.assertRaises(sqlite.OperationalError) as cm:
|
||||
result = con.execute(sql).fetchall()
|
||||
self.assertEqual(str(cm.exception), 'no such collation sequence: mycoll')
|
||||
|
||||
def CheckCollationReturnsLargeInteger(self):
|
||||
def mycoll(x, y):
|
||||
# reverse order
|
||||
return -((x > y) - (x < y)) * 2**32
|
||||
con = sqlite.connect(":memory:")
|
||||
con.create_collation("mycoll", mycoll)
|
||||
sql = """
|
||||
select x from (
|
||||
select 'a' as x
|
||||
union
|
||||
select 'b' as x
|
||||
union
|
||||
select 'c' as x
|
||||
) order by x collate mycoll
|
||||
"""
|
||||
result = con.execute(sql).fetchall()
|
||||
self.assertEqual(result, [('c',), ('b',), ('a',)],
|
||||
msg="the expected order was not returned")
|
||||
|
||||
def CheckCollationRegisterTwice(self):
|
||||
"""
|
||||
Register two different collation functions under the same name.
|
||||
Verify that the last one is actually used.
|
||||
"""
|
||||
con = sqlite.connect(":memory:")
|
||||
con.create_collation("mycoll", lambda x, y: (x > y) - (x < y))
|
||||
con.create_collation("mycoll", lambda x, y: -((x > y) - (x < y)))
|
||||
result = con.execute("""
|
||||
select x from (select 'a' as x union select 'b' as x) order by x collate mycoll
|
||||
""").fetchall()
|
||||
self.assertEqual(result[0][0], 'b')
|
||||
self.assertEqual(result[1][0], 'a')
|
||||
|
||||
def CheckDeregisterCollation(self):
|
||||
"""
|
||||
Register a collation, then deregister it. Make sure an error is raised if we try
|
||||
to use it.
|
||||
"""
|
||||
con = sqlite.connect(":memory:")
|
||||
con.create_collation("mycoll", lambda x, y: (x > y) - (x < y))
|
||||
con.create_collation("mycoll", None)
|
||||
with self.assertRaises(sqlite.OperationalError) as cm:
|
||||
con.execute("select 'a' as x union select 'b' as x order by x collate mycoll")
|
||||
self.assertEqual(str(cm.exception), 'no such collation sequence: mycoll')
|
||||
|
||||
class ProgressTests(unittest.TestCase):
|
||||
def CheckProgressHandlerUsed(self):
|
||||
"""
|
||||
Test that the progress handler is invoked once it is set.
|
||||
"""
|
||||
con = sqlite.connect(":memory:")
|
||||
progress_calls = []
|
||||
def progress():
|
||||
progress_calls.append(None)
|
||||
return 0
|
||||
con.set_progress_handler(progress, 1)
|
||||
con.execute("""
|
||||
create table foo(a, b)
|
||||
""")
|
||||
self.assertTrue(progress_calls)
|
||||
|
||||
|
||||
def CheckOpcodeCount(self):
|
||||
"""
|
||||
Test that the opcode argument is respected.
|
||||
"""
|
||||
con = sqlite.connect(":memory:")
|
||||
progress_calls = []
|
||||
def progress():
|
||||
progress_calls.append(None)
|
||||
return 0
|
||||
con.set_progress_handler(progress, 1)
|
||||
curs = con.cursor()
|
||||
curs.execute("""
|
||||
create table foo (a, b)
|
||||
""")
|
||||
first_count = len(progress_calls)
|
||||
progress_calls = []
|
||||
con.set_progress_handler(progress, 2)
|
||||
curs.execute("""
|
||||
create table bar (a, b)
|
||||
""")
|
||||
second_count = len(progress_calls)
|
||||
self.assertGreaterEqual(first_count, second_count)
|
||||
|
||||
def CheckCancelOperation(self):
|
||||
"""
|
||||
Test that returning a non-zero value stops the operation in progress.
|
||||
"""
|
||||
con = sqlite.connect(":memory:")
|
||||
def progress():
|
||||
return 1
|
||||
con.set_progress_handler(progress, 1)
|
||||
curs = con.cursor()
|
||||
self.assertRaises(
|
||||
sqlite.OperationalError,
|
||||
curs.execute,
|
||||
"create table bar (a, b)")
|
||||
|
||||
def CheckClearHandler(self):
|
||||
"""
|
||||
Test that setting the progress handler to None clears the previously set handler.
|
||||
"""
|
||||
con = sqlite.connect(":memory:")
|
||||
action = 0
|
||||
def progress():
|
||||
nonlocal action
|
||||
action = 1
|
||||
return 0
|
||||
con.set_progress_handler(progress, 1)
|
||||
con.set_progress_handler(None, 1)
|
||||
con.execute("select 1 union select 2 union select 3").fetchall()
|
||||
self.assertEqual(action, 0, "progress handler was not cleared")
|
||||
|
||||
class TraceCallbackTests(unittest.TestCase):
|
||||
def CheckTraceCallbackUsed(self):
|
||||
"""
|
||||
Test that the trace callback is invoked once it is set.
|
||||
"""
|
||||
con = sqlite.connect(":memory:")
|
||||
traced_statements = []
|
||||
def trace(statement):
|
||||
traced_statements.append(statement)
|
||||
con.set_trace_callback(trace)
|
||||
con.execute("create table foo(a, b)")
|
||||
self.assertTrue(traced_statements)
|
||||
self.assertTrue(any("create table foo" in stmt for stmt in traced_statements))
|
||||
|
||||
def CheckClearTraceCallback(self):
|
||||
"""
|
||||
Test that setting the trace callback to None clears the previously set callback.
|
||||
"""
|
||||
con = sqlite.connect(":memory:")
|
||||
traced_statements = []
|
||||
def trace(statement):
|
||||
traced_statements.append(statement)
|
||||
con.set_trace_callback(trace)
|
||||
con.set_trace_callback(None)
|
||||
con.execute("create table foo(a, b)")
|
||||
self.assertFalse(traced_statements, "trace callback was not cleared")
|
||||
|
||||
def CheckUnicodeContent(self):
|
||||
"""
|
||||
Test that the statement can contain unicode literals.
|
||||
"""
|
||||
unicode_value = '\xf6\xe4\xfc\xd6\xc4\xdc\xdf\u20ac'
|
||||
con = sqlite.connect(":memory:")
|
||||
traced_statements = []
|
||||
def trace(statement):
|
||||
traced_statements.append(statement)
|
||||
con.set_trace_callback(trace)
|
||||
con.execute("create table foo(x)")
|
||||
# Can't execute bound parameters as their values don't appear
|
||||
# in traced statements before SQLite 3.6.21
|
||||
# (cf. http://www.sqlite.org/draft/releaselog/3_6_21.html)
|
||||
con.execute("insert into foo(x) values ('%s')" % unicode_value)
|
||||
con.commit()
|
||||
self.assertTrue(any(unicode_value in stmt for stmt in traced_statements),
|
||||
"Unicode data %s garbled in trace callback: %s"
|
||||
% (ascii(unicode_value), ', '.join(map(ascii, traced_statements))))
|
||||
|
||||
@unittest.skipIf(sqlite.sqlite_version_info < (3, 3, 9), "sqlite3_prepare_v2 is not available")
|
||||
def CheckTraceCallbackContent(self):
|
||||
# set_trace_callback() shouldn't produce duplicate content (bpo-26187)
|
||||
traced_statements = []
|
||||
def trace(statement):
|
||||
traced_statements.append(statement)
|
||||
|
||||
queries = ["create table foo(x)",
|
||||
"insert into foo(x) values(1)"]
|
||||
self.addCleanup(unlink, TESTFN)
|
||||
con1 = sqlite.connect(TESTFN, isolation_level=None)
|
||||
con2 = sqlite.connect(TESTFN)
|
||||
con1.set_trace_callback(trace)
|
||||
cur = con1.cursor()
|
||||
cur.execute(queries[0])
|
||||
con2.execute("create table bar(x)")
|
||||
cur.execute(queries[1])
|
||||
|
||||
# Extract from SQLite 3.7.15 changelog:
|
||||
# Avoid invoking the sqlite3_trace() callback multiple times when a
|
||||
# statement is automatically reprepared due to SQLITE_SCHEMA errors.
|
||||
#
|
||||
# See bpo-40810
|
||||
if sqlite.sqlite_version_info < (3, 7, 15):
|
||||
queries.append(queries[-1])
|
||||
self.assertEqual(traced_statements, queries)
|
||||
|
||||
|
||||
def suite():
|
||||
collation_suite = unittest.makeSuite(CollationTests, "Check")
|
||||
progress_suite = unittest.makeSuite(ProgressTests, "Check")
|
||||
trace_suite = unittest.makeSuite(TraceCallbackTests, "Check")
|
||||
return unittest.TestSuite((collation_suite, progress_suite, trace_suite))
|
||||
|
||||
def test():
|
||||
runner = unittest.TextTestRunner()
|
||||
runner.run(suite())
|
||||
|
||||
if __name__ == "__main__":
|
||||
test()
|
||||
@@ -0,0 +1,470 @@
|
||||
#-*- coding: iso-8859-1 -*-
|
||||
# pysqlite2/test/regression.py: pysqlite regression tests
|
||||
#
|
||||
# Copyright (C) 2006-2010 Gerhard Häring <gh@ghaering.de>
|
||||
#
|
||||
# This file is part of pysqlite.
|
||||
#
|
||||
# This software is provided 'as-is', without any express or implied
|
||||
# warranty. In no event will the authors be held liable for any damages
|
||||
# arising from the use of this software.
|
||||
#
|
||||
# Permission is granted to anyone to use this software for any purpose,
|
||||
# including commercial applications, and to alter it and redistribute it
|
||||
# freely, subject to the following restrictions:
|
||||
#
|
||||
# 1. The origin of this software must not be misrepresented; you must not
|
||||
# claim that you wrote the original software. If you use this software
|
||||
# in a product, an acknowledgment in the product documentation would be
|
||||
# appreciated but is not required.
|
||||
# 2. Altered source versions must be plainly marked as such, and must not be
|
||||
# misrepresented as being the original software.
|
||||
# 3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
import datetime
|
||||
import unittest
|
||||
import sqlite3 as sqlite
|
||||
import weakref
|
||||
import functools
|
||||
from test import support
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
|
||||
class RegressionTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.con = sqlite.connect(":memory:")
|
||||
|
||||
def tearDown(self):
|
||||
self.con.close()
|
||||
|
||||
def CheckPragmaUserVersion(self):
|
||||
# This used to crash pysqlite because this pragma command returns NULL for the column name
|
||||
cur = self.con.cursor()
|
||||
cur.execute("pragma user_version")
|
||||
|
||||
def CheckPragmaSchemaVersion(self):
|
||||
# This still crashed pysqlite <= 2.2.1
|
||||
con = sqlite.connect(":memory:", detect_types=sqlite.PARSE_COLNAMES)
|
||||
try:
|
||||
cur = self.con.cursor()
|
||||
cur.execute("pragma schema_version")
|
||||
finally:
|
||||
cur.close()
|
||||
con.close()
|
||||
|
||||
def CheckStatementReset(self):
|
||||
# pysqlite 2.1.0 to 2.2.0 have the problem that not all statements are
|
||||
# reset before a rollback, but only those that are still in the
|
||||
# statement cache. The others are not accessible from the connection object.
|
||||
con = sqlite.connect(":memory:", cached_statements=5)
|
||||
cursors = [con.cursor() for x in range(5)]
|
||||
cursors[0].execute("create table test(x)")
|
||||
for i in range(10):
|
||||
cursors[0].executemany("insert into test(x) values (?)", [(x,) for x in range(10)])
|
||||
|
||||
for i in range(5):
|
||||
cursors[i].execute(" " * i + "select x from test")
|
||||
|
||||
con.rollback()
|
||||
|
||||
def CheckColumnNameWithSpaces(self):
|
||||
cur = self.con.cursor()
|
||||
cur.execute('select 1 as "foo bar [datetime]"')
|
||||
self.assertEqual(cur.description[0][0], "foo bar [datetime]")
|
||||
|
||||
cur.execute('select 1 as "foo baz"')
|
||||
self.assertEqual(cur.description[0][0], "foo baz")
|
||||
|
||||
def CheckStatementFinalizationOnCloseDb(self):
|
||||
# pysqlite versions <= 2.3.3 only finalized statements in the statement
|
||||
# cache when closing the database. statements that were still
|
||||
# referenced in cursors weren't closed and could provoke "
|
||||
# "OperationalError: Unable to close due to unfinalised statements".
|
||||
con = sqlite.connect(":memory:")
|
||||
cursors = []
|
||||
# default statement cache size is 100
|
||||
for i in range(105):
|
||||
cur = con.cursor()
|
||||
cursors.append(cur)
|
||||
cur.execute("select 1 x union select " + str(i))
|
||||
con.close()
|
||||
|
||||
@unittest.skipIf(sqlite.sqlite_version_info < (3, 2, 2), 'needs sqlite 3.2.2 or newer')
|
||||
def CheckOnConflictRollback(self):
|
||||
con = sqlite.connect(":memory:")
|
||||
con.execute("create table foo(x, unique(x) on conflict rollback)")
|
||||
con.execute("insert into foo(x) values (1)")
|
||||
try:
|
||||
con.execute("insert into foo(x) values (1)")
|
||||
except sqlite.DatabaseError:
|
||||
pass
|
||||
con.execute("insert into foo(x) values (2)")
|
||||
try:
|
||||
con.commit()
|
||||
except sqlite.OperationalError:
|
||||
self.fail("pysqlite knew nothing about the implicit ROLLBACK")
|
||||
|
||||
def CheckWorkaroundForBuggySqliteTransferBindings(self):
|
||||
"""
|
||||
pysqlite would crash with older SQLite versions unless
|
||||
a workaround is implemented.
|
||||
"""
|
||||
self.con.execute("create table foo(bar)")
|
||||
self.con.execute("drop table foo")
|
||||
self.con.execute("create table foo(bar)")
|
||||
|
||||
def CheckEmptyStatement(self):
|
||||
"""
|
||||
pysqlite used to segfault with SQLite versions 3.5.x. These return NULL
|
||||
for "no-operation" statements
|
||||
"""
|
||||
self.con.execute("")
|
||||
|
||||
def CheckTypeMapUsage(self):
|
||||
"""
|
||||
pysqlite until 2.4.1 did not rebuild the row_cast_map when recompiling
|
||||
a statement. This test exhibits the problem.
|
||||
"""
|
||||
SELECT = "select * from foo"
|
||||
con = sqlite.connect(":memory:",detect_types=sqlite.PARSE_DECLTYPES)
|
||||
con.execute("create table foo(bar timestamp)")
|
||||
con.execute("insert into foo(bar) values (?)", (datetime.datetime.now(),))
|
||||
con.execute(SELECT).close()
|
||||
con.execute("drop table foo")
|
||||
con.execute("create table foo(bar integer)")
|
||||
con.execute("insert into foo(bar) values (5)")
|
||||
con.execute(SELECT).close()
|
||||
|
||||
def CheckBindMutatingList(self):
|
||||
# Issue41662: Crash when mutate a list of parameters during iteration.
|
||||
class X:
|
||||
def __conform__(self, protocol):
|
||||
parameters.clear()
|
||||
return "..."
|
||||
parameters = [X(), 0]
|
||||
con = sqlite.connect(":memory:",detect_types=sqlite.PARSE_DECLTYPES)
|
||||
con.execute("create table foo(bar X, baz integer)")
|
||||
# Should not crash
|
||||
with self.assertRaises(IndexError):
|
||||
con.execute("insert into foo(bar, baz) values (?, ?)", parameters)
|
||||
|
||||
def CheckErrorMsgDecodeError(self):
|
||||
# When porting the module to Python 3.0, the error message about
|
||||
# decoding errors disappeared. This verifies they're back again.
|
||||
with self.assertRaises(sqlite.OperationalError) as cm:
|
||||
self.con.execute("select 'xxx' || ? || 'yyy' colname",
|
||||
(bytes(bytearray([250])),)).fetchone()
|
||||
msg = "Could not decode to UTF-8 column 'colname' with text 'xxx"
|
||||
self.assertIn(msg, str(cm.exception))
|
||||
|
||||
def CheckRegisterAdapter(self):
|
||||
"""
|
||||
See issue 3312.
|
||||
"""
|
||||
self.assertRaises(TypeError, sqlite.register_adapter, {}, None)
|
||||
|
||||
def CheckSetIsolationLevel(self):
|
||||
# See issue 27881.
|
||||
class CustomStr(str):
|
||||
def upper(self):
|
||||
return None
|
||||
def __del__(self):
|
||||
con.isolation_level = ""
|
||||
|
||||
con = sqlite.connect(":memory:")
|
||||
con.isolation_level = None
|
||||
for level in "", "DEFERRED", "IMMEDIATE", "EXCLUSIVE":
|
||||
with self.subTest(level=level):
|
||||
con.isolation_level = level
|
||||
con.isolation_level = level.lower()
|
||||
con.isolation_level = level.capitalize()
|
||||
con.isolation_level = CustomStr(level)
|
||||
|
||||
# setting isolation_level failure should not alter previous state
|
||||
con.isolation_level = None
|
||||
con.isolation_level = "DEFERRED"
|
||||
pairs = [
|
||||
(1, TypeError), (b'', TypeError), ("abc", ValueError),
|
||||
("IMMEDIATE\0EXCLUSIVE", ValueError), ("\xe9", ValueError),
|
||||
]
|
||||
for value, exc in pairs:
|
||||
with self.subTest(level=value):
|
||||
with self.assertRaises(exc):
|
||||
con.isolation_level = value
|
||||
self.assertEqual(con.isolation_level, "DEFERRED")
|
||||
|
||||
def CheckCursorConstructorCallCheck(self):
|
||||
"""
|
||||
Verifies that cursor methods check whether base class __init__ was
|
||||
called.
|
||||
"""
|
||||
class Cursor(sqlite.Cursor):
|
||||
def __init__(self, con):
|
||||
pass
|
||||
|
||||
con = sqlite.connect(":memory:")
|
||||
cur = Cursor(con)
|
||||
with self.assertRaises(sqlite.ProgrammingError):
|
||||
cur.execute("select 4+5").fetchall()
|
||||
with self.assertRaisesRegex(sqlite.ProgrammingError,
|
||||
r'^Base Cursor\.__init__ not called\.$'):
|
||||
cur.close()
|
||||
|
||||
def CheckStrSubclass(self):
|
||||
"""
|
||||
The Python 3.0 port of the module didn't cope with values of subclasses of str.
|
||||
"""
|
||||
class MyStr(str): pass
|
||||
self.con.execute("select ?", (MyStr("abc"),))
|
||||
|
||||
def CheckConnectionConstructorCallCheck(self):
|
||||
"""
|
||||
Verifies that connection methods check whether base class __init__ was
|
||||
called.
|
||||
"""
|
||||
class Connection(sqlite.Connection):
|
||||
def __init__(self, name):
|
||||
pass
|
||||
|
||||
con = Connection(":memory:")
|
||||
with self.assertRaises(sqlite.ProgrammingError):
|
||||
cur = con.cursor()
|
||||
|
||||
def CheckCursorRegistration(self):
|
||||
"""
|
||||
Verifies that subclassed cursor classes are correctly registered with
|
||||
the connection object, too. (fetch-across-rollback problem)
|
||||
"""
|
||||
class Connection(sqlite.Connection):
|
||||
def cursor(self):
|
||||
return Cursor(self)
|
||||
|
||||
class Cursor(sqlite.Cursor):
|
||||
def __init__(self, con):
|
||||
sqlite.Cursor.__init__(self, con)
|
||||
|
||||
con = Connection(":memory:")
|
||||
cur = con.cursor()
|
||||
cur.execute("create table foo(x)")
|
||||
cur.executemany("insert into foo(x) values (?)", [(3,), (4,), (5,)])
|
||||
cur.execute("select x from foo")
|
||||
con.rollback()
|
||||
with self.assertRaises(sqlite.InterfaceError):
|
||||
cur.fetchall()
|
||||
|
||||
def CheckAutoCommit(self):
|
||||
"""
|
||||
Verifies that creating a connection in autocommit mode works.
|
||||
2.5.3 introduced a regression so that these could no longer
|
||||
be created.
|
||||
"""
|
||||
con = sqlite.connect(":memory:", isolation_level=None)
|
||||
|
||||
def CheckPragmaAutocommit(self):
|
||||
"""
|
||||
Verifies that running a PRAGMA statement that does an autocommit does
|
||||
work. This did not work in 2.5.3/2.5.4.
|
||||
"""
|
||||
cur = self.con.cursor()
|
||||
cur.execute("create table foo(bar)")
|
||||
cur.execute("insert into foo(bar) values (5)")
|
||||
|
||||
cur.execute("pragma page_size")
|
||||
row = cur.fetchone()
|
||||
|
||||
def CheckConnectionCall(self):
|
||||
"""
|
||||
Call a connection with a non-string SQL request: check error handling
|
||||
of the statement constructor.
|
||||
"""
|
||||
self.assertRaises(TypeError, self.con, 1)
|
||||
|
||||
def CheckCollation(self):
|
||||
def collation_cb(a, b):
|
||||
return 1
|
||||
self.assertRaises(sqlite.ProgrammingError, self.con.create_collation,
|
||||
# Lone surrogate cannot be encoded to the default encoding (utf8)
|
||||
"\uDC80", collation_cb)
|
||||
|
||||
def CheckRecursiveCursorUse(self):
|
||||
"""
|
||||
http://bugs.python.org/issue10811
|
||||
|
||||
Recursively using a cursor, such as when reusing it from a generator led to segfaults.
|
||||
Now we catch recursive cursor usage and raise a ProgrammingError.
|
||||
"""
|
||||
con = sqlite.connect(":memory:")
|
||||
|
||||
cur = con.cursor()
|
||||
cur.execute("create table a (bar)")
|
||||
cur.execute("create table b (baz)")
|
||||
|
||||
def foo():
|
||||
cur.execute("insert into a (bar) values (?)", (1,))
|
||||
yield 1
|
||||
|
||||
with self.assertRaises(sqlite.ProgrammingError):
|
||||
cur.executemany("insert into b (baz) values (?)",
|
||||
((i,) for i in foo()))
|
||||
|
||||
def CheckConvertTimestampMicrosecondPadding(self):
|
||||
"""
|
||||
http://bugs.python.org/issue14720
|
||||
|
||||
The microsecond parsing of convert_timestamp() should pad with zeros,
|
||||
since the microsecond string "456" actually represents "456000".
|
||||
"""
|
||||
|
||||
con = sqlite.connect(":memory:", detect_types=sqlite.PARSE_DECLTYPES)
|
||||
cur = con.cursor()
|
||||
cur.execute("CREATE TABLE t (x TIMESTAMP)")
|
||||
|
||||
# Microseconds should be 456000
|
||||
cur.execute("INSERT INTO t (x) VALUES ('2012-04-04 15:06:00.456')")
|
||||
|
||||
# Microseconds should be truncated to 123456
|
||||
cur.execute("INSERT INTO t (x) VALUES ('2012-04-04 15:06:00.123456789')")
|
||||
|
||||
cur.execute("SELECT * FROM t")
|
||||
values = [x[0] for x in cur.fetchall()]
|
||||
|
||||
self.assertEqual(values, [
|
||||
datetime.datetime(2012, 4, 4, 15, 6, 0, 456000),
|
||||
datetime.datetime(2012, 4, 4, 15, 6, 0, 123456),
|
||||
])
|
||||
|
||||
def CheckInvalidIsolationLevelType(self):
|
||||
# isolation level is a string, not an integer
|
||||
self.assertRaises(TypeError,
|
||||
sqlite.connect, ":memory:", isolation_level=123)
|
||||
|
||||
|
||||
def CheckNullCharacter(self):
|
||||
# Issue #21147
|
||||
con = sqlite.connect(":memory:")
|
||||
self.assertRaises(ValueError, con, "\0select 1")
|
||||
self.assertRaises(ValueError, con, "select 1\0")
|
||||
cur = con.cursor()
|
||||
self.assertRaises(ValueError, cur.execute, " \0select 2")
|
||||
self.assertRaises(ValueError, cur.execute, "select 2\0")
|
||||
|
||||
def CheckCommitCursorReset(self):
|
||||
"""
|
||||
Connection.commit() did reset cursors, which made sqlite3
|
||||
to return rows multiple times when fetched from cursors
|
||||
after commit. See issues 10513 and 23129 for details.
|
||||
"""
|
||||
con = sqlite.connect(":memory:")
|
||||
con.executescript("""
|
||||
create table t(c);
|
||||
create table t2(c);
|
||||
insert into t values(0);
|
||||
insert into t values(1);
|
||||
insert into t values(2);
|
||||
""")
|
||||
|
||||
self.assertEqual(con.isolation_level, "")
|
||||
|
||||
counter = 0
|
||||
for i, row in enumerate(con.execute("select c from t")):
|
||||
with self.subTest(i=i, row=row):
|
||||
con.execute("insert into t2(c) values (?)", (i,))
|
||||
con.commit()
|
||||
if counter == 0:
|
||||
self.assertEqual(row[0], 0)
|
||||
elif counter == 1:
|
||||
self.assertEqual(row[0], 1)
|
||||
elif counter == 2:
|
||||
self.assertEqual(row[0], 2)
|
||||
counter += 1
|
||||
self.assertEqual(counter, 3, "should have returned exactly three rows")
|
||||
|
||||
def CheckBpo31770(self):
|
||||
"""
|
||||
The interpreter shouldn't crash in case Cursor.__init__() is called
|
||||
more than once.
|
||||
"""
|
||||
def callback(*args):
|
||||
pass
|
||||
con = sqlite.connect(":memory:")
|
||||
cur = sqlite.Cursor(con)
|
||||
ref = weakref.ref(cur, callback)
|
||||
cur.__init__(con)
|
||||
del cur
|
||||
# The interpreter shouldn't crash when ref is collected.
|
||||
del ref
|
||||
support.gc_collect()
|
||||
|
||||
def CheckDelIsolation_levelSegfault(self):
|
||||
with self.assertRaises(AttributeError):
|
||||
del self.con.isolation_level
|
||||
|
||||
def CheckBpo37347(self):
|
||||
class Printer:
|
||||
def log(self, *args):
|
||||
return sqlite.SQLITE_OK
|
||||
|
||||
for method in [self.con.set_trace_callback,
|
||||
functools.partial(self.con.set_progress_handler, n=1),
|
||||
self.con.set_authorizer]:
|
||||
printer_instance = Printer()
|
||||
method(printer_instance.log)
|
||||
method(printer_instance.log)
|
||||
self.con.execute("select 1") # trigger seg fault
|
||||
method(None)
|
||||
|
||||
|
||||
|
||||
class RecursiveUseOfCursors(unittest.TestCase):
|
||||
# GH-80254: sqlite3 should not segfault for recursive use of cursors.
|
||||
msg = "Recursive use of cursors not allowed"
|
||||
|
||||
def setUp(self):
|
||||
self.con = sqlite.connect(":memory:",
|
||||
detect_types=sqlite.PARSE_COLNAMES)
|
||||
self.cur = self.con.cursor()
|
||||
self.cur.execute("create table test(x foo)")
|
||||
self.cur.executemany("insert into test(x) values (?)",
|
||||
[("foo",), ("bar",)])
|
||||
|
||||
def tearDown(self):
|
||||
self.cur.close()
|
||||
self.con.close()
|
||||
del self.cur
|
||||
del self.con
|
||||
|
||||
def test_recursive_cursor_init(self):
|
||||
conv = lambda x: self.cur.__init__(self.con)
|
||||
with patch.dict(sqlite.converters, {"INIT": conv}):
|
||||
with self.assertRaisesRegex(sqlite.ProgrammingError, self.msg):
|
||||
self.cur.execute(f'select x as "x [INIT]", x from test')
|
||||
|
||||
def test_recursive_cursor_close(self):
|
||||
conv = lambda x: self.cur.close()
|
||||
with patch.dict(sqlite.converters, {"CLOSE": conv}):
|
||||
with self.assertRaisesRegex(sqlite.ProgrammingError, self.msg):
|
||||
self.cur.execute(f'select x as "x [CLOSE]", x from test')
|
||||
|
||||
def test_recursive_cursor_fetch(self):
|
||||
conv = lambda x, l=[]: self.cur.fetchone() if l else l.append(None)
|
||||
with patch.dict(sqlite.converters, {"ITER": conv}):
|
||||
self.cur.execute(f'select x as "x [ITER]", x from test')
|
||||
with self.assertRaisesRegex(sqlite.ProgrammingError, self.msg):
|
||||
self.cur.fetchall()
|
||||
|
||||
|
||||
def suite():
|
||||
regression_suite = unittest.makeSuite(RegressionTests, "Check")
|
||||
recursive_cursor = unittest.makeSuite(RecursiveUseOfCursors)
|
||||
return unittest.TestSuite((
|
||||
regression_suite,
|
||||
recursive_cursor,
|
||||
))
|
||||
|
||||
def test():
|
||||
runner = unittest.TextTestRunner()
|
||||
runner.run(suite())
|
||||
|
||||
if __name__ == "__main__":
|
||||
test()
|
||||
@@ -0,0 +1,214 @@
|
||||
#-*- coding: iso-8859-1 -*-
|
||||
# pysqlite2/test/transactions.py: tests transactions
|
||||
#
|
||||
# Copyright (C) 2005-2007 Gerhard Häring <gh@ghaering.de>
|
||||
#
|
||||
# This file is part of pysqlite.
|
||||
#
|
||||
# This software is provided 'as-is', without any express or implied
|
||||
# warranty. In no event will the authors be held liable for any damages
|
||||
# arising from the use of this software.
|
||||
#
|
||||
# Permission is granted to anyone to use this software for any purpose,
|
||||
# including commercial applications, and to alter it and redistribute it
|
||||
# freely, subject to the following restrictions:
|
||||
#
|
||||
# 1. The origin of this software must not be misrepresented; you must not
|
||||
# claim that you wrote the original software. If you use this software
|
||||
# in a product, an acknowledgment in the product documentation would be
|
||||
# appreciated but is not required.
|
||||
# 2. Altered source versions must be plainly marked as such, and must not be
|
||||
# misrepresented as being the original software.
|
||||
# 3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
import os, unittest
|
||||
import sqlite3 as sqlite
|
||||
|
||||
def get_db_path():
|
||||
return "sqlite_testdb"
|
||||
|
||||
class TransactionTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
try:
|
||||
os.remove(get_db_path())
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
self.con1 = sqlite.connect(get_db_path(), timeout=0.1)
|
||||
self.cur1 = self.con1.cursor()
|
||||
|
||||
self.con2 = sqlite.connect(get_db_path(), timeout=0.1)
|
||||
self.cur2 = self.con2.cursor()
|
||||
|
||||
def tearDown(self):
|
||||
self.cur1.close()
|
||||
self.con1.close()
|
||||
|
||||
self.cur2.close()
|
||||
self.con2.close()
|
||||
|
||||
try:
|
||||
os.unlink(get_db_path())
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
def CheckDMLDoesNotAutoCommitBefore(self):
|
||||
self.cur1.execute("create table test(i)")
|
||||
self.cur1.execute("insert into test(i) values (5)")
|
||||
self.cur1.execute("create table test2(j)")
|
||||
self.cur2.execute("select i from test")
|
||||
res = self.cur2.fetchall()
|
||||
self.assertEqual(len(res), 0)
|
||||
|
||||
def CheckInsertStartsTransaction(self):
|
||||
self.cur1.execute("create table test(i)")
|
||||
self.cur1.execute("insert into test(i) values (5)")
|
||||
self.cur2.execute("select i from test")
|
||||
res = self.cur2.fetchall()
|
||||
self.assertEqual(len(res), 0)
|
||||
|
||||
def CheckUpdateStartsTransaction(self):
|
||||
self.cur1.execute("create table test(i)")
|
||||
self.cur1.execute("insert into test(i) values (5)")
|
||||
self.con1.commit()
|
||||
self.cur1.execute("update test set i=6")
|
||||
self.cur2.execute("select i from test")
|
||||
res = self.cur2.fetchone()[0]
|
||||
self.assertEqual(res, 5)
|
||||
|
||||
def CheckDeleteStartsTransaction(self):
|
||||
self.cur1.execute("create table test(i)")
|
||||
self.cur1.execute("insert into test(i) values (5)")
|
||||
self.con1.commit()
|
||||
self.cur1.execute("delete from test")
|
||||
self.cur2.execute("select i from test")
|
||||
res = self.cur2.fetchall()
|
||||
self.assertEqual(len(res), 1)
|
||||
|
||||
def CheckReplaceStartsTransaction(self):
|
||||
self.cur1.execute("create table test(i)")
|
||||
self.cur1.execute("insert into test(i) values (5)")
|
||||
self.con1.commit()
|
||||
self.cur1.execute("replace into test(i) values (6)")
|
||||
self.cur2.execute("select i from test")
|
||||
res = self.cur2.fetchall()
|
||||
self.assertEqual(len(res), 1)
|
||||
self.assertEqual(res[0][0], 5)
|
||||
|
||||
def CheckToggleAutoCommit(self):
|
||||
self.cur1.execute("create table test(i)")
|
||||
self.cur1.execute("insert into test(i) values (5)")
|
||||
self.con1.isolation_level = None
|
||||
self.assertEqual(self.con1.isolation_level, None)
|
||||
self.cur2.execute("select i from test")
|
||||
res = self.cur2.fetchall()
|
||||
self.assertEqual(len(res), 1)
|
||||
|
||||
self.con1.isolation_level = "DEFERRED"
|
||||
self.assertEqual(self.con1.isolation_level , "DEFERRED")
|
||||
self.cur1.execute("insert into test(i) values (5)")
|
||||
self.cur2.execute("select i from test")
|
||||
res = self.cur2.fetchall()
|
||||
self.assertEqual(len(res), 1)
|
||||
|
||||
@unittest.skipIf(sqlite.sqlite_version_info < (3, 2, 2),
|
||||
'test hangs on sqlite versions older than 3.2.2')
|
||||
def CheckRaiseTimeout(self):
|
||||
self.cur1.execute("create table test(i)")
|
||||
self.cur1.execute("insert into test(i) values (5)")
|
||||
with self.assertRaises(sqlite.OperationalError):
|
||||
self.cur2.execute("insert into test(i) values (5)")
|
||||
|
||||
@unittest.skipIf(sqlite.sqlite_version_info < (3, 2, 2),
|
||||
'test hangs on sqlite versions older than 3.2.2')
|
||||
def CheckLocking(self):
|
||||
"""
|
||||
This tests the improved concurrency with pysqlite 2.3.4. You needed
|
||||
to roll back con2 before you could commit con1.
|
||||
"""
|
||||
self.cur1.execute("create table test(i)")
|
||||
self.cur1.execute("insert into test(i) values (5)")
|
||||
with self.assertRaises(sqlite.OperationalError):
|
||||
self.cur2.execute("insert into test(i) values (5)")
|
||||
# NO self.con2.rollback() HERE!!!
|
||||
self.con1.commit()
|
||||
|
||||
def CheckRollbackCursorConsistency(self):
|
||||
"""
|
||||
Checks if cursors on the connection are set into a "reset" state
|
||||
when a rollback is done on the connection.
|
||||
"""
|
||||
con = sqlite.connect(":memory:")
|
||||
cur = con.cursor()
|
||||
cur.execute("create table test(x)")
|
||||
cur.execute("insert into test(x) values (5)")
|
||||
cur.execute("select 1 union select 2 union select 3")
|
||||
|
||||
con.rollback()
|
||||
with self.assertRaises(sqlite.InterfaceError):
|
||||
cur.fetchall()
|
||||
|
||||
class SpecialCommandTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.con = sqlite.connect(":memory:")
|
||||
self.cur = self.con.cursor()
|
||||
|
||||
def CheckDropTable(self):
|
||||
self.cur.execute("create table test(i)")
|
||||
self.cur.execute("insert into test(i) values (5)")
|
||||
self.cur.execute("drop table test")
|
||||
|
||||
def CheckPragma(self):
|
||||
self.cur.execute("create table test(i)")
|
||||
self.cur.execute("insert into test(i) values (5)")
|
||||
self.cur.execute("pragma count_changes=1")
|
||||
|
||||
def tearDown(self):
|
||||
self.cur.close()
|
||||
self.con.close()
|
||||
|
||||
class TransactionalDDL(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.con = sqlite.connect(":memory:")
|
||||
|
||||
def CheckDdlDoesNotAutostartTransaction(self):
|
||||
# For backwards compatibility reasons, DDL statements should not
|
||||
# implicitly start a transaction.
|
||||
self.con.execute("create table test(i)")
|
||||
self.con.rollback()
|
||||
result = self.con.execute("select * from test").fetchall()
|
||||
self.assertEqual(result, [])
|
||||
|
||||
def CheckImmediateTransactionalDDL(self):
|
||||
# You can achieve transactional DDL by issuing a BEGIN
|
||||
# statement manually.
|
||||
self.con.execute("begin immediate")
|
||||
self.con.execute("create table test(i)")
|
||||
self.con.rollback()
|
||||
with self.assertRaises(sqlite.OperationalError):
|
||||
self.con.execute("select * from test")
|
||||
|
||||
def CheckTransactionalDDL(self):
|
||||
# You can achieve transactional DDL by issuing a BEGIN
|
||||
# statement manually.
|
||||
self.con.execute("begin")
|
||||
self.con.execute("create table test(i)")
|
||||
self.con.rollback()
|
||||
with self.assertRaises(sqlite.OperationalError):
|
||||
self.con.execute("select * from test")
|
||||
|
||||
def tearDown(self):
|
||||
self.con.close()
|
||||
|
||||
def suite():
|
||||
default_suite = unittest.makeSuite(TransactionTests, "Check")
|
||||
special_command_suite = unittest.makeSuite(SpecialCommandTests, "Check")
|
||||
ddl_suite = unittest.makeSuite(TransactionalDDL, "Check")
|
||||
return unittest.TestSuite((default_suite, special_command_suite, ddl_suite))
|
||||
|
||||
def test():
|
||||
runner = unittest.TextTestRunner()
|
||||
runner.run(suite())
|
||||
|
||||
if __name__ == "__main__":
|
||||
test()
|
||||
@@ -0,0 +1,443 @@
|
||||
#-*- coding: iso-8859-1 -*-
|
||||
# pysqlite2/test/types.py: tests for type conversion and detection
|
||||
#
|
||||
# Copyright (C) 2005 Gerhard Häring <gh@ghaering.de>
|
||||
#
|
||||
# This file is part of pysqlite.
|
||||
#
|
||||
# This software is provided 'as-is', without any express or implied
|
||||
# warranty. In no event will the authors be held liable for any damages
|
||||
# arising from the use of this software.
|
||||
#
|
||||
# Permission is granted to anyone to use this software for any purpose,
|
||||
# including commercial applications, and to alter it and redistribute it
|
||||
# freely, subject to the following restrictions:
|
||||
#
|
||||
# 1. The origin of this software must not be misrepresented; you must not
|
||||
# claim that you wrote the original software. If you use this software
|
||||
# in a product, an acknowledgment in the product documentation would be
|
||||
# appreciated but is not required.
|
||||
# 2. Altered source versions must be plainly marked as such, and must not be
|
||||
# misrepresented as being the original software.
|
||||
# 3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
import datetime
|
||||
import unittest
|
||||
import sqlite3 as sqlite
|
||||
try:
|
||||
import zlib
|
||||
except ImportError:
|
||||
zlib = None
|
||||
|
||||
|
||||
class SqliteTypeTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.con = sqlite.connect(":memory:")
|
||||
self.cur = self.con.cursor()
|
||||
self.cur.execute("create table test(i integer, s varchar, f number, b blob)")
|
||||
|
||||
def tearDown(self):
|
||||
self.cur.close()
|
||||
self.con.close()
|
||||
|
||||
def CheckString(self):
|
||||
self.cur.execute("insert into test(s) values (?)", ("Österreich",))
|
||||
self.cur.execute("select s from test")
|
||||
row = self.cur.fetchone()
|
||||
self.assertEqual(row[0], "Österreich")
|
||||
|
||||
def CheckSmallInt(self):
|
||||
self.cur.execute("insert into test(i) values (?)", (42,))
|
||||
self.cur.execute("select i from test")
|
||||
row = self.cur.fetchone()
|
||||
self.assertEqual(row[0], 42)
|
||||
|
||||
def CheckLargeInt(self):
|
||||
num = 2**40
|
||||
self.cur.execute("insert into test(i) values (?)", (num,))
|
||||
self.cur.execute("select i from test")
|
||||
row = self.cur.fetchone()
|
||||
self.assertEqual(row[0], num)
|
||||
|
||||
def CheckFloat(self):
|
||||
val = 3.14
|
||||
self.cur.execute("insert into test(f) values (?)", (val,))
|
||||
self.cur.execute("select f from test")
|
||||
row = self.cur.fetchone()
|
||||
self.assertEqual(row[0], val)
|
||||
|
||||
def CheckBlob(self):
|
||||
sample = b"Guglhupf"
|
||||
val = memoryview(sample)
|
||||
self.cur.execute("insert into test(b) values (?)", (val,))
|
||||
self.cur.execute("select b from test")
|
||||
row = self.cur.fetchone()
|
||||
self.assertEqual(row[0], sample)
|
||||
|
||||
def CheckUnicodeExecute(self):
|
||||
self.cur.execute("select 'Österreich'")
|
||||
row = self.cur.fetchone()
|
||||
self.assertEqual(row[0], "Österreich")
|
||||
|
||||
class DeclTypesTests(unittest.TestCase):
|
||||
class Foo:
|
||||
def __init__(self, _val):
|
||||
if isinstance(_val, bytes):
|
||||
# sqlite3 always calls __init__ with a bytes created from a
|
||||
# UTF-8 string when __conform__ was used to store the object.
|
||||
_val = _val.decode('utf-8')
|
||||
self.val = _val
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(other, DeclTypesTests.Foo):
|
||||
return NotImplemented
|
||||
return self.val == other.val
|
||||
|
||||
def __conform__(self, protocol):
|
||||
if protocol is sqlite.PrepareProtocol:
|
||||
return self.val
|
||||
else:
|
||||
return None
|
||||
|
||||
def __str__(self):
|
||||
return "<%s>" % self.val
|
||||
|
||||
class BadConform:
|
||||
def __init__(self, exc):
|
||||
self.exc = exc
|
||||
def __conform__(self, protocol):
|
||||
raise self.exc
|
||||
|
||||
def setUp(self):
|
||||
self.con = sqlite.connect(":memory:", detect_types=sqlite.PARSE_DECLTYPES)
|
||||
self.cur = self.con.cursor()
|
||||
self.cur.execute("create table test(i int, s str, f float, b bool, u unicode, foo foo, bin blob, n1 number, n2 number(5), bad bad)")
|
||||
|
||||
# override float, make them always return the same number
|
||||
sqlite.converters["FLOAT"] = lambda x: 47.2
|
||||
|
||||
# and implement two custom ones
|
||||
sqlite.converters["BOOL"] = lambda x: bool(int(x))
|
||||
sqlite.converters["FOO"] = DeclTypesTests.Foo
|
||||
sqlite.converters["BAD"] = DeclTypesTests.BadConform
|
||||
sqlite.converters["WRONG"] = lambda x: "WRONG"
|
||||
sqlite.converters["NUMBER"] = float
|
||||
|
||||
def tearDown(self):
|
||||
del sqlite.converters["FLOAT"]
|
||||
del sqlite.converters["BOOL"]
|
||||
del sqlite.converters["FOO"]
|
||||
del sqlite.converters["BAD"]
|
||||
del sqlite.converters["WRONG"]
|
||||
del sqlite.converters["NUMBER"]
|
||||
self.cur.close()
|
||||
self.con.close()
|
||||
|
||||
def CheckString(self):
|
||||
# default
|
||||
self.cur.execute("insert into test(s) values (?)", ("foo",))
|
||||
self.cur.execute('select s as "s [WRONG]" from test')
|
||||
row = self.cur.fetchone()
|
||||
self.assertEqual(row[0], "foo")
|
||||
|
||||
def CheckSmallInt(self):
|
||||
# default
|
||||
self.cur.execute("insert into test(i) values (?)", (42,))
|
||||
self.cur.execute("select i from test")
|
||||
row = self.cur.fetchone()
|
||||
self.assertEqual(row[0], 42)
|
||||
|
||||
def CheckLargeInt(self):
|
||||
# default
|
||||
num = 2**40
|
||||
self.cur.execute("insert into test(i) values (?)", (num,))
|
||||
self.cur.execute("select i from test")
|
||||
row = self.cur.fetchone()
|
||||
self.assertEqual(row[0], num)
|
||||
|
||||
def CheckFloat(self):
|
||||
# custom
|
||||
val = 3.14
|
||||
self.cur.execute("insert into test(f) values (?)", (val,))
|
||||
self.cur.execute("select f from test")
|
||||
row = self.cur.fetchone()
|
||||
self.assertEqual(row[0], 47.2)
|
||||
|
||||
def CheckBool(self):
|
||||
# custom
|
||||
self.cur.execute("insert into test(b) values (?)", (False,))
|
||||
self.cur.execute("select b from test")
|
||||
row = self.cur.fetchone()
|
||||
self.assertIs(row[0], False)
|
||||
|
||||
self.cur.execute("delete from test")
|
||||
self.cur.execute("insert into test(b) values (?)", (True,))
|
||||
self.cur.execute("select b from test")
|
||||
row = self.cur.fetchone()
|
||||
self.assertIs(row[0], True)
|
||||
|
||||
def CheckUnicode(self):
|
||||
# default
|
||||
val = "\xd6sterreich"
|
||||
self.cur.execute("insert into test(u) values (?)", (val,))
|
||||
self.cur.execute("select u from test")
|
||||
row = self.cur.fetchone()
|
||||
self.assertEqual(row[0], val)
|
||||
|
||||
def CheckFoo(self):
|
||||
val = DeclTypesTests.Foo("bla")
|
||||
self.cur.execute("insert into test(foo) values (?)", (val,))
|
||||
self.cur.execute("select foo from test")
|
||||
row = self.cur.fetchone()
|
||||
self.assertEqual(row[0], val)
|
||||
|
||||
def CheckErrorInConform(self):
|
||||
val = DeclTypesTests.BadConform(TypeError)
|
||||
with self.assertRaises(sqlite.InterfaceError):
|
||||
self.cur.execute("insert into test(bad) values (?)", (val,))
|
||||
with self.assertRaises(sqlite.InterfaceError):
|
||||
self.cur.execute("insert into test(bad) values (:val)", {"val": val})
|
||||
|
||||
val = DeclTypesTests.BadConform(KeyboardInterrupt)
|
||||
with self.assertRaises(KeyboardInterrupt):
|
||||
self.cur.execute("insert into test(bad) values (?)", (val,))
|
||||
with self.assertRaises(KeyboardInterrupt):
|
||||
self.cur.execute("insert into test(bad) values (:val)", {"val": val})
|
||||
|
||||
def CheckUnsupportedSeq(self):
|
||||
class Bar: pass
|
||||
val = Bar()
|
||||
with self.assertRaises(sqlite.InterfaceError):
|
||||
self.cur.execute("insert into test(f) values (?)", (val,))
|
||||
|
||||
def CheckUnsupportedDict(self):
|
||||
class Bar: pass
|
||||
val = Bar()
|
||||
with self.assertRaises(sqlite.InterfaceError):
|
||||
self.cur.execute("insert into test(f) values (:val)", {"val": val})
|
||||
|
||||
def CheckBlob(self):
|
||||
# default
|
||||
sample = b"Guglhupf"
|
||||
val = memoryview(sample)
|
||||
self.cur.execute("insert into test(bin) values (?)", (val,))
|
||||
self.cur.execute("select bin from test")
|
||||
row = self.cur.fetchone()
|
||||
self.assertEqual(row[0], sample)
|
||||
|
||||
def CheckNumber1(self):
|
||||
self.cur.execute("insert into test(n1) values (5)")
|
||||
value = self.cur.execute("select n1 from test").fetchone()[0]
|
||||
# if the converter is not used, it's an int instead of a float
|
||||
self.assertEqual(type(value), float)
|
||||
|
||||
def CheckNumber2(self):
|
||||
"""Checks whether converter names are cut off at '(' characters"""
|
||||
self.cur.execute("insert into test(n2) values (5)")
|
||||
value = self.cur.execute("select n2 from test").fetchone()[0]
|
||||
# if the converter is not used, it's an int instead of a float
|
||||
self.assertEqual(type(value), float)
|
||||
|
||||
class ColNamesTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.con = sqlite.connect(":memory:", detect_types=sqlite.PARSE_COLNAMES)
|
||||
self.cur = self.con.cursor()
|
||||
self.cur.execute("create table test(x foo)")
|
||||
|
||||
sqlite.converters["FOO"] = lambda x: "[%s]" % x.decode("ascii")
|
||||
sqlite.converters["BAR"] = lambda x: "<%s>" % x.decode("ascii")
|
||||
sqlite.converters["EXC"] = lambda x: 5/0
|
||||
sqlite.converters["B1B1"] = lambda x: "MARKER"
|
||||
|
||||
def tearDown(self):
|
||||
del sqlite.converters["FOO"]
|
||||
del sqlite.converters["BAR"]
|
||||
del sqlite.converters["EXC"]
|
||||
del sqlite.converters["B1B1"]
|
||||
self.cur.close()
|
||||
self.con.close()
|
||||
|
||||
def CheckDeclTypeNotUsed(self):
|
||||
"""
|
||||
Assures that the declared type is not used when PARSE_DECLTYPES
|
||||
is not set.
|
||||
"""
|
||||
self.cur.execute("insert into test(x) values (?)", ("xxx",))
|
||||
self.cur.execute("select x from test")
|
||||
val = self.cur.fetchone()[0]
|
||||
self.assertEqual(val, "xxx")
|
||||
|
||||
def CheckNone(self):
|
||||
self.cur.execute("insert into test(x) values (?)", (None,))
|
||||
self.cur.execute("select x from test")
|
||||
val = self.cur.fetchone()[0]
|
||||
self.assertEqual(val, None)
|
||||
|
||||
def CheckColName(self):
|
||||
self.cur.execute("insert into test(x) values (?)", ("xxx",))
|
||||
self.cur.execute('select x as "x y [bar]" from test')
|
||||
val = self.cur.fetchone()[0]
|
||||
self.assertEqual(val, "<xxx>")
|
||||
|
||||
# Check if the stripping of colnames works. Everything after the first
|
||||
# '[' (and the preceeding space) should be stripped.
|
||||
self.assertEqual(self.cur.description[0][0], "x y")
|
||||
|
||||
def CheckCaseInConverterName(self):
|
||||
self.cur.execute("select 'other' as \"x [b1b1]\"")
|
||||
val = self.cur.fetchone()[0]
|
||||
self.assertEqual(val, "MARKER")
|
||||
|
||||
def CheckCursorDescriptionNoRow(self):
|
||||
"""
|
||||
cursor.description should at least provide the column name(s), even if
|
||||
no row returned.
|
||||
"""
|
||||
self.cur.execute("select * from test where 0 = 1")
|
||||
self.assertEqual(self.cur.description[0][0], "x")
|
||||
|
||||
def CheckCursorDescriptionInsert(self):
|
||||
self.cur.execute("insert into test values (1)")
|
||||
self.assertIsNone(self.cur.description)
|
||||
|
||||
|
||||
@unittest.skipIf(sqlite.sqlite_version_info < (3, 8, 3), "CTEs not supported")
|
||||
class CommonTableExpressionTests(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.con = sqlite.connect(":memory:")
|
||||
self.cur = self.con.cursor()
|
||||
self.cur.execute("create table test(x foo)")
|
||||
|
||||
def tearDown(self):
|
||||
self.cur.close()
|
||||
self.con.close()
|
||||
|
||||
def CheckCursorDescriptionCTESimple(self):
|
||||
self.cur.execute("with one as (select 1) select * from one")
|
||||
self.assertIsNotNone(self.cur.description)
|
||||
self.assertEqual(self.cur.description[0][0], "1")
|
||||
|
||||
def CheckCursorDescriptionCTESMultipleColumns(self):
|
||||
self.cur.execute("insert into test values(1)")
|
||||
self.cur.execute("insert into test values(2)")
|
||||
self.cur.execute("with testCTE as (select * from test) select * from testCTE")
|
||||
self.assertIsNotNone(self.cur.description)
|
||||
self.assertEqual(self.cur.description[0][0], "x")
|
||||
|
||||
def CheckCursorDescriptionCTE(self):
|
||||
self.cur.execute("insert into test values (1)")
|
||||
self.cur.execute("with bar as (select * from test) select * from test where x = 1")
|
||||
self.assertIsNotNone(self.cur.description)
|
||||
self.assertEqual(self.cur.description[0][0], "x")
|
||||
self.cur.execute("with bar as (select * from test) select * from test where x = 2")
|
||||
self.assertIsNotNone(self.cur.description)
|
||||
self.assertEqual(self.cur.description[0][0], "x")
|
||||
|
||||
|
||||
class ObjectAdaptationTests(unittest.TestCase):
|
||||
def cast(obj):
|
||||
return float(obj)
|
||||
cast = staticmethod(cast)
|
||||
|
||||
def setUp(self):
|
||||
self.con = sqlite.connect(":memory:")
|
||||
try:
|
||||
del sqlite.adapters[int]
|
||||
except:
|
||||
pass
|
||||
sqlite.register_adapter(int, ObjectAdaptationTests.cast)
|
||||
self.cur = self.con.cursor()
|
||||
|
||||
def tearDown(self):
|
||||
del sqlite.adapters[(int, sqlite.PrepareProtocol)]
|
||||
self.cur.close()
|
||||
self.con.close()
|
||||
|
||||
def CheckCasterIsUsed(self):
|
||||
self.cur.execute("select ?", (4,))
|
||||
val = self.cur.fetchone()[0]
|
||||
self.assertEqual(type(val), float)
|
||||
|
||||
@unittest.skipUnless(zlib, "requires zlib")
|
||||
class BinaryConverterTests(unittest.TestCase):
|
||||
def convert(s):
|
||||
return zlib.decompress(s)
|
||||
convert = staticmethod(convert)
|
||||
|
||||
def setUp(self):
|
||||
self.con = sqlite.connect(":memory:", detect_types=sqlite.PARSE_COLNAMES)
|
||||
sqlite.register_converter("bin", BinaryConverterTests.convert)
|
||||
|
||||
def tearDown(self):
|
||||
self.con.close()
|
||||
|
||||
def CheckBinaryInputForConverter(self):
|
||||
testdata = b"abcdefg" * 10
|
||||
result = self.con.execute('select ? as "x [bin]"', (memoryview(zlib.compress(testdata)),)).fetchone()[0]
|
||||
self.assertEqual(testdata, result)
|
||||
|
||||
class DateTimeTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.con = sqlite.connect(":memory:", detect_types=sqlite.PARSE_DECLTYPES)
|
||||
self.cur = self.con.cursor()
|
||||
self.cur.execute("create table test(d date, ts timestamp)")
|
||||
|
||||
def tearDown(self):
|
||||
self.cur.close()
|
||||
self.con.close()
|
||||
|
||||
def CheckSqliteDate(self):
|
||||
d = sqlite.Date(2004, 2, 14)
|
||||
self.cur.execute("insert into test(d) values (?)", (d,))
|
||||
self.cur.execute("select d from test")
|
||||
d2 = self.cur.fetchone()[0]
|
||||
self.assertEqual(d, d2)
|
||||
|
||||
def CheckSqliteTimestamp(self):
|
||||
ts = sqlite.Timestamp(2004, 2, 14, 7, 15, 0)
|
||||
self.cur.execute("insert into test(ts) values (?)", (ts,))
|
||||
self.cur.execute("select ts from test")
|
||||
ts2 = self.cur.fetchone()[0]
|
||||
self.assertEqual(ts, ts2)
|
||||
|
||||
@unittest.skipIf(sqlite.sqlite_version_info < (3, 1),
|
||||
'the date functions are available on 3.1 or later')
|
||||
def CheckSqlTimestamp(self):
|
||||
now = datetime.datetime.utcnow()
|
||||
self.cur.execute("insert into test(ts) values (current_timestamp)")
|
||||
self.cur.execute("select ts from test")
|
||||
ts = self.cur.fetchone()[0]
|
||||
self.assertEqual(type(ts), datetime.datetime)
|
||||
self.assertEqual(ts.year, now.year)
|
||||
|
||||
def CheckDateTimeSubSeconds(self):
|
||||
ts = sqlite.Timestamp(2004, 2, 14, 7, 15, 0, 500000)
|
||||
self.cur.execute("insert into test(ts) values (?)", (ts,))
|
||||
self.cur.execute("select ts from test")
|
||||
ts2 = self.cur.fetchone()[0]
|
||||
self.assertEqual(ts, ts2)
|
||||
|
||||
def CheckDateTimeSubSecondsFloatingPoint(self):
|
||||
ts = sqlite.Timestamp(2004, 2, 14, 7, 15, 0, 510241)
|
||||
self.cur.execute("insert into test(ts) values (?)", (ts,))
|
||||
self.cur.execute("select ts from test")
|
||||
ts2 = self.cur.fetchone()[0]
|
||||
self.assertEqual(ts, ts2)
|
||||
|
||||
def suite():
|
||||
sqlite_type_suite = unittest.makeSuite(SqliteTypeTests, "Check")
|
||||
decltypes_type_suite = unittest.makeSuite(DeclTypesTests, "Check")
|
||||
colnames_type_suite = unittest.makeSuite(ColNamesTests, "Check")
|
||||
adaptation_suite = unittest.makeSuite(ObjectAdaptationTests, "Check")
|
||||
bin_suite = unittest.makeSuite(BinaryConverterTests, "Check")
|
||||
date_suite = unittest.makeSuite(DateTimeTests, "Check")
|
||||
cte_suite = unittest.makeSuite(CommonTableExpressionTests, "Check")
|
||||
return unittest.TestSuite((sqlite_type_suite, decltypes_type_suite, colnames_type_suite, adaptation_suite, bin_suite, date_suite, cte_suite))
|
||||
|
||||
def test():
|
||||
runner = unittest.TextTestRunner()
|
||||
runner.run(suite())
|
||||
|
||||
if __name__ == "__main__":
|
||||
test()
|
||||
@@ -0,0 +1,548 @@
|
||||
# pysqlite2/test/userfunctions.py: tests for user-defined functions and
|
||||
# aggregates.
|
||||
#
|
||||
# Copyright (C) 2005-2007 Gerhard Häring <gh@ghaering.de>
|
||||
#
|
||||
# This file is part of pysqlite.
|
||||
#
|
||||
# This software is provided 'as-is', without any express or implied
|
||||
# warranty. In no event will the authors be held liable for any damages
|
||||
# arising from the use of this software.
|
||||
#
|
||||
# Permission is granted to anyone to use this software for any purpose,
|
||||
# including commercial applications, and to alter it and redistribute it
|
||||
# freely, subject to the following restrictions:
|
||||
#
|
||||
# 1. The origin of this software must not be misrepresented; you must not
|
||||
# claim that you wrote the original software. If you use this software
|
||||
# in a product, an acknowledgment in the product documentation would be
|
||||
# appreciated but is not required.
|
||||
# 2. Altered source versions must be plainly marked as such, and must not be
|
||||
# misrepresented as being the original software.
|
||||
# 3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
import unittest
|
||||
import unittest.mock
|
||||
import sqlite3 as sqlite
|
||||
|
||||
def func_returntext():
|
||||
return "foo"
|
||||
def func_returntextwithnull():
|
||||
return "1\x002"
|
||||
def func_returnunicode():
|
||||
return "bar"
|
||||
def func_returnint():
|
||||
return 42
|
||||
def func_returnfloat():
|
||||
return 3.14
|
||||
def func_returnnull():
|
||||
return None
|
||||
def func_returnblob():
|
||||
return b"blob"
|
||||
def func_returnlonglong():
|
||||
return 1<<31
|
||||
def func_raiseexception():
|
||||
5/0
|
||||
|
||||
class AggrNoStep:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def finalize(self):
|
||||
return 1
|
||||
|
||||
class AggrNoFinalize:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def step(self, x):
|
||||
pass
|
||||
|
||||
class AggrExceptionInInit:
|
||||
def __init__(self):
|
||||
5/0
|
||||
|
||||
def step(self, x):
|
||||
pass
|
||||
|
||||
def finalize(self):
|
||||
pass
|
||||
|
||||
class AggrExceptionInStep:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def step(self, x):
|
||||
5/0
|
||||
|
||||
def finalize(self):
|
||||
return 42
|
||||
|
||||
class AggrExceptionInFinalize:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def step(self, x):
|
||||
pass
|
||||
|
||||
def finalize(self):
|
||||
5/0
|
||||
|
||||
class AggrCheckType:
|
||||
def __init__(self):
|
||||
self.val = None
|
||||
|
||||
def step(self, whichType, val):
|
||||
theType = {"str": str, "int": int, "float": float, "None": type(None),
|
||||
"blob": bytes}
|
||||
self.val = int(theType[whichType] is type(val))
|
||||
|
||||
def finalize(self):
|
||||
return self.val
|
||||
|
||||
class AggrCheckTypes:
|
||||
def __init__(self):
|
||||
self.val = 0
|
||||
|
||||
def step(self, whichType, *vals):
|
||||
theType = {"str": str, "int": int, "float": float, "None": type(None),
|
||||
"blob": bytes}
|
||||
for val in vals:
|
||||
self.val += int(theType[whichType] is type(val))
|
||||
|
||||
def finalize(self):
|
||||
return self.val
|
||||
|
||||
class AggrSum:
|
||||
def __init__(self):
|
||||
self.val = 0.0
|
||||
|
||||
def step(self, val):
|
||||
self.val += val
|
||||
|
||||
def finalize(self):
|
||||
return self.val
|
||||
|
||||
class AggrText:
|
||||
def __init__(self):
|
||||
self.txt = ""
|
||||
def step(self, txt):
|
||||
self.txt = self.txt + txt
|
||||
def finalize(self):
|
||||
return self.txt
|
||||
|
||||
|
||||
class FunctionTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.con = sqlite.connect(":memory:")
|
||||
|
||||
self.con.create_function("returntext", 0, func_returntext)
|
||||
self.con.create_function("returntextwithnull", 0, func_returntextwithnull)
|
||||
self.con.create_function("returnunicode", 0, func_returnunicode)
|
||||
self.con.create_function("returnint", 0, func_returnint)
|
||||
self.con.create_function("returnfloat", 0, func_returnfloat)
|
||||
self.con.create_function("returnnull", 0, func_returnnull)
|
||||
self.con.create_function("returnblob", 0, func_returnblob)
|
||||
self.con.create_function("returnlonglong", 0, func_returnlonglong)
|
||||
self.con.create_function("returnnan", 0, lambda: float("nan"))
|
||||
self.con.create_function("returntoolargeint", 0, lambda: 1 << 65)
|
||||
self.con.create_function("raiseexception", 0, func_raiseexception)
|
||||
|
||||
self.con.create_function("isblob", 1, lambda x: isinstance(x, bytes))
|
||||
self.con.create_function("isnone", 1, lambda x: x is None)
|
||||
self.con.create_function("spam", -1, lambda *x: len(x))
|
||||
self.con.execute("create table test(t text)")
|
||||
|
||||
def tearDown(self):
|
||||
self.con.close()
|
||||
|
||||
def CheckFuncErrorOnCreate(self):
|
||||
with self.assertRaises(sqlite.OperationalError):
|
||||
self.con.create_function("bla", -100, lambda x: 2*x)
|
||||
|
||||
def CheckFuncRefCount(self):
|
||||
def getfunc():
|
||||
def f():
|
||||
return 1
|
||||
return f
|
||||
f = getfunc()
|
||||
globals()["foo"] = f
|
||||
# self.con.create_function("reftest", 0, getfunc())
|
||||
self.con.create_function("reftest", 0, f)
|
||||
cur = self.con.cursor()
|
||||
cur.execute("select reftest()")
|
||||
|
||||
def CheckFuncReturnText(self):
|
||||
cur = self.con.cursor()
|
||||
cur.execute("select returntext()")
|
||||
val = cur.fetchone()[0]
|
||||
self.assertEqual(type(val), str)
|
||||
self.assertEqual(val, "foo")
|
||||
|
||||
def CheckFuncReturnTextWithNullChar(self):
|
||||
cur = self.con.cursor()
|
||||
res = cur.execute("select returntextwithnull()").fetchone()[0]
|
||||
self.assertEqual(type(res), str)
|
||||
self.assertEqual(res, "1\x002")
|
||||
|
||||
def CheckFuncReturnUnicode(self):
|
||||
cur = self.con.cursor()
|
||||
cur.execute("select returnunicode()")
|
||||
val = cur.fetchone()[0]
|
||||
self.assertEqual(type(val), str)
|
||||
self.assertEqual(val, "bar")
|
||||
|
||||
def CheckFuncReturnInt(self):
|
||||
cur = self.con.cursor()
|
||||
cur.execute("select returnint()")
|
||||
val = cur.fetchone()[0]
|
||||
self.assertEqual(type(val), int)
|
||||
self.assertEqual(val, 42)
|
||||
|
||||
def CheckFuncReturnFloat(self):
|
||||
cur = self.con.cursor()
|
||||
cur.execute("select returnfloat()")
|
||||
val = cur.fetchone()[0]
|
||||
self.assertEqual(type(val), float)
|
||||
if val < 3.139 or val > 3.141:
|
||||
self.fail("wrong value")
|
||||
|
||||
def CheckFuncReturnNull(self):
|
||||
cur = self.con.cursor()
|
||||
cur.execute("select returnnull()")
|
||||
val = cur.fetchone()[0]
|
||||
self.assertEqual(type(val), type(None))
|
||||
self.assertEqual(val, None)
|
||||
|
||||
def CheckFuncReturnBlob(self):
|
||||
cur = self.con.cursor()
|
||||
cur.execute("select returnblob()")
|
||||
val = cur.fetchone()[0]
|
||||
self.assertEqual(type(val), bytes)
|
||||
self.assertEqual(val, b"blob")
|
||||
|
||||
def CheckFuncReturnLongLong(self):
|
||||
cur = self.con.cursor()
|
||||
cur.execute("select returnlonglong()")
|
||||
val = cur.fetchone()[0]
|
||||
self.assertEqual(val, 1<<31)
|
||||
|
||||
def CheckFuncReturnNaN(self):
|
||||
cur = self.con.cursor()
|
||||
cur.execute("select returnnan()")
|
||||
self.assertIsNone(cur.fetchone()[0])
|
||||
|
||||
def CheckFuncReturnTooLargeInt(self):
|
||||
cur = self.con.cursor()
|
||||
with self.assertRaises(sqlite.OperationalError):
|
||||
self.con.execute("select returntoolargeint()")
|
||||
|
||||
def CheckFuncException(self):
|
||||
cur = self.con.cursor()
|
||||
with self.assertRaises(sqlite.OperationalError) as cm:
|
||||
cur.execute("select raiseexception()")
|
||||
cur.fetchone()
|
||||
self.assertEqual(str(cm.exception), 'user-defined function raised exception')
|
||||
|
||||
def CheckAnyArguments(self):
|
||||
cur = self.con.cursor()
|
||||
cur.execute("select spam(?, ?)", (1, 2))
|
||||
val = cur.fetchone()[0]
|
||||
self.assertEqual(val, 2)
|
||||
|
||||
def CheckEmptyBlob(self):
|
||||
cur = self.con.execute("select isblob(x'')")
|
||||
self.assertTrue(cur.fetchone()[0])
|
||||
|
||||
def CheckNaNFloat(self):
|
||||
cur = self.con.execute("select isnone(?)", (float("nan"),))
|
||||
# SQLite has no concept of nan; it is converted to NULL
|
||||
self.assertTrue(cur.fetchone()[0])
|
||||
|
||||
def CheckTooLargeInt(self):
|
||||
err = "Python int too large to convert to SQLite INTEGER"
|
||||
self.assertRaisesRegex(OverflowError, err, self.con.execute,
|
||||
"select spam(?)", (1 << 65,))
|
||||
|
||||
def CheckNonContiguousBlob(self):
|
||||
self.assertRaisesRegex(ValueError, "could not convert BLOB to buffer",
|
||||
self.con.execute, "select spam(?)",
|
||||
(memoryview(b"blob")[::2],))
|
||||
|
||||
def CheckParamSurrogates(self):
|
||||
self.assertRaisesRegex(UnicodeEncodeError, "surrogates not allowed",
|
||||
self.con.execute, "select spam(?)",
|
||||
("\ud803\ude6d",))
|
||||
|
||||
def CheckFuncParams(self):
|
||||
results = []
|
||||
def append_result(arg):
|
||||
results.append((arg, type(arg)))
|
||||
self.con.create_function("test_params", 1, append_result)
|
||||
|
||||
dataset = [
|
||||
(42, int),
|
||||
(-1, int),
|
||||
(1234567890123456789, int),
|
||||
(4611686018427387905, int), # 63-bit int with non-zero low bits
|
||||
(3.14, float),
|
||||
(float('inf'), float),
|
||||
("text", str),
|
||||
("1\x002", str),
|
||||
("\u02e2q\u02e1\u2071\u1d57\u1d49", str),
|
||||
(b"blob", bytes),
|
||||
(bytearray(range(2)), bytes),
|
||||
(memoryview(b"blob"), bytes),
|
||||
(None, type(None)),
|
||||
]
|
||||
for val, _ in dataset:
|
||||
cur = self.con.execute("select test_params(?)", (val,))
|
||||
cur.fetchone()
|
||||
self.assertEqual(dataset, results)
|
||||
|
||||
# Regarding deterministic functions:
|
||||
#
|
||||
# Between 3.8.3 and 3.15.0, deterministic functions were only used to
|
||||
# optimize inner loops, so for those versions we can only test if the
|
||||
# sqlite machinery has factored out a call or not. From 3.15.0 and onward,
|
||||
# deterministic functions were permitted in WHERE clauses of partial
|
||||
# indices, which allows testing based on syntax, iso. the query optimizer.
|
||||
@unittest.skipIf(sqlite.sqlite_version_info < (3, 8, 3), "Requires SQLite 3.8.3 or higher")
|
||||
def CheckFuncNonDeterministic(self):
|
||||
mock = unittest.mock.Mock(return_value=None)
|
||||
self.con.create_function("nondeterministic", 0, mock, deterministic=False)
|
||||
if sqlite.sqlite_version_info < (3, 15, 0):
|
||||
self.con.execute("select nondeterministic() = nondeterministic()")
|
||||
self.assertEqual(mock.call_count, 2)
|
||||
else:
|
||||
with self.assertRaises(sqlite.OperationalError):
|
||||
self.con.execute("create index t on test(t) where nondeterministic() is not null")
|
||||
|
||||
@unittest.skipIf(sqlite.sqlite_version_info < (3, 8, 3), "Requires SQLite 3.8.3 or higher")
|
||||
def CheckFuncDeterministic(self):
|
||||
mock = unittest.mock.Mock(return_value=None)
|
||||
self.con.create_function("deterministic", 0, mock, deterministic=True)
|
||||
if sqlite.sqlite_version_info < (3, 15, 0):
|
||||
self.con.execute("select deterministic() = deterministic()")
|
||||
self.assertEqual(mock.call_count, 1)
|
||||
else:
|
||||
try:
|
||||
self.con.execute("create index t on test(t) where deterministic() is not null")
|
||||
except sqlite.OperationalError:
|
||||
self.fail("Unexpected failure while creating partial index")
|
||||
|
||||
@unittest.skipIf(sqlite.sqlite_version_info >= (3, 8, 3), "SQLite < 3.8.3 needed")
|
||||
def CheckFuncDeterministicNotSupported(self):
|
||||
with self.assertRaises(sqlite.NotSupportedError):
|
||||
self.con.create_function("deterministic", 0, int, deterministic=True)
|
||||
|
||||
def CheckFuncDeterministicKeywordOnly(self):
|
||||
with self.assertRaises(TypeError):
|
||||
self.con.create_function("deterministic", 0, int, True)
|
||||
|
||||
|
||||
class AggregateTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.con = sqlite.connect(":memory:")
|
||||
cur = self.con.cursor()
|
||||
cur.execute("""
|
||||
create table test(
|
||||
t text,
|
||||
i integer,
|
||||
f float,
|
||||
n,
|
||||
b blob
|
||||
)
|
||||
""")
|
||||
cur.execute("insert into test(t, i, f, n, b) values (?, ?, ?, ?, ?)",
|
||||
("foo", 5, 3.14, None, memoryview(b"blob"),))
|
||||
|
||||
self.con.create_aggregate("nostep", 1, AggrNoStep)
|
||||
self.con.create_aggregate("nofinalize", 1, AggrNoFinalize)
|
||||
self.con.create_aggregate("excInit", 1, AggrExceptionInInit)
|
||||
self.con.create_aggregate("excStep", 1, AggrExceptionInStep)
|
||||
self.con.create_aggregate("excFinalize", 1, AggrExceptionInFinalize)
|
||||
self.con.create_aggregate("checkType", 2, AggrCheckType)
|
||||
self.con.create_aggregate("checkTypes", -1, AggrCheckTypes)
|
||||
self.con.create_aggregate("mysum", 1, AggrSum)
|
||||
self.con.create_aggregate("aggtxt", 1, AggrText)
|
||||
|
||||
def tearDown(self):
|
||||
#self.cur.close()
|
||||
#self.con.close()
|
||||
pass
|
||||
|
||||
def CheckAggrErrorOnCreate(self):
|
||||
with self.assertRaises(sqlite.OperationalError):
|
||||
self.con.create_function("bla", -100, AggrSum)
|
||||
|
||||
def CheckAggrNoStep(self):
|
||||
cur = self.con.cursor()
|
||||
with self.assertRaises(AttributeError) as cm:
|
||||
cur.execute("select nostep(t) from test")
|
||||
self.assertEqual(str(cm.exception), "'AggrNoStep' object has no attribute 'step'")
|
||||
|
||||
def CheckAggrNoFinalize(self):
|
||||
cur = self.con.cursor()
|
||||
with self.assertRaises(sqlite.OperationalError) as cm:
|
||||
cur.execute("select nofinalize(t) from test")
|
||||
val = cur.fetchone()[0]
|
||||
self.assertEqual(str(cm.exception), "user-defined aggregate's 'finalize' method raised error")
|
||||
|
||||
def CheckAggrExceptionInInit(self):
|
||||
cur = self.con.cursor()
|
||||
with self.assertRaises(sqlite.OperationalError) as cm:
|
||||
cur.execute("select excInit(t) from test")
|
||||
val = cur.fetchone()[0]
|
||||
self.assertEqual(str(cm.exception), "user-defined aggregate's '__init__' method raised error")
|
||||
|
||||
def CheckAggrExceptionInStep(self):
|
||||
cur = self.con.cursor()
|
||||
with self.assertRaises(sqlite.OperationalError) as cm:
|
||||
cur.execute("select excStep(t) from test")
|
||||
val = cur.fetchone()[0]
|
||||
self.assertEqual(str(cm.exception), "user-defined aggregate's 'step' method raised error")
|
||||
|
||||
def CheckAggrExceptionInFinalize(self):
|
||||
cur = self.con.cursor()
|
||||
with self.assertRaises(sqlite.OperationalError) as cm:
|
||||
cur.execute("select excFinalize(t) from test")
|
||||
val = cur.fetchone()[0]
|
||||
self.assertEqual(str(cm.exception), "user-defined aggregate's 'finalize' method raised error")
|
||||
|
||||
def CheckAggrCheckParamStr(self):
|
||||
cur = self.con.cursor()
|
||||
cur.execute("select checkTypes('str', ?, ?)", ("foo", str()))
|
||||
val = cur.fetchone()[0]
|
||||
self.assertEqual(val, 2)
|
||||
|
||||
def CheckAggrCheckParamInt(self):
|
||||
cur = self.con.cursor()
|
||||
cur.execute("select checkType('int', ?)", (42,))
|
||||
val = cur.fetchone()[0]
|
||||
self.assertEqual(val, 1)
|
||||
|
||||
def CheckAggrCheckParamsInt(self):
|
||||
cur = self.con.cursor()
|
||||
cur.execute("select checkTypes('int', ?, ?)", (42, 24))
|
||||
val = cur.fetchone()[0]
|
||||
self.assertEqual(val, 2)
|
||||
|
||||
def CheckAggrCheckParamFloat(self):
|
||||
cur = self.con.cursor()
|
||||
cur.execute("select checkType('float', ?)", (3.14,))
|
||||
val = cur.fetchone()[0]
|
||||
self.assertEqual(val, 1)
|
||||
|
||||
def CheckAggrCheckParamNone(self):
|
||||
cur = self.con.cursor()
|
||||
cur.execute("select checkType('None', ?)", (None,))
|
||||
val = cur.fetchone()[0]
|
||||
self.assertEqual(val, 1)
|
||||
|
||||
def CheckAggrCheckParamBlob(self):
|
||||
cur = self.con.cursor()
|
||||
cur.execute("select checkType('blob', ?)", (memoryview(b"blob"),))
|
||||
val = cur.fetchone()[0]
|
||||
self.assertEqual(val, 1)
|
||||
|
||||
def CheckAggrCheckAggrSum(self):
|
||||
cur = self.con.cursor()
|
||||
cur.execute("delete from test")
|
||||
cur.executemany("insert into test(i) values (?)", [(10,), (20,), (30,)])
|
||||
cur.execute("select mysum(i) from test")
|
||||
val = cur.fetchone()[0]
|
||||
self.assertEqual(val, 60)
|
||||
|
||||
def CheckAggrText(self):
|
||||
cur = self.con.cursor()
|
||||
for txt in ["foo", "1\x002"]:
|
||||
with self.subTest(txt=txt):
|
||||
cur.execute("select aggtxt(?) from test", (txt,))
|
||||
val = cur.fetchone()[0]
|
||||
self.assertEqual(val, txt)
|
||||
|
||||
|
||||
class AuthorizerTests(unittest.TestCase):
|
||||
@staticmethod
|
||||
def authorizer_cb(action, arg1, arg2, dbname, source):
|
||||
if action != sqlite.SQLITE_SELECT:
|
||||
return sqlite.SQLITE_DENY
|
||||
if arg2 == 'c2' or arg1 == 't2':
|
||||
return sqlite.SQLITE_DENY
|
||||
return sqlite.SQLITE_OK
|
||||
|
||||
def setUp(self):
|
||||
self.con = sqlite.connect(":memory:")
|
||||
self.con.executescript("""
|
||||
create table t1 (c1, c2);
|
||||
create table t2 (c1, c2);
|
||||
insert into t1 (c1, c2) values (1, 2);
|
||||
insert into t2 (c1, c2) values (4, 5);
|
||||
""")
|
||||
|
||||
# For our security test:
|
||||
self.con.execute("select c2 from t2")
|
||||
|
||||
self.con.set_authorizer(self.authorizer_cb)
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
def test_table_access(self):
|
||||
with self.assertRaises(sqlite.DatabaseError) as cm:
|
||||
self.con.execute("select * from t2")
|
||||
self.assertIn('prohibited', str(cm.exception))
|
||||
|
||||
def test_column_access(self):
|
||||
with self.assertRaises(sqlite.DatabaseError) as cm:
|
||||
self.con.execute("select c2 from t1")
|
||||
self.assertIn('prohibited', str(cm.exception))
|
||||
|
||||
class AuthorizerRaiseExceptionTests(AuthorizerTests):
|
||||
@staticmethod
|
||||
def authorizer_cb(action, arg1, arg2, dbname, source):
|
||||
if action != sqlite.SQLITE_SELECT:
|
||||
raise ValueError
|
||||
if arg2 == 'c2' or arg1 == 't2':
|
||||
raise ValueError
|
||||
return sqlite.SQLITE_OK
|
||||
|
||||
class AuthorizerIllegalTypeTests(AuthorizerTests):
|
||||
@staticmethod
|
||||
def authorizer_cb(action, arg1, arg2, dbname, source):
|
||||
if action != sqlite.SQLITE_SELECT:
|
||||
return 0.0
|
||||
if arg2 == 'c2' or arg1 == 't2':
|
||||
return 0.0
|
||||
return sqlite.SQLITE_OK
|
||||
|
||||
class AuthorizerLargeIntegerTests(AuthorizerTests):
|
||||
@staticmethod
|
||||
def authorizer_cb(action, arg1, arg2, dbname, source):
|
||||
if action != sqlite.SQLITE_SELECT:
|
||||
return 2**32
|
||||
if arg2 == 'c2' or arg1 == 't2':
|
||||
return 2**32
|
||||
return sqlite.SQLITE_OK
|
||||
|
||||
|
||||
def suite():
|
||||
function_suite = unittest.makeSuite(FunctionTests, "Check")
|
||||
aggregate_suite = unittest.makeSuite(AggregateTests, "Check")
|
||||
authorizer_suite = unittest.makeSuite(AuthorizerTests)
|
||||
return unittest.TestSuite((
|
||||
function_suite,
|
||||
aggregate_suite,
|
||||
authorizer_suite,
|
||||
unittest.makeSuite(AuthorizerRaiseExceptionTests),
|
||||
unittest.makeSuite(AuthorizerIllegalTypeTests),
|
||||
unittest.makeSuite(AuthorizerLargeIntegerTests),
|
||||
))
|
||||
|
||||
def test():
|
||||
runner = unittest.TextTestRunner()
|
||||
runner.run(suite())
|
||||
|
||||
if __name__ == "__main__":
|
||||
test()
|
||||
Reference in New Issue
Block a user