Skip to content

Commit 22fb16b

Browse files
author
Erlend E. Aasland
committed
Require SQLite 3.7.3
Remove code required to to support SQLite pre 3.7.3. Integrate setup.py, docs and unit test changes from PR #17413 Style changes not related to bpo-40744 were dropped from the merge. Berker Peksag's suggested documentation changes was included. See #17413 Co-written-by: Berker Peksag <[email protected]> Co-written-by: Sergey Fedoseev <[email protected]>
1 parent 426f2b4 commit 22fb16b

File tree

12 files changed

+27
-94
lines changed

12 files changed

+27
-94
lines changed

Doc/library/sqlite3.rst

+2-6
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ application using SQLite and then port the code to a larger database such as
1818
PostgreSQL or Oracle.
1919

2020
The sqlite3 module was written by Gerhard Häring. It provides a SQL interface
21-
compliant with the DB-API 2.0 specification described by :pep:`249`.
21+
compliant with the DB-API 2.0 specification described by :pep:`249`, and
22+
requires SQLite 3.7.3 or newer.
2223

2324
To use the module, you must first create a :class:`Connection` object that
2425
represents the database. Here the data will be stored in the
@@ -591,8 +592,6 @@ Connection Objects
591592
dest = sqlite3.connect(':memory:')
592593
source.backup(dest)
593594

594-
Availability: SQLite 3.6.11 or higher
595-
596595
.. versionadded:: 3.7
597596

598597

@@ -701,9 +700,6 @@ Cursor Objects
701700
statements because we cannot determine the number of rows a query produced
702701
until all rows were fetched.
703702

704-
With SQLite versions before 3.6.5, :attr:`rowcount` is set to 0 if
705-
you make a ``DELETE FROM table`` without any condition.
706-
707703
.. attribute:: lastrowid
708704

709705
This read-only attribute provides the rowid of the last modified row. It is

Doc/whatsnew/3.10.rst

+5
Original file line numberDiff line numberDiff line change
@@ -191,10 +191,15 @@ that may require changes to your code.
191191
Build Changes
192192
=============
193193

194+
194195
* The C99 functions :c:func:`snprintf` and :c:func:`vsnprintf` are now required
195196
to build Python.
196197
(Contributed by Victor Stinner in :issue:`36020`.)
197198

199+
* :mod:`sqlite3` requires SQLite 3.7.3 or higher.
200+
(Contributed by Sergey Fedoseev and Erlend E. Aasland :issue:`40744`.)
201+
202+
198203

199204
C API Changes
200205
=============

Lib/sqlite3/test/backup.py

-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
import unittest
33

44

5-
@unittest.skipIf(sqlite.sqlite_version_info < (3, 6, 11), "Backup API not supported")
65
class BackupTests(unittest.TestCase):
76
def setUp(self):
87
cx = self.cx = sqlite.connect(":memory:")

Lib/sqlite3/test/dbapi.py

-6
Original file line numberDiff line numberDiff line change
@@ -185,12 +185,6 @@ def CheckOpenUri(self):
185185
with self.assertRaises(sqlite.OperationalError):
186186
cx.execute('insert into test(id) values(1)')
187187

188-
@unittest.skipIf(sqlite.sqlite_version_info >= (3, 3, 1),
189-
'needs sqlite versions older than 3.3.1')
190-
def CheckSameThreadErrorOnOldVersion(self):
191-
with self.assertRaises(sqlite.NotSupportedError) as cm:
192-
sqlite.connect(':memory:', check_same_thread=False)
193-
self.assertEqual(str(cm.exception), 'shared connections not available')
194188

195189
class CursorTests(unittest.TestCase):
196190
def setUp(self):

Lib/sqlite3/test/hooks.py

-6
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,6 @@ def upper(self):
6161
self.assertEqual(result[0][0], 'b')
6262
self.assertEqual(result[1][0], 'a')
6363

64-
@unittest.skipIf(sqlite.sqlite_version_info < (3, 2, 1),
65-
'old SQLite versions crash on this test')
6664
def CheckCollationIsUsed(self):
6765
def mycoll(x, y):
6866
# reverse order
@@ -240,16 +238,12 @@ def trace(statement):
240238
traced_statements.append(statement)
241239
con.set_trace_callback(trace)
242240
con.execute("create table foo(x)")
243-
# Can't execute bound parameters as their values don't appear
244-
# in traced statements before SQLite 3.6.21
245-
# (cf. http://www.sqlite.org/draft/releaselog/3_6_21.html)
246241
con.execute('insert into foo(x) values ("%s")' % unicode_value)
247242
con.commit()
248243
self.assertTrue(any(unicode_value in stmt for stmt in traced_statements),
249244
"Unicode data %s garbled in trace callback: %s"
250245
% (ascii(unicode_value), ', '.join(map(ascii, traced_statements))))
251246

252-
@unittest.skipIf(sqlite.sqlite_version_info < (3, 3, 9), "sqlite3_prepare_v2 is not available")
253247
def CheckTraceCallbackContent(self):
254248
# set_trace_callback() shouldn't produce duplicate content (bpo-26187)
255249
traced_statements = []

Lib/sqlite3/test/regression.py

-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,6 @@ def CheckStatementFinalizationOnCloseDb(self):
8787
cur.execute("select 1 x union select " + str(i))
8888
con.close()
8989

90-
@unittest.skipIf(sqlite.sqlite_version_info < (3, 2, 2), 'needs sqlite 3.2.2 or newer')
9190
def CheckOnConflictRollback(self):
9291
con = sqlite.connect(":memory:")
9392
con.execute("create table foo(x, unique(x) on conflict rollback)")

Lib/sqlite3/test/transactions.py

-4
Original file line numberDiff line numberDiff line change
@@ -111,16 +111,12 @@ def CheckToggleAutoCommit(self):
111111
res = self.cur2.fetchall()
112112
self.assertEqual(len(res), 1)
113113

114-
@unittest.skipIf(sqlite.sqlite_version_info < (3, 2, 2),
115-
'test hangs on sqlite versions older than 3.2.2')
116114
def CheckRaiseTimeout(self):
117115
self.cur1.execute("create table test(i)")
118116
self.cur1.execute("insert into test(i) values (5)")
119117
with self.assertRaises(sqlite.OperationalError):
120118
self.cur2.execute("insert into test(i) values (5)")
121119

122-
@unittest.skipIf(sqlite.sqlite_version_info < (3, 2, 2),
123-
'test hangs on sqlite versions older than 3.2.2')
124120
def CheckLocking(self):
125121
"""
126122
This tests the improved concurrency with pysqlite 2.3.4. You needed

Lib/sqlite3/test/types.py

-2
Original file line numberDiff line numberDiff line change
@@ -401,8 +401,6 @@ def CheckSqliteTimestamp(self):
401401
ts2 = self.cur.fetchone()[0]
402402
self.assertEqual(ts, ts2)
403403

404-
@unittest.skipIf(sqlite.sqlite_version_info < (3, 1),
405-
'the date functions are available on 3.1 or later')
406404
def CheckSqlTimestamp(self):
407405
now = datetime.datetime.utcnow()
408406
self.cur.execute("insert into test(ts) values (current_timestamp)")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Drop support for SQLite3 pre v3.7.3. Patch by Sergey Fedoseev and Erlend E.
2+
Aasland.

Modules/_sqlite/connection.c

+9-48
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,6 @@
3333
#define ACTION_FINALIZE 1
3434
#define ACTION_RESET 2
3535

36-
#if SQLITE_VERSION_NUMBER >= 3003008
37-
#ifndef SQLITE_OMIT_LOAD_EXTENSION
38-
#define HAVE_LOAD_EXTENSION
39-
#endif
40-
#endif
41-
42-
#if SQLITE_VERSION_NUMBER >= 3006011
43-
#define HAVE_BACKUP_API
44-
#endif
45-
4636
#if SQLITE_VERSION_NUMBER >= 3014000
4737
#define HAVE_TRACE_V2
4838
#endif
@@ -61,18 +51,6 @@ static int pysqlite_connection_set_isolation_level(pysqlite_Connection* self, Py
6151
static void _pysqlite_drop_unused_cursor_references(pysqlite_Connection* self);
6252

6353

64-
static void _sqlite3_result_error(sqlite3_context* ctx, const char* errmsg, int len)
65-
{
66-
/* in older SQLite versions, calling sqlite3_result_error in callbacks
67-
* triggers a bug in SQLite that leads either to irritating results or
68-
* segfaults, depending on the SQLite version */
69-
#if SQLITE_VERSION_NUMBER >= 3003003
70-
sqlite3_result_error(ctx, errmsg, len);
71-
#else
72-
PyErr_SetString(pysqlite_OperationalError, errmsg);
73-
#endif
74-
}
75-
7654
int pysqlite_connection_init(pysqlite_Connection* self, PyObject* args, PyObject* kwargs)
7755
{
7856
static char *kwlist[] = {
@@ -182,10 +160,6 @@ int pysqlite_connection_init(pysqlite_Connection* self, PyObject* args, PyObject
182160
self->timeout = timeout;
183161
(void)sqlite3_busy_timeout(self->db, (int)(timeout*1000));
184162
self->thread_ident = PyThread_get_thread_ident();
185-
if (!check_same_thread && sqlite3_libversion_number() < 3003001) {
186-
PyErr_SetString(pysqlite_NotSupportedError, "shared connections not available");
187-
return -1;
188-
}
189163
self->check_same_thread = check_same_thread;
190164

191165
self->function_pinboard_trace_callback = NULL;
@@ -620,7 +594,7 @@ void _pysqlite_func_callback(sqlite3_context* context, int argc, sqlite3_value**
620594
} else {
621595
PyErr_Clear();
622596
}
623-
_sqlite3_result_error(context, "user-defined function raised exception", -1);
597+
sqlite3_result_error(context, "user-defined function raised exception", -1);
624598
}
625599

626600
PyGILState_Release(threadstate);
@@ -652,7 +626,7 @@ static void _pysqlite_step_callback(sqlite3_context *context, int argc, sqlite3_
652626
} else {
653627
PyErr_Clear();
654628
}
655-
_sqlite3_result_error(context, "user-defined aggregate's '__init__' method raised error", -1);
629+
sqlite3_result_error(context, "user-defined aggregate's '__init__' method raised error", -1);
656630
goto error;
657631
}
658632
}
@@ -676,7 +650,7 @@ static void _pysqlite_step_callback(sqlite3_context *context, int argc, sqlite3_
676650
} else {
677651
PyErr_Clear();
678652
}
679-
_sqlite3_result_error(context, "user-defined aggregate's 'step' method raised error", -1);
653+
sqlite3_result_error(context, "user-defined aggregate's 'step' method raised error", -1);
680654
}
681655

682656
error:
@@ -693,7 +667,6 @@ void _pysqlite_final_callback(sqlite3_context* context)
693667
_Py_IDENTIFIER(finalize);
694668
int ok;
695669
PyObject *exception, *value, *tb;
696-
int restore;
697670

698671
PyGILState_STATE threadstate;
699672

@@ -709,7 +682,6 @@ void _pysqlite_final_callback(sqlite3_context* context)
709682

710683
/* Keep the exception (if any) of the last call to step() */
711684
PyErr_Fetch(&exception, &value, &tb);
712-
restore = 1;
713685

714686
function_result = _PyObject_CallMethodIdNoArgs(*aggregate_instance, &PyId_finalize);
715687

@@ -726,19 +698,12 @@ void _pysqlite_final_callback(sqlite3_context* context)
726698
} else {
727699
PyErr_Clear();
728700
}
729-
_sqlite3_result_error(context, "user-defined aggregate's 'finalize' method raised error", -1);
730-
#if SQLITE_VERSION_NUMBER < 3003003
731-
/* with old SQLite versions, _sqlite3_result_error() sets a new Python
732-
exception, so don't restore the previous exception */
733-
restore = 0;
734-
#endif
701+
sqlite3_result_error(context, "user-defined aggregate's 'finalize' method raised error", -1);
735702
}
736703

737-
if (restore) {
738-
/* Restore the exception (if any) of the last call to step(),
739-
but clear also the current exception if finalize() failed */
740-
PyErr_Restore(exception, value, tb);
741-
}
704+
/* Restore the exception (if any) of the last call to step(),
705+
but clear also the current exception if finalize() failed */
706+
PyErr_Restore(exception, value, tb);
742707

743708
error:
744709
PyGILState_Release(threadstate);
@@ -1110,7 +1075,7 @@ static PyObject* pysqlite_connection_set_trace_callback(pysqlite_Connection* sel
11101075
Py_RETURN_NONE;
11111076
}
11121077

1113-
#ifdef HAVE_LOAD_EXTENSION
1078+
#ifndef SQLITE_OMIT_LOAD_EXTENSION
11141079
static PyObject* pysqlite_enable_load_extension(pysqlite_Connection* self, PyObject* args)
11151080
{
11161081
int rc;
@@ -1513,7 +1478,6 @@ pysqlite_connection_iterdump(pysqlite_Connection* self, PyObject* args)
15131478
return retval;
15141479
}
15151480

1516-
#ifdef HAVE_BACKUP_API
15171481
static PyObject *
15181482
pysqlite_connection_backup(pysqlite_Connection *self, PyObject *args, PyObject *kwds)
15191483
{
@@ -1664,7 +1628,6 @@ pysqlite_connection_backup(pysqlite_Connection *self, PyObject *args, PyObject *
16641628
return NULL;
16651629
}
16661630
}
1667-
#endif
16681631

16691632
static PyObject *
16701633
pysqlite_connection_create_collation(pysqlite_Connection* self, PyObject* args)
@@ -1816,7 +1779,7 @@ static PyMethodDef connection_methods[] = {
18161779
PyDoc_STR("Creates a new aggregate. Non-standard.")},
18171780
{"set_authorizer", (PyCFunction)(void(*)(void))pysqlite_connection_set_authorizer, METH_VARARGS|METH_KEYWORDS,
18181781
PyDoc_STR("Sets authorizer callback. Non-standard.")},
1819-
#ifdef HAVE_LOAD_EXTENSION
1782+
#ifndef SQLITE_OMIT_LOAD_EXTENSION
18201783
{"enable_load_extension", (PyCFunction)pysqlite_enable_load_extension, METH_VARARGS,
18211784
PyDoc_STR("Enable dynamic loading of SQLite extension modules. Non-standard.")},
18221785
{"load_extension", (PyCFunction)pysqlite_load_extension, METH_VARARGS,
@@ -1838,10 +1801,8 @@ static PyMethodDef connection_methods[] = {
18381801
PyDoc_STR("Abort any pending database operation. Non-standard.")},
18391802
{"iterdump", (PyCFunction)pysqlite_connection_iterdump, METH_NOARGS,
18401803
PyDoc_STR("Returns iterator to the dump of the database in an SQL text format. Non-standard.")},
1841-
#ifdef HAVE_BACKUP_API
18421804
{"backup", (PyCFunction)(void(*)(void))pysqlite_connection_backup, METH_VARARGS | METH_KEYWORDS,
18431805
PyDoc_STR("Makes a backup of the database. Non-standard.")},
1844-
#endif
18451806
{"__enter__", (PyCFunction)pysqlite_connection_enter, METH_NOARGS,
18461807
PyDoc_STR("For context manager. Non-standard.")},
18471808
{"__exit__", (PyCFunction)pysqlite_connection_exit, METH_VARARGS,

Modules/_sqlite/module.c

+7-18
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@
2929
#include "microprotocols.h"
3030
#include "row.h"
3131

32-
#if SQLITE_VERSION_NUMBER >= 3003003
33-
#define HAVE_SHARED_CACHE
32+
#if SQLITE_VERSION_NUMBER < 3007003
33+
#error "SQLite 3.7.3 or higher required"
3434
#endif
3535

3636
/* static objects at module-level */
@@ -131,7 +131,6 @@ PyDoc_STRVAR(module_complete_doc,
131131
\n\
132132
Checks if a string contains a complete SQL statement. Non-standard.");
133133

134-
#ifdef HAVE_SHARED_CACHE
135134
static PyObject* module_enable_shared_cache(PyObject* self, PyObject* args, PyObject*
136135
kwargs)
137136
{
@@ -159,7 +158,6 @@ PyDoc_STRVAR(module_enable_shared_cache_doc,
159158
\n\
160159
Enable or disable shared cache mode for the calling thread.\n\
161160
Experimental/Non-standard.");
162-
#endif /* HAVE_SHARED_CACHE */
163161

164162
static PyObject* module_register_adapter(PyObject* self, PyObject* args)
165163
{
@@ -253,10 +251,8 @@ static PyMethodDef module_methods[] = {
253251
METH_VARARGS | METH_KEYWORDS, module_connect_doc},
254252
{"complete_statement", (PyCFunction)(void(*)(void))module_complete,
255253
METH_VARARGS | METH_KEYWORDS, module_complete_doc},
256-
#ifdef HAVE_SHARED_CACHE
257254
{"enable_shared_cache", (PyCFunction)(void(*)(void))module_enable_shared_cache,
258255
METH_VARARGS | METH_KEYWORDS, module_enable_shared_cache_doc},
259-
#endif
260256
{"register_adapter", (PyCFunction)module_register_adapter,
261257
METH_VARARGS, module_register_adapter_doc},
262258
{"register_converter", (PyCFunction)module_register_converter,
@@ -307,29 +303,17 @@ static const IntConstantPair _int_constants[] = {
307303
{"SQLITE_UPDATE", SQLITE_UPDATE},
308304
{"SQLITE_ATTACH", SQLITE_ATTACH},
309305
{"SQLITE_DETACH", SQLITE_DETACH},
310-
#if SQLITE_VERSION_NUMBER >= 3002001
311306
{"SQLITE_ALTER_TABLE", SQLITE_ALTER_TABLE},
312307
{"SQLITE_REINDEX", SQLITE_REINDEX},
313-
#endif
314-
#if SQLITE_VERSION_NUMBER >= 3003000
315308
{"SQLITE_ANALYZE", SQLITE_ANALYZE},
316-
#endif
317-
#if SQLITE_VERSION_NUMBER >= 3003007
318309
{"SQLITE_CREATE_VTABLE", SQLITE_CREATE_VTABLE},
319310
{"SQLITE_DROP_VTABLE", SQLITE_DROP_VTABLE},
320-
#endif
321-
#if SQLITE_VERSION_NUMBER >= 3003008
322311
{"SQLITE_FUNCTION", SQLITE_FUNCTION},
323-
#endif
324-
#if SQLITE_VERSION_NUMBER >= 3006008
325312
{"SQLITE_SAVEPOINT", SQLITE_SAVEPOINT},
326-
#endif
327313
#if SQLITE_VERSION_NUMBER >= 3008003
328314
{"SQLITE_RECURSIVE", SQLITE_RECURSIVE},
329315
#endif
330-
#if SQLITE_VERSION_NUMBER >= 3006011
331316
{"SQLITE_DONE", SQLITE_DONE},
332-
#endif
333317
{(char*)NULL, 0}
334318
};
335319

@@ -360,6 +344,11 @@ PyMODINIT_FUNC PyInit__sqlite3(void)
360344
PyObject *tmp_obj;
361345
int i;
362346

347+
if (sqlite3_libversion_number() < 3007003) {
348+
PyErr_SetString(PyExc_ImportError, MODULE_NAME ": SQLite 3.7.3 or higher required");
349+
return NULL;
350+
}
351+
363352
module = PyModule_Create(&_sqlite3module);
364353

365354
if (!module ||

setup.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1452,7 +1452,6 @@ def detect_sqlite(self):
14521452
sqlite_setup_debug = False # verbose debug prints from this script?
14531453

14541454
# We hunt for #define SQLITE_VERSION "n.n.n"
1455-
# We need to find >= sqlite version 3.3.9, for sqlite3_prepare_v2
14561455
sqlite_incdir = sqlite_libdir = None
14571456
sqlite_inc_paths = [ '/usr/include',
14581457
'/usr/include/sqlite',
@@ -1463,7 +1462,8 @@ def detect_sqlite(self):
14631462
]
14641463
if CROSS_COMPILING:
14651464
sqlite_inc_paths = []
1466-
MIN_SQLITE_VERSION_NUMBER = (3, 7, 2)
1465+
# We need to find >= sqlite version 3.7.3, for sqlite3_create_function_v2()
1466+
MIN_SQLITE_VERSION_NUMBER = (3, 7, 3)
14671467
MIN_SQLITE_VERSION = ".".join([str(x)
14681468
for x in MIN_SQLITE_VERSION_NUMBER])
14691469

0 commit comments

Comments
 (0)