Changeset 336


Ignore:
Timestamp:
Oct 31, 2008, 1:13:50 PM (11 years ago)
Author:
cito
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.

Location:
trunk/module
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/module/TEST_PyGreSQL_dbapi20.py

    r311 r336  
    11#!/usr/bin/env python
    2 # $Id: TEST_PyGreSQL_dbapi20.py,v 1.7 2006-12-30 07:06:49 darcy Exp $
     2# $Id: TEST_PyGreSQL_dbapi20.py,v 1.8 2008-10-31 17:13:50 cito Exp $
    33
    44import dbapi20
     
    5252        self.assertEqual(curs.fetchone(), {'a': 1, 'b': 2})
    5353
    54     def test_nextset(self): pass
    55     def test_setoutputsize(self): pass
     54    def test_fetch_2_rows(self):
     55        Decimal = pgdb.Decimal
     56        values = ['test', 'test', True, 5, 6L, 5.7,
     57            Decimal('234.234234'), Decimal('75.45'),
     58            '2008-10-20 15:25:35', 7897234L]
     59        table = self.table_prefix + 'booze'
     60        con = self._connect()
     61        try:
     62            cur = con.cursor()
     63            cur.execute("create table %s ("
     64                "stringtest varchar,"
     65                "binarytest bytea,"
     66                "booltest bool,"
     67                "integertest int4,"
     68                "longtest int8,"
     69                "floattest float8,"
     70                "numerictest numeric,"
     71                "moneytest money,"
     72                "datetimetest timestamp,"
     73                "rowidtest oid)" % table)
     74            for i in range(2):
     75                cur.execute("insert into %s values ("
     76                    "%%s,%%s,%%s,%%s,%%s,%%s,%%s,"
     77                    "'%%s'::money,%%s,%%s)" % table, values)
     78            cur.execute("select * from %s" % table)
     79            rows = cur.fetchall()
     80            self.assertEqual(len(rows), 2)
     81            self.assertEqual(rows[0], values)
     82            self.assertEqual(rows[0], rows[1])
     83        finally:
     84            con.close()
     85
     86    def test_nextset(self):
     87        pass
     88
     89    def test_setoutputsize(self):
     90        pass
    5691
    5792if __name__ == '__main__':
  • trunk/module/pgdb.py

    r335 r336  
    55# Written by D'Arcy J.M. Cain
    66#
    7 # $Id: pgdb.py,v 1.38 2008-10-10 05:49:34 cito Exp $
     7# $Id: pgdb.py,v 1.39 2008-10-31 17:13:50 cito Exp $
    88#
    99
     
    9898                self._src = cnx.source()
    9999                self._cache = {}
     100                self._casters = {}
    100101
    101102        def typecast(self, typ, value):
    102                 if value is None:
    103                         # for NULL values, no typecast is necessary
     103                return self._typecaster(typ)(value)
     104
     105        def _typecaster(self, typ):
     106                # Type comparisons are very expensive because of the
     107                # shear amount of string comparisons it will generate.
     108                # Cache type casters for much better performance
     109                # when fetching many values.
     110                try:
     111                        return self._casters[typ]
     112                except KeyError:
     113                        caster = self._create_typecaster(typ)
     114                        self._casters[typ] = caster
     115                        return caster
     116
     117        def _create_typecaster(self, typ):
     118
     119                def no_cast(value):
    104120                        return value
    105                 if typ == STRING:
    106                         pass
    107                 elif typ == BINARY:
    108                         pass
    109                 elif typ == BOOL:
    110                         value = (value[:1] in ['t','T'])
     121
     122                def cast_bool(value):
     123                        return value[:1] in ['t','T']
     124
     125                def cast_money(value):
     126                        return Decimal(''.join(filter(
     127                                lambda v: v in '0123456789.-', value)))
     128
     129                def cast(caster):
     130                        def cast_if_not_none(value):
     131                                if value is None:
     132                                        # NULL/None are equivalent regardless of type
     133                                        return None
     134                                else:
     135                                        return caster(value)
     136                        return cast_if_not_none
     137
     138                if typ == BOOL:
     139                        return cast(cast_bool)
     140                elif typ == STRING or typ == BINARY:
     141                        return no_cast
    111142                elif typ == INTEGER:
    112                         value = int(value)
     143                        return cast(int)
    113144                elif typ == LONG:
    114                         value = long(value)
     145                        return cast(long)
    115146                elif typ == FLOAT:
    116                         value = float(value)
     147                        return cast(float)
    117148                elif typ == NUMERIC:
    118                         value = Decimal(value)
     149                        return cast(Decimal)
    119150                elif typ == MONEY:
    120                         value = ''.join(filter(lambda v: v in '0123456789.-', value))
    121                         value = Decimal(value)
     151                        return cast(cast_money)
    122152                elif typ == DATETIME:
    123153                        # format may differ ... we'll give string
    124                         pass
     154                        return no_cast
    125155                elif typ == ROWID:
    126                         value = long(value)
    127                 return value
     156                        return cast(long)
     157                else:
     158                        return no_cast
    128159
    129160        def getdescr(self, oid):
Note: See TracChangeset for help on using the changeset viewer.