]> granicus.if.org Git - python/commitdiff
Implemented feature request 2157: Converter names are cut off at '('
authorGerhard Häring <gh@ghaering.de>
Sun, 4 May 2008 13:42:44 +0000 (13:42 +0000)
committerGerhard Häring <gh@ghaering.de>
Sun, 4 May 2008 13:42:44 +0000 (13:42 +0000)
characters. This avoids the common case of something like 'NUMBER(10)' not
being parsed as 'NUMBER', like expected. Also corrected the docs about
converter names being case-sensitive. They aren't any longer.

Doc/library/sqlite3.rst
Lib/sqlite3/test/types.py
Modules/_sqlite/cursor.c

index 85925f4b453fc73b57a6709f71abd5165cc505a2..5408630f449505029e583483c558f66b842f1f93 100644 (file)
@@ -114,10 +114,11 @@ Module functions and constants
    :func:`connect` function.
 
    Setting it makes the :mod:`sqlite3` module parse the declared type for each
-   column it returns.  It will parse out the first word of the declared type, i. e.
-   for "integer primary key", it will parse out "integer". Then for that column, it
-   will look into the converters dictionary and use the converter function
-   registered for that type there.  Converter names are case-sensitive!
+   column it returns.  It will parse out the first word of the declared type,
+   i. e.  for "integer primary key", it will parse out "integer", or for
+   "number(10)" it will parse out "number". Then for that column, it will look
+   into the converters dictionary and use the converter function registered for
+   that type there.
 
 
 .. data:: PARSE_COLNAMES
@@ -666,10 +667,6 @@ and constructs a :class:`Point` object from it.
    Converter functions **always** get called with a string, no matter under which
    data type you sent the value to SQLite.
 
-.. note::
-
-   Converter names are looked up in a case-sensitive manner.
-
 ::
 
    def convert_point(s):
index 197040172c7d01a853018d7c4dab869f54bb857d..471425d6042a76d11cd9c1ba52bb64d6c7bdfcdd 100644 (file)
@@ -98,7 +98,7 @@ class DeclTypesTests(unittest.TestCase):
     def setUp(self):
         self.con = sqlite.connect(":memory:", detect_types=sqlite.PARSE_DECLTYPES)
         self.cur = self.con.cursor()
-        self.cur.execute("create table test(i int, s str, f float, b bool, u unicode, foo foo, bin blob)")
+        self.cur.execute("create table test(i int, s str, f float, b bool, u unicode, foo foo, bin blob, n1 number, n2 number(5))")
 
         # override float, make them always return the same number
         sqlite.converters["FLOAT"] = lambda x: 47.2
@@ -107,11 +107,13 @@ class DeclTypesTests(unittest.TestCase):
         sqlite.converters["BOOL"] = lambda x: bool(int(x))
         sqlite.converters["FOO"] = DeclTypesTests.Foo
         sqlite.converters["WRONG"] = lambda x: "WRONG"
+        sqlite.converters["NUMBER"] = float
 
     def tearDown(self):
         del sqlite.converters["FLOAT"]
         del sqlite.converters["BOOL"]
         del sqlite.converters["FOO"]
+        del sqlite.converters["NUMBER"]
         self.cur.close()
         self.con.close()
 
@@ -203,6 +205,19 @@ class DeclTypesTests(unittest.TestCase):
         row = self.cur.fetchone()
         self.failUnlessEqual(row[0], val)
 
+    def CheckNumber1(self):
+        self.cur.execute("insert into test(n1) values (5)")
+        value = self.cur.execute("select n1 from test").fetchone()[0]
+        # if the converter is not used, it's an int instead of a float
+        self.failUnlessEqual(type(value), float)
+
+    def CheckNumber2(self):
+        """Checks wether converter names are cut off at '(' characters"""
+        self.cur.execute("insert into test(n2) values (5)")
+        value = self.cur.execute("select n2 from test").fetchone()[0]
+        # if the converter is not used, it's an int instead of a float
+        self.failUnlessEqual(type(value), float)
+
 class ColNamesTests(unittest.TestCase):
     def setUp(self):
         self.con = sqlite.connect(":memory:", detect_types=sqlite.PARSE_COLNAMES)
index 2681fc79f5f93d41ab96a29222986e4ce0405956..308823c50d990fefaed02f50969430c349000d42 100644 (file)
@@ -202,7 +202,11 @@ int pysqlite_build_row_cast_map(pysqlite_Cursor* self)
             decltype = sqlite3_column_decltype(self->statement->st, i);
             if (decltype) {
                 for (pos = decltype;;pos++) {
-                    if (*pos == ' ' || *pos == 0) {
+                    /* Converter names are split at '(' and blanks.
+                     * This allows 'INTEGER NOT NULL' to be treated as 'INTEGER' and
+                     * 'NUMBER(10)' to be treated as 'NUMBER', for example.
+                     * In other words, it will work as people expect it to work.*/
+                    if (*pos == ' ' || *pos == '(' || *pos == 0) {
                         py_decltype = PyString_FromStringAndSize(decltype, pos - decltype);
                         if (!py_decltype) {
                             return -1;