Skip to content

Commit a53c9ef

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 4649202 commit a53c9ef

File tree

12 files changed

+25
-94
lines changed

12 files changed

+25
-94
lines changed

Doc/library/sqlite3.rst

Lines changed: 2 additions & 6 deletions
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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,9 @@ that may require changes to your code.
125125
Build Changes
126126
=============
127127

128+
* :mod:`sqlite3` requires SQLite 3.7.3 or higher. (Contributed by Sergey Fedoseev
129+
and Erlend E. Aasland :issue:`40744`.)
130+
128131

129132
C API Changes
130133
=============

Lib/sqlite3/test/backup.py

Lines changed: 0 additions & 1 deletion
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

Lines changed: 0 additions & 6 deletions
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

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,6 @@ def upper(self):
6060
self.assertEqual(result[0][0], 'b')
6161
self.assertEqual(result[1][0], 'a')
6262

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

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

Lib/sqlite3/test/regression.py

Lines changed: 0 additions & 1 deletion
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

Lines changed: 0 additions & 4 deletions
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

Lines changed: 0 additions & 2 deletions
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)")
Lines changed: 2 additions & 0 deletions
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

Lines changed: 9 additions & 48 deletions
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
_Py_IDENTIFIER(cursor);
4737

4838
static const char * const begin_statements[] = {
@@ -57,18 +47,6 @@ static int pysqlite_connection_set_isolation_level(pysqlite_Connection* self, Py
5747
static void _pysqlite_drop_unused_cursor_references(pysqlite_Connection* self);
5848

5949

60-
static void _sqlite3_result_error(sqlite3_context* ctx, const char* errmsg, int len)
61-
{
62-
/* in older SQLite versions, calling sqlite3_result_error in callbacks
63-
* triggers a bug in SQLite that leads either to irritating results or
64-
* segfaults, depending on the SQLite version */
65-
#if SQLITE_VERSION_NUMBER >= 3003003
66-
sqlite3_result_error(ctx, errmsg, len);
67-
#else
68-
PyErr_SetString(pysqlite_OperationalError, errmsg);
69-
#endif
70-
}
71-
7250
int pysqlite_connection_init(pysqlite_Connection* self, PyObject* args, PyObject* kwargs)
7351
{
7452
static char *kwlist[] = {
@@ -178,10 +156,6 @@ int pysqlite_connection_init(pysqlite_Connection* self, PyObject* args, PyObject
178156
self->timeout = timeout;
179157
(void)sqlite3_busy_timeout(self->db, (int)(timeout*1000));
180158
self->thread_ident = PyThread_get_thread_ident();
181-
if (!check_same_thread && sqlite3_libversion_number() < 3003001) {
182-
PyErr_SetString(pysqlite_NotSupportedError, "shared connections not available");
183-
return -1;
184-
}
185159
self->check_same_thread = check_same_thread;
186160

187161
self->function_pinboard_trace_callback = NULL;
@@ -616,7 +590,7 @@ void _pysqlite_func_callback(sqlite3_context* context, int argc, sqlite3_value**
616590
} else {
617591
PyErr_Clear();
618592
}
619-
_sqlite3_result_error(context, "user-defined function raised exception", -1);
593+
sqlite3_result_error(context, "user-defined function raised exception", -1);
620594
}
621595

622596
PyGILState_Release(threadstate);
@@ -648,7 +622,7 @@ static void _pysqlite_step_callback(sqlite3_context *context, int argc, sqlite3_
648622
} else {
649623
PyErr_Clear();
650624
}
651-
_sqlite3_result_error(context, "user-defined aggregate's '__init__' method raised error", -1);
625+
sqlite3_result_error(context, "user-defined aggregate's '__init__' method raised error", -1);
652626
goto error;
653627
}
654628
}
@@ -672,7 +646,7 @@ static void _pysqlite_step_callback(sqlite3_context *context, int argc, sqlite3_
672646
} else {
673647
PyErr_Clear();
674648
}
675-
_sqlite3_result_error(context, "user-defined aggregate's 'step' method raised error", -1);
649+
sqlite3_result_error(context, "user-defined aggregate's 'step' method raised error", -1);
676650
}
677651

678652
error:
@@ -689,7 +663,6 @@ void _pysqlite_final_callback(sqlite3_context* context)
689663
_Py_IDENTIFIER(finalize);
690664
int ok;
691665
PyObject *exception, *value, *tb;
692-
int restore;
693666

694667
PyGILState_STATE threadstate;
695668

@@ -705,7 +678,6 @@ void _pysqlite_final_callback(sqlite3_context* context)
705678

706679
/* Keep the exception (if any) of the last call to step() */
707680
PyErr_Fetch(&exception, &value, &tb);
708-
restore = 1;
709681

710682
function_result = _PyObject_CallMethodIdNoArgs(*aggregate_instance, &PyId_finalize);
711683

@@ -722,19 +694,12 @@ void _pysqlite_final_callback(sqlite3_context* context)
722694
} else {
723695
PyErr_Clear();
724696
}
725-
_sqlite3_result_error(context, "user-defined aggregate's 'finalize' method raised error", -1);
726-
#if SQLITE_VERSION_NUMBER < 3003003
727-
/* with old SQLite versions, _sqlite3_result_error() sets a new Python
728-
exception, so don't restore the previous exception */
729-
restore = 0;
730-
#endif
697+
sqlite3_result_error(context, "user-defined aggregate's 'finalize' method raised error", -1);
731698
}
732699

733-
if (restore) {
734-
/* Restore the exception (if any) of the last call to step(),
735-
but clear also the current exception if finalize() failed */
736-
PyErr_Restore(exception, value, tb);
737-
}
700+
/* Restore the exception (if any) of the last call to step(),
701+
but clear also the current exception if finalize() failed */
702+
PyErr_Restore(exception, value, tb);
738703

739704
error:
740705
PyGILState_Release(threadstate);
@@ -1074,7 +1039,7 @@ static PyObject* pysqlite_connection_set_trace_callback(pysqlite_Connection* sel
10741039
Py_RETURN_NONE;
10751040
}
10761041

1077-
#ifdef HAVE_LOAD_EXTENSION
1042+
#ifndef SQLITE_OMIT_LOAD_EXTENSION
10781043
static PyObject* pysqlite_enable_load_extension(pysqlite_Connection* self, PyObject* args)
10791044
{
10801045
int rc;
@@ -1477,7 +1442,6 @@ pysqlite_connection_iterdump(pysqlite_Connection* self, PyObject* args)
14771442
return retval;
14781443
}
14791444

1480-
#ifdef HAVE_BACKUP_API
14811445
static PyObject *
14821446
pysqlite_connection_backup(pysqlite_Connection *self, PyObject *args, PyObject *kwds)
14831447
{
@@ -1628,7 +1592,6 @@ pysqlite_connection_backup(pysqlite_Connection *self, PyObject *args, PyObject *
16281592
return NULL;
16291593
}
16301594
}
1631-
#endif
16321595

16331596
static PyObject *
16341597
pysqlite_connection_create_collation(pysqlite_Connection* self, PyObject* args)
@@ -1780,7 +1743,7 @@ static PyMethodDef connection_methods[] = {
17801743
PyDoc_STR("Creates a new aggregate. Non-standard.")},
17811744
{"set_authorizer", (PyCFunction)(void(*)(void))pysqlite_connection_set_authorizer, METH_VARARGS|METH_KEYWORDS,
17821745
PyDoc_STR("Sets authorizer callback. Non-standard.")},
1783-
#ifdef HAVE_LOAD_EXTENSION
1746+
#ifndef SQLITE_OMIT_LOAD_EXTENSION
17841747
{"enable_load_extension", (PyCFunction)pysqlite_enable_load_extension, METH_VARARGS,
17851748
PyDoc_STR("Enable dynamic loading of SQLite extension modules. Non-standard.")},
17861749
{"load_extension", (PyCFunction)pysqlite_load_extension, METH_VARARGS,
@@ -1802,10 +1765,8 @@ static PyMethodDef connection_methods[] = {
18021765
PyDoc_STR("Abort any pending database operation. Non-standard.")},
18031766
{"iterdump", (PyCFunction)pysqlite_connection_iterdump, METH_NOARGS,
18041767
PyDoc_STR("Returns iterator to the dump of the database in an SQL text format. Non-standard.")},
1805-
#ifdef HAVE_BACKUP_API
18061768
{"backup", (PyCFunction)(void(*)(void))pysqlite_connection_backup, METH_VARARGS | METH_KEYWORDS,
18071769
PyDoc_STR("Makes a backup of the database. Non-standard.")},
1808-
#endif
18091770
{"__enter__", (PyCFunction)pysqlite_connection_enter, METH_NOARGS,
18101771
PyDoc_STR("For context manager. Non-standard.")},
18111772
{"__exit__", (PyCFunction)pysqlite_connection_exit, METH_VARARGS,

Modules/_sqlite/module.c

Lines changed: 7 additions & 18 deletions
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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1453,7 +1453,6 @@ def detect_sqlite(self):
14531453
sqlite_setup_debug = False # verbose debug prints from this script?
14541454

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

0 commit comments

Comments
 (0)