summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGerhard Häring <gh@ghaering.de>2010-03-05 09:12:37 (GMT)
committerGerhard Häring <gh@ghaering.de>2010-03-05 09:12:37 (GMT)
commit3bbb67273a8c146a38de91080a37e716e2699622 (patch)
tree19a3d1e79cb51cc42760af73724c4f4615d4c21c
parent2bb66e03b72ae5a0468dab0b7020316f31c8cfdf (diff)
downloadcpython-3bbb67273a8c146a38de91080a37e716e2699622.zip
cpython-3bbb67273a8c146a38de91080a37e716e2699622.tar.gz
cpython-3bbb67273a8c146a38de91080a37e716e2699622.tar.bz2
Merged code from pysqlite 2.6.0.
-rw-r--r--Doc/includes/sqlite3/load_extension.py26
-rw-r--r--Doc/library/sqlite3.rst21
-rw-r--r--Lib/sqlite3/test/dbapi.py111
-rw-r--r--Lib/sqlite3/test/regression.py111
-rw-r--r--Lib/sqlite3/test/transactions.py20
-rw-r--r--Lib/sqlite3/test/types.py27
-rw-r--r--Misc/NEWS3
-rw-r--r--Modules/_sqlite/cache.c3
-rw-r--r--Modules/_sqlite/cache.h2
-rw-r--r--Modules/_sqlite/connection.c206
-rw-r--r--Modules/_sqlite/connection.h11
-rw-r--r--Modules/_sqlite/cursor.c85
-rw-r--r--Modules/_sqlite/cursor.h9
-rw-r--r--Modules/_sqlite/module.c2
-rw-r--r--Modules/_sqlite/module.h4
-rw-r--r--Modules/_sqlite/prepare_protocol.c3
-rw-r--r--Modules/_sqlite/prepare_protocol.h2
-rw-r--r--Modules/_sqlite/row.c20
-rw-r--r--Modules/_sqlite/row.h2
-rw-r--r--Modules/_sqlite/sqlitecompat.h31
-rw-r--r--Modules/_sqlite/statement.c2
-rw-r--r--Modules/_sqlite/statement.h2
-rw-r--r--Modules/_sqlite/util.c2
-rw-r--r--Modules/_sqlite/util.h2
-rw-r--r--setup.py2
25 files changed, 626 insertions, 83 deletions
diff --git a/Doc/includes/sqlite3/load_extension.py b/Doc/includes/sqlite3/load_extension.py
new file mode 100644
index 0000000..7f893c9
--- /dev/null
+++ b/Doc/includes/sqlite3/load_extension.py
@@ -0,0 +1,26 @@
+import sqlite3
+
+con = sqlite3.connect(":memory:")
+
+# enable extension loading
+con.enable_load_extension(True)
+
+# Load the fulltext search extension
+con.execute("select load_extension('./fts3.so')")
+
+# alternatively you can load the extension using an API call:
+# con.load_extension("./fts3.so")
+
+# disable extension laoding again
+con.enable_load_extension(False)
+
+# example from SQLite wiki
+con.execute("create virtual table recipe using fts3(name, ingredients)")
+con.executescript("""
+ insert into recipe (name, ingredients) values ('broccoli stew', 'broccoli peppers cheese tomatoes');
+ insert into recipe (name, ingredients) values ('pumpkin stew', 'pumpkin onions garlic celery');
+ insert into recipe (name, ingredients) values ('broccoli pie', 'broccoli cheese onions flour');
+ insert into recipe (name, ingredients) values ('pumpkin pie', 'pumpkin sugar flour butter');
+ """)
+for row in con.execute("select rowid, name, ingredients from recipe where name match 'pie'"):
+ print row
diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst
index 8ccb0ab..439ca23 100644
--- a/Doc/library/sqlite3.rst
+++ b/Doc/library/sqlite3.rst
@@ -368,6 +368,25 @@ Connection Objects
method with :const:`None` for *handler*.
+.. method:: Connection.enable_load_extension(enabled)
+
+ .. versionadded:: 2.7
+
+ This routine allows/disallows the SQLite engine to load SQLite extensions
+ from shared libraries. SQLite extensions can define new functions,
+ aggregates or whole new virtual table implementations. One well-known
+ extension is the fulltext-search extension distributed with SQLite.
+
+ .. literalinclude:: ../includes/sqlite3/load_extension.py
+
+.. method:: Connection.load_extension(path)
+
+ .. versionadded:: 2.7
+
+ This routine loads a SQLite extension from a shared library. You have to
+ enable extension loading with ``enable_load_extension`` before you can use
+ this routine.
+
.. attribute:: Connection.row_factory
You can change this attribute to a callable that accepts the cursor and the
@@ -439,7 +458,7 @@ Connection Objects
Cursor Objects
--------------
-.. class:: Cursor
+A :class:`Cursor` instance has the following attributes and methods:
A SQLite database cursor has the following attributes and methods:
diff --git a/Lib/sqlite3/test/dbapi.py b/Lib/sqlite3/test/dbapi.py
index 83ce174..9d87212 100644
--- a/Lib/sqlite3/test/dbapi.py
+++ b/Lib/sqlite3/test/dbapi.py
@@ -1,7 +1,7 @@
#-*- coding: ISO-8859-1 -*-
# pysqlite2/test/dbapi.py: tests for DB-API compliance
#
-# Copyright (C) 2004-2007 Gerhard Häring <gh@ghaering.de>
+# Copyright (C) 2004-2010 Gerhard Häring <gh@ghaering.de>
#
# This file is part of pysqlite.
#
@@ -672,13 +672,13 @@ class ExtensionTests(unittest.TestCase):
res = cur.fetchone()[0]
self.assertEqual(res, 6)
- def CheckScriptErrorIncomplete(self):
+ def CheckScriptSyntaxError(self):
con = sqlite.connect(":memory:")
cur = con.cursor()
raised = False
try:
- cur.executescript("create table test(sadfsadfdsa")
- except sqlite.ProgrammingError:
+ cur.executescript("create table test(x); asdf; create table test2(x)")
+ except sqlite.OperationalError:
raised = True
self.assertEqual(raised, True, "should have raised an exception")
@@ -711,7 +711,7 @@ class ExtensionTests(unittest.TestCase):
result = con.execute("select foo from test").fetchone()[0]
self.assertEqual(result, 5, "Basic test of Connection.executescript")
-class ClosedTests(unittest.TestCase):
+class ClosedConTests(unittest.TestCase):
def setUp(self):
pass
@@ -763,6 +763,102 @@ class ClosedTests(unittest.TestCase):
except:
self.fail("Should have raised a ProgrammingError")
+ def CheckClosedCreateFunction(self):
+ con = sqlite.connect(":memory:")
+ con.close()
+ def f(x): return 17
+ try:
+ con.create_function("foo", 1, f)
+ self.fail("Should have raised a ProgrammingError")
+ except sqlite.ProgrammingError:
+ pass
+ except:
+ self.fail("Should have raised a ProgrammingError")
+
+ def CheckClosedCreateAggregate(self):
+ con = sqlite.connect(":memory:")
+ con.close()
+ class Agg:
+ def __init__(self):
+ pass
+ def step(self, x):
+ pass
+ def finalize(self):
+ return 17
+ try:
+ con.create_aggregate("foo", 1, Agg)
+ self.fail("Should have raised a ProgrammingError")
+ except sqlite.ProgrammingError:
+ pass
+ except:
+ self.fail("Should have raised a ProgrammingError")
+
+ def CheckClosedSetAuthorizer(self):
+ con = sqlite.connect(":memory:")
+ con.close()
+ def authorizer(*args):
+ return sqlite.DENY
+ try:
+ con.set_authorizer(authorizer)
+ self.fail("Should have raised a ProgrammingError")
+ except sqlite.ProgrammingError:
+ pass
+ except:
+ self.fail("Should have raised a ProgrammingError")
+
+ def CheckClosedSetProgressCallback(self):
+ con = sqlite.connect(":memory:")
+ con.close()
+ def progress(): pass
+ try:
+ con.set_progress_handler(progress, 100)
+ self.fail("Should have raised a ProgrammingError")
+ except sqlite.ProgrammingError:
+ pass
+ except:
+ self.fail("Should have raised a ProgrammingError")
+
+ def CheckClosedCall(self):
+ con = sqlite.connect(":memory:")
+ con.close()
+ try:
+ con()
+ self.fail("Should have raised a ProgrammingError")
+ except sqlite.ProgrammingError:
+ pass
+ except:
+ self.fail("Should have raised a ProgrammingError")
+
+class ClosedCurTests(unittest.TestCase):
+ def setUp(self):
+ pass
+
+ def tearDown(self):
+ pass
+
+ def CheckClosed(self):
+ con = sqlite.connect(":memory:")
+ cur = con.cursor()
+ cur.close()
+
+ for method_name in ("execute", "executemany", "executescript", "fetchall", "fetchmany", "fetchone"):
+ if method_name in ("execute", "executescript"):
+ params = ("select 4 union select 5",)
+ elif method_name == "executemany":
+ params = ("insert into foo(bar) values (?)", [(3,), (4,)])
+ else:
+ params = []
+
+ try:
+ method = getattr(cur, method_name)
+
+ method(*params)
+ self.fail("Should have raised a ProgrammingError: method " + method_name)
+ except sqlite.ProgrammingError:
+ pass
+ except:
+ self.fail("Should have raised a ProgrammingError: " + method_name)
+
def suite():
module_suite = unittest.makeSuite(ModuleTests, "Check")
connection_suite = unittest.makeSuite(ConnectionTests, "Check")
@@ -770,8 +866,9 @@ def suite():
thread_suite = unittest.makeSuite(ThreadTests, "Check")
constructor_suite = unittest.makeSuite(ConstructorTests, "Check")
ext_suite = unittest.makeSuite(ExtensionTests, "Check")
- closed_suite = unittest.makeSuite(ClosedTests, "Check")
- return unittest.TestSuite((module_suite, connection_suite, cursor_suite, thread_suite, constructor_suite, ext_suite, closed_suite))
+ closed_con_suite = unittest.makeSuite(ClosedConTests, "Check")
+ closed_cur_suite = unittest.makeSuite(ClosedCurTests, "Check")
+ return unittest.TestSuite((module_suite, connection_suite, cursor_suite, thread_suite, constructor_suite, ext_suite, closed_con_suite, closed_cur_suite))
def test():
runner = unittest.TextTestRunner()
diff --git a/Lib/sqlite3/test/regression.py b/Lib/sqlite3/test/regression.py
index 49e1651..85eb3b4 100644
--- a/Lib/sqlite3/test/regression.py
+++ b/Lib/sqlite3/test/regression.py
@@ -70,16 +70,6 @@ class RegressionTests(unittest.TestCase):
cur.execute('select 1 as "foo baz"')
self.assertEqual(cur.description[0][0], "foo baz")
- def CheckStatementAvailable(self):
- # pysqlite up to 2.3.2 crashed on this, because the active statement handle was not checked
- # before trying to fetch data from it. close() destroys the active statement ...
- con = sqlite.connect(":memory:", detect_types=sqlite.PARSE_DECLTYPES)
- cur = con.cursor()
- cur.execute("select 4 union select 5")
- cur.close()
- cur.fetchone()
- cur.fetchone()
-
def CheckStatementFinalizationOnCloseDb(self):
# pysqlite versions <= 2.3.3 only finalized statements in the statement
# cache when closing the database. statements that were still
@@ -167,6 +157,107 @@ class RegressionTests(unittest.TestCase):
self.assertRaises(UnicodeEncodeError, setattr, con,
"isolation_level", u"\xe9")
+ def CheckCursorConstructorCallCheck(self):
+ """
+ Verifies that cursor methods check wether base class __init__ was called.
+ """
+ class Cursor(sqlite.Cursor):
+ def __init__(self, con):
+ pass
+
+ con = sqlite.connect(":memory:")
+ cur = Cursor(con)
+ try:
+ cur.execute("select 4+5").fetchall()
+ self.fail("should have raised ProgrammingError")
+ except sqlite.ProgrammingError:
+ pass
+ except:
+ self.fail("should have raised ProgrammingError")
+
+ def CheckConnectionConstructorCallCheck(self):
+ """
+ Verifies that connection methods check wether base class __init__ was called.
+ """
+ class Connection(sqlite.Connection):
+ def __init__(self, name):
+ pass
+
+ con = Connection(":memory:")
+ try:
+ cur = con.cursor()
+ self.fail("should have raised ProgrammingError")
+ except sqlite.ProgrammingError:
+ pass
+ except:
+ self.fail("should have raised ProgrammingError")
+
+ def CheckCursorRegistration(self):
+ """
+ Verifies that subclassed cursor classes are correctly registered with
+ the connection object, too. (fetch-across-rollback problem)
+ """
+ class Connection(sqlite.Connection):
+ def cursor(self):
+ return Cursor(self)
+
+ class Cursor(sqlite.Cursor):
+ def __init__(self, con):
+ sqlite.Cursor.__init__(self, con)
+
+ con = Connection(":memory:")
+ cur = con.cursor()
+ cur.execute("create table foo(x)")
+ cur.executemany("insert into foo(x) values (?)", [(3,), (4,), (5,)])
+ cur.execute("select x from foo")
+ con.rollback()
+ try:
+ cur.fetchall()
+ self.fail("should have raised InterfaceError")
+ except sqlite.InterfaceError:
+ pass
+ except:
+ self.fail("should have raised InterfaceError")
+
+ def CheckAutoCommit(self):
+ """
+ Verifies that creating a connection in autocommit mode works.
+ 2.5.3 introduced a regression so that these could no longer
+ be created.
+ """
+ con = sqlite.connect(":memory:", isolation_level=None)
+
+ def CheckPragmaAutocommit(self):
+ """
+ Verifies that running a PRAGMA statement that does an autocommit does
+ work. This did not work in 2.5.3/2.5.4.
+ """
+ con = sqlite.connect(":memory:")
+ cur = con.cursor()
+ cur.execute("create table foo(bar)")
+ cur.execute("insert into foo(bar) values (5)")
+
+ cur.execute("pragma page_size")
+ row = cur.fetchone()
+
+ def CheckSetDict(self):
+ """
+ See http://bugs.python.org/issue7478
+
+ It was possible to successfully register callbacks that could not be
+ hashed. Return codes of PyDict_SetItem were not checked properly.
+ """
+ class NotHashable:
+ def __call__(self, *args, **kw):
+ pass
+ def __hash__(self):
+ raise TypeError()
+ var = NotHashable()
+ con = sqlite.connect(":memory:")
+ self.assertRaises(TypeError, con.create_function, var)
+ self.assertRaises(TypeError, con.create_aggregate, var)
+ self.assertRaises(TypeError, con.set_authorizer, var)
+ self.assertRaises(TypeError, con.set_progress_handler, var)
def suite():
regression_suite = unittest.makeSuite(RegressionTests, "Check")
diff --git a/Lib/sqlite3/test/transactions.py b/Lib/sqlite3/test/transactions.py
index c08b56f..a732251 100644
--- a/Lib/sqlite3/test/transactions.py
+++ b/Lib/sqlite3/test/transactions.py
@@ -148,6 +148,26 @@ class TransactionTests(unittest.TestCase):
# NO self.con2.rollback() HERE!!!
self.con1.commit()
+ def CheckRollbackCursorConsistency(self):
+ """
+ Checks if cursors on the connection are set into a "reset" state
+ when a rollback is done on the connection.
+ """
+ con = sqlite.connect(":memory:")
+ cur = con.cursor()
+ cur.execute("create table test(x)")
+ cur.execute("insert into test(x) values (5)")
+ cur.execute("select 1 union select 2 union select 3")
+
+ con.rollback()
+ try:
+ cur.fetchall()
+ self.fail("InterfaceError should have been raised")
+ except sqlite.InterfaceError, e:
+ pass
+ except:
+ self.fail("InterfaceError should have been raised")
+
class SpecialCommandTests(unittest.TestCase):
def setUp(self):
self.con = sqlite.connect(":memory:")
diff --git a/Lib/sqlite3/test/types.py b/Lib/sqlite3/test/types.py
index b38c8f4..70d20dc 100644
--- a/Lib/sqlite3/test/types.py
+++ b/Lib/sqlite3/test/types.py
@@ -78,6 +78,33 @@ class SqliteTypeTests(unittest.TestCase):
row = self.cur.fetchone()
self.assertEqual(row[0], u"Österreich")
+ def CheckNonUtf8_Default(self):
+ try:
+ self.cur.execute("select ?", (chr(150),))
+ self.fail("should have raised a ProgrammingError")
+ except sqlite.ProgrammingError:
+ pass
+
+ def CheckNonUtf8_TextFactoryString(self):
+ orig_text_factory = self.con.text_factory
+ try:
+ self.con.text_factory = str
+ self.cur.execute("select ?", (chr(150),))
+ finally:
+ self.con.text_factory = orig_text_factory
+
+ def CheckNonUtf8_TextFactoryOptimizedUnicode(self):
+ orig_text_factory = self.con.text_factory
+ try:
+ try:
+ self.con.text_factory = sqlite.OptimizedUnicode
+ self.cur.execute("select ?", (chr(150),))
+ self.fail("should have raised a ProgrammingError")
+ except sqlite.ProgrammingError:
+ pass
+ finally:
+ self.con.text_factory = orig_text_factory
+
class DeclTypesTests(unittest.TestCase):
class Foo:
def __init__(self, _val):
diff --git a/Misc/NEWS b/Misc/NEWS
index 107c991..24aab35 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -103,6 +103,9 @@ Library
Extension Modules
-----------------
+- The sqlite3 module was updated to pysqlite 2.6.0. This fixes several obscure
+ bugs and allows loading SQLite extensions from shared libraries.
+
- Issue #7808: Fix reference leaks in _bsddb and related tests.
- Issue #6544: fix a reference leak in the kqueue implementation's error
diff --git a/Modules/_sqlite/cache.c b/Modules/_sqlite/cache.c
index 85118fc..0653367 100644
--- a/Modules/_sqlite/cache.c
+++ b/Modules/_sqlite/cache.c
@@ -1,6 +1,6 @@
/* cache .c - a LRU cache
*
- * Copyright (C) 2004-2007 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2004-2010 Gerhard Häring <gh@ghaering.de>
*
* This file is part of pysqlite.
*
@@ -21,6 +21,7 @@
* 3. This notice may not be removed or altered from any source distribution.
*/
+#include "sqlitecompat.h"
#include "cache.h"
#include <limits.h>
diff --git a/Modules/_sqlite/cache.h b/Modules/_sqlite/cache.h
index d6f7f13..b09517c 100644
--- a/Modules/_sqlite/cache.h
+++ b/Modules/_sqlite/cache.h
@@ -1,6 +1,6 @@
/* cache.h - definitions for the LRU cache
*
- * Copyright (C) 2004-2007 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2004-2010 Gerhard Häring <gh@ghaering.de>
*
* This file is part of pysqlite.
*
diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c
index 7417791..6bc495a 100644
--- a/Modules/_sqlite/connection.c
+++ b/Modules/_sqlite/connection.c
@@ -1,6 +1,6 @@
/* connection.c - the connection type
*
- * Copyright (C) 2004-2007 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2004-2010 Gerhard Häring <gh@ghaering.de>
*
* This file is part of pysqlite.
*
@@ -35,7 +35,14 @@
#define ACTION_FINALIZE 1
#define ACTION_RESET 2
+#if SQLITE_VERSION_NUMBER >= 3003008
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
+#define HAVE_LOAD_EXTENSION
+#endif
+#endif
+
static int pysqlite_connection_set_isolation_level(pysqlite_Connection* self, PyObject* isolation_level);
+static void _pysqlite_drop_unused_cursor_references(pysqlite_Connection* self);
static void _sqlite3_result_error(sqlite3_context* ctx, const char* errmsg, int len)
@@ -73,10 +80,13 @@ int pysqlite_connection_init(pysqlite_Connection* self, PyObject* args, PyObject
return -1;
}
+ self->initialized = 1;
+
self->begin_statement = NULL;
self->statement_cache = NULL;
self->statements = NULL;
+ self->cursors = NULL;
Py_INCREF(Py_None);
self->row_factory = Py_None;
@@ -150,11 +160,15 @@ int pysqlite_connection_init(pysqlite_Connection* self, PyObject* args, PyObject
return -1;
}
+ self->created_statements = 0;
+ self->created_cursors = 0;
+
+ /* Create lists of weak references to statements/cursors */
self->statements = PyList_New(0);
- if (!self->statements) {
+ self->cursors = PyList_New(0);
+ if (!self->statements || !self->cursors) {
return -1;
}
- self->created_statements = 0;
/* By default, the Cache class INCREFs the factory in its initializer, and
* decrefs it in its deallocator method. Since this would create a circular
@@ -218,11 +232,12 @@ void pysqlite_flush_statement_cache(pysqlite_Connection* self)
}
/* action in (ACTION_RESET, ACTION_FINALIZE) */
-void pysqlite_do_all_statements(pysqlite_Connection* self, int action)
+void pysqlite_do_all_statements(pysqlite_Connection* self, int action, int reset_cursors)
{
int i;
PyObject* weakref;
PyObject* statement;
+ pysqlite_Cursor* cursor;
for (i = 0; i < PyList_Size(self->statements); i++) {
weakref = PyList_GetItem(self->statements, i);
@@ -235,6 +250,16 @@ void pysqlite_do_all_statements(pysqlite_Connection* self, int action)
}
}
}
+
+ if (reset_cursors) {
+ for (i = 0; i < PyList_Size(self->cursors); i++) {
+ weakref = PyList_GetItem(self->cursors, i);
+ cursor = (pysqlite_Cursor*)PyWeakref_GetObject(weakref);
+ if ((PyObject*)cursor != Py_None) {
+ cursor->reset = 1;
+ }
+ }
+ }
}
void pysqlite_connection_dealloc(pysqlite_Connection* self)
@@ -263,17 +288,43 @@ void pysqlite_connection_dealloc(pysqlite_Connection* self)
Py_XDECREF(self->text_factory);
Py_XDECREF(self->collations);
Py_XDECREF(self->statements);
+ Py_XDECREF(self->cursors);
self->ob_type->tp_free((PyObject*)self);
}
+/*
+ * Registers a cursor with the connection.
+ *
+ * 0 => error; 1 => ok
+ */
+int pysqlite_connection_register_cursor(pysqlite_Connection* connection, PyObject* cursor)
+{
+ PyObject* weakref;
+
+ weakref = PyWeakref_NewRef((PyObject*)cursor, NULL);
+ if (!weakref) {
+ goto error;
+ }
+
+ if (PyList_Append(connection->cursors, weakref) != 0) {
+ Py_CLEAR(weakref);
+ goto error;
+ }
+
+ Py_DECREF(weakref);
+
+ return 1;
+error:
+ return 0;
+}
+
PyObject* pysqlite_connection_cursor(pysqlite_Connection* self, PyObject* args, PyObject* kwargs)
{
static char *kwlist[] = {"factory", NULL, NULL};
PyObject* factory = NULL;
PyObject* cursor;
-
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O", kwlist,
&factory)) {
return NULL;
@@ -289,6 +340,8 @@ PyObject* pysqlite_connection_cursor(pysqlite_Connection* self, PyObject* args,
cursor = PyObject_CallFunction(factory, "O", self);
+ _pysqlite_drop_unused_cursor_references(self);
+
if (cursor && self->row_factory != Py_None) {
Py_XDECREF(((pysqlite_Cursor*)cursor)->row_factory);
Py_INCREF(self->row_factory);
@@ -307,7 +360,7 @@ PyObject* pysqlite_connection_close(pysqlite_Connection* self, PyObject* args)
return NULL;
}
- pysqlite_do_all_statements(self, ACTION_FINALIZE);
+ pysqlite_do_all_statements(self, ACTION_FINALIZE, 1);
if (self->db) {
if (self->apsw_connection) {
@@ -341,6 +394,11 @@ PyObject* pysqlite_connection_close(pysqlite_Connection* self, PyObject* args)
*/
int pysqlite_check_connection(pysqlite_Connection* con)
{
+ if (!con->initialized) {
+ PyErr_SetString(pysqlite_ProgrammingError, "Base Connection.__init__ not called.");
+ return 0;
+ }
+
if (!con->db) {
PyErr_SetString(pysqlite_ProgrammingError, "Cannot operate on a closed database.");
return 0;
@@ -399,6 +457,8 @@ PyObject* pysqlite_connection_commit(pysqlite_Connection* self, PyObject* args)
}
if (self->inTransaction) {
+ pysqlite_do_all_statements(self, ACTION_RESET, 0);
+
Py_BEGIN_ALLOW_THREADS
rc = sqlite3_prepare(self->db, "COMMIT", -1, &statement, &tail);
Py_END_ALLOW_THREADS
@@ -443,7 +503,7 @@ PyObject* pysqlite_connection_rollback(pysqlite_Connection* self, PyObject* args
}
if (self->inTransaction) {
- pysqlite_do_all_statements(self, ACTION_RESET);
+ pysqlite_do_all_statements(self, ACTION_RESET, 1);
Py_BEGIN_ALLOW_THREADS
rc = sqlite3_prepare(self->db, "ROLLBACK", -1, &statement, &tail);
@@ -724,7 +784,7 @@ error:
#endif
}
-void _pysqlite_drop_unused_statement_references(pysqlite_Connection* self)
+static void _pysqlite_drop_unused_statement_references(pysqlite_Connection* self)
{
PyObject* new_list;
PyObject* weakref;
@@ -756,6 +816,38 @@ void _pysqlite_drop_unused_statement_references(pysqlite_Connection* self)
self->statements = new_list;
}
+static void _pysqlite_drop_unused_cursor_references(pysqlite_Connection* self)
+{
+ PyObject* new_list;
+ PyObject* weakref;
+ int i;
+
+ /* we only need to do this once in a while */
+ if (self->created_cursors++ < 200) {
+ return;
+ }
+
+ self->created_cursors = 0;
+
+ new_list = PyList_New(0);
+ if (!new_list) {
+ return;
+ }
+
+ for (i = 0; i < PyList_Size(self->cursors); i++) {
+ weakref = PyList_GetItem(self->cursors, i);
+ if (PyWeakref_GetObject(weakref) != Py_None) {
+ if (PyList_Append(new_list, weakref) != 0) {
+ Py_DECREF(new_list);
+ return;
+ }
+ }
+ }
+
+ Py_DECREF(self->cursors);
+ self->cursors = new_list;
+}
+
PyObject* pysqlite_connection_create_function(pysqlite_Connection* self, PyObject* args, PyObject* kwargs)
{
static char *kwlist[] = {"name", "narg", "func", NULL, NULL};
@@ -765,6 +857,10 @@ PyObject* pysqlite_connection_create_function(pysqlite_Connection* self, PyObjec
int narg;
int rc;
+ if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
+ return NULL;
+ }
+
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "siO", kwlist,
&name, &narg, &func))
{
@@ -778,7 +874,8 @@ PyObject* pysqlite_connection_create_function(pysqlite_Connection* self, PyObjec
PyErr_SetString(pysqlite_OperationalError, "Error creating function");
return NULL;
} else {
- PyDict_SetItem(self->function_pinboard, func, Py_None);
+ if (PyDict_SetItem(self->function_pinboard, func, Py_None) == -1)
+ return NULL;
Py_INCREF(Py_None);
return Py_None;
@@ -794,6 +891,10 @@ PyObject* pysqlite_connection_create_aggregate(pysqlite_Connection* self, PyObje
static char *kwlist[] = { "name", "n_arg", "aggregate_class", NULL };
int rc;
+ if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
+ return NULL;
+ }
+
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "siO:create_aggregate",
kwlist, &name, &n_arg, &aggregate_class)) {
return NULL;
@@ -805,7 +906,8 @@ PyObject* pysqlite_connection_create_aggregate(pysqlite_Connection* self, PyObje
PyErr_SetString(pysqlite_OperationalError, "Error creating aggregate");
return NULL;
} else {
- PyDict_SetItem(self->function_pinboard, aggregate_class, Py_None);
+ if (PyDict_SetItem(self->function_pinboard, aggregate_class, Py_None) == -1)
+ return NULL;
Py_INCREF(Py_None);
return Py_None;
@@ -877,13 +979,17 @@ static int _progress_handler(void* user_arg)
return rc;
}
-PyObject* pysqlite_connection_set_authorizer(pysqlite_Connection* self, PyObject* args, PyObject* kwargs)
+static PyObject* pysqlite_connection_set_authorizer(pysqlite_Connection* self, PyObject* args, PyObject* kwargs)
{
PyObject* authorizer_cb;
static char *kwlist[] = { "authorizer_callback", NULL };
int rc;
+ if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
+ return NULL;
+ }
+
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O:set_authorizer",
kwlist, &authorizer_cb)) {
return NULL;
@@ -895,20 +1001,25 @@ PyObject* pysqlite_connection_set_authorizer(pysqlite_Connection* self, PyObject
PyErr_SetString(pysqlite_OperationalError, "Error setting authorizer callback");
return NULL;
} else {
- PyDict_SetItem(self->function_pinboard, authorizer_cb, Py_None);
+ if (PyDict_SetItem(self->function_pinboard, authorizer_cb, Py_None) == -1)
+ return NULL;
Py_INCREF(Py_None);
return Py_None;
}
}
-PyObject* pysqlite_connection_set_progress_handler(pysqlite_Connection* self, PyObject* args, PyObject* kwargs)
+static PyObject* pysqlite_connection_set_progress_handler(pysqlite_Connection* self, PyObject* args, PyObject* kwargs)
{
PyObject* progress_handler;
int n;
static char *kwlist[] = { "progress_handler", "n", NULL };
+ if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
+ return NULL;
+ }
+
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Oi:set_progress_handler",
kwlist, &progress_handler, &n)) {
return NULL;
@@ -919,13 +1030,64 @@ PyObject* pysqlite_connection_set_progress_handler(pysqlite_Connection* self, Py
sqlite3_progress_handler(self->db, 0, 0, (void*)0);
} else {
sqlite3_progress_handler(self->db, n, _progress_handler, progress_handler);
- PyDict_SetItem(self->function_pinboard, progress_handler, Py_None);
+ if (PyDict_SetItem(self->function_pinboard, progress_handler, Py_None) == -1)
+ return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
+#ifdef HAVE_LOAD_EXTENSION
+static PyObject* pysqlite_enable_load_extension(pysqlite_Connection* self, PyObject* args)
+{
+ int rc;
+ int onoff;
+
+ if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
+ return NULL;
+ }
+
+ if (!PyArg_ParseTuple(args, "i", &onoff)) {
+ return NULL;
+ }
+
+ rc = sqlite3_enable_load_extension(self->db, onoff);
+
+ if (rc != SQLITE_OK) {
+ PyErr_SetString(pysqlite_OperationalError, "Error enabling load extension");
+ return NULL;
+ } else {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+}
+
+static PyObject* pysqlite_load_extension(pysqlite_Connection* self, PyObject* args)
+{
+ int rc;
+ char* extension_name;
+ char* errmsg;
+
+ if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
+ return NULL;
+ }
+
+ if (!PyArg_ParseTuple(args, "s", &extension_name)) {
+ return NULL;
+ }
+
+ rc = sqlite3_load_extension(self->db, extension_name, 0, &errmsg);
+ if (rc != 0) {
+ PyErr_SetString(pysqlite_OperationalError, errmsg);
+ return NULL;
+ } else {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+}
+#endif
+
int pysqlite_check_thread(pysqlite_Connection* self)
{
#ifdef WITH_THREAD
@@ -1020,6 +1182,10 @@ PyObject* pysqlite_connection_call(pysqlite_Connection* self, PyObject* args, Py
PyObject* weakref;
int rc;
+ if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
+ return NULL;
+ }
+
if (!PyArg_ParseTuple(args, "O", &sql)) {
return NULL;
}
@@ -1309,9 +1475,11 @@ pysqlite_connection_create_collation(pysqlite_Connection* self, PyObject* args)
}
if (callable != Py_None) {
- PyDict_SetItem(self->collations, uppercase_name, callable);
+ if (PyDict_SetItem(self->collations, uppercase_name, callable) == -1)
+ goto finally;
} else {
- PyDict_DelItem(self->collations, uppercase_name);
+ if (PyDict_DelItem(self->collations, uppercase_name) == -1)
+ goto finally;
}
rc = sqlite3_create_collation(self->db,
@@ -1400,6 +1568,12 @@ static PyMethodDef connection_methods[] = {
PyDoc_STR("Creates a new aggregate. Non-standard.")},
{"set_authorizer", (PyCFunction)pysqlite_connection_set_authorizer, METH_VARARGS|METH_KEYWORDS,
PyDoc_STR("Sets authorizer callback. Non-standard.")},
+ #ifdef HAVE_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,
+ PyDoc_STR("Load SQLite extension module. Non-standard.")},
+ #endif
{"set_progress_handler", (PyCFunction)pysqlite_connection_set_progress_handler, METH_VARARGS|METH_KEYWORDS,
PyDoc_STR("Sets progress handler callback. Non-standard.")},
{"execute", (PyCFunction)pysqlite_connection_execute, METH_VARARGS,
diff --git a/Modules/_sqlite/connection.h b/Modules/_sqlite/connection.h
index 3b1c632..3fc5a70 100644
--- a/Modules/_sqlite/connection.h
+++ b/Modules/_sqlite/connection.h
@@ -1,6 +1,6 @@
/* connection.h - definitions for the connection type
*
- * Copyright (C) 2004-2007 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2004-2010 Gerhard Häring <gh@ghaering.de>
*
* This file is part of pysqlite.
*
@@ -63,17 +63,21 @@ typedef struct
* used from the same thread it was created in */
int check_same_thread;
+ int initialized;
+
/* thread identification of the thread the connection was created in */
long thread_ident;
pysqlite_Cache* statement_cache;
- /* A list of weak references to statements used within this connection */
+ /* Lists of weak references to statements and cursors used within this connection */
PyObject* statements;
+ PyObject* cursors;
- /* a counter for how many statements were created in the connection. May be
+ /* Counters for how many statements/cursors were created in the connection. May be
* reset to 0 at certain intervals */
int created_statements;
+ int created_cursors;
PyObject* row_factory;
@@ -125,6 +129,7 @@ PyObject* pysqlite_connection_rollback(pysqlite_Connection* self, PyObject* args
PyObject* pysqlite_connection_new(PyTypeObject* type, PyObject* args, PyObject* kw);
int pysqlite_connection_init(pysqlite_Connection* self, PyObject* args, PyObject* kwargs);
+int pysqlite_connection_register_cursor(pysqlite_Connection* connection, PyObject* cursor);
int pysqlite_check_thread(pysqlite_Connection* self);
int pysqlite_check_connection(pysqlite_Connection* con);
diff --git a/Modules/_sqlite/cursor.c b/Modules/_sqlite/cursor.c
index 6572a559..26e3307 100644
--- a/Modules/_sqlite/cursor.c
+++ b/Modules/_sqlite/cursor.c
@@ -1,6 +1,6 @@
/* cursor.c - the cursor type
*
- * Copyright (C) 2004-2007 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2004-2010 Gerhard Häring <gh@ghaering.de>
*
* This file is part of pysqlite.
*
@@ -36,6 +36,8 @@
PyObject* pysqlite_cursor_iternext(pysqlite_Cursor* self);
+static char* errmsg_fetch_across_rollback = "Cursor needed to be reset because of commit/rollback and can no longer be fetched from.";
+
static pysqlite_StatementKind detect_statement_type(char* statement)
{
char buf[20];
@@ -74,7 +76,7 @@ static pysqlite_StatementKind detect_statement_type(char* statement)
}
}
-int pysqlite_cursor_init(pysqlite_Cursor* self, PyObject* args, PyObject* kwargs)
+static int pysqlite_cursor_init(pysqlite_Cursor* self, PyObject* args, PyObject* kwargs)
{
pysqlite_Connection* connection;
@@ -87,6 +89,7 @@ int pysqlite_cursor_init(pysqlite_Cursor* self, PyObject* args, PyObject* kwargs
self->connection = connection;
self->statement = NULL;
self->next_row = NULL;
+ self->in_weakreflist = NULL;
self->row_cast_map = PyList_New(0);
if (!self->row_cast_map) {
@@ -100,6 +103,8 @@ int pysqlite_cursor_init(pysqlite_Cursor* self, PyObject* args, PyObject* kwargs
self->lastrowid= Py_None;
self->arraysize = 1;
+ self->closed = 0;
+ self->reset = 0;
self->rowcount = -1L;
@@ -110,10 +115,16 @@ int pysqlite_cursor_init(pysqlite_Cursor* self, PyObject* args, PyObject* kwargs
return -1;
}
+ if (!pysqlite_connection_register_cursor(connection, (PyObject*)self)) {
+ return -1;
+ }
+
+ self->initialized = 1;
+
return 0;
}
-void pysqlite_cursor_dealloc(pysqlite_Cursor* self)
+static void pysqlite_cursor_dealloc(pysqlite_Cursor* self)
{
int rc;
@@ -130,7 +141,11 @@ void pysqlite_cursor_dealloc(pysqlite_Cursor* self)
Py_XDECREF(self->row_factory);
Py_XDECREF(self->next_row);
- Py_TYPE(self)->tp_free((PyObject*)self);
+ if (self->in_weakreflist != NULL) {
+ PyObject_ClearWeakRefs((PyObject*)self);
+ }
+
+ self->ob_type->tp_free((PyObject*)self);
}
PyObject* _pysqlite_get_converter(PyObject* key)
@@ -301,6 +316,11 @@ PyObject* _pysqlite_fetch_one_row(pysqlite_Cursor* self)
char buf[200];
const char* colname;
+ if (self->reset) {
+ PyErr_SetString(pysqlite_InterfaceError, errmsg_fetch_across_rollback);
+ return NULL;
+ }
+
Py_BEGIN_ALLOW_THREADS
numcols = sqlite3_data_count(self->statement->st);
Py_END_ALLOW_THREADS
@@ -406,6 +426,26 @@ PyObject* _pysqlite_fetch_one_row(pysqlite_Cursor* self)
return row;
}
+/*
+ * Checks if a cursor object is usable.
+ *
+ * 0 => error; 1 => ok
+ */
+static int check_cursor(pysqlite_Cursor* cur)
+{
+ if (!cur->initialized) {
+ PyErr_SetString(pysqlite_ProgrammingError, "Base Cursor.__init__ not called.");
+ return 0;
+ }
+
+ if (cur->closed) {
+ PyErr_SetString(pysqlite_ProgrammingError, "Cannot operate on a closed cursor.");
+ return 0;
+ } else {
+ return pysqlite_check_thread(cur->connection) && pysqlite_check_connection(cur->connection);
+ }
+}
+
PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* args)
{
PyObject* operation;
@@ -425,13 +465,15 @@ PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject*
PyObject* second_argument = NULL;
int allow_8bit_chars;
- if (!pysqlite_check_thread(self->connection) || !pysqlite_check_connection(self->connection)) {
+ if (!check_cursor(self)) {
return NULL;
}
+ self->reset = 0;
+
/* Make shooting yourself in the foot with not utf-8 decodable 8-bit-strings harder */
allow_8bit_chars = ((self->connection->text_factory != (PyObject*)&PyUnicode_Type) &&
- (self->connection->text_factory != (PyObject*)&PyUnicode_Type && pysqlite_OptimizedUnicode));
+ (self->connection->text_factory != pysqlite_OptimizedUnicode));
Py_XDECREF(self->next_row);
self->next_row = NULL;
@@ -753,16 +795,17 @@ PyObject* pysqlite_cursor_executescript(pysqlite_Cursor* self, PyObject* args)
sqlite3_stmt* statement;
int rc;
PyObject* result;
- int statement_completed = 0;
if (!PyArg_ParseTuple(args, "O", &script_obj)) {
return NULL;
}
- if (!pysqlite_check_thread(self->connection) || !pysqlite_check_connection(self->connection)) {
+ if (!check_cursor(self)) {
return NULL;
}
+ self->reset = 0;
+
if (PyString_Check(script_obj)) {
script_cstr = PyString_AsString(script_obj);
} else if (PyUnicode_Check(script_obj)) {
@@ -785,11 +828,6 @@ PyObject* pysqlite_cursor_executescript(pysqlite_Cursor* self, PyObject* args)
Py_DECREF(result);
while (1) {
- if (!sqlite3_complete(script_cstr)) {
- break;
- }
- statement_completed = 1;
-
Py_BEGIN_ALLOW_THREADS
rc = sqlite3_prepare(self->connection->db,
script_cstr,
@@ -820,15 +858,15 @@ PyObject* pysqlite_cursor_executescript(pysqlite_Cursor* self, PyObject* args)
_pysqlite_seterror(self->connection->db, NULL);
goto error;
}
+
+ if (*script_cstr == (char)0) {
+ break;
+ }
}
error:
Py_XDECREF(script_str);
- if (!statement_completed) {
- PyErr_SetString(pysqlite_ProgrammingError, "you did not provide a complete SQL statement");
- }
-
if (PyErr_Occurred()) {
return NULL;
} else {
@@ -849,7 +887,12 @@ PyObject* pysqlite_cursor_iternext(pysqlite_Cursor *self)
PyObject* next_row;
int rc;
- if (!pysqlite_check_thread(self->connection) || !pysqlite_check_connection(self->connection)) {
+ if (!check_cursor(self)) {
+ return NULL;
+ }
+
+ if (self->reset) {
+ PyErr_SetString(pysqlite_InterfaceError, errmsg_fetch_across_rollback);
return NULL;
}
@@ -992,6 +1035,8 @@ PyObject* pysqlite_cursor_close(pysqlite_Cursor* self, PyObject* args)
Py_CLEAR(self->statement);
}
+ self->closed = 1;
+
Py_INCREF(Py_None);
return Py_None;
}
@@ -1052,12 +1097,12 @@ PyTypeObject pysqlite_CursorType = {
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_ITER|Py_TPFLAGS_BASETYPE, /* tp_flags */
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_ITER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */
cursor_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
+ offsetof(pysqlite_Cursor, in_weakreflist), /* tp_weaklistoffset */
(getiterfunc)pysqlite_cursor_getiter, /* tp_iter */
(iternextfunc)pysqlite_cursor_iternext, /* tp_iternext */
cursor_methods, /* tp_methods */
diff --git a/Modules/_sqlite/cursor.h b/Modules/_sqlite/cursor.h
index 54d816d..82f5972 100644
--- a/Modules/_sqlite/cursor.h
+++ b/Modules/_sqlite/cursor.h
@@ -1,6 +1,6 @@
/* cursor.h - definitions for the cursor type
*
- * Copyright (C) 2004-2007 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2004-2010 Gerhard Häring <gh@ghaering.de>
*
* This file is part of pysqlite.
*
@@ -40,9 +40,14 @@ typedef struct
long rowcount;
PyObject* row_factory;
pysqlite_Statement* statement;
+ int closed;
+ int reset;
+ int initialized;
/* the next row to be returned, NULL if no next row available */
PyObject* next_row;
+
+ PyObject* in_weakreflist; /* List of weak references */
} pysqlite_Cursor;
typedef enum {
@@ -53,8 +58,6 @@ typedef enum {
extern PyTypeObject pysqlite_CursorType;
-int pysqlite_cursor_init(pysqlite_Cursor* self, PyObject* args, PyObject* kwargs);
-void pysqlite_cursor_dealloc(pysqlite_Cursor* self);
PyObject* pysqlite_cursor_execute(pysqlite_Cursor* self, PyObject* args);
PyObject* pysqlite_cursor_executemany(pysqlite_Cursor* self, PyObject* args);
PyObject* pysqlite_cursor_getiter(pysqlite_Cursor *self);
diff --git a/Modules/_sqlite/module.c b/Modules/_sqlite/module.c
index c16b7c7..33611d9 100644
--- a/Modules/_sqlite/module.c
+++ b/Modules/_sqlite/module.c
@@ -1,6 +1,6 @@
/* module.c - the module itself
*
- * Copyright (C) 2004-2007 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2004-2010 Gerhard Häring <gh@ghaering.de>
*
* This file is part of pysqlite.
*
diff --git a/Modules/_sqlite/module.h b/Modules/_sqlite/module.h
index b14be2a..8d17d61 100644
--- a/Modules/_sqlite/module.h
+++ b/Modules/_sqlite/module.h
@@ -1,6 +1,6 @@
/* module.h - definitions for the module
*
- * Copyright (C) 2004-2007 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2004-2010 Gerhard Häring <gh@ghaering.de>
*
* This file is part of pysqlite.
*
@@ -25,7 +25,7 @@
#define PYSQLITE_MODULE_H
#include "Python.h"
-#define PYSQLITE_VERSION "2.4.1"
+#define PYSQLITE_VERSION "2.6.0"
extern PyObject* pysqlite_Error;
extern PyObject* pysqlite_Warning;
diff --git a/Modules/_sqlite/prepare_protocol.c b/Modules/_sqlite/prepare_protocol.c
index c018c96..9ed25e1 100644
--- a/Modules/_sqlite/prepare_protocol.c
+++ b/Modules/_sqlite/prepare_protocol.c
@@ -1,6 +1,6 @@
/* prepare_protocol.c - the protocol for preparing values for SQLite
*
- * Copyright (C) 2005-2006 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2005-2010 Gerhard Häring <gh@ghaering.de>
*
* This file is part of pysqlite.
*
@@ -21,6 +21,7 @@
* 3. This notice may not be removed or altered from any source distribution.
*/
+#include "sqlitecompat.h"
#include "prepare_protocol.h"
int pysqlite_prepare_protocol_init(pysqlite_PrepareProtocol* self, PyObject* args, PyObject* kwargs)
diff --git a/Modules/_sqlite/prepare_protocol.h b/Modules/_sqlite/prepare_protocol.h
index 153472e..1cdf708 100644
--- a/Modules/_sqlite/prepare_protocol.h
+++ b/Modules/_sqlite/prepare_protocol.h
@@ -1,6 +1,6 @@
/* prepare_protocol.h - the protocol for preparing values for SQLite
*
- * Copyright (C) 2005-2007 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2005-2010 Gerhard Häring <gh@ghaering.de>
*
* This file is part of pysqlite.
*
diff --git a/Modules/_sqlite/row.c b/Modules/_sqlite/row.c
index f1e1c43..480b482 100644
--- a/Modules/_sqlite/row.c
+++ b/Modules/_sqlite/row.c
@@ -1,6 +1,6 @@
/* row.c - an enhanced tuple for database rows
*
- * Copyright (C) 2005-2006 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2005-2010 Gerhard Häring <gh@ghaering.de>
*
* This file is part of pysqlite.
*
@@ -177,17 +177,17 @@ static long pysqlite_row_hash(pysqlite_Row *self)
static PyObject* pysqlite_row_richcompare(pysqlite_Row *self, PyObject *_other, int opid)
{
if (opid != Py_EQ && opid != Py_NE) {
- Py_INCREF(Py_NotImplemented);
- return Py_NotImplemented;
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
}
if (PyType_IsSubtype(Py_TYPE(_other), &pysqlite_RowType)) {
- pysqlite_Row *other = (pysqlite_Row *)_other;
- PyObject *res = PyObject_RichCompare(self->description, other->description, opid);
- if ((opid == Py_EQ && res == Py_True)
- || (opid == Py_NE && res == Py_False)) {
- Py_DECREF(res);
- return PyObject_RichCompare(self->data, other->data, opid);
- }
+ pysqlite_Row *other = (pysqlite_Row *)_other;
+ PyObject *res = PyObject_RichCompare(self->description, other->description, opid);
+ if ((opid == Py_EQ && res == Py_True)
+ || (opid == Py_NE && res == Py_False)) {
+ Py_DECREF(res);
+ return PyObject_RichCompare(self->data, other->data, opid);
+ }
}
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
diff --git a/Modules/_sqlite/row.h b/Modules/_sqlite/row.h
index 8ed69ae..dd9b0c3 100644
--- a/Modules/_sqlite/row.h
+++ b/Modules/_sqlite/row.h
@@ -1,6 +1,6 @@
/* row.h - an enhanced tuple for database rows
*
- * Copyright (C) 2005-2007 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2005-2010 Gerhard Häring <gh@ghaering.de>
*
* This file is part of pysqlite.
*
diff --git a/Modules/_sqlite/sqlitecompat.h b/Modules/_sqlite/sqlitecompat.h
index c379825..3408fc2 100644
--- a/Modules/_sqlite/sqlitecompat.h
+++ b/Modules/_sqlite/sqlitecompat.h
@@ -1,6 +1,6 @@
/* sqlitecompat.h - compatibility macros
*
- * Copyright (C) 2006 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2006-2010 Gerhard Häring <gh@ghaering.de>
*
* This file is part of pysqlite.
*
@@ -21,6 +21,8 @@
* 3. This notice may not be removed or altered from any source distribution.
*/
+#include "Python.h"
+
#ifndef PYSQLITE_COMPAT_H
#define PYSQLITE_COMPAT_H
@@ -31,4 +33,31 @@ typedef int Py_ssize_t;
typedef int (*lenfunc)(PyObject*);
#endif
+
+/* define PyDict_CheckExact for pre-2.4 versions of Python */
+#ifndef PyDict_CheckExact
+#define PyDict_CheckExact(op) ((op)->ob_type == &PyDict_Type)
+#endif
+
+/* define Py_CLEAR for pre-2.4 versions of Python */
+#ifndef Py_CLEAR
+#define Py_CLEAR(op) \
+ do { \
+ if (op) { \
+ PyObject *tmp = (PyObject *)(op); \
+ (op) = NULL; \
+ Py_DECREF(tmp); \
+ } \
+ } while (0)
+#endif
+
+#ifndef PyVarObject_HEAD_INIT
+#define PyVarObject_HEAD_INIT(type, size) \
+ PyObject_HEAD_INIT(type) size,
+#endif
+
+#ifndef Py_TYPE
+#define Py_TYPE(ob) ((ob)->ob_type)
+#endif
+
#endif
diff --git a/Modules/_sqlite/statement.c b/Modules/_sqlite/statement.c
index f200c56..9d08f2b 100644
--- a/Modules/_sqlite/statement.c
+++ b/Modules/_sqlite/statement.c
@@ -1,6 +1,6 @@
/* statement.c - the statement type
*
- * Copyright (C) 2005-2007 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2005-2010 Gerhard Häring <gh@ghaering.de>
*
* This file is part of pysqlite.
*
diff --git a/Modules/_sqlite/statement.h b/Modules/_sqlite/statement.h
index bfa2091..05fd5ff 100644
--- a/Modules/_sqlite/statement.h
+++ b/Modules/_sqlite/statement.h
@@ -1,6 +1,6 @@
/* statement.h - definitions for the statement type
*
- * Copyright (C) 2005-2007 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2005-2010 Gerhard Häring <gh@ghaering.de>
*
* This file is part of pysqlite.
*
diff --git a/Modules/_sqlite/util.c b/Modules/_sqlite/util.c
index 6be39ae..6b57b76 100644
--- a/Modules/_sqlite/util.c
+++ b/Modules/_sqlite/util.c
@@ -1,6 +1,6 @@
/* util.c - various utility functions
*
- * Copyright (C) 2005-2007 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2005-2010 Gerhard Häring <gh@ghaering.de>
*
* This file is part of pysqlite.
*
diff --git a/Modules/_sqlite/util.h b/Modules/_sqlite/util.h
index 2a45636..4269003 100644
--- a/Modules/_sqlite/util.h
+++ b/Modules/_sqlite/util.h
@@ -1,6 +1,6 @@
/* util.h - various utility functions
*
- * Copyright (C) 2005-2007 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2005-2010 Gerhard Häring <gh@ghaering.de>
*
* This file is part of pysqlite.
*
diff --git a/setup.py b/setup.py
index 6327879..c65f286 100644
--- a/setup.py
+++ b/setup.py
@@ -955,6 +955,8 @@ class PyBuildExt(build_ext):
else:
sqlite_defines.append(('MODULE_NAME', '\\"sqlite3\\"'))
+ # Comment this out if you want the sqlite3 module to be able to load extensions.
+ sqlite_defines.append(("SQLITE_OMIT_LOAD_EXTENSION", "1"))
if sys.platform == 'darwin':
# In every directory on the search path search for a dynamic