diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index ccb82278bdaa13..13aa8c512d0319 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -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 diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index eb5ae01a7c04d4..f6f276a8bfa495 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -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 ============= diff --git a/Lib/sqlite3/test/backup.py b/Lib/sqlite3/test/backup.py index 903bacf490301c..2752a4db337ddd 100644 --- a/Lib/sqlite3/test/backup.py +++ b/Lib/sqlite3/test/backup.py @@ -2,7 +2,6 @@ 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:") diff --git a/Lib/sqlite3/test/dbapi.py b/Lib/sqlite3/test/dbapi.py index 119da12170331f..a8dfeb9b2d6933 100644 --- a/Lib/sqlite3/test/dbapi.py +++ b/Lib/sqlite3/test/dbapi.py @@ -185,12 +185,6 @@ def CheckOpenUri(self): 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): diff --git a/Lib/sqlite3/test/hooks.py b/Lib/sqlite3/test/hooks.py index b08adf1d8097b3..2e620ecdf864cb 100644 --- a/Lib/sqlite3/test/hooks.py +++ b/Lib/sqlite3/test/hooks.py @@ -61,8 +61,6 @@ def upper(self): 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 @@ 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 = [] diff --git a/Lib/sqlite3/test/regression.py b/Lib/sqlite3/test/regression.py index cbd46d4978afb9..0735a5c129226d 100644 --- a/Lib/sqlite3/test/regression.py +++ b/Lib/sqlite3/test/regression.py @@ -87,7 +87,6 @@ def CheckStatementFinalizationOnCloseDb(self): 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)") diff --git a/Lib/sqlite3/test/transactions.py b/Lib/sqlite3/test/transactions.py index b8a13de55bc720..c463f7490da573 100644 --- a/Lib/sqlite3/test/transactions.py +++ b/Lib/sqlite3/test/transactions.py @@ -111,16 +111,12 @@ def CheckToggleAutoCommit(self): 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 diff --git a/Lib/sqlite3/test/types.py b/Lib/sqlite3/test/types.py index d26a9cb93f0888..75a9d5601d5808 100644 --- a/Lib/sqlite3/test/types.py +++ b/Lib/sqlite3/test/types.py @@ -401,8 +401,6 @@ def CheckSqliteTimestamp(self): 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)") diff --git a/Misc/NEWS.d/next/Library/2020-05-30-08-10-23.bpo-40744.jKURVV.rst b/Misc/NEWS.d/next/Library/2020-05-30-08-10-23.bpo-40744.jKURVV.rst new file mode 100644 index 00000000000000..2d1d1f9a20e32e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-05-30-08-10-23.bpo-40744.jKURVV.rst @@ -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. diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c index 1bf9710763a5ab..f765ba1df24669 100644 --- a/Modules/_sqlite/connection.c +++ b/Modules/_sqlite/connection.c @@ -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); - } + /* 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 @@ pysqlite_connection_iterdump(pysqlite_Connection* self, PyObject* args) 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, diff --git a/Modules/_sqlite/module.c b/Modules/_sqlite/module.c index 71d951ee887e47..82f58eb2480261 100644 --- a/Modules/_sqlite/module.c +++ b/Modules/_sqlite/module.c @@ -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 || diff --git a/setup.py b/setup.py index 21a5a58981fc15..04b1358bc916e1 100644 --- a/setup.py +++ b/setup.py @@ -1452,7 +1452,6 @@ def detect_sqlite(self): 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 @@ def detect_sqlite(self): ] 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]) pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy