Skip to content

Commit 6849acb

Browse files
gh-105875: Require SQLite 3.15.2 or newer (#105876)
SQLite 3.15.2 was released 2016-11-28.
1 parent bc07c8f commit 6849acb

File tree

13 files changed

+61
-202
lines changed

13 files changed

+61
-202
lines changed

Doc/library/sqlite3.rst

+1-4
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ PostgreSQL or Oracle.
2929

3030
The :mod:`!sqlite3` module was written by Gerhard Häring. It provides an SQL interface
3131
compliant with the DB-API 2.0 specification described by :pep:`249`, and
32-
requires SQLite 3.7.15 or newer.
32+
requires SQLite 3.15.2 or newer.
3333

3434
This document includes four main sections:
3535

@@ -734,9 +734,6 @@ Connection objects
734734
`deterministic <https://sqlite.org/deterministic.html>`_,
735735
which allows SQLite to perform additional optimizations.
736736

737-
:raises NotSupportedError:
738-
If *deterministic* is used with SQLite versions older than 3.8.3.
739-
740737
.. versionadded:: 3.8
741738
The *deterministic* parameter.
742739

Doc/whatsnew/3.13.rst

+3
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,9 @@ Build Changes
410410
:file:`!configure`.
411411
(Contributed by Christian Heimes in :gh:`89886`.)
412412

413+
* SQLite 3.15.2 or newer is required to build the :mod:`sqlite3` extension module.
414+
(Contributed by Erlend Aasland in :gh:`105875`.)
415+
413416

414417
C API Changes
415418
=============

Lib/test/test_sqlite3/test_backup.py

-2
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,6 @@ def test_bad_target_in_transaction(self):
5050
bck.executemany('INSERT INTO bar (key) VALUES (?)', [(3,), (4,)])
5151
with self.assertRaises(sqlite.OperationalError) as cm:
5252
self.cx.backup(bck)
53-
if sqlite.sqlite_version_info < (3, 8, 8):
54-
self.assertEqual(str(cm.exception), 'target is in transaction')
5553

5654
def test_keyword_only_args(self):
5755
with self.assertRaises(TypeError):

Lib/test/test_sqlite3/test_dbapi.py

+28-47
Original file line numberDiff line numberDiff line change
@@ -165,20 +165,23 @@ def test_module_constants(self):
165165
"SQLITE_INTERNAL",
166166
"SQLITE_INTERRUPT",
167167
"SQLITE_IOERR",
168+
"SQLITE_LIMIT_WORKER_THREADS",
168169
"SQLITE_LOCKED",
169170
"SQLITE_MISMATCH",
170171
"SQLITE_MISUSE",
171172
"SQLITE_NOLFS",
172173
"SQLITE_NOMEM",
173174
"SQLITE_NOTADB",
174175
"SQLITE_NOTFOUND",
176+
"SQLITE_NOTICE",
175177
"SQLITE_OK",
176178
"SQLITE_PERM",
177179
"SQLITE_PRAGMA",
178180
"SQLITE_PROTOCOL",
179181
"SQLITE_RANGE",
180182
"SQLITE_READ",
181183
"SQLITE_READONLY",
184+
"SQLITE_RECURSIVE",
182185
"SQLITE_REINDEX",
183186
"SQLITE_ROW",
184187
"SQLITE_SAVEPOINT",
@@ -187,6 +190,7 @@ def test_module_constants(self):
187190
"SQLITE_TOOBIG",
188191
"SQLITE_TRANSACTION",
189192
"SQLITE_UPDATE",
193+
"SQLITE_WARNING",
190194
# Run-time limit categories
191195
"SQLITE_LIMIT_LENGTH",
192196
"SQLITE_LIMIT_SQL_LENGTH",
@@ -200,32 +204,43 @@ def test_module_constants(self):
200204
"SQLITE_LIMIT_VARIABLE_NUMBER",
201205
"SQLITE_LIMIT_TRIGGER_DEPTH",
202206
]
203-
if sqlite.sqlite_version_info >= (3, 7, 17):
204-
consts += ["SQLITE_NOTICE", "SQLITE_WARNING"]
205-
if sqlite.sqlite_version_info >= (3, 8, 3):
206-
consts.append("SQLITE_RECURSIVE")
207-
if sqlite.sqlite_version_info >= (3, 8, 7):
208-
consts.append("SQLITE_LIMIT_WORKER_THREADS")
209207
consts += ["PARSE_DECLTYPES", "PARSE_COLNAMES"]
210208
# Extended result codes
211209
consts += [
212210
"SQLITE_ABORT_ROLLBACK",
211+
"SQLITE_AUTH_USER",
213212
"SQLITE_BUSY_RECOVERY",
213+
"SQLITE_BUSY_SNAPSHOT",
214+
"SQLITE_CANTOPEN_CONVPATH",
214215
"SQLITE_CANTOPEN_FULLPATH",
215216
"SQLITE_CANTOPEN_ISDIR",
216217
"SQLITE_CANTOPEN_NOTEMPDIR",
218+
"SQLITE_CONSTRAINT_CHECK",
219+
"SQLITE_CONSTRAINT_COMMITHOOK",
220+
"SQLITE_CONSTRAINT_FOREIGNKEY",
221+
"SQLITE_CONSTRAINT_FUNCTION",
222+
"SQLITE_CONSTRAINT_NOTNULL",
223+
"SQLITE_CONSTRAINT_PRIMARYKEY",
224+
"SQLITE_CONSTRAINT_ROWID",
225+
"SQLITE_CONSTRAINT_TRIGGER",
226+
"SQLITE_CONSTRAINT_UNIQUE",
227+
"SQLITE_CONSTRAINT_VTAB",
217228
"SQLITE_CORRUPT_VTAB",
218229
"SQLITE_IOERR_ACCESS",
230+
"SQLITE_IOERR_AUTH",
219231
"SQLITE_IOERR_BLOCKED",
220232
"SQLITE_IOERR_CHECKRESERVEDLOCK",
221233
"SQLITE_IOERR_CLOSE",
234+
"SQLITE_IOERR_CONVPATH",
222235
"SQLITE_IOERR_DELETE",
223236
"SQLITE_IOERR_DELETE_NOENT",
224237
"SQLITE_IOERR_DIR_CLOSE",
225238
"SQLITE_IOERR_DIR_FSYNC",
226239
"SQLITE_IOERR_FSTAT",
227240
"SQLITE_IOERR_FSYNC",
241+
"SQLITE_IOERR_GETTEMPPATH",
228242
"SQLITE_IOERR_LOCK",
243+
"SQLITE_IOERR_MMAP",
229244
"SQLITE_IOERR_NOMEM",
230245
"SQLITE_IOERR_RDLOCK",
231246
"SQLITE_IOERR_READ",
@@ -237,50 +252,18 @@ def test_module_constants(self):
237252
"SQLITE_IOERR_SHORT_READ",
238253
"SQLITE_IOERR_TRUNCATE",
239254
"SQLITE_IOERR_UNLOCK",
255+
"SQLITE_IOERR_VNODE",
240256
"SQLITE_IOERR_WRITE",
241257
"SQLITE_LOCKED_SHAREDCACHE",
258+
"SQLITE_NOTICE_RECOVER_ROLLBACK",
259+
"SQLITE_NOTICE_RECOVER_WAL",
260+
"SQLITE_OK_LOAD_PERMANENTLY",
242261
"SQLITE_READONLY_CANTLOCK",
262+
"SQLITE_READONLY_DBMOVED",
243263
"SQLITE_READONLY_RECOVERY",
264+
"SQLITE_READONLY_ROLLBACK",
265+
"SQLITE_WARNING_AUTOINDEX",
244266
]
245-
if sqlite.sqlite_version_info >= (3, 7, 16):
246-
consts += [
247-
"SQLITE_CONSTRAINT_CHECK",
248-
"SQLITE_CONSTRAINT_COMMITHOOK",
249-
"SQLITE_CONSTRAINT_FOREIGNKEY",
250-
"SQLITE_CONSTRAINT_FUNCTION",
251-
"SQLITE_CONSTRAINT_NOTNULL",
252-
"SQLITE_CONSTRAINT_PRIMARYKEY",
253-
"SQLITE_CONSTRAINT_TRIGGER",
254-
"SQLITE_CONSTRAINT_UNIQUE",
255-
"SQLITE_CONSTRAINT_VTAB",
256-
"SQLITE_READONLY_ROLLBACK",
257-
]
258-
if sqlite.sqlite_version_info >= (3, 7, 17):
259-
consts += [
260-
"SQLITE_IOERR_MMAP",
261-
"SQLITE_NOTICE_RECOVER_ROLLBACK",
262-
"SQLITE_NOTICE_RECOVER_WAL",
263-
]
264-
if sqlite.sqlite_version_info >= (3, 8, 0):
265-
consts += [
266-
"SQLITE_BUSY_SNAPSHOT",
267-
"SQLITE_IOERR_GETTEMPPATH",
268-
"SQLITE_WARNING_AUTOINDEX",
269-
]
270-
if sqlite.sqlite_version_info >= (3, 8, 1):
271-
consts += ["SQLITE_CANTOPEN_CONVPATH", "SQLITE_IOERR_CONVPATH"]
272-
if sqlite.sqlite_version_info >= (3, 8, 2):
273-
consts.append("SQLITE_CONSTRAINT_ROWID")
274-
if sqlite.sqlite_version_info >= (3, 8, 3):
275-
consts.append("SQLITE_READONLY_DBMOVED")
276-
if sqlite.sqlite_version_info >= (3, 8, 7):
277-
consts.append("SQLITE_AUTH_USER")
278-
if sqlite.sqlite_version_info >= (3, 9, 0):
279-
consts.append("SQLITE_IOERR_VNODE")
280-
if sqlite.sqlite_version_info >= (3, 10, 0):
281-
consts.append("SQLITE_IOERR_AUTH")
282-
if sqlite.sqlite_version_info >= (3, 14, 1):
283-
consts.append("SQLITE_OK_LOAD_PERMANENTLY")
284267
if sqlite.sqlite_version_info >= (3, 21, 0):
285268
consts += [
286269
"SQLITE_IOERR_BEGIN_ATOMIC",
@@ -330,8 +313,6 @@ def test_error_code_on_exception(self):
330313
self.assertEqual(e.sqlite_errorcode, err_code)
331314
self.assertTrue(e.sqlite_errorname.startswith("SQLITE_CANTOPEN"))
332315

333-
@unittest.skipIf(sqlite.sqlite_version_info <= (3, 7, 16),
334-
"Requires SQLite 3.7.16 or newer")
335316
def test_extended_error_code_on_exception(self):
336317
with memory_database() as con:
337318
with con:

Lib/test/test_sqlite3/test_hooks.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ def test_trace_expanded_sql(self):
323323
)
324324
def test_trace_too_much_expanded_sql(self):
325325
# If the expanded string is too large, we'll fall back to the
326-
# unexpanded SQL statement (for SQLite 3.14.0 and newer).
326+
# unexpanded SQL statement.
327327
# The resulting string length is limited by the runtime limit
328328
# SQLITE_LIMIT_LENGTH.
329329
template = "select 1 as a where a="
@@ -334,8 +334,6 @@ def test_trace_too_much_expanded_sql(self):
334334

335335
unexpanded_query = template + "?"
336336
expected = [unexpanded_query]
337-
if sqlite.sqlite_version_info < (3, 14, 0):
338-
expected = []
339337
with self.check_stmt_trace(cx, expected):
340338
cx.execute(unexpanded_query, (bad_param,))
341339

Lib/test/test_sqlite3/test_types.py

-1
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,6 @@ def test_cursor_description_insert(self):
371371
self.assertIsNone(self.cur.description)
372372

373373

374-
@unittest.skipIf(sqlite.sqlite_version_info < (3, 8, 3), "CTEs not supported")
375374
class CommonTableExpressionTests(unittest.TestCase):
376375

377376
def setUp(self):

Lib/test/test_sqlite3/test_userfunctions.py

+9-25
Original file line numberDiff line numberDiff line change
@@ -381,38 +381,22 @@ def append_result(arg):
381381
# Regarding deterministic functions:
382382
#
383383
# Between 3.8.3 and 3.15.0, deterministic functions were only used to
384-
# optimize inner loops, so for those versions we can only test if the
385-
# sqlite machinery has factored out a call or not. From 3.15.0 and onward,
386-
# deterministic functions were permitted in WHERE clauses of partial
387-
# indices, which allows testing based on syntax, iso. the query optimizer.
388-
@unittest.skipIf(sqlite.sqlite_version_info < (3, 8, 3), "Requires SQLite 3.8.3 or higher")
384+
# optimize inner loops. From 3.15.0 and onward, deterministic functions
385+
# were permitted in WHERE clauses of partial indices, which allows testing
386+
# based on syntax, iso. the query optimizer.
389387
def test_func_non_deterministic(self):
390388
mock = Mock(return_value=None)
391389
self.con.create_function("nondeterministic", 0, mock, deterministic=False)
392-
if sqlite.sqlite_version_info < (3, 15, 0):
393-
self.con.execute("select nondeterministic() = nondeterministic()")
394-
self.assertEqual(mock.call_count, 2)
395-
else:
396-
with self.assertRaises(sqlite.OperationalError):
397-
self.con.execute("create index t on test(t) where nondeterministic() is not null")
390+
with self.assertRaises(sqlite.OperationalError):
391+
self.con.execute("create index t on test(t) where nondeterministic() is not null")
398392

399-
@unittest.skipIf(sqlite.sqlite_version_info < (3, 8, 3), "Requires SQLite 3.8.3 or higher")
400393
def test_func_deterministic(self):
401394
mock = Mock(return_value=None)
402395
self.con.create_function("deterministic", 0, mock, deterministic=True)
403-
if sqlite.sqlite_version_info < (3, 15, 0):
404-
self.con.execute("select deterministic() = deterministic()")
405-
self.assertEqual(mock.call_count, 1)
406-
else:
407-
try:
408-
self.con.execute("create index t on test(t) where deterministic() is not null")
409-
except sqlite.OperationalError:
410-
self.fail("Unexpected failure while creating partial index")
411-
412-
@unittest.skipIf(sqlite.sqlite_version_info >= (3, 8, 3), "SQLite < 3.8.3 needed")
413-
def test_func_deterministic_not_supported(self):
414-
with self.assertRaises(sqlite.NotSupportedError):
415-
self.con.create_function("deterministic", 0, int, deterministic=True)
396+
try:
397+
self.con.execute("create index t on test(t) where deterministic() is not null")
398+
except sqlite.OperationalError:
399+
self.fail("Unexpected failure while creating partial index")
416400

417401
def test_func_deterministic_keyword_only(self):
418402
with self.assertRaises(TypeError):
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
SQLite 3.15.2 or newer is required to build the :mod:`sqlite3` extension
2+
module. Patch by Erlend Aasland.

Modules/_sqlite/blob.c

-8
Original file line numberDiff line numberDiff line change
@@ -108,14 +108,6 @@ static void
108108
blob_seterror(pysqlite_Blob *self, int rc)
109109
{
110110
assert(self->connection != NULL);
111-
#if SQLITE_VERSION_NUMBER < 3008008
112-
// SQLite pre 3.8.8 does not set this blob error on the connection
113-
if (rc == SQLITE_ABORT) {
114-
PyErr_SetString(self->connection->OperationalError,
115-
"Cannot operate on an expired blob handle");
116-
return;
117-
}
118-
#endif
119111
_pysqlite_seterror(self->connection->state, self->connection->db);
120112
}
121113

0 commit comments

Comments
 (0)