bpo-40744: Drop support for SQLite pre 3.7.3 (GH-20909)
Remove code required to support SQLite pre 3.7.3. Co-written-by: Berker Peksag <berker.peksag@gmail.com> Co-written-by: Sergey Fedoseev <fedoseev.sergey@gmail.com>
This commit is contained in:
parent
22748a83d9
commit
207c321f13
|
@ -18,7 +18,8 @@ application using SQLite and then port the code to a larger database such as
|
|||
PostgreSQL or Oracle.
|
||||
|
||||
The sqlite3 module was written by Gerhard Häring. It provides a SQL interface
|
||||
compliant with the DB-API 2.0 specification described by :pep:`249`.
|
||||
compliant with the DB-API 2.0 specification described by :pep:`249`, and
|
||||
requires SQLite 3.7.3 or newer.
|
||||
|
||||
To use the module, you must first create a :class:`Connection` object that
|
||||
represents the database. Here the data will be stored in the
|
||||
|
@ -591,8 +592,6 @@ Connection Objects
|
|||
dest = sqlite3.connect(':memory:')
|
||||
source.backup(dest)
|
||||
|
||||
Availability: SQLite 3.6.11 or higher
|
||||
|
||||
.. versionadded:: 3.7
|
||||
|
||||
|
||||
|
@ -701,9 +700,6 @@ Cursor Objects
|
|||
statements because we cannot determine the number of rows a query produced
|
||||
until all rows were fetched.
|
||||
|
||||
With SQLite versions before 3.6.5, :attr:`rowcount` is set to 0 if
|
||||
you make a ``DELETE FROM table`` without any condition.
|
||||
|
||||
.. attribute:: lastrowid
|
||||
|
||||
This read-only attribute provides the rowid of the last modified row. It is
|
||||
|
|
|
@ -191,10 +191,15 @@ that may require changes to your code.
|
|||
Build Changes
|
||||
=============
|
||||
|
||||
|
||||
* The C99 functions :c:func:`snprintf` and :c:func:`vsnprintf` are now required
|
||||
to build Python.
|
||||
(Contributed by Victor Stinner in :issue:`36020`.)
|
||||
|
||||
* :mod:`sqlite3` requires SQLite 3.7.3 or higher.
|
||||
(Contributed by Sergey Fedoseev and Erlend E. Aasland :issue:`40744`.)
|
||||
|
||||
|
||||
|
||||
C API Changes
|
||||
=============
|
||||
|
|
|
@ -2,7 +2,6 @@ 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:")
|
||||
|
|
|
@ -185,12 +185,6 @@ class ConnectionTests(unittest.TestCase):
|
|||
with self.assertRaises(sqlite.OperationalError):
|
||||
cx.execute('insert into test(id) values(1)')
|
||||
|
||||
@unittest.skipIf(sqlite.sqlite_version_info >= (3, 3, 1),
|
||||
'needs sqlite versions older than 3.3.1')
|
||||
def CheckSameThreadErrorOnOldVersion(self):
|
||||
with self.assertRaises(sqlite.NotSupportedError) as cm:
|
||||
sqlite.connect(':memory:', check_same_thread=False)
|
||||
self.assertEqual(str(cm.exception), 'shared connections not available')
|
||||
|
||||
class CursorTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
|
|
|
@ -61,8 +61,6 @@ class CollationTests(unittest.TestCase):
|
|||
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
|
||||
|
@ -240,16 +238,12 @@ class TraceCallbackTests(unittest.TestCase):
|
|||
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 = []
|
||||
|
|
|
@ -87,7 +87,6 @@ class RegressionTests(unittest.TestCase):
|
|||
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)")
|
||||
|
|
|
@ -111,16 +111,12 @@ class TransactionTests(unittest.TestCase):
|
|||
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
|
||||
|
|
|
@ -401,8 +401,6 @@ class DateTimeTests(unittest.TestCase):
|
|||
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)")
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
The :mod:`sqlite3` module uses SQLite API functions that require SQLite
|
||||
v3.7.3 or higher. This patch removes support for older SQLite versions, and
|
||||
explicitly requires SQLite 3.7.3 both at build, compile and runtime. Patch by
|
||||
Sergey Fedoseev and Erlend E. Aasland.
|
|
@ -33,16 +33,6 @@
|
|||
#define ACTION_FINALIZE 1
|
||||
#define ACTION_RESET 2
|
||||
|
||||
#if SQLITE_VERSION_NUMBER >= 3003008
|
||||
#ifndef SQLITE_OMIT_LOAD_EXTENSION
|
||||
#define HAVE_LOAD_EXTENSION
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if SQLITE_VERSION_NUMBER >= 3006011
|
||||
#define HAVE_BACKUP_API
|
||||
#endif
|
||||
|
||||
#if SQLITE_VERSION_NUMBER >= 3014000
|
||||
#define HAVE_TRACE_V2
|
||||
#endif
|
||||
|
@ -61,18 +51,6 @@ static int pysqlite_connection_set_isolation_level(pysqlite_Connection* self, Py
|
|||
static void _pysqlite_drop_unused_cursor_references(pysqlite_Connection* self);
|
||||
|
||||
|
||||
static void _sqlite3_result_error(sqlite3_context* ctx, const char* errmsg, int len)
|
||||
{
|
||||
/* in older SQLite versions, calling sqlite3_result_error in callbacks
|
||||
* triggers a bug in SQLite that leads either to irritating results or
|
||||
* segfaults, depending on the SQLite version */
|
||||
#if SQLITE_VERSION_NUMBER >= 3003003
|
||||
sqlite3_result_error(ctx, errmsg, len);
|
||||
#else
|
||||
PyErr_SetString(pysqlite_OperationalError, errmsg);
|
||||
#endif
|
||||
}
|
||||
|
||||
int pysqlite_connection_init(pysqlite_Connection* self, PyObject* args, PyObject* kwargs)
|
||||
{
|
||||
static char *kwlist[] = {
|
||||
|
@ -182,10 +160,6 @@ int pysqlite_connection_init(pysqlite_Connection* self, PyObject* args, PyObject
|
|||
self->timeout = timeout;
|
||||
(void)sqlite3_busy_timeout(self->db, (int)(timeout*1000));
|
||||
self->thread_ident = PyThread_get_thread_ident();
|
||||
if (!check_same_thread && sqlite3_libversion_number() < 3003001) {
|
||||
PyErr_SetString(pysqlite_NotSupportedError, "shared connections not available");
|
||||
return -1;
|
||||
}
|
||||
self->check_same_thread = check_same_thread;
|
||||
|
||||
self->function_pinboard_trace_callback = NULL;
|
||||
|
@ -620,7 +594,7 @@ void _pysqlite_func_callback(sqlite3_context* context, int argc, sqlite3_value**
|
|||
} else {
|
||||
PyErr_Clear();
|
||||
}
|
||||
_sqlite3_result_error(context, "user-defined function raised exception", -1);
|
||||
sqlite3_result_error(context, "user-defined function raised exception", -1);
|
||||
}
|
||||
|
||||
PyGILState_Release(threadstate);
|
||||
|
@ -652,7 +626,7 @@ static void _pysqlite_step_callback(sqlite3_context *context, int argc, sqlite3_
|
|||
} else {
|
||||
PyErr_Clear();
|
||||
}
|
||||
_sqlite3_result_error(context, "user-defined aggregate's '__init__' method raised error", -1);
|
||||
sqlite3_result_error(context, "user-defined aggregate's '__init__' method raised error", -1);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
@ -676,7 +650,7 @@ static void _pysqlite_step_callback(sqlite3_context *context, int argc, sqlite3_
|
|||
} else {
|
||||
PyErr_Clear();
|
||||
}
|
||||
_sqlite3_result_error(context, "user-defined aggregate's 'step' method raised error", -1);
|
||||
sqlite3_result_error(context, "user-defined aggregate's 'step' method raised error", -1);
|
||||
}
|
||||
|
||||
error:
|
||||
|
@ -693,7 +667,6 @@ void _pysqlite_final_callback(sqlite3_context* context)
|
|||
_Py_IDENTIFIER(finalize);
|
||||
int ok;
|
||||
PyObject *exception, *value, *tb;
|
||||
int restore;
|
||||
|
||||
PyGILState_STATE threadstate;
|
||||
|
||||
|
@ -709,7 +682,6 @@ void _pysqlite_final_callback(sqlite3_context* context)
|
|||
|
||||
/* Keep the exception (if any) of the last call to step() */
|
||||
PyErr_Fetch(&exception, &value, &tb);
|
||||
restore = 1;
|
||||
|
||||
function_result = _PyObject_CallMethodIdNoArgs(*aggregate_instance, &PyId_finalize);
|
||||
|
||||
|
@ -726,19 +698,12 @@ void _pysqlite_final_callback(sqlite3_context* context)
|
|||
} else {
|
||||
PyErr_Clear();
|
||||
}
|
||||
_sqlite3_result_error(context, "user-defined aggregate's 'finalize' method raised error", -1);
|
||||
#if SQLITE_VERSION_NUMBER < 3003003
|
||||
/* with old SQLite versions, _sqlite3_result_error() sets a new Python
|
||||
exception, so don't restore the previous exception */
|
||||
restore = 0;
|
||||
#endif
|
||||
sqlite3_result_error(context, "user-defined aggregate's 'finalize' method raised error", -1);
|
||||
}
|
||||
|
||||
if (restore) {
|
||||
/* Restore the exception (if any) of the last call to step(),
|
||||
but clear also the current exception if finalize() failed */
|
||||
PyErr_Restore(exception, value, tb);
|
||||
}
|
||||
|
||||
error:
|
||||
PyGILState_Release(threadstate);
|
||||
|
@ -1110,7 +1075,7 @@ static PyObject* pysqlite_connection_set_trace_callback(pysqlite_Connection* sel
|
|||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LOAD_EXTENSION
|
||||
#ifndef SQLITE_OMIT_LOAD_EXTENSION
|
||||
static PyObject* pysqlite_enable_load_extension(pysqlite_Connection* self, PyObject* args)
|
||||
{
|
||||
int rc;
|
||||
|
@ -1513,7 +1478,6 @@ finally:
|
|||
return retval;
|
||||
}
|
||||
|
||||
#ifdef HAVE_BACKUP_API
|
||||
static PyObject *
|
||||
pysqlite_connection_backup(pysqlite_Connection *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
|
@ -1664,7 +1628,6 @@ pysqlite_connection_backup(pysqlite_Connection *self, PyObject *args, PyObject *
|
|||
return NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static PyObject *
|
||||
pysqlite_connection_create_collation(pysqlite_Connection* self, PyObject* args)
|
||||
|
@ -1816,7 +1779,7 @@ static PyMethodDef connection_methods[] = {
|
|||
PyDoc_STR("Creates a new aggregate. Non-standard.")},
|
||||
{"set_authorizer", (PyCFunction)(void(*)(void))pysqlite_connection_set_authorizer, METH_VARARGS|METH_KEYWORDS,
|
||||
PyDoc_STR("Sets authorizer callback. Non-standard.")},
|
||||
#ifdef HAVE_LOAD_EXTENSION
|
||||
#ifndef SQLITE_OMIT_LOAD_EXTENSION
|
||||
{"enable_load_extension", (PyCFunction)pysqlite_enable_load_extension, METH_VARARGS,
|
||||
PyDoc_STR("Enable dynamic loading of SQLite extension modules. Non-standard.")},
|
||||
{"load_extension", (PyCFunction)pysqlite_load_extension, METH_VARARGS,
|
||||
|
@ -1838,10 +1801,8 @@ static PyMethodDef connection_methods[] = {
|
|||
PyDoc_STR("Abort any pending database operation. Non-standard.")},
|
||||
{"iterdump", (PyCFunction)pysqlite_connection_iterdump, METH_NOARGS,
|
||||
PyDoc_STR("Returns iterator to the dump of the database in an SQL text format. Non-standard.")},
|
||||
#ifdef HAVE_BACKUP_API
|
||||
{"backup", (PyCFunction)(void(*)(void))pysqlite_connection_backup, METH_VARARGS | METH_KEYWORDS,
|
||||
PyDoc_STR("Makes a backup of the database. Non-standard.")},
|
||||
#endif
|
||||
{"__enter__", (PyCFunction)pysqlite_connection_enter, METH_NOARGS,
|
||||
PyDoc_STR("For context manager. Non-standard.")},
|
||||
{"__exit__", (PyCFunction)pysqlite_connection_exit, METH_VARARGS,
|
||||
|
|
|
@ -29,8 +29,8 @@
|
|||
#include "microprotocols.h"
|
||||
#include "row.h"
|
||||
|
||||
#if SQLITE_VERSION_NUMBER >= 3003003
|
||||
#define HAVE_SHARED_CACHE
|
||||
#if SQLITE_VERSION_NUMBER < 3007003
|
||||
#error "SQLite 3.7.3 or higher required"
|
||||
#endif
|
||||
|
||||
/* static objects at module-level */
|
||||
|
@ -131,7 +131,6 @@ PyDoc_STRVAR(module_complete_doc,
|
|||
\n\
|
||||
Checks if a string contains a complete SQL statement. Non-standard.");
|
||||
|
||||
#ifdef HAVE_SHARED_CACHE
|
||||
static PyObject* module_enable_shared_cache(PyObject* self, PyObject* args, PyObject*
|
||||
kwargs)
|
||||
{
|
||||
|
@ -159,7 +158,6 @@ PyDoc_STRVAR(module_enable_shared_cache_doc,
|
|||
\n\
|
||||
Enable or disable shared cache mode for the calling thread.\n\
|
||||
Experimental/Non-standard.");
|
||||
#endif /* HAVE_SHARED_CACHE */
|
||||
|
||||
static PyObject* module_register_adapter(PyObject* self, PyObject* args)
|
||||
{
|
||||
|
@ -253,10 +251,8 @@ static PyMethodDef module_methods[] = {
|
|||
METH_VARARGS | METH_KEYWORDS, module_connect_doc},
|
||||
{"complete_statement", (PyCFunction)(void(*)(void))module_complete,
|
||||
METH_VARARGS | METH_KEYWORDS, module_complete_doc},
|
||||
#ifdef HAVE_SHARED_CACHE
|
||||
{"enable_shared_cache", (PyCFunction)(void(*)(void))module_enable_shared_cache,
|
||||
METH_VARARGS | METH_KEYWORDS, module_enable_shared_cache_doc},
|
||||
#endif
|
||||
{"register_adapter", (PyCFunction)module_register_adapter,
|
||||
METH_VARARGS, module_register_adapter_doc},
|
||||
{"register_converter", (PyCFunction)module_register_converter,
|
||||
|
@ -307,29 +303,17 @@ static const IntConstantPair _int_constants[] = {
|
|||
{"SQLITE_UPDATE", SQLITE_UPDATE},
|
||||
{"SQLITE_ATTACH", SQLITE_ATTACH},
|
||||
{"SQLITE_DETACH", SQLITE_DETACH},
|
||||
#if SQLITE_VERSION_NUMBER >= 3002001
|
||||
{"SQLITE_ALTER_TABLE", SQLITE_ALTER_TABLE},
|
||||
{"SQLITE_REINDEX", SQLITE_REINDEX},
|
||||
#endif
|
||||
#if SQLITE_VERSION_NUMBER >= 3003000
|
||||
{"SQLITE_ANALYZE", SQLITE_ANALYZE},
|
||||
#endif
|
||||
#if SQLITE_VERSION_NUMBER >= 3003007
|
||||
{"SQLITE_CREATE_VTABLE", SQLITE_CREATE_VTABLE},
|
||||
{"SQLITE_DROP_VTABLE", SQLITE_DROP_VTABLE},
|
||||
#endif
|
||||
#if SQLITE_VERSION_NUMBER >= 3003008
|
||||
{"SQLITE_FUNCTION", SQLITE_FUNCTION},
|
||||
#endif
|
||||
#if SQLITE_VERSION_NUMBER >= 3006008
|
||||
{"SQLITE_SAVEPOINT", SQLITE_SAVEPOINT},
|
||||
#endif
|
||||
#if SQLITE_VERSION_NUMBER >= 3008003
|
||||
{"SQLITE_RECURSIVE", SQLITE_RECURSIVE},
|
||||
#endif
|
||||
#if SQLITE_VERSION_NUMBER >= 3006011
|
||||
{"SQLITE_DONE", SQLITE_DONE},
|
||||
#endif
|
||||
{(char*)NULL, 0}
|
||||
};
|
||||
|
||||
|
@ -360,6 +344,11 @@ PyMODINIT_FUNC PyInit__sqlite3(void)
|
|||
PyObject *tmp_obj;
|
||||
int i;
|
||||
|
||||
if (sqlite3_libversion_number() < 3007003) {
|
||||
PyErr_SetString(PyExc_ImportError, MODULE_NAME ": SQLite 3.7.3 or higher required");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
module = PyModule_Create(&_sqlite3module);
|
||||
|
||||
if (!module ||
|
||||
|
|
4
setup.py
4
setup.py
|
@ -1452,7 +1452,6 @@ class PyBuildExt(build_ext):
|
|||
sqlite_setup_debug = False # verbose debug prints from this script?
|
||||
|
||||
# We hunt for #define SQLITE_VERSION "n.n.n"
|
||||
# We need to find >= sqlite version 3.3.9, for sqlite3_prepare_v2
|
||||
sqlite_incdir = sqlite_libdir = None
|
||||
sqlite_inc_paths = [ '/usr/include',
|
||||
'/usr/include/sqlite',
|
||||
|
@ -1463,7 +1462,8 @@ class PyBuildExt(build_ext):
|
|||
]
|
||||
if CROSS_COMPILING:
|
||||
sqlite_inc_paths = []
|
||||
MIN_SQLITE_VERSION_NUMBER = (3, 7, 2)
|
||||
# We need to find >= sqlite version 3.7.3, for sqlite3_create_function_v2()
|
||||
MIN_SQLITE_VERSION_NUMBER = (3, 7, 3)
|
||||
MIN_SQLITE_VERSION = ".".join([str(x)
|
||||
for x in MIN_SQLITE_VERSION_NUMBER])
|
||||
|
||||
|
|
Loading…
Reference in New Issue