Update of /usr/cvs/Public/pygresql/module
In directory druid.net:/tmp/cvs-serv7038
Modified Files:
TEST_PyGreSQL_dbapi20.py pgdb.py
Log Message:
As suggested by Peter Schuller, increase fetchall() performance for big result
sets by using type casters. Also fix type casting of boolean values which was
accidentally broken in 1.34. Added unit test to check the type casting.
To see the diffs for this commit:
http://www.druid.net/pygresql/viewcvs.cgi/cvs/pygresql/module/TEST_PyGreSQL_dbapi20.py.diff?r1=1.7&r2=1.8
Index: TEST_PyGreSQL_dbapi20.py
===================================================================
RCS file: /usr/cvs/Public/pygresql/module/TEST_PyGreSQL_dbapi20.py,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- TEST_PyGreSQL_dbapi20.py 30 Dec 2006 07:06:49 -0000 1.7
+++ TEST_PyGreSQL_dbapi20.py 31 Oct 2008 17:13:50 -0000 1.8
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-# $Id: TEST_PyGreSQL_dbapi20.py,v 1.7 2006/12/30 07:06:49 darcy Exp $
+# $Id: TEST_PyGreSQL_dbapi20.py,v 1.8 2008/10/31 17:13:50 cito Exp $
import dbapi20
import unittest
@@ -51,8 +51,43 @@
curs.execute("SELECT 1 AS a, 2 AS b")
self.assertEqual(curs.fetchone(), {'a': 1, 'b': 2})
- def test_nextset(self): pass
- def test_setoutputsize(self): pass
+ def test_fetch_2_rows(self):
+ Decimal = pgdb.Decimal
+ values = ['test', 'test', True, 5, 6L, 5.7,
+ Decimal('234.234234'), Decimal('75.45'),
+ '2008-10-20 15:25:35', 7897234L]
+ table = self.table_prefix + 'booze'
+ con = self._connect()
+ try:
+ cur = con.cursor()
+ cur.execute("create table %s ("
+ "stringtest varchar,"
+ "binarytest bytea,"
+ "booltest bool,"
+ "integertest int4,"
+ "longtest int8,"
+ "floattest float8,"
+ "numerictest numeric,"
+ "moneytest money,"
+ "datetimetest timestamp,"
+ "rowidtest oid)" % table)
+ for i in range(2):
+ cur.execute("insert into %s values ("
+ "%%s,%%s,%%s,%%s,%%s,%%s,%%s,"
+ "'%%s'::money,%%s,%%s)" % table, values)
+ cur.execute("select * from %s" % table)
+ rows = cur.fetchall()
+ self.assertEqual(len(rows), 2)
+ self.assertEqual(rows[0], values)
+ self.assertEqual(rows[0], rows[1])
+ finally:
+ con.close()
+
+ def test_nextset(self):
+ pass
+
+ def test_setoutputsize(self):
+ pass
if __name__ == '__main__':
unittest.main()
http://www.druid.net/pygresql/viewcvs.cgi/cvs/pygresql/module/pgdb.py.diff?r1=1.38&r2=1.39
Index: pgdb.py
===================================================================
RCS file: /usr/cvs/Public/pygresql/module/pgdb.py,v
retrieving revision 1.38
retrieving revision 1.39
diff -u -r1.38 -r1.39
--- pgdb.py 10 Oct 2008 05:49:34 -0000 1.38
+++ pgdb.py 31 Oct 2008 17:13:50 -0000 1.39
@@ -4,7 +4,7 @@
#
# Written by D'Arcy J.M. Cain
#
-# $Id: pgdb.py,v 1.38 2008/10/10 05:49:34 cito Exp $
+# $Id: pgdb.py,v 1.39 2008/10/31 17:13:50 cito Exp $
#
"""pgdb - DB-API 2.0 compliant module for PygreSQL.
@@ -97,34 +97,65 @@
def __init__(self, cnx):
self._src = cnx.source()
self._cache = {}
+ self._casters = {}
def typecast(self, typ, value):
- if value is None:
- # for NULL values, no typecast is necessary
+ return self._typecaster(typ)(value)
+
+ def _typecaster(self, typ):
+ # Type comparisons are very expensive because of the
+ # shear amount of string comparisons it will generate.
+ # Cache type casters for much better performance
+ # when fetching many values.
+ try:
+ return self._casters[typ]
+ except KeyError:
+ caster = self._create_typecaster(typ)
+ self._casters[typ] = caster
+ return caster
+
+ def _create_typecaster(self, typ):
+
+ def no_cast(value):
return value
- if typ == STRING:
- pass
- elif typ == BINARY:
- pass
- elif typ == BOOL:
- value = (value[:1] in ['t','T'])
+
+ def cast_bool(value):
+ return value[:1] in ['t','T']
+
+ def cast_money(value):
+ return Decimal(''.join(filter(
+ lambda v: v in '0123456789.-', value)))
+
+ def cast(caster):
+ def cast_if_not_none(value):
+ if value is None:
+ # NULL/None are equivalent regardless
of type
+ return None
+ else:
+ return caster(value)
+ return cast_if_not_none
+
+ if typ == BOOL:
+ return cast(cast_bool)
+ elif typ == STRING or typ == BINARY:
+ return no_cast
elif typ == INTEGER:
- value = int(value)
+ return cast(int)
elif typ == LONG:
- value = long(value)
+ return cast(long)
elif typ == FLOAT:
- value = float(value)
+ return cast(float)
elif typ == NUMERIC:
- value = Decimal(value)
+ return cast(Decimal)
elif typ == MONEY:
- value = ''.join(filter(lambda v: v in '0123456789.-',
value))
- value = Decimal(value)
+ return cast(cast_money)
elif typ == DATETIME:
# format may differ ... we'll give string
- pass
+ return no_cast
elif typ == ROWID:
- value = long(value)
- return value
+ return cast(long)
+ else:
+ return no_cast
def getdescr(self, oid):
try:
_______________________________________________
PyGreSQL mailing list
[email protected]
http://mailman.vex.net/mailman/listinfo/pygresql