Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions Doc/library/sqlite3.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -591,8 +592,6 @@ Connection Objects
dest = sqlite3.connect(':memory:')
source.backup(dest)

Availability: SQLite 3.6.11 or higher

.. versionadded:: 3.7


Expand Down Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions Doc/whatsnew/3.10.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
=============
Expand Down
1 change: 0 additions & 1 deletion Lib/sqlite3/test/backup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:")
Expand Down
6 changes: 0 additions & 6 deletions Lib/sqlite3/test/dbapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
6 changes: 0 additions & 6 deletions Lib/sqlite3/test/hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 = []
Expand Down
1 change: 0 additions & 1 deletion Lib/sqlite3/test/regression.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)")
Expand Down
4 changes: 0 additions & 4 deletions Lib/sqlite3/test/transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 0 additions & 2 deletions Lib/sqlite3/test/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Drop support for SQLite3 pre v3.7.3. Patch by Sergey Fedoseev and Erlend E.
Aasland.
57 changes: 9 additions & 48 deletions Modules/_sqlite/connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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[] = {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
}
}
Expand All @@ -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:
Expand All @@ -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;

Expand All @@ -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);

Expand All @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down
25 changes: 7 additions & 18 deletions Modules/_sqlite/module.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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}
};

Expand Down Expand Up @@ -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 ||
Expand Down
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -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])

Expand Down