diff options
| author | Anthony Baxter <anthonybaxter@gmail.com> | 2006-04-04 06:29:05 +0000 | 
|---|---|---|
| committer | Anthony Baxter <anthonybaxter@gmail.com> | 2006-04-04 06:29:05 +0000 | 
| commit | 72289a616c90949f7a2d3b2af12cd1044e64717d (patch) | |
| tree | 278f2963d2f72baad0859e6b5e9056b9daddd446 | |
| parent | a058836e969eba03142bc8f01418a28741f70dc3 (diff) | |
| download | cpython-git-72289a616c90949f7a2d3b2af12cd1044e64717d.tar.gz | |
Update to pysqlite 2.2.0
| -rw-r--r-- | Lib/sqlite3/test/dbapi.py | 6 | ||||
| -rw-r--r-- | Lib/sqlite3/test/hooks.py | 115 | ||||
| -rw-r--r-- | Lib/sqlite3/test/regression.py | 48 | ||||
| -rw-r--r-- | Lib/sqlite3/test/transactions.py | 4 | ||||
| -rw-r--r-- | Modules/_sqlite/cache.c | 41 | ||||
| -rw-r--r-- | Modules/_sqlite/connection.c | 156 | ||||
| -rw-r--r-- | Modules/_sqlite/connection.h | 3 | ||||
| -rw-r--r-- | Modules/_sqlite/cursor.c | 109 | ||||
| -rw-r--r-- | Modules/_sqlite/microprotocols.c | 18 | ||||
| -rw-r--r-- | Modules/_sqlite/module.c | 91 | ||||
| -rw-r--r-- | Modules/_sqlite/prepare_protocol.c | 2 | ||||
| -rw-r--r-- | Modules/_sqlite/row.c | 15 | ||||
| -rw-r--r-- | Modules/_sqlite/sqlitecompat.h | 34 | ||||
| -rw-r--r-- | Modules/_sqlite/statement.c | 1 | ||||
| -rw-r--r-- | Modules/_sqlite/util.c | 71 | ||||
| -rw-r--r-- | Modules/_sqlite/util.h | 4 | ||||
| -rw-r--r-- | setup.py | 2 | 
17 files changed, 589 insertions, 131 deletions
diff --git a/Lib/sqlite3/test/dbapi.py b/Lib/sqlite3/test/dbapi.py index 0d47977099..b08da9c5fa 100644 --- a/Lib/sqlite3/test/dbapi.py +++ b/Lib/sqlite3/test/dbapi.py @@ -268,6 +268,12 @@ class CursorTests(unittest.TestCase):          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 0000000000..21f7b88116 --- /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 0000000000..648ada5b9e --- /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 28202cb260..1f0b19aa9b 100644 --- a/Lib/sqlite3/test/transactions.py +++ b/Lib/sqlite3/test/transactions.py @@ -25,7 +25,7 @@ import os, unittest  import sqlite3 as sqlite  def get_db_path(): -    return "testdb" +    return "sqlite_testdb"  class TransactionTests(unittest.TestCase):      def setUp(self): @@ -47,6 +47,8 @@ class TransactionTests(unittest.TestCase):          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 0c7d4a36d3..d36b52be0a 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* new_node(PyObject* key, PyObject* data)      Node* node;      node = (Node*) (NodeType.tp_alloc(&NodeType, 0)); -    /*node = PyObject_New(Node, &NodeType);*/      if (!node) {          return NULL;      } @@ -72,7 +71,12 @@ int cache_init(Cache* self, PyObject* args, PyObject* kwargs)      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 @@ void cache_dealloc(Cache* self)  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 @@ PyObject* cache_get(Cache* self, PyObject* args)          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 @@ PyObject* cache_get(Cache* self, PyObject* args)          }          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 @@ PyObject* cache_display(Cache* self, PyObject* args)          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 @@ PyObject* cache_display(Cache* self, PyObject* args)  }  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 0445b38c34..3e97f6e739 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 @@ int connection_init(Connection* self, PyObject* args, PyObject* kwargs)      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 @@ void connection_dealloc(Connection* self)      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 @@ PyObject* _build_py_params(sqlite3_context *context, int argc, sqlite3_value** a      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 @@ static PyObject* connection_get_isolation_level(Connection* self, void* unused)      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 @@ static int connection_set_isolation_level(Connection* self, PyObject* isolation_          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 @@ error:      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 @@ static PyMethodDef connection_methods[] = {          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 ef03bc4f96..faae6e4e37 100644 --- a/Modules/_sqlite/connection.h +++ b/Modules/_sqlite/connection.h @@ -69,6 +69,9 @@ typedef struct       * 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 fe6cff9aaa..e68a2755c6 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 @@ int cursor_init(Cursor* self, PyObject* args, PyObject* kwargs)      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 @@ int cursor_init(Cursor* self, PyObject* args, PyObject* kwargs)      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 @@ void cursor_dealloc(Cursor* self)      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 @@ void build_row_cast_map(Cursor* self)      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 @@ void build_row_cast_map(Cursor* self)                      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 @@ void build_row_cast_map(Cursor* self)                  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 @@ void build_row_cast_map(Cursor* self)              }          } -        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 @@ PyObject* _fetch_one_row(Cursor* self)      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 @@ PyObject* _fetch_one_row(Cursor* self)                  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 @@ PyObject* _query_execute(Cursor* self, int multiple, PyObject* args)          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 @@ PyObject* _query_execute(Cursor* self, int multiple, PyObject* args)      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 @@ PyObject* _query_execute(Cursor* self, int multiple, PyObject* args)                     - 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 @@ PyObject* _query_execute(Cursor* self, int multiple, PyObject* args)                                  "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 @@ PyObject* _query_execute(Cursor* self, int multiple, PyObject* args)      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 @@ PyObject* _query_execute(Cursor* self, int multiple, PyObject* args)              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 @@ PyObject* _query_execute(Cursor* self, int multiple, PyObject* args)              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 @@ error:      if (PyErr_Occurred()) {          return NULL;      } else { -        Py_INCREF(Py_None); -        return Py_None; +        Py_INCREF(self); +        return (PyObject*)self;      }  } @@ -658,6 +726,9 @@ PyObject* cursor_executescript(Cursor* self, PyObject* args)      /* 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 @@ error:      if (PyErr_Occurred()) {          return NULL;      } else { -        Py_INCREF(Py_None); -        return Py_None; +        Py_INCREF(self); +        return (PyObject*)self;      }  } @@ -789,9 +860,12 @@ PyObject* cursor_fetchmany(Cursor* self, PyObject* args)      }      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* cursor_fetchall(Cursor* self, PyObject* args)      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 5df41a1901..5040acdc0d 100644 --- a/Modules/_sqlite/microprotocols.c +++ b/Modules/_sqlite/microprotocols.c @@ -45,9 +45,7 @@ microprotocols_init(PyObject *dict)          return -1;      } -    PyDict_SetItemString(dict, "adapters", psyco_adapters); - -    return 0; +    return PyDict_SetItemString(dict, "adapters", psyco_adapters);  } @@ -65,8 +63,17 @@ microprotocols_add(PyTypeObject *type, PyObject *proto, PyObject *cast)              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 @@ microprotocols_adapt(PyObject *obj, PyObject *proto, PyObject *alt)      /* 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 70993d073f..60d0d6319d 100644 --- a/Modules/_sqlite/module.c +++ b/Modules/_sqlite/module.c @@ -39,9 +39,6 @@ PyObject* Error, *Warning, *InterfaceError, *DatabaseError, *InternalError,      *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 @@ static PyObject* module_register_converter(PyObject* self, PyObject* args, PyObj          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 @@ static PyObject* module_register_converter(PyObject* self, PyObject* args, PyObj  void converters_init(PyObject* dict)  {      converters = PyDict_New(); +    if (!converters) { +        return; +    }      PyDict_SetItemString(dict, "converters", converters);  } @@ -169,8 +171,8 @@ static PyMethodDef module_methods[] = {  #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 @@ static PyMethodDef module_methods[] = {  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 @@ PyMODINIT_FUNC init_sqlite3(void)      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 @@ PyMODINIT_FUNC init_sqlite3(void)      /* 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 2e8349c169..522f1d107f 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 61de801736..77c7896e5b 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 @@ PyObject* row_subscript(Row* self, PyObject* idx)      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 @@ PyObject* row_subscript(Row* self, PyObject* idx)          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 0000000000..c3798257bf --- /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 4a957d6f4f..ae48b4b99b 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 ec400a1faa..33748a6b40 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 @@ int _seterror(sqlite3* db)          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)); +        case SQLITE_NOMEM: +            (void)PyErr_NoMemory();              break; +        case SQLITE_ERROR: +        case SQLITE_PERM:          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_READONLY: -            PyErr_SetString(OperationalError, sqlite3_errmsg(db)); -            break;          case SQLITE_INTERRUPT: -            PyErr_SetString(OperationalError, sqlite3_errmsg(db)); -            break;          case SQLITE_IOERR: -            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_CORRUPT: +            PyErr_SetString(DatabaseError, 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 @@ int _seterror(sqlite3* db)              break;          default:              PyErr_SetString(DatabaseError, sqlite3_errmsg(db)); +            break;      }      return errorcode; diff --git a/Modules/_sqlite/util.h b/Modules/_sqlite/util.h index 6e74b2dea6..e99a4dd81b 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);  /** @@ -752,7 +752,7 @@ class PyBuildExt(build_ext):                  '_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',  | 
