Update to pysqlite 2.2.0
diff --git a/Lib/sqlite3/test/dbapi.py b/Lib/sqlite3/test/dbapi.py
index 0d47977..b08da9c 100644
--- a/Lib/sqlite3/test/dbapi.py
+++ b/Lib/sqlite3/test/dbapi.py
@@ -268,6 +268,12 @@
         self.cu.executemany("insert into test(name) values (?)", [(1,), (2,), (3,)])
         self.failUnlessEqual(self.cu.rowcount, 3)
 
+    def CheckTotalChanges(self):
+        self.cu.execute("insert into test(name) values ('foo')")
+        self.cu.execute("insert into test(name) values ('foo')")
+        if self.cx.total_changes < 2:
+            self.fail("total changes reported wrong value")
+
     # Checks for executemany:
     # Sequences are required by the DB-API, iterators
     # enhancements in pysqlite.
diff --git a/Lib/sqlite3/test/hooks.py b/Lib/sqlite3/test/hooks.py
new file mode 100644
index 0000000..21f7b88
--- /dev/null
+++ b/Lib/sqlite3/test/hooks.py
@@ -0,0 +1,115 @@
+#-*- coding: ISO-8859-1 -*-
+# pysqlite2/test/hooks.py: tests for various SQLite-specific hooks
+#
+# Copyright (C) 2006 Gerhard Häring <gh@ghaering.de>
+#
+# This file is part of pysqlite.
+#
+# This software is provided 'as-is', without any express or implied
+# warranty.  In no event will the authors be held liable for any damages
+# arising from the use of this software.
+#
+# Permission is granted to anyone to use this software for any purpose,
+# including commercial applications, and to alter it and redistribute it
+# freely, subject to the following restrictions:
+#
+# 1. The origin of this software must not be misrepresented; you must not
+#    claim that you wrote the original software. If you use this software
+#    in a product, an acknowledgment in the product documentation would be
+#    appreciated but is not required.
+# 2. Altered source versions must be plainly marked as such, and must not be
+#    misrepresented as being the original software.
+# 3. This notice may not be removed or altered from any source distribution.
+
+import os, unittest
+import pysqlite2.dbapi2 as sqlite
+
+class CollationTests(unittest.TestCase):
+    def setUp(self):
+        pass
+
+    def tearDown(self):
+        pass
+
+    def CheckCreateCollationNotCallable(self):
+        con = sqlite.connect(":memory:")
+        try:
+            con.create_collation("X", 42)
+            self.fail("should have raised a TypeError")
+        except TypeError, e:
+            self.failUnlessEqual(e.args[0], "parameter must be callable")
+
+    def CheckCreateCollationNotAscii(self):
+        con = sqlite.connect(":memory:")
+        try:
+            con.create_collation("collä", cmp)
+            self.fail("should have raised a ProgrammingError")
+        except sqlite.ProgrammingError, e:
+            pass
+
+    def CheckCollationIsUsed(self):
+        def mycoll(x, y):
+            # reverse order
+            return -cmp(x, y)
+
+        con = sqlite.connect(":memory:")
+        con.create_collation("mycoll", mycoll)
+        sql = """
+            select x from (
+            select 'a' as x
+            union
+            select 'b' as x
+            union
+            select 'c' as x
+            ) order by x collate mycoll
+            """
+        result = con.execute(sql).fetchall()
+        if result[0][0] != "c" or result[1][0] != "b" or result[2][0] != "a":
+            self.fail("the expected order was not returned")
+
+        con.create_collation("mycoll", None)
+        try:
+            result = con.execute(sql).fetchall()
+            self.fail("should have raised an OperationalError")
+        except sqlite.OperationalError, e:
+            self.failUnlessEqual(e.args[0], "no such collation sequence: mycoll")
+
+    def CheckCollationRegisterTwice(self):
+        """
+        Register two different collation functions under the same name.
+        Verify that the last one is actually used.
+        """
+        con = sqlite.connect(":memory:")
+        con.create_collation("mycoll", cmp)
+        con.create_collation("mycoll", lambda x, y: -cmp(x, y))
+        result = con.execute("""
+            select x from (select 'a' as x union select 'b' as x) order by x collate mycoll
+            """).fetchall()
+        if result[0][0] != 'b' or result[1][0] != 'a':
+            self.fail("wrong collation function is used")
+
+    def CheckDeregisterCollation(self):
+        """
+        Register a collation, then deregister it. Make sure an error is raised if we try
+        to use it.
+        """
+        con = sqlite.connect(":memory:")
+        con.create_collation("mycoll", cmp)
+        con.create_collation("mycoll", None)
+        try:
+            con.execute("select 'a' as x union select 'b' as x order by x collate mycoll")
+            self.fail("should have raised an OperationalError")
+        except sqlite.OperationalError, e:
+            if not e.args[0].startswith("no such collation sequence"):
+                self.fail("wrong OperationalError raised")
+
+def suite():
+    collation_suite = unittest.makeSuite(CollationTests, "Check")
+    return unittest.TestSuite((collation_suite,))
+
+def test():
+    runner = unittest.TextTestRunner()
+    runner.run(suite())
+
+if __name__ == "__main__":
+    test()
diff --git a/Lib/sqlite3/test/regression.py b/Lib/sqlite3/test/regression.py
new file mode 100644
index 0000000..648ada5
--- /dev/null
+++ b/Lib/sqlite3/test/regression.py
@@ -0,0 +1,48 @@
+#-*- coding: ISO-8859-1 -*-
+# pysqlite2/test/regression.py: pysqlite regression tests
+#
+# Copyright (C) 2006 Gerhard Häring <gh@ghaering.de>
+#
+# This file is part of pysqlite.
+#
+# This software is provided 'as-is', without any express or implied
+# warranty.  In no event will the authors be held liable for any damages
+# arising from the use of this software.
+#
+# Permission is granted to anyone to use this software for any purpose,
+# including commercial applications, and to alter it and redistribute it
+# freely, subject to the following restrictions:
+#
+# 1. The origin of this software must not be misrepresented; you must not
+#    claim that you wrote the original software. If you use this software
+#    in a product, an acknowledgment in the product documentation would be
+#    appreciated but is not required.
+# 2. Altered source versions must be plainly marked as such, and must not be
+#    misrepresented as being the original software.
+# 3. This notice may not be removed or altered from any source distribution.
+
+import unittest
+import pysqlite2.dbapi2 as sqlite
+
+class RegressionTests(unittest.TestCase):
+    def setUp(self):
+        self.con = sqlite.connect(":memory:")
+
+    def tearDown(self):
+        self.con.close()
+
+    def CheckPragmaUserVersion(self):
+        # This used to crash pysqlite because this pragma command returns NULL for the column name
+        cur = self.con.cursor()
+        cur.execute("pragma user_version")
+
+def suite():
+    regression_suite = unittest.makeSuite(RegressionTests, "Check")
+    return unittest.TestSuite((regression_suite,))
+
+def test():
+    runner = unittest.TextTestRunner()
+    runner.run(suite())
+
+if __name__ == "__main__":
+    test()
diff --git a/Lib/sqlite3/test/transactions.py b/Lib/sqlite3/test/transactions.py
index 28202cb..1f0b19a 100644
--- a/Lib/sqlite3/test/transactions.py
+++ b/Lib/sqlite3/test/transactions.py
@@ -25,7 +25,7 @@
 import sqlite3 as sqlite
 
 def get_db_path():
-    return "testdb"
+    return "sqlite_testdb"
 
 class TransactionTests(unittest.TestCase):
     def setUp(self):
@@ -47,6 +47,8 @@
         self.cur2.close()
         self.con2.close()
 
+        os.unlink(get_db_path())
+
     def CheckDMLdoesAutoCommitBefore(self):
         self.cur1.execute("create table test(i)")
         self.cur1.execute("insert into test(i) values (5)")
diff --git a/Modules/_sqlite/cache.c b/Modules/_sqlite/cache.c
index 0c7d4a3..d36b52b 100644
--- a/Modules/_sqlite/cache.c
+++ b/Modules/_sqlite/cache.c
@@ -1,6 +1,6 @@
 /* cache .c - a LRU cache
  *
- * Copyright (C) 2004-2005 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2004-2006 Gerhard Häring <gh@ghaering.de>
  *
  * This file is part of pysqlite.
  *
@@ -29,7 +29,6 @@
     Node* node;
 
     node = (Node*) (NodeType.tp_alloc(&NodeType, 0));
-    /*node = PyObject_New(Node, &NodeType);*/
     if (!node) {
         return NULL;
     }
@@ -72,7 +71,12 @@
     self->size = size;
     self->first = NULL;
     self->last = NULL;
+
     self->mapping = PyDict_New();
+    if (!self->mapping) {
+        return -1;
+    }
+
     Py_INCREF(factory);
     self->factory = factory;
 
@@ -108,16 +112,11 @@
 
 PyObject* cache_get(Cache* self, PyObject* args)
 {
-    PyObject* key;
+    PyObject* key = args;
     Node* node;
     Node* ptr;
     PyObject* data;
 
-    if (!PyArg_ParseTuple(args, "O", &key))
-    {
-        return NULL; 
-    }
-
     node = (Node*)PyDict_GetItem(self->mapping, key);
     if (node) {
         node->count++;
@@ -153,7 +152,11 @@
         if (PyDict_Size(self->mapping) == self->size) {
             if (self->last) {
                 node = self->last;
-                PyDict_DelItem(self->mapping, self->last->key);
+
+                if (PyDict_DelItem(self->mapping, self->last->key) != 0) {
+                    return NULL;
+                }
+
                 if (node->prev) {
                     node->prev->next = NULL;
                 }
@@ -171,17 +174,24 @@
         }
 
         node = new_node(key, data);
+        if (!node) {
+            return NULL;
+        }
         node->prev = self->last;
 
         Py_DECREF(data);
 
+        if (PyDict_SetItem(self->mapping, key, (PyObject*)node) != 0) {
+            Py_DECREF(node);
+            return NULL;
+        }
+
         if (self->last) {
             self->last->next = node;
         } else {
             self->first = node;
         }
         self->last = node;
-        PyDict_SetItem(self->mapping, key, (PyObject*)node);
     }
 
     Py_INCREF(node->data);
@@ -215,10 +225,19 @@
         Py_INCREF(nextkey);
 
         fmt_args = Py_BuildValue("OOO", prevkey, ptr->key, nextkey);
+        if (!fmt_args) {
+            return NULL;
+        }
         template = PyString_FromString("%s <- %s ->%s\n");
+        if (!template) {
+            return NULL;
+        }
         display_str = PyString_Format(template, fmt_args);
         Py_DECREF(template);
         Py_DECREF(fmt_args);
+        if (!display_str) {
+            return NULL;
+        }
         PyObject_Print(display_str, stdout, Py_PRINT_RAW);
         Py_DECREF(display_str);
 
@@ -233,7 +252,7 @@
 }
 
 static PyMethodDef cache_methods[] = {
-    {"get", (PyCFunction)cache_get, METH_VARARGS,
+    {"get", (PyCFunction)cache_get, METH_O,
         PyDoc_STR("Gets an entry from the cache.")},
     {"display", (PyCFunction)cache_display, METH_NOARGS,
         PyDoc_STR("For debugging only.")},
diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c
index 0445b38..3e97f6e 100644
--- a/Modules/_sqlite/connection.c
+++ b/Modules/_sqlite/connection.c
@@ -3,7 +3,7 @@
  * Copyright (C) 2004-2006 Gerhard Häring <gh@ghaering.de>
  *
  * This file is part of pysqlite.
- *
+ * 
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
  * arising from the use of this software.
@@ -28,6 +28,8 @@
 #include "cursor.h"
 #include "prepare_protocol.h"
 #include "util.h"
+#include "sqlitecompat.h"
+
 #include "pythread.h"
 
 static int connection_set_isolation_level(Connection* self, PyObject* isolation_level);
@@ -101,6 +103,14 @@
     self->check_same_thread = check_same_thread;
 
     self->function_pinboard = PyDict_New();
+    if (!self->function_pinboard) {
+        return -1;
+    }
+
+    self->collations = PyDict_New();
+    if (!self->collations) {
+        return -1;
+    }
 
     self->Warning = Warning;
     self->Error = Error;
@@ -167,6 +177,7 @@
     Py_XDECREF(self->function_pinboard);
     Py_XDECREF(self->row_factory);
     Py_XDECREF(self->text_factory);
+    Py_XDECREF(self->collations);
 
     self->ob_type->tp_free((PyObject*)self);
 }
@@ -420,6 +431,9 @@
     void* raw_buffer;
 
     args = PyTuple_New(argc);
+    if (!args) {
+        return NULL;
+    }
 
     for (i = 0; i < argc; i++) {
         cur_value = argv[i];
@@ -655,6 +669,15 @@
     return self->isolation_level;
 }
 
+static PyObject* connection_get_total_changes(Connection* self, void* unused)
+{
+    if (!check_connection(self)) {
+        return NULL;
+    } else {
+        return Py_BuildValue("i", sqlite3_total_changes(self->db));
+    }
+}
+
 static int connection_set_isolation_level(Connection* self, PyObject* isolation_level)
 {
     PyObject* empty;
@@ -669,7 +692,13 @@
         self->isolation_level = Py_None;
 
         empty = PyTuple_New(0);
+        if (!empty) {
+            return -1;
+        }
         res = connection_commit(self, empty);
+        if (!res) {
+            return -1;
+        }
         Py_DECREF(empty);
         Py_DECREF(res);
 
@@ -825,11 +854,134 @@
     return cursor;
 }
 
+/* ------------------------- COLLATION CODE ------------------------ */
+
+static int
+collation_callback(
+        void* context,
+        int text1_length, const void* text1_data,
+        int text2_length, const void* text2_data)
+{
+    PyObject* callback = (PyObject*)context;
+    PyObject* string1 = 0;
+    PyObject* string2 = 0;
+    PyGILState_STATE gilstate;
+
+    PyObject* retval = NULL;
+    int result = 0;
+
+    gilstate = PyGILState_Ensure();
+
+    if (PyErr_Occurred()) {
+        goto finally;
+    }
+
+    string1 = PyString_FromStringAndSize((const char*)text1_data, text1_length);
+    string2 = PyString_FromStringAndSize((const char*)text2_data, text2_length);
+
+    if (!string1 || !string2) {
+        goto finally; /* failed to allocate strings */
+    }
+
+    retval = PyObject_CallFunctionObjArgs(callback, string1, string2, NULL);
+
+    if (!retval) {
+        /* execution failed */
+        goto finally;
+    }
+
+    result = PyInt_AsLong(retval);
+    if (PyErr_Occurred()) {
+        result = 0;
+    }
+
+finally:
+    Py_XDECREF(string1);
+    Py_XDECREF(string2);
+    Py_XDECREF(retval);
+
+    PyGILState_Release(gilstate);
+
+    return result;
+}
+
+static PyObject *
+connection_create_collation(Connection* self, PyObject* args)
+{
+    PyObject* callable;
+    PyObject* uppercase_name = 0;
+    PyObject* name;
+    PyObject* retval;
+    char* chk;
+    int rc;
+
+    if (!check_thread(self) || !check_connection(self)) {
+        goto finally;
+    }
+
+    if (!PyArg_ParseTuple(args, "O!O:create_collation(name, callback)", &PyString_Type, &name, &callable)) {
+        goto finally;
+    }
+
+    uppercase_name = PyObject_CallMethod(name, "upper", "");
+    if (!uppercase_name) {
+        goto finally;
+    }
+
+    chk = PyString_AsString(uppercase_name);
+    while (*chk) {
+        if ((*chk >= '0' && *chk <= '9')
+         || (*chk >= 'A' && *chk <= 'Z')
+         || (*chk == '_'))
+        {
+            chk++;
+        } else {
+            PyErr_SetString(ProgrammingError, "invalid character in collation name");
+            goto finally;
+        }
+    }
+
+    if (callable != Py_None && !PyCallable_Check(callable)) {
+        PyErr_SetString(PyExc_TypeError, "parameter must be callable");
+        goto finally;
+    }
+
+    if (callable != Py_None) {
+        PyDict_SetItem(self->collations, uppercase_name, callable);
+    } else {
+        PyDict_DelItem(self->collations, uppercase_name);
+    }
+
+    rc = sqlite3_create_collation(self->db,
+                                  PyString_AsString(uppercase_name),
+                                  SQLITE_UTF8,
+                                  (callable != Py_None) ? callable : NULL,
+                                  (callable != Py_None) ? collation_callback : NULL);
+    if (rc != SQLITE_OK) {
+        PyDict_DelItem(self->collations, uppercase_name);
+        _seterror(self->db);
+        goto finally;
+    }
+
+finally:
+    Py_XDECREF(uppercase_name);
+
+    if (PyErr_Occurred()) {
+        retval = NULL;
+    } else {
+        Py_INCREF(Py_None);
+        retval = Py_None;
+    }
+
+    return retval;
+}
+
 static char connection_doc[] =
 PyDoc_STR("<missing docstring>");
 
 static PyGetSetDef connection_getset[] = {
     {"isolation_level",  (getter)connection_get_isolation_level, (setter)connection_set_isolation_level},
+    {"total_changes",  (getter)connection_get_total_changes, (setter)0},
     {NULL}
 };
 
@@ -852,6 +1004,8 @@
         PyDoc_STR("Repeatedly executes a SQL statement. Non-standard.")},
     {"executescript", (PyCFunction)connection_executescript, METH_VARARGS,
         PyDoc_STR("Executes a multiple SQL statements at once. Non-standard.")},
+    {"create_collation", (PyCFunction)connection_create_collation, METH_VARARGS,
+        PyDoc_STR("Creates a collation function.")},
     {NULL, NULL}
 };
 
diff --git a/Modules/_sqlite/connection.h b/Modules/_sqlite/connection.h
index ef03bc4..faae6e4 100644
--- a/Modules/_sqlite/connection.h
+++ b/Modules/_sqlite/connection.h
@@ -69,6 +69,9 @@
      * in connection_dealloc */
     PyObject* function_pinboard;
 
+    /* a dictionary of registered collation name => collation callable mappings */
+    PyObject* collations;
+
     /* Exception objects */
     PyObject* Warning;
     PyObject* Error;
diff --git a/Modules/_sqlite/cursor.c b/Modules/_sqlite/cursor.c
index fe6cff9..e68a275 100644
--- a/Modules/_sqlite/cursor.c
+++ b/Modules/_sqlite/cursor.c
@@ -24,6 +24,7 @@
 #include "cursor.h"
 #include "module.h"
 #include "util.h"
+#include "sqlitecompat.h"
 
 /* used to decide wether to call PyInt_FromLong or PyLong_FromLongLong */
 #define INT32_MIN (-2147483647 - 1)
@@ -84,6 +85,9 @@
     self->next_row = NULL;
 
     self->row_cast_map = PyList_New(0);
+    if (!self->row_cast_map) {
+        return -1;
+    }
 
     Py_INCREF(Py_None);
     self->description = Py_None;
@@ -94,6 +98,9 @@
     self->arraysize = 1;
 
     self->rowcount = PyInt_FromLong(-1L);
+    if (!self->rowcount) {
+        return -1;
+    }
 
     Py_INCREF(Py_None);
     self->row_factory = Py_None;
@@ -126,7 +133,7 @@
     self->ob_type->tp_free((PyObject*)self);
 }
 
-void build_row_cast_map(Cursor* self)
+int build_row_cast_map(Cursor* self)
 {
     int i;
     const char* type_start = (const char*)-1;
@@ -139,10 +146,10 @@
     PyObject* key;
 
     if (!self->connection->detect_types) {
-        return;
+        return 0;
     }
 
-    Py_DECREF(self->row_cast_map);
+    Py_XDECREF(self->row_cast_map);
     self->row_cast_map = PyList_New(0);
 
     for (i = 0; i < sqlite3_column_count(self->statement->st); i++) {
@@ -156,6 +163,13 @@
                     type_start = pos + 1;
                 } else if (*pos == ']' && type_start != (const char*)-1) {
                     key = PyString_FromStringAndSize(type_start, pos - type_start);
+                    if (!key) {
+                        /* creating a string failed, but it is too complicated
+                         * to propagate the error here, we just assume there is
+                         * no converter and proceed */
+                        break;
+                    }
+
                     converter = PyDict_GetItem(converters, key);
                     Py_DECREF(key);
                     break;
@@ -170,6 +184,9 @@
                 for (pos = decltype;;pos++) {
                     if (*pos == ' ' || *pos == 0) {
                         py_decltype = PyString_FromStringAndSize(decltype, pos - decltype);
+                        if (!py_decltype) {
+                            return -1;
+                        }
                         break;
                     }
                 }
@@ -179,18 +196,33 @@
             }
         }
 
-        if (converter) {
-            PyList_Append(self->row_cast_map, converter);
-        } else {
-            PyList_Append(self->row_cast_map, Py_None);
+        if (!converter) {
+            converter = Py_None;
+        }
+
+        if (PyList_Append(self->row_cast_map, converter) != 0) {
+            if (converter != Py_None) {
+                Py_DECREF(converter);
+            }
+            Py_XDECREF(self->row_cast_map);
+            self->row_cast_map = NULL;
+
+            return -1;
         }
     }
+
+    return 0;
 }
 
 PyObject* _build_column_name(const char* colname)
 {
     const char* pos;
 
+    if (!colname) {
+        Py_INCREF(Py_None);
+        return Py_None;
+    }
+
     for (pos = colname;; pos++) {
         if (*pos == 0 || *pos == ' ') {
             return PyString_FromStringAndSize(colname, pos - colname);
@@ -250,6 +282,9 @@
     Py_END_ALLOW_THREADS
 
     row = PyTuple_New(numcols);
+    if (!row) {
+        return NULL;
+    }
 
     for (i = 0; i < numcols; i++) {
         if (self->connection->detect_types) {
@@ -268,6 +303,9 @@
                 converted = Py_None;
             } else {
                 item = PyString_FromString(val_str);
+                if (!item) {
+                    return NULL;
+                }
                 converted = PyObject_CallFunction(converter, "O", item);
                 if (!converted) {
                     /* TODO: have a way to log these errors */
@@ -404,10 +442,16 @@
 
         if (second_argument == NULL) {
             second_argument = PyTuple_New(0);
+            if (!second_argument) {
+                return NULL;
+            }
         } else {
             Py_INCREF(second_argument);
         }
-        PyList_Append(parameters_list, second_argument);
+        if (PyList_Append(parameters_list, second_argument) != 0) {
+            Py_DECREF(second_argument);
+            return NULL;
+        }
         Py_DECREF(second_argument);
 
         parameters_iter = PyObject_GetIter(parameters_list);
@@ -436,6 +480,9 @@
 
     Py_DECREF(self->rowcount);
     self->rowcount = PyInt_FromLong(-1L);
+    if (!self->rowcount) {
+        goto error;
+    }
 
     statement_type = detect_statement_type(operation_cstr);
     if (self->connection->begin_statement) {
@@ -457,6 +504,9 @@
                    - we better COMMIT first so it works for all cases */
                 if (self->connection->inTransaction) {
                     func_args = PyTuple_New(0);
+                    if (!func_args) {
+                        goto error;
+                    }
                     result = connection_commit(self->connection, func_args);
                     Py_DECREF(func_args);
                     if (!result) {
@@ -471,12 +521,18 @@
                                 "You cannot execute SELECT statements in executemany().");
                     goto error;
                 }
+                break;
         }
     }
 
     func_args = PyTuple_New(1);
+    if (!func_args) {
+        goto error;
+    }
     Py_INCREF(operation);
-    PyTuple_SetItem(func_args, 0, operation);
+    if (PyTuple_SetItem(func_args, 0, operation) != 0) {
+        goto error;
+    }
 
     if (self->statement) {
         (void)statement_reset(self->statement);
@@ -493,6 +549,9 @@
     if (self->statement->in_use) {
         Py_DECREF(self->statement);
         self->statement = PyObject_New(Statement, &StatementType);
+        if (!self->statement) {
+            goto error;
+        }
         rc = statement_create(self->statement, self->connection, operation);
         if (rc != SQLITE_OK) {
             self->statement = 0;
@@ -516,7 +575,10 @@
             goto error;
         }
 
-        build_row_cast_map(self);
+        if (build_row_cast_map(self) != 0) {
+            PyErr_SetString(OperationalError, "Error while building row_cast_map");
+            goto error;
+        }
 
         rc = _sqlite_step_with_busyhandler(self->statement->st, self->connection);
         if (rc != SQLITE_DONE && rc != SQLITE_ROW) {
@@ -543,8 +605,14 @@
             if (self->description == Py_None) {
                 Py_DECREF(self->description);
                 self->description = PyTuple_New(numcols);
+                if (!self->description) {
+                    goto error;
+                }
                 for (i = 0; i < numcols; i++) {
                     descriptor = PyTuple_New(7);
+                    if (!descriptor) {
+                        goto error;
+                    }
                     PyTuple_SetItem(descriptor, 0, _build_column_name(sqlite3_column_name(self->statement->st, i)));
                     Py_INCREF(Py_None); PyTuple_SetItem(descriptor, 1, Py_None);
                     Py_INCREF(Py_None); PyTuple_SetItem(descriptor, 2, Py_None);
@@ -608,8 +676,8 @@
     if (PyErr_Occurred()) {
         return NULL;
     } else {
-        Py_INCREF(Py_None);
-        return Py_None;
+        Py_INCREF(self);
+        return (PyObject*)self;
     }
 }
 
@@ -658,6 +726,9 @@
 
     /* commit first */
     func_args = PyTuple_New(0);
+    if (!func_args) {
+        goto error;
+    }
     result = connection_commit(self->connection, func_args);
     Py_DECREF(func_args);
     if (!result) {
@@ -710,8 +781,8 @@
     if (PyErr_Occurred()) {
         return NULL;
     } else {
-        Py_INCREF(Py_None);
-        return Py_None;
+        Py_INCREF(self);
+        return (PyObject*)self;
     }
 }
 
@@ -789,9 +860,12 @@
     }
 
     list = PyList_New(0);
+    if (!list) {
+        return NULL;
+    }
 
     /* just make sure we enter the loop */
-    row = (PyObject*)1;
+    row = Py_None;
 
     while (row) {
         row = cursor_iternext(self);
@@ -821,9 +895,12 @@
     PyObject* list;
 
     list = PyList_New(0);
+    if (!list) {
+        return NULL;
+    }
 
     /* just make sure we enter the loop */
-    row = (PyObject*)1;
+    row = (PyObject*)Py_None;
 
     while (row) {
         row = cursor_iternext(self);
diff --git a/Modules/_sqlite/microprotocols.c b/Modules/_sqlite/microprotocols.c
index 5df41a1..5040acd 100644
--- a/Modules/_sqlite/microprotocols.c
+++ b/Modules/_sqlite/microprotocols.c
@@ -45,9 +45,7 @@
         return -1;
     }
 
-    PyDict_SetItemString(dict, "adapters", psyco_adapters);
-
-    return 0;
+    return PyDict_SetItemString(dict, "adapters", psyco_adapters);
 }
 
 
@@ -65,8 +63,17 @@
             cast, type->tp_name);
     */
 
+
     key = Py_BuildValue("(OO)", (PyObject*)type, proto);
-    PyDict_SetItem(psyco_adapters, key, cast);
+    if (!key) {
+        return -1;
+    }
+
+    if (PyDict_SetItem(psyco_adapters, key, cast) != 0) {
+        Py_DECREF(key);
+        return -1;
+    }
+
     Py_DECREF(key);
 
     return 0;
@@ -85,6 +92,9 @@
 
     /* look for an adapter in the registry */
     key = Py_BuildValue("(OO)", (PyObject*)obj->ob_type, proto);
+    if (!key) {
+        return NULL;
+    }
     adapter = PyDict_GetItem(psyco_adapters, key);
     Py_DECREF(key);
     if (adapter) {
diff --git a/Modules/_sqlite/module.c b/Modules/_sqlite/module.c
index 70993d0..60d0d63 100644
--- a/Modules/_sqlite/module.c
+++ b/Modules/_sqlite/module.c
@@ -39,9 +39,6 @@
     *OperationalError, *ProgrammingError, *IntegrityError, *DataError,
     *NotSupportedError, *OptimizedUnicode;
 
-PyObject* time_time;
-PyObject* time_sleep;
-
 PyObject* converters;
 
 static PyObject* module_connect(PyObject* self, PyObject* args, PyObject*
@@ -150,7 +147,9 @@
         return NULL;
     }
 
-    PyDict_SetItem(converters, name, callable);
+    if (PyDict_SetItem(converters, name, callable) != 0) {
+        return NULL;
+    }
 
     Py_INCREF(Py_None);
     return Py_None;
@@ -159,6 +158,9 @@
 void converters_init(PyObject* dict)
 {
     converters = PyDict_New();
+    if (!converters) {
+        return;
+    }
 
     PyDict_SetItemString(dict, "converters", converters);
 }
@@ -169,8 +171,8 @@
 #ifdef HAVE_SHARED_CACHE
     {"enable_shared_cache",  (PyCFunction)module_enable_shared_cache,  METH_VARARGS|METH_KEYWORDS, PyDoc_STR("Enable or disable shared cache mode for the calling thread.")},
 #endif
-    {"register_adapter", (PyCFunction)module_register_adapter, METH_VARARGS, PyDoc_STR("Registers an adapter with pysqlite's adapter registry.")},
-    {"register_converter", (PyCFunction)module_register_converter, METH_VARARGS, PyDoc_STR("Registers a converter with pysqlite.")},
+    {"register_adapter", (PyCFunction)module_register_adapter, METH_VARARGS, PyDoc_STR("Registers an adapter with sqlite's adapter registry.")},
+    {"register_converter", (PyCFunction)module_register_converter, METH_VARARGS, PyDoc_STR("Registers a converter with sqlite.")},
     {"adapt",  (PyCFunction)psyco_microprotocols_adapt, METH_VARARGS, psyco_microprotocols_adapt_doc},
     {NULL, NULL}
 };
@@ -178,11 +180,11 @@
 PyMODINIT_FUNC init_sqlite3(void)
 {
     PyObject *module, *dict;
-    PyObject* time_module;
+    PyObject *tmp_obj;
 
     module = Py_InitModule("_sqlite3", module_methods);
 
-    if (
+    if (!module ||
         (row_setup_types() < 0) ||
         (cursor_setup_types() < 0) ||
         (connection_setup_types() < 0) ||
@@ -206,56 +208,93 @@
     Py_INCREF(&RowType);
     PyModule_AddObject(module, "Row", (PyObject*) &RowType);
 
-    if (!(dict = PyModule_GetDict(module)))
-    {
+    if (!(dict = PyModule_GetDict(module))) {
         goto error;
     }
 
     /*** Create DB-API Exception hierarchy */
 
-    Error = PyErr_NewException("sqlite3.Error", PyExc_StandardError, NULL);
+    if (!(Error = PyErr_NewException("sqlite3.Error", PyExc_StandardError, NULL))) {
+        goto error;
+    }
     PyDict_SetItemString(dict, "Error", Error);
 
-    Warning = PyErr_NewException("sqlite3.Warning", PyExc_StandardError, NULL);
+    if (!(Warning = PyErr_NewException("sqlite3.Warning", PyExc_StandardError, NULL))) {
+        goto error;
+    }
     PyDict_SetItemString(dict, "Warning", Warning);
 
     /* Error subclasses */
 
-    InterfaceError = PyErr_NewException("sqlite3.InterfaceError", Error, NULL);
+    if (!(InterfaceError = PyErr_NewException("sqlite3.InterfaceError", Error, NULL))) {
+        goto error;
+    }
     PyDict_SetItemString(dict, "InterfaceError", InterfaceError);
 
-    DatabaseError = PyErr_NewException("sqlite3.DatabaseError", Error, NULL);
+    if (!(DatabaseError = PyErr_NewException("sqlite3.DatabaseError", Error, NULL))) {
+        goto error;
+    }
     PyDict_SetItemString(dict, "DatabaseError", DatabaseError);
 
     /* DatabaseError subclasses */
 
-    InternalError = PyErr_NewException("sqlite3.InternalError", DatabaseError, NULL);
+    if (!(InternalError = PyErr_NewException("sqlite3.InternalError", DatabaseError, NULL))) {
+        goto error;
+    }
     PyDict_SetItemString(dict, "InternalError", InternalError);
 
-    OperationalError = PyErr_NewException("sqlite3.OperationalError", DatabaseError, NULL);
+    if (!(OperationalError = PyErr_NewException("sqlite3.OperationalError", DatabaseError, NULL))) {
+        goto error;
+    }
     PyDict_SetItemString(dict, "OperationalError", OperationalError);
 
-    ProgrammingError = PyErr_NewException("sqlite3.ProgrammingError", DatabaseError, NULL);
+    if (!(ProgrammingError = PyErr_NewException("sqlite3.ProgrammingError", DatabaseError, NULL))) {
+        goto error;
+    }
     PyDict_SetItemString(dict, "ProgrammingError", ProgrammingError);
 
-    IntegrityError = PyErr_NewException("sqlite3.IntegrityError", DatabaseError,NULL);
+    if (!(IntegrityError = PyErr_NewException("sqlite3.IntegrityError", DatabaseError,NULL))) {
+        goto error;
+    }
     PyDict_SetItemString(dict, "IntegrityError", IntegrityError);
 
-    DataError = PyErr_NewException("sqlite3.DataError", DatabaseError, NULL);
+    if (!(DataError = PyErr_NewException("sqlite3.DataError", DatabaseError, NULL))) {
+        goto error;
+    }
     PyDict_SetItemString(dict, "DataError", DataError);
 
-    NotSupportedError = PyErr_NewException("sqlite3.NotSupportedError", DatabaseError, NULL);
+    if (!(NotSupportedError = PyErr_NewException("sqlite3.NotSupportedError", DatabaseError, NULL))) {
+        goto error;
+    }
     PyDict_SetItemString(dict, "NotSupportedError", NotSupportedError);
 
+    /* We just need "something" unique for OptimizedUnicode. It does not really
+     * need to be a string subclass. Just anything that can act as a special
+     * marker for us. So I pulled PyCell_Type out of my magic hat.
+     */
     Py_INCREF((PyObject*)&PyCell_Type);
     OptimizedUnicode = (PyObject*)&PyCell_Type;
     PyDict_SetItemString(dict, "OptimizedUnicode", OptimizedUnicode);
 
-    PyDict_SetItemString(dict, "PARSE_DECLTYPES", PyInt_FromLong(PARSE_DECLTYPES));
-    PyDict_SetItemString(dict, "PARSE_COLNAMES", PyInt_FromLong(PARSE_COLNAMES));
+    if (!(tmp_obj = PyInt_FromLong(PARSE_DECLTYPES))) {
+        goto error;
+    }
+    PyDict_SetItemString(dict, "PARSE_DECLTYPES", tmp_obj);
 
-    PyDict_SetItemString(dict, "version", PyString_FromString(PYSQLITE_VERSION));
-    PyDict_SetItemString(dict, "sqlite_version", PyString_FromString(sqlite3_libversion()));
+    if (!(tmp_obj = PyInt_FromLong(PARSE_COLNAMES))) {
+        goto error;
+    }
+    PyDict_SetItemString(dict, "PARSE_COLNAMES", tmp_obj);
+
+    if (!(tmp_obj = PyString_FromString(PYSQLITE_VERSION))) {
+        goto error;
+    }
+    PyDict_SetItemString(dict, "version", tmp_obj);
+
+    if (!(tmp_obj = PyString_FromString(sqlite3_libversion()))) {
+        goto error;
+    }
+    PyDict_SetItemString(dict, "sqlite_version", tmp_obj);
 
     /* initialize microprotocols layer */
     microprotocols_init(dict);
@@ -263,10 +302,6 @@
     /* initialize the default converters */
     converters_init(dict);
 
-    time_module = PyImport_ImportModule("time");
-    time_time =  PyObject_GetAttrString(time_module, "time");
-    time_sleep = PyObject_GetAttrString(time_module, "sleep");
-
     /* Original comment form _bsddb.c in the Python core. This is also still
      * needed nowadays for Python 2.3/2.4.
      * 
diff --git a/Modules/_sqlite/prepare_protocol.c b/Modules/_sqlite/prepare_protocol.c
index 2e8349c..522f1d1 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 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2005-2006 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 61de801..77c7896 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 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2005-2006 Gerhard Häring <gh@ghaering.de>
  *
  * This file is part of pysqlite.
  *
@@ -23,6 +23,7 @@
 
 #include "row.h"
 #include "cursor.h"
+#include "sqlitecompat.h"
 
 void row_dealloc(Row* self)
 {
@@ -78,9 +79,12 @@
     if (PyInt_Check(idx)) {
         _idx = PyInt_AsLong(idx);
         item = PyTuple_GetItem(self->data, _idx);
-        if (item) {
-            Py_INCREF(item);
-        }
+        Py_XINCREF(item);
+        return item;
+    } else if (PyLong_Check(idx)) {
+        _idx = PyLong_AsLong(idx);
+        item = PyTuple_GetItem(self->data, _idx);
+        Py_XINCREF(item);
         return item;
     } else if (PyString_Check(idx)) {
         key = PyString_AsString(idx);
@@ -89,6 +93,9 @@
 
         for (i = 0; i < nitems; i++) {
             compare_key = PyString_AsString(PyTuple_GET_ITEM(PyTuple_GET_ITEM(self->description, i), 0));
+            if (!compare_key) {
+                return NULL;
+            }
 
             p1 = key;
             p2 = compare_key;
diff --git a/Modules/_sqlite/sqlitecompat.h b/Modules/_sqlite/sqlitecompat.h
new file mode 100644
index 0000000..c379825
--- /dev/null
+++ b/Modules/_sqlite/sqlitecompat.h
@@ -0,0 +1,34 @@
+/* sqlitecompat.h - compatibility macros
+ *
+ * Copyright (C) 2006 Gerhard Häring <gh@ghaering.de>
+ *
+ * This file is part of pysqlite.
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+
+#ifndef PYSQLITE_COMPAT_H
+#define PYSQLITE_COMPAT_H
+
+/* define Py_ssize_t for pre-2.5 versions of Python */
+
+#if PY_VERSION_HEX < 0x02050000
+typedef int Py_ssize_t;
+typedef int (*lenfunc)(PyObject*);
+#endif
+
+#endif
diff --git a/Modules/_sqlite/statement.c b/Modules/_sqlite/statement.c
index 4a957d6..ae48b4b 100644
--- a/Modules/_sqlite/statement.c
+++ b/Modules/_sqlite/statement.c
@@ -26,6 +26,7 @@
 #include "connection.h"
 #include "microprotocols.h"
 #include "prepare_protocol.h"
+#include "sqlitecompat.h"
 
 /* prototypes */
 int check_remaining_sql(const char* tail);
diff --git a/Modules/_sqlite/util.c b/Modules/_sqlite/util.c
index ec400a1..33748a6 100644
--- a/Modules/_sqlite/util.c
+++ b/Modules/_sqlite/util.c
@@ -1,6 +1,6 @@
 /* util.c - various utility functions
  *
- * Copyright (C) 2005 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2005-2006 Gerhard Häring <gh@ghaering.de>
  *
  * This file is part of pysqlite.
  *
@@ -24,30 +24,6 @@
 #include "module.h"
 #include "connection.h"
 
-/*
- * it's not so trivial to write a portable sleep in C. For now, the simplest
- * solution is to just use Python's sleep().
- */
-void pysqlite_sleep(double seconds)
-{
-    PyObject* ret;
-
-    ret = PyObject_CallFunction(time_sleep, "d", seconds);
-    Py_DECREF(ret);
-}
-
-double pysqlite_time(void)
-{
-    PyObject* ret;
-    double time;
-
-    ret = PyObject_CallFunction(time_time, "");
-    time = PyFloat_AsDouble(ret);
-    Py_DECREF(ret);
-
-    return time;
-}
-
 int _sqlite_step_with_busyhandler(sqlite3_stmt* statement, Connection* connection
 )
 {
@@ -75,63 +51,35 @@
         case SQLITE_OK:
             PyErr_Clear();
             break;
-        case SQLITE_ERROR:
-            PyErr_SetString(OperationalError, sqlite3_errmsg(db));
-            break;
         case SQLITE_INTERNAL:
+        case SQLITE_NOTFOUND:
             PyErr_SetString(InternalError, sqlite3_errmsg(db));
             break;
-        case SQLITE_PERM:
-            PyErr_SetString(OperationalError, sqlite3_errmsg(db));
-            break;
-        case SQLITE_ABORT:
-            PyErr_SetString(OperationalError, sqlite3_errmsg(db));
-            break;
-        case SQLITE_BUSY:
-            PyErr_SetString(OperationalError, sqlite3_errmsg(db));
-            break;
-        case SQLITE_LOCKED:
-            PyErr_SetString(OperationalError, sqlite3_errmsg(db));
-            break;
         case SQLITE_NOMEM:
             (void)PyErr_NoMemory();
             break;
+        case SQLITE_ERROR:
+        case SQLITE_PERM:
+        case SQLITE_ABORT:
+        case SQLITE_BUSY:
+        case SQLITE_LOCKED:
         case SQLITE_READONLY:
-            PyErr_SetString(OperationalError, sqlite3_errmsg(db));
-            break;
         case SQLITE_INTERRUPT:
-            PyErr_SetString(OperationalError, sqlite3_errmsg(db));
-            break;
         case SQLITE_IOERR:
+        case SQLITE_FULL:
+        case SQLITE_CANTOPEN:
+        case SQLITE_PROTOCOL:
+        case SQLITE_EMPTY:
+        case SQLITE_SCHEMA:
             PyErr_SetString(OperationalError, sqlite3_errmsg(db));
             break;
         case SQLITE_CORRUPT:
             PyErr_SetString(DatabaseError, sqlite3_errmsg(db));
             break;
-        case SQLITE_NOTFOUND:
-            PyErr_SetString(InternalError, sqlite3_errmsg(db));
-            break;
-        case SQLITE_FULL:
-            PyErr_SetString(OperationalError, sqlite3_errmsg(db));
-            break;
-        case SQLITE_CANTOPEN:
-            PyErr_SetString(OperationalError, sqlite3_errmsg(db));
-            break;
-        case SQLITE_PROTOCOL:
-            PyErr_SetString(OperationalError, sqlite3_errmsg(db));
-            break;
-        case SQLITE_EMPTY:
-            PyErr_SetString(OperationalError, sqlite3_errmsg(db));
-            break;
-        case SQLITE_SCHEMA:
-            PyErr_SetString(OperationalError, sqlite3_errmsg(db));
-            break;
         case SQLITE_TOOBIG:
             PyErr_SetString(DataError, sqlite3_errmsg(db));
             break;
         case SQLITE_CONSTRAINT:
-            PyErr_SetString(IntegrityError, sqlite3_errmsg(db));
-            break;
         case SQLITE_MISMATCH:
             PyErr_SetString(IntegrityError, sqlite3_errmsg(db));
             break;
@@ -140,6 +88,7 @@
             break;
         default:
             PyErr_SetString(DatabaseError, sqlite3_errmsg(db));
+            break;
     }
 
     return errorcode;
diff --git a/Modules/_sqlite/util.h b/Modules/_sqlite/util.h
index 6e74b2d..e99a4dd 100644
--- a/Modules/_sqlite/util.h
+++ b/Modules/_sqlite/util.h
@@ -1,6 +1,6 @@
 /* util.h - various utility functions
  *
- * Copyright (C) 2005 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2005-2006 Gerhard Häring <gh@ghaering.de>
  *
  * This file is part of pysqlite.
  *
@@ -28,8 +28,6 @@
 #include "sqlite3.h"
 #include "connection.h"
 
-void pysqlite_sleep(double seconds);
-
 int _sqlite_step_with_busyhandler(sqlite3_stmt* statement, Connection* connection);
 
 /**
diff --git a/setup.py b/setup.py
index affa20a..ad952f1 100644
--- a/setup.py
+++ b/setup.py
@@ -752,7 +752,7 @@
                 '_sqlite/statement.c',
                 '_sqlite/util.c', ]
 
-            PYSQLITE_VERSION = "2.1.3"
+            PYSQLITE_VERSION = "2.2.0"
             sqlite_defines = []
             if sys.platform != "win32":
                 sqlite_defines.append(('PYSQLITE_VERSION',