Skip to content

Commit d2b056f

Browse files
author
gerhard.haering
committed
Implemented feature request 2157: Converter names are cut off at '('
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. git-svn-id: http://svn.python.org/projects/python/trunk@62702 6015fed2-1504-0410-9fe1-9d1591cc4771
1 parent 1713f20 commit d2b056f

3 files changed

Lines changed: 26 additions & 10 deletions

File tree

Doc/library/sqlite3.rst

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,11 @@ Module functions and constants
114114
:func:`connect` function.
115115

116116
Setting it makes the :mod:`sqlite3` module parse the declared type for each
117-
column it returns. It will parse out the first word of the declared type, i. e.
118-
for "integer primary key", it will parse out "integer". Then for that column, it
119-
will look into the converters dictionary and use the converter function
120-
registered for that type there. Converter names are case-sensitive!
117+
column it returns. It will parse out the first word of the declared type,
118+
i. e. for "integer primary key", it will parse out "integer", or for
119+
"number(10)" it will parse out "number". Then for that column, it will look
120+
into the converters dictionary and use the converter function registered for
121+
that type there.
121122

122123

123124
.. data:: PARSE_COLNAMES
@@ -666,10 +667,6 @@ and constructs a :class:`Point` object from it.
666667
Converter functions **always** get called with a string, no matter under which
667668
data type you sent the value to SQLite.
668669

669-
.. note::
670-
671-
Converter names are looked up in a case-sensitive manner.
672-
673670
::
674671

675672
def convert_point(s):

Lib/sqlite3/test/types.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ def __str__(self):
9898
def setUp(self):
9999
self.con = sqlite.connect(":memory:", detect_types=sqlite.PARSE_DECLTYPES)
100100
self.cur = self.con.cursor()
101-
self.cur.execute("create table test(i int, s str, f float, b bool, u unicode, foo foo, bin blob)")
101+
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))")
102102

103103
# override float, make them always return the same number
104104
sqlite.converters["FLOAT"] = lambda x: 47.2
@@ -107,11 +107,13 @@ def setUp(self):
107107
sqlite.converters["BOOL"] = lambda x: bool(int(x))
108108
sqlite.converters["FOO"] = DeclTypesTests.Foo
109109
sqlite.converters["WRONG"] = lambda x: "WRONG"
110+
sqlite.converters["NUMBER"] = float
110111

111112
def tearDown(self):
112113
del sqlite.converters["FLOAT"]
113114
del sqlite.converters["BOOL"]
114115
del sqlite.converters["FOO"]
116+
del sqlite.converters["NUMBER"]
115117
self.cur.close()
116118
self.con.close()
117119

@@ -203,6 +205,19 @@ def CheckBlob(self):
203205
row = self.cur.fetchone()
204206
self.failUnlessEqual(row[0], val)
205207

208+
def CheckNumber1(self):
209+
self.cur.execute("insert into test(n1) values (5)")
210+
value = self.cur.execute("select n1 from test").fetchone()[0]
211+
# if the converter is not used, it's an int instead of a float
212+
self.failUnlessEqual(type(value), float)
213+
214+
def CheckNumber2(self):
215+
"""Checks wether converter names are cut off at '(' characters"""
216+
self.cur.execute("insert into test(n2) values (5)")
217+
value = self.cur.execute("select n2 from test").fetchone()[0]
218+
# if the converter is not used, it's an int instead of a float
219+
self.failUnlessEqual(type(value), float)
220+
206221
class ColNamesTests(unittest.TestCase):
207222
def setUp(self):
208223
self.con = sqlite.connect(":memory:", detect_types=sqlite.PARSE_COLNAMES)

Modules/_sqlite/cursor.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,11 @@ int pysqlite_build_row_cast_map(pysqlite_Cursor* self)
202202
decltype = sqlite3_column_decltype(self->statement->st, i);
203203
if (decltype) {
204204
for (pos = decltype;;pos++) {
205-
if (*pos == ' ' || *pos == 0) {
205+
/* Converter names are split at '(' and blanks.
206+
* This allows 'INTEGER NOT NULL' to be treated as 'INTEGER' and
207+
* 'NUMBER(10)' to be treated as 'NUMBER', for example.
208+
* In other words, it will work as people expect it to work.*/
209+
if (*pos == ' ' || *pos == '(' || *pos == 0) {
206210
py_decltype = PyString_FromStringAndSize(decltype, pos - decltype);
207211
if (!py_decltype) {
208212
return -1;

0 commit comments

Comments
 (0)