From: Gerhard H?r. <gha...@us...> - 2002-05-15 16:24:21
|
Update of /cvsroot/pypgsql/pypgsql/pyPgSQL In directory usw-pr-cvs1:/tmp/cvs-serv12703/pyPgSQL Modified Files: PgSQL.py Log Message: 15MAY2002 gh Got rid of redundant building and storing of the mapping of column names to column positions in the PgResultSet class. Now, rows of the same query are instances of a dynamically created class, which has this mapping as a class attribute instead of an attri- bute of the instance. This saves a lot of space, and also slightly increases performance of cursor fetches. Index: PgSQL.py =================================================================== RCS file: /cvsroot/pypgsql/pypgsql/pyPgSQL/PgSQL.py,v retrieving revision 1.9 retrieving revision 1.10 diff -C2 -d -r1.9 -r1.10 *** PgSQL.py 21 Apr 2002 21:01:48 -0000 1.9 --- PgSQL.py 15 May 2002 16:24:18 -0000 1.10 *************** *** 30,33 **** --- 30,40 ---- # Date Ini Description | # --------- --- ------------------------------------------------------- | + # 15MAY2002 gh Got rid of redundant building and storing of the | + # mapping of column names to column positions in the | + # PgResultSet class. Now, rows of the same query are | + # instances of a dynamically created class, which has | + # this mapping as a class attribute instead of an attri- | + # bute of the instance. This saves a lot of space, and | + # also slightly increases performance of cursor fetches. | # 21APR2002 gh Improved the array parsing, so that it now passes all | # the new mean testcases. Added support for parsing | *************** *** 309,312 **** --- 316,320 ---- import string import re + import new try: *************** *** 1410,1413 **** --- 1418,1422 ---- return 'NULL' + #-----------------------------------------------------------------------+ # Name: PgResultSet | *************** *** 1417,1440 **** # feature of being able to reference an attribute by | # column name in addition to a zero-based numeric index. | #-----------------------------------------------------------------------+ class PgResultSet: ! def __init__(self, value, description, mapname=None): self.__dict__['baseObj'] = value - self.__dict__['_desc_'] = description - - # Now we set up attributes based on the column names in the result set - self.__dict__['_xlatkey'] = {} - if mapname is None: - for _i in range(len(description)): - self.__dict__['_xlatkey'][description[_i][0]] = _i - else: - self.__dict__['_xlatkey'].update(mapname) - return def __getattr__(self, key): ! if self._xlatkey.has_key(key): ! return self.baseObj[self._xlatkey[key]] raise AttributeError, key --- 1426,1452 ---- # feature of being able to reference an attribute by | # column name in addition to a zero-based numeric index. | + # | + # This class isn't used directly, instead it's used as a | + # base class for the actual result set class created with | + # make_PgResultSetClass. | + # | #-----------------------------------------------------------------------+ class PgResultSet: ! # It may not be obvious what self.__class__ does: ! # Apart from the __init__ method, all methods are called on instances of a ! # class dynamically created make_PgResultSetClass, which means that when ! # you call a method, self.__class__ is *not* PgResultSet, but a subclass of ! # it created with make_PgResultSetClass (using the new module). The ! # subclass will have a class attribute called _xlatkey, which is a mapping ! # of column names to column positions. ! ! def __init__(self, value): self.__dict__['baseObj'] = value def __getattr__(self, key): ! if self.__class__._xlatkey.has_key(key): ! return self.baseObj[self.__class__._xlatkey[key]] raise AttributeError, key *************** *** 1445,1450 **** raise AttributeError, "%s is read-only." % key ! if self._xlatkey.has_key(key): ! self.__dict__['baseObj'][self._xlatkey(key)] = value else: raise AttributeError, key --- 1457,1462 ---- raise AttributeError, "%s is read-only." % key ! if self.__class__._xlatkey.has_key(key): ! self.__dict__['baseObj'][self.__class__._xlatkey(key)] = value else: raise AttributeError, key *************** *** 1455,1495 **** def __getitem__(self, key): if type(key) is StringType: ! key = self._xlatkey[key] return self.baseObj[key] def __setitem__(self, key, value): if type(key) is StringType: ! key = self._xlatkey[key] self.baseObj[key] = value return def __getslice__(self, i, j): ! return PgResultSet(self.baseObj[i:j], self._desc_[i:j]) ! ! def __setslice__(self, i, j, value): ! # If we are passed a PgResultSet object, convert it to the base ! # sequence object for the result set. Also update the description from ! # the PgResultSet. ! if i < 0: ! i = len(self.baseObj) + i ! if j < 0: ! j = len(self.baseObj) + j ! elif j > len(self.baseObj): ! j = len(self.baseObj) ! if isinstance(value, PgResultSet): ! self.__dict__['_desc_'][i:j] = value._desc_ ! self.__dict__['_xlatkey'] = {} ! for _i in range(len(self._desc_)): ! self.__dict__['_xlatkey'][self._desc_[_i][0]] = _i ! value = value.baseObj ! else: ! try: ! if len(value) != (j - i): ! raise ValueError, 'slice size mis-match' ! except: ! raise TypeError, 'illegal argument type for built-in operation' ! ! self.baseObj[i:j] = value ! return def __repr__(self): --- 1467,1483 ---- def __getitem__(self, key): if type(key) is StringType: ! key = self.__class__._xlatkey[key] return self.baseObj[key] def __setitem__(self, key, value): if type(key) is StringType: ! key = self.__class__._xlatkey[key] self.baseObj[key] = value return def __getslice__(self, i, j): ! klass = make_PgResultSetClass(self.__class__._desc_[i:j]) ! obj = klass(self.baseObj[i:j]) ! return obj def __repr__(self): *************** *** 1521,1529 **** def has_key(self, key): ! return self._xlatkey.has_key(key) def get(self, key): return self[key] #-----------------------------------------------------------------------+ # Define the PgSQL function calls: | --- 1509,1531 ---- def has_key(self, key): ! return self.__class__._xlatkey.has_key(key) def get(self, key): return self[key] + def make_PgResultSetClass(description, mapname=None): + """Dynamically create a new subclass of PgResultSet.""" + klass = new.classobj("PgResultSetConcreteClass", (PgResultSet,), {}) + klass.__dict__['_desc_'] = description + + klass.__dict__['_xlatkey'] = {} + if mapname is None: + for _i in range(len(description)): + klass.__dict__['_xlatkey'][description[_i][0]] = _i + else: + klass.__dict__['_xlatkey'].update(mapname) + return klass + + #-----------------------------------------------------------------------+ # Define the PgSQL function calls: | *************** *** 2025,2028 **** --- 2027,2032 ---- raise Warning, self.conn.notices.pop() self.conn.__dict__["inTransaction"] = 1 + self.__dict__["PgResultSetClass"] = None + def __del__(self): *************** *** 2085,2091 **** self.__dict__['rowcount'] = 1 - # Return a new PgResultSet. Note that we pass a copy of the descrip- - # tion to PgResultSet. - if fetchReturnsList: # Return a list (This is the minimum required by DB-API 2.0 --- 2089,2092 ---- *************** *** 2093,2099 **** return _j else: ! # Return a new PgResultSet. Note that we pass a copy of the ! # description to PgResultSet. ! return PgResultSet(_j, self.description[:], self._mapname) def __fetchManyRows(self, count, iList=[]): --- 2094,2098 ---- return _j else: ! return self.PgResultSetClass(_j) def __fetchManyRows(self, count, iList=[]): *************** *** 2198,2201 **** --- 2197,2204 ---- # Add the fieldname:fieldindex to the _mapname dictionary self._mapname[_j[0]] = _i + + # Create a subclass of PgResultSet. Note that we pass a copy of the + # description to this class. + self.PgResultSetClass = make_PgResultSetClass(self.description[:], self._mapname) def callproc(self, proc, *args): |