]> granicus.if.org Git - python/commitdiff
Merged changes from external pysqlite 2.3.0 release. Documentation updates will
authorGerhard Häring <gh@ghaering.de>
Tue, 13 Jun 2006 22:24:47 +0000 (22:24 +0000)
committerGerhard Häring <gh@ghaering.de>
Tue, 13 Jun 2006 22:24:47 +0000 (22:24 +0000)
follow in a few hours at the latest. Then we should be ready for beta1.

Lib/sqlite3/test/regression.py
Lib/sqlite3/test/types.py
Lib/sqlite3/test/userfunctions.py
Modules/_sqlite/connection.c
Modules/_sqlite/cursor.c
Modules/_sqlite/module.c
Modules/_sqlite/module.h

index 25e4b63a89c613d0d4539ba28761b32d7786c3dd..c8733b9639ce6496ae522a5a8b24544a9e824e32 100644 (file)
@@ -61,6 +61,14 @@ class RegressionTests(unittest.TestCase):
 
         con.rollback()
 
+    def CheckColumnNameWithSpaces(self):
+        cur = self.con.cursor()
+        cur.execute('select 1 as "foo bar [datetime]"')
+        self.failUnlessEqual(cur.description[0][0], "foo bar")
+
+        cur.execute('select 1 as "foo baz"')
+        self.failUnlessEqual(cur.description[0][0], "foo baz")
+
 def suite():
     regression_suite = unittest.makeSuite(RegressionTests, "Check")
     return unittest.TestSuite((regression_suite,))
index e49f7dd9b17c9c475b8068db13839a0b017abb53..c238ef9a6bb47aa72ea8edbba07251f2015c30cc 100644 (file)
@@ -101,16 +101,16 @@ class DeclTypesTests(unittest.TestCase):
         self.cur.execute("create table test(i int, s str, f float, b bool, u unicode, foo foo, bin blob)")
 
         # override float, make them always return the same number
-        sqlite.converters["float"] = lambda x: 47.2
+        sqlite.converters["FLOAT"] = lambda x: 47.2
 
         # and implement two custom ones
-        sqlite.converters["bool"] = lambda x: bool(int(x))
-        sqlite.converters["foo"] = DeclTypesTests.Foo
+        sqlite.converters["BOOL"] = lambda x: bool(int(x))
+        sqlite.converters["FOO"] = DeclTypesTests.Foo
 
     def tearDown(self):
-        del sqlite.converters["float"]
-        del sqlite.converters["bool"]
-        del sqlite.converters["foo"]
+        del sqlite.converters["FLOAT"]
+        del sqlite.converters["BOOL"]
+        del sqlite.converters["FOO"]
         self.cur.close()
         self.con.close()
 
@@ -208,14 +208,14 @@ class ColNamesTests(unittest.TestCase):
         self.cur = self.con.cursor()
         self.cur.execute("create table test(x foo)")
 
-        sqlite.converters["foo"] = lambda x: "[%s]" % x
-        sqlite.converters["bar"] = lambda x: "<%s>" % x
-        sqlite.converters["exc"] = lambda x: 5/0
+        sqlite.converters["FOO"] = lambda x: "[%s]" % x
+        sqlite.converters["BAR"] = lambda x: "<%s>" % x
+        sqlite.converters["EXC"] = lambda x: 5/0
 
     def tearDown(self):
-        del sqlite.converters["foo"]
-        del sqlite.converters["bar"]
-        del sqlite.converters["exc"]
+        del sqlite.converters["FOO"]
+        del sqlite.converters["BAR"]
+        del sqlite.converters["EXC"]
         self.cur.close()
         self.con.close()
 
@@ -231,12 +231,6 @@ class ColNamesTests(unittest.TestCase):
         val = self.cur.fetchone()[0]
         self.failUnlessEqual(val, None)
 
-    def CheckExc(self):
-        # Exceptions in type converters result in returned Nones
-        self.cur.execute('select 5 as "x [exc]"')
-        val = self.cur.fetchone()[0]
-        self.failUnlessEqual(val, None)
-
     def CheckColName(self):
         self.cur.execute("insert into test(x) values (?)", ("xxx",))
         self.cur.execute('select x as "x [bar]" from test')
index 78656e7e337d2ac05c6805a2e4aeeb8c600b3151..bcc5ae3665e54f504c5ba0e8d0b757e91f64c4b6 100644 (file)
@@ -55,6 +55,9 @@ class AggrNoStep:
     def __init__(self):
         pass
 
+    def finalize(self):
+        return 1
+
 class AggrNoFinalize:
     def __init__(self):
         pass
@@ -144,9 +147,12 @@ class FunctionTests(unittest.TestCase):
     def CheckFuncRefCount(self):
         def getfunc():
             def f():
-                return val
+                return 1
             return f
-        self.con.create_function("reftest", 0, getfunc())
+        f = getfunc()
+        globals()["foo"] = f
+        # self.con.create_function("reftest", 0, getfunc())
+        self.con.create_function("reftest", 0, f)
         cur = self.con.cursor()
         cur.execute("select reftest()")
 
@@ -195,9 +201,12 @@ class FunctionTests(unittest.TestCase):
 
     def CheckFuncException(self):
         cur = self.con.cursor()
-        cur.execute("select raiseexception()")
-        val = cur.fetchone()[0]
-        self.failUnlessEqual(val, None)
+        try:
+            cur.execute("select raiseexception()")
+            cur.fetchone()
+            self.fail("should have raised OperationalError")
+        except sqlite.OperationalError, e:
+            self.failUnlessEqual(e.args[0], 'user-defined function raised exception')
 
     def CheckParamString(self):
         cur = self.con.cursor()
@@ -267,31 +276,47 @@ class AggregateTests(unittest.TestCase):
 
     def CheckAggrNoStep(self):
         cur = self.con.cursor()
-        cur.execute("select nostep(t) from test")
+        try:
+            cur.execute("select nostep(t) from test")
+            self.fail("should have raised an AttributeError")
+        except AttributeError, e:
+            self.failUnlessEqual(e.args[0], "AggrNoStep instance has no attribute 'step'")
 
     def CheckAggrNoFinalize(self):
         cur = self.con.cursor()
-        cur.execute("select nofinalize(t) from test")
-        val = cur.fetchone()[0]
-        self.failUnlessEqual(val, None)
+        try:
+            cur.execute("select nofinalize(t) from test")
+            val = cur.fetchone()[0]
+            self.fail("should have raised an OperationalError")
+        except sqlite.OperationalError, e:
+            self.failUnlessEqual(e.args[0], "user-defined aggregate's 'finalize' method raised error")
 
     def CheckAggrExceptionInInit(self):
         cur = self.con.cursor()
-        cur.execute("select excInit(t) from test")
-        val = cur.fetchone()[0]
-        self.failUnlessEqual(val, None)
+        try:
+            cur.execute("select excInit(t) from test")
+            val = cur.fetchone()[0]
+            self.fail("should have raised an OperationalError")
+        except sqlite.OperationalError, e:
+            self.failUnlessEqual(e.args[0], "user-defined aggregate's '__init__' method raised error")
 
     def CheckAggrExceptionInStep(self):
         cur = self.con.cursor()
-        cur.execute("select excStep(t) from test")
-        val = cur.fetchone()[0]
-        self.failUnlessEqual(val, 42)
+        try:
+            cur.execute("select excStep(t) from test")
+            val = cur.fetchone()[0]
+            self.fail("should have raised an OperationalError")
+        except sqlite.OperationalError, e:
+            self.failUnlessEqual(e.args[0], "user-defined aggregate's 'step' method raised error")
 
     def CheckAggrExceptionInFinalize(self):
         cur = self.con.cursor()
-        cur.execute("select excFinalize(t) from test")
-        val = cur.fetchone()[0]
-        self.failUnlessEqual(val, None)
+        try:
+            cur.execute("select excFinalize(t) from test")
+            val = cur.fetchone()[0]
+            self.fail("should have raised an OperationalError")
+        except sqlite.OperationalError, e:
+            self.failUnlessEqual(e.args[0], "user-defined aggregate's 'finalize' method raised error")
 
     def CheckAggrCheckParamStr(self):
         cur = self.con.cursor()
@@ -331,10 +356,55 @@ class AggregateTests(unittest.TestCase):
         val = cur.fetchone()[0]
         self.failUnlessEqual(val, 60)
 
+def authorizer_cb(action, arg1, arg2, dbname, source):
+    if action != sqlite.SQLITE_SELECT:
+        return sqlite.SQLITE_DENY
+    if arg2 == 'c2' or arg1 == 't2':
+        return sqlite.SQLITE_DENY
+    return sqlite.SQLITE_OK
+
+class AuthorizerTests(unittest.TestCase):
+    def setUp(self):
+        sqlite.enable_callback_tracebacks(1)
+        self.con = sqlite.connect(":memory:")
+        self.con.executescript("""
+            create table t1 (c1, c2);
+            create table t2 (c1, c2);
+            insert into t1 (c1, c2) values (1, 2);
+            insert into t2 (c1, c2) values (4, 5);
+            """)
+
+        # For our security test:
+        self.con.execute("select c2 from t2")
+
+        self.con.set_authorizer(authorizer_cb)
+
+    def tearDown(self):
+        pass
+
+    def CheckTableAccess(self):
+        try:
+            self.con.execute("select * from t2")
+        except sqlite.DatabaseError, e:
+            if not e.args[0].endswith("prohibited"):
+                self.fail("wrong exception text: %s" % e.args[0])
+            return
+        self.fail("should have raised an exception due to missing privileges")
+
+    def CheckColumnAccess(self):
+        try:
+            self.con.execute("select c2 from t1")
+        except sqlite.DatabaseError, e:
+            if not e.args[0].endswith("prohibited"):
+                self.fail("wrong exception text: %s" % e.args[0])
+            return
+        self.fail("should have raised an exception due to missing privileges")
+
 def suite():
     function_suite = unittest.makeSuite(FunctionTests, "Check")
     aggregate_suite = unittest.makeSuite(AggregateTests, "Check")
-    return unittest.TestSuite((function_suite, aggregate_suite))
+    authorizer_suite = unittest.makeSuite(AuthorizerTests, "Check") 
+    return unittest.TestSuite((function_suite, aggregate_suite, authorizer_suite))
 
 def test():
     runner = unittest.TextTestRunner()
index 64e43ebcbcec3003ed319fddac0306fbad39f34f..bf74710f8c42a6c65b9d9f4e76e3ec03b890589d 100644 (file)
@@ -405,8 +405,6 @@ void _set_result(sqlite3_context* context, PyObject* py_val)
     PyObject* stringval;
 
     if ((!py_val) || PyErr_Occurred()) {
-        /* Errors in callbacks are ignored, and we return NULL */
-        PyErr_Clear();
         sqlite3_result_null(context);
     } else if (py_val == Py_None) {
         sqlite3_result_null(context);
@@ -519,8 +517,17 @@ void _func_callback(sqlite3_context* context, int argc, sqlite3_value** argv)
         Py_DECREF(args);
     }
 
-    _set_result(context, py_retval);
-    Py_XDECREF(py_retval);
+    if (py_retval) {
+        _set_result(context, py_retval);
+        Py_DECREF(py_retval);
+    } else {
+        if (_enable_callback_tracebacks) {
+            PyErr_Print();
+        } else {
+            PyErr_Clear();
+        }
+        sqlite3_result_error(context, "user-defined function raised exception", -1);
+    }
 
     PyGILState_Release(threadstate);
 }
@@ -545,8 +552,13 @@ static void _step_callback(sqlite3_context *context, int argc, sqlite3_value** p
         *aggregate_instance = PyObject_CallFunction(aggregate_class, "");
 
         if (PyErr_Occurred()) {
-            PyErr_Clear();
             *aggregate_instance = 0;
+            if (_enable_callback_tracebacks) {
+                PyErr_Print();
+            } else {
+                PyErr_Clear();
+            }
+            sqlite3_result_error(context, "user-defined aggregate's '__init__' method raised error", -1);
             goto error;
         }
     }
@@ -565,7 +577,12 @@ static void _step_callback(sqlite3_context *context, int argc, sqlite3_value** p
     Py_DECREF(args);
 
     if (!function_result) {
-        PyErr_Clear();
+        if (_enable_callback_tracebacks) {
+            PyErr_Print();
+        } else {
+            PyErr_Clear();
+        }
+        sqlite3_result_error(context, "user-defined aggregate's 'step' method raised error", -1);
     }
 
 error:
@@ -597,13 +614,16 @@ void _final_callback(sqlite3_context* context)
 
     function_result = PyObject_CallMethod(*aggregate_instance, "finalize", "");
     if (!function_result) {
-        PyErr_Clear();
-        Py_INCREF(Py_None);
-        function_result = Py_None;
+        if (_enable_callback_tracebacks) {
+            PyErr_Print();
+        } else {
+            PyErr_Clear();
+        }
+        sqlite3_result_error(context, "user-defined aggregate's 'finalize' method raised error", -1);
+    } else {
+        _set_result(context, function_result);
     }
 
-    _set_result(context, function_result);
-
 error:
     Py_XDECREF(*aggregate_instance);
     Py_XDECREF(function_result);
@@ -699,6 +719,61 @@ PyObject* connection_create_aggregate(Connection* self, PyObject* args, PyObject
     }
 }
 
+int _authorizer_callback(void* user_arg, int action, const char* arg1, const char* arg2 , const char* dbname, const char* access_attempt_source)
+{
+    PyObject *ret;
+    int rc;
+    PyGILState_STATE gilstate;
+
+    gilstate = PyGILState_Ensure();
+    ret = PyObject_CallFunction((PyObject*)user_arg, "issss", action, arg1, arg2, dbname, access_attempt_source);
+
+    if (!ret) {
+        if (_enable_callback_tracebacks) {
+            PyErr_Print();
+        } else {
+            PyErr_Clear();
+        }
+
+        rc = SQLITE_DENY;
+    } else {
+        if (PyInt_Check(ret)) {
+            rc = (int)PyInt_AsLong(ret);
+        } else {
+            rc = SQLITE_DENY;
+        }
+        Py_DECREF(ret);
+    }
+
+    PyGILState_Release(gilstate);
+    return rc;
+}
+
+PyObject* connection_set_authorizer(Connection* self, PyObject* args, PyObject* kwargs)
+{
+    PyObject* authorizer_cb;
+
+    static char *kwlist[] = { "authorizer_callback", NULL };
+    int rc;
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O:set_authorizer",
+                                      kwlist, &authorizer_cb)) {
+        return NULL;
+    }
+
+    rc = sqlite3_set_authorizer(self->db, _authorizer_callback, (void*)authorizer_cb);
+
+    if (rc != SQLITE_OK) {
+        PyErr_SetString(OperationalError, "Error setting authorizer callback");
+        return NULL;
+    } else {
+        PyDict_SetItem(self->function_pinboard, authorizer_cb, Py_None);
+
+        Py_INCREF(Py_None);
+        return Py_None;
+    }
+}
+
 int check_thread(Connection* self)
 {
     if (self->check_same_thread) {
@@ -974,6 +1049,24 @@ finally:
     return result;
 }
 
+static PyObject *
+connection_interrupt(Connection* self, PyObject* args)
+{
+    PyObject* retval = NULL;
+
+    if (!check_connection(self)) {
+        goto finally;
+    }
+
+    sqlite3_interrupt(self->db);
+
+    Py_INCREF(Py_None);
+    retval = Py_None;
+
+finally:
+    return retval;
+}
+
 static PyObject *
 connection_create_collation(Connection* self, PyObject* args)
 {
@@ -1067,6 +1160,8 @@ static PyMethodDef connection_methods[] = {
         PyDoc_STR("Creates a new function. Non-standard.")},
     {"create_aggregate", (PyCFunction)connection_create_aggregate, METH_VARARGS|METH_KEYWORDS,
         PyDoc_STR("Creates a new aggregate. Non-standard.")},
+    {"set_authorizer", (PyCFunction)connection_set_authorizer, METH_VARARGS|METH_KEYWORDS,
+        PyDoc_STR("Sets authorizer callback. Non-standard.")},
     {"execute", (PyCFunction)connection_execute, METH_VARARGS,
         PyDoc_STR("Executes a SQL statement. Non-standard.")},
     {"executemany", (PyCFunction)connection_executemany, METH_VARARGS,
@@ -1075,6 +1170,8 @@ static PyMethodDef connection_methods[] = {
         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. Non-standard.")},
+    {"interrupt", (PyCFunction)connection_interrupt, METH_NOARGS,
+        PyDoc_STR("Abort any pending database operation. Non-standard.")},
     {NULL, NULL}
 };
 
index 6ee8beaf90481c589eb1bde18348c2eda44fe2dc..98f5e0d825950c91519f14080c24e0446cc3890f 100644 (file)
@@ -137,6 +137,22 @@ void cursor_dealloc(Cursor* self)
     self->ob_type->tp_free((PyObject*)self);
 }
 
+PyObject* _get_converter(PyObject* key)
+{
+    PyObject* upcase_key;
+    PyObject* retval;
+
+    upcase_key = PyObject_CallMethod(key, "upper", "");
+    if (!upcase_key) {
+        return NULL;
+    }
+
+    retval = PyDict_GetItem(converters, upcase_key);
+    Py_DECREF(upcase_key);
+
+    return retval;
+}
+
 int build_row_cast_map(Cursor* self)
 {
     int i;
@@ -174,7 +190,7 @@ int build_row_cast_map(Cursor* self)
                             break;
                         }
 
-                        converter = PyDict_GetItem(converters, key);
+                        converter = _get_converter(key);
                         Py_DECREF(key);
                         break;
                     }
@@ -195,7 +211,7 @@ int build_row_cast_map(Cursor* self)
                     }
                 }
 
-                converter = PyDict_GetItem(converters, py_decltype);
+                converter = _get_converter(py_decltype);
                 Py_DECREF(py_decltype);
             }
         }
@@ -228,7 +244,10 @@ PyObject* _build_column_name(const char* colname)
     }
 
     for (pos = colname;; pos++) {
-        if (*pos == 0 || *pos == ' ') {
+        if (*pos == 0 || *pos == '[') {
+            if ((*pos == '[') && (pos > colname) && (*(pos-1) == ' ')) {
+                pos--;
+            }
             return PyString_FromStringAndSize(colname, pos - colname);
         }
     }
@@ -312,13 +331,10 @@ PyObject* _fetch_one_row(Cursor* self)
                     return NULL;
                 }
                 converted = PyObject_CallFunction(converter, "O", item);
+                Py_DECREF(item);
                 if (!converted) {
-                    /* TODO: have a way to log these errors */
-                    Py_INCREF(Py_None);
-                    converted = Py_None;
-                    PyErr_Clear();
+                    break;
                 }
-                Py_DECREF(item);
             }
         } else {
             Py_BEGIN_ALLOW_THREADS
@@ -346,10 +362,10 @@ PyObject* _fetch_one_row(Cursor* self)
 
                     if (!converted) {
                         colname = sqlite3_column_name(self->statement->st, i);
-                        if (colname) {
+                        if (!colname) {
                             colname = "<unknown column name>";
                         }
-                        PyOS_snprintf(buf, sizeof(buf) - 1, "Could not decode to UTF-8 column %s with text %s",
+                        PyOS_snprintf(buf, sizeof(buf) - 1, "Could not decode to UTF-8 column '%s' with text '%s'",
                                      colname , val_str);
                         PyErr_SetString(OperationalError, buf);
                     }
@@ -373,7 +389,12 @@ PyObject* _fetch_one_row(Cursor* self)
             }
         }
 
-        PyTuple_SetItem(row, i, converted);
+        if (converted) {
+            PyTuple_SetItem(row, i, converted);
+        } else {
+            Py_INCREF(Py_None);
+            PyTuple_SetItem(row, i, Py_None);
+        }
     }
 
     if (PyErr_Occurred()) {
@@ -598,6 +619,14 @@ PyObject* _query_execute(Cursor* self, int multiple, PyObject* args)
                     goto error;
                 }
             } else {
+                if (PyErr_Occurred()) {
+                    /* there was an error that occured in a user-defined callback */
+                    if (_enable_callback_tracebacks) {
+                        PyErr_Print();
+                    } else {
+                        PyErr_Clear();
+                    }
+                }
                 _seterror(self->connection->db);
                 goto error;
             }
index 71d0aaa70b14a7bef018b4f4df87ca3f54969168..606454ca1f8b769469fc6b6dbeeb8872443607db 100644 (file)
@@ -1,25 +1,25 @@
-/* module.c - the module itself
- *
- * 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.
- *
- * 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.
- */
+    /* module.c - the module itself
    *
    * 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.
    *
    * 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.
    */
 
 #include "connection.h"
 #include "statement.h"
@@ -40,6 +40,7 @@ PyObject* Error, *Warning, *InterfaceError, *DatabaseError, *InternalError,
     *NotSupportedError, *OptimizedUnicode;
 
 PyObject* converters;
+int _enable_callback_tracebacks;
 
 static PyObject* module_connect(PyObject* self, PyObject* args, PyObject*
         kwargs)
@@ -140,14 +141,42 @@ static PyObject* module_register_adapter(PyObject* self, PyObject* args, PyObjec
 
 static PyObject* module_register_converter(PyObject* self, PyObject* args, PyObject* kwargs)
 {
-    PyObject* name;
+    char* orig_name;
+    char* name = NULL;
+    char* c;
     PyObject* callable;
+    PyObject* retval = NULL;
 
-    if (!PyArg_ParseTuple(args, "OO", &name, &callable)) {
+    if (!PyArg_ParseTuple(args, "sO", &orig_name, &callable)) {
         return NULL;
     }
 
-    if (PyDict_SetItem(converters, name, callable) != 0) {
+    /* convert the name to lowercase */
+    name = PyMem_Malloc(strlen(orig_name) + 2);
+    if (!name) {
+        goto error;
+    }
+    strcpy(name, orig_name);
+    for (c = name; *c != (char)0; c++) {
+        *c = (*c) & 0xDF;
+    }
+
+    if (PyDict_SetItemString(converters, name, callable) != 0) {
+        goto error;
+    }
+
+    Py_INCREF(Py_None);
+    retval = Py_None;
+error:
+    if (name) {
+        PyMem_Free(name);
+    }
+    return retval;
+}
+
+static PyObject* enable_callback_tracebacks(PyObject* self, PyObject* args, PyObject* kwargs)
+{
+    if (!PyArg_ParseTuple(args, "i", &_enable_callback_tracebacks)) {
         return NULL;
     }
 
@@ -174,13 +203,64 @@ static PyMethodDef module_methods[] = {
     {"register_adapter", (PyCFunction)module_register_adapter, METH_VARARGS, PyDoc_STR("Registers an adapter with pysqlite's adapter registry. Non-standard.")},
     {"register_converter", (PyCFunction)module_register_converter, METH_VARARGS, PyDoc_STR("Registers a converter with pysqlite. Non-standard.")},
     {"adapt",  (PyCFunction)psyco_microprotocols_adapt, METH_VARARGS, psyco_microprotocols_adapt_doc},
+    {"enable_callback_tracebacks",  (PyCFunction)enable_callback_tracebacks, METH_VARARGS, PyDoc_STR("Enable or disable callback functions throwing errors to stderr.")},
     {NULL, NULL}
 };
 
+struct _IntConstantPair {
+    char* constant_name;
+    int constant_value;
+};
+
+typedef struct _IntConstantPair IntConstantPair;
+
+static IntConstantPair _int_constants[] = {
+    {"PARSE_DECLTYPES", PARSE_DECLTYPES},
+    {"PARSE_COLNAMES", PARSE_COLNAMES},
+
+    {"SQLITE_OK", SQLITE_OK},
+    {"SQLITE_DENY", SQLITE_DENY},
+    {"SQLITE_IGNORE", SQLITE_IGNORE},
+    {"SQLITE_CREATE_INDEX", SQLITE_CREATE_INDEX},
+    {"SQLITE_CREATE_TABLE", SQLITE_CREATE_TABLE},
+    {"SQLITE_CREATE_TEMP_INDEX", SQLITE_CREATE_TEMP_INDEX},
+    {"SQLITE_CREATE_TEMP_TABLE", SQLITE_CREATE_TEMP_TABLE},
+    {"SQLITE_CREATE_TEMP_TRIGGER", SQLITE_CREATE_TEMP_TRIGGER},
+    {"SQLITE_CREATE_TEMP_VIEW", SQLITE_CREATE_TEMP_VIEW},
+    {"SQLITE_CREATE_TRIGGER", SQLITE_CREATE_TRIGGER},
+    {"SQLITE_CREATE_VIEW", SQLITE_CREATE_VIEW},
+    {"SQLITE_DELETE", SQLITE_DELETE},
+    {"SQLITE_DROP_INDEX", SQLITE_DROP_INDEX},
+    {"SQLITE_DROP_TABLE", SQLITE_DROP_TABLE},
+    {"SQLITE_DROP_TEMP_INDEX", SQLITE_DROP_TEMP_INDEX},
+    {"SQLITE_DROP_TEMP_TABLE", SQLITE_DROP_TEMP_TABLE},
+    {"SQLITE_DROP_TEMP_TRIGGER", SQLITE_DROP_TEMP_TRIGGER},
+    {"SQLITE_DROP_TEMP_VIEW", SQLITE_DROP_TEMP_VIEW},
+    {"SQLITE_DROP_TRIGGER", SQLITE_DROP_TRIGGER},
+    {"SQLITE_DROP_VIEW", SQLITE_DROP_VIEW},
+    {"SQLITE_INSERT", SQLITE_INSERT},
+    {"SQLITE_PRAGMA", SQLITE_PRAGMA},
+    {"SQLITE_READ", SQLITE_READ},
+    {"SQLITE_SELECT", SQLITE_SELECT},
+    {"SQLITE_TRANSACTION", SQLITE_TRANSACTION},
+    {"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
+    {(char*)NULL, 0}
+};
+
 PyMODINIT_FUNC init_sqlite3(void)
 {
     PyObject *module, *dict;
     PyObject *tmp_obj;
+    int i;
 
     module = Py_InitModule("_sqlite3", module_methods);
 
@@ -276,17 +356,15 @@ PyMODINIT_FUNC init_sqlite3(void)
     OptimizedUnicode = (PyObject*)&PyCell_Type;
     PyDict_SetItemString(dict, "OptimizedUnicode", OptimizedUnicode);
 
-    if (!(tmp_obj = PyInt_FromLong(PARSE_DECLTYPES))) {
-        goto error;
+    /* Set integer constants */
+    for (i = 0; _int_constants[i].constant_name != 0; i++) {
+        tmp_obj = PyInt_FromLong(_int_constants[i].constant_value);
+        if (!tmp_obj) {
+            goto error;
+        }
+        PyDict_SetItemString(dict, _int_constants[i].constant_name, tmp_obj);
+        Py_DECREF(tmp_obj);
     }
-    PyDict_SetItemString(dict, "PARSE_DECLTYPES", tmp_obj);
-    Py_DECREF(tmp_obj);
-
-    if (!(tmp_obj = PyInt_FromLong(PARSE_COLNAMES))) {
-        goto error;
-    }
-    PyDict_SetItemString(dict, "PARSE_COLNAMES", tmp_obj);
-    Py_DECREF(tmp_obj);
 
     if (!(tmp_obj = PyString_FromString(PYSQLITE_VERSION))) {
         goto error;
@@ -306,6 +384,8 @@ PyMODINIT_FUNC init_sqlite3(void)
     /* initialize the default converters */
     converters_init(dict);
 
+    _enable_callback_tracebacks = 0;
+
     /* Original comment form _bsddb.c in the Python core. This is also still
      * needed nowadays for Python 2.3/2.4.
      * 
index f3e2aa11932508e71fb33631007922d23380df93..00eff1f6ab11913f4438cd3e03b23b591dd6c995 100644 (file)
@@ -25,7 +25,7 @@
 #define PYSQLITE_MODULE_H
 #include "Python.h"
 
-#define PYSQLITE_VERSION "2.2.2"
+#define PYSQLITE_VERSION "2.3.0"
 
 extern PyObject* Error;
 extern PyObject* Warning;
@@ -50,6 +50,8 @@ extern PyObject* time_sleep;
  */
 extern PyObject* converters;
 
+extern int _enable_callback_tracebacks;
+
 #define PARSE_DECLTYPES 1
 #define PARSE_COLNAMES 2
 #endif