From: Gerhard H?r. <gha...@us...> - 2002-04-21 21:01:50
|
Update of /cvsroot/pypgsql/pypgsql/pyPgSQL In directory usw-pr-cvs1:/tmp/cvs-serv20866/pyPgSQL Modified Files: PgSQL.py Log Message: 21APR2002 gh Improved the array parsing, so that it now passes all the new mean testcases. Added support for parsing multidimensional arrays. Eventually, the array parsing code should go as a support function into libpq. --- Replaced all typechecks with "is" operators instead of equals. Mark McEahern had a problem with using pyPgSQL in combination with a FixedPoint class where the reason was that the FixedPoint class was not com- parable to None. The consensus on python-list was that None and all types are singletons, so they should be checked using "is", which is also faster, because it only checks for object identity. Index: PgSQL.py =================================================================== RCS file: /cvsroot/pypgsql/pypgsql/pyPgSQL/PgSQL.py,v retrieving revision 1.8 retrieving revision 1.9 diff -C2 -d -r1.8 -r1.9 *** PgSQL.py 16 Apr 2002 00:14:01 -0000 1.8 --- PgSQL.py 21 Apr 2002 21:01:48 -0000 1.9 *************** *** 30,33 **** --- 30,45 ---- # Date Ini Description | # --------- --- ------------------------------------------------------- | + # 21APR2002 gh Improved the array parsing, so that it now passes all | + # the new mean testcases. Added support for parsing | + # multidimensional arrays. Eventually, the array parsing | + # code should go as a support function into libpq. | + # --- Replaced all typechecks with "is" operators instead | + # of equals. Mark McEahern had a problem with using | + # pyPgSQL in combination with a FixedPoint class where | + # the reason was that the FixedPoint class was not com- | + # parable to None. The consensus on python-list was that | + # None and all types are singletons, so they should be | + # checked using "is", which is also faster, because it | + # only checks for object identity. | # 16APR2002 gh Fix the array parsing so it also works with PostgreSQL | # versions 7.2.x. The PostgreSQL developers changed the | *************** *** 261,265 **** or affected (for DML statement). ! cursor.oidValue The object ID of the inserted record, if the last SQL command was an INSERT, otherwise it returns 0 (aka. InvalidOid) --- 273,277 ---- or affected (for DML statement). ! cursor.oidValue The object ID of the inserted record, if the last SQL command was an INSERT, otherwise it returns 0 (aka. InvalidOid) *************** *** 482,486 **** """ class LeaveLoopException(Exception): pass ! lst = [] s = s[1:-1] # drop '{' and '}' at start/end --- 494,498 ---- """ class LeaveLoopException(Exception): pass ! lst = [] s = s[1:-1] # drop '{' and '}' at start/end *************** *** 496,505 **** # A quoted element, find the end-quote, which is the next # quote char that is not escaped. ! end_quote_pos = pos while 1: ! end_quote_pos = s.find('"', end_quote_pos + 1) ! assert(end_quote_pos > pos) ! if s[end_quote_pos - 1] != '\\': ! break lst.append(s[pos + 1:end_quote_pos]) --- 508,523 ---- # A quoted element, find the end-quote, which is the next # quote char that is not escaped. ! end_quote_pos = pos + 1 ! escape = 0 while 1: ! if s[end_quote_pos] == '\\': ! escape = not escape ! elif s[end_quote_pos] == '"': ! if not escape: ! break ! escape = 0 ! else: ! escape = 0 ! end_quote_pos += 1 lst.append(s[pos + 1:end_quote_pos]) *************** *** 513,535 **** # This array element is not quoted, so it ends either at # the next comma that isn't escaped, or at the end of the ! # string. ! next_comma_pos = pos ! while 1: ! next_comma_pos = s.find(',', next_comma_pos + 1) ! if next_comma_pos < 0: ! # This is the last array element. ! lst.append(s[pos:]) ! raise LeaveLoopException else: ! if s[next_comma_pos - 1] != '\\': ! break ! lst.append(s[pos:next_comma_pos]) ! pos = next_comma_pos + 1 except LeaveLoopException: pass ! # Get rid of the array's backslash escaping level def convertEscapes(s): ! return s.replace('\\"', '"') lst = map(convertEscapes, lst) return lst --- 531,639 ---- # This array element is not quoted, so it ends either at # the next comma that isn't escaped, or at the end of the ! # string, or, if it contains a subarray, at the position ! # of the corresponding curly brace. ! if s[pos] != '{': ! next_comma_pos = pos + 1 ! escape = 0 ! while 1: ! if next_comma_pos >= len(s): ! # This is the last array element. ! lst.append(s[pos:]) ! raise LeaveLoopException ! ! if s[next_comma_pos] == '\\': ! escape = not escape ! elif s[next_comma_pos] == ',': ! if not escape: ! break ! escape = 0 ! else: ! escape = 0 ! next_comma_pos += 1 ! ! curelem = s[pos:next_comma_pos] ! if curelem.startswith("{"): ! lst.append(self.parseArray(curelem[1:-1])) else: ! lst.append(curelem) ! pos = next_comma_pos + 1 ! if s[pos] == ',': ! pos += 1 ! else: ! # The current character is '{', which means we've ! # found a sub-array: ! # We find the end of the sub-array, then feed this ! # string into parseArray again. ! escape = 0 ! open_braces = 1 ! closing_brace_pos = pos + 1 ! in_quotes = 0 ! while 1: ! if s[closing_brace_pos] == '\\': ! escape = not escape ! elif s[closing_brace_pos] == '{': ! if (not escape) and (not in_quotes): ! open_braces += 1 ! escape = 0 ! elif s[closing_brace_pos] == '}': ! if (not escape) and (not in_quotes): ! open_braces -= 1 ! if open_braces == 0: ! break ! escape = 0 ! elif s[closing_brace_pos] == '"': ! if not escape: ! in_quotes = not in_quotes ! escape = 0 ! else: ! escape = 0 ! closing_brace_pos += 1 ! ! curelem = s[pos:closing_brace_pos + 1] ! lst.append(self.parseArray(curelem)) ! pos = closing_brace_pos + 1 ! if pos >= len(s): ! break ! if s[pos] == ',': ! pos += 1 ! except LeaveLoopException: pass ! # Get rid of the escaping in the array string def convertEscapes(s): ! # If we're called with a list in a multi-dimensional ! # array, simply return the list. We only convert the ! # elements of the multi-dimensional array. ! if type(s) is ListType: ! return s ! ! schars = [] ! escape = 0 ! octdigits = [] ! ! for char in s: ! if char == '\\': ! escape += 1 ! if escape == 2: ! schars.append(char) ! escape = 0 ! else: ! if escape: ! if char in string.digits: ! octdigits.append(char) ! else: ! if octdigits != []: ! curchar = chr(int(octdigits[0]) * 64) + \ ! chr(int(octdigits[1]) * 8) + \ ! chr(int(octdigits[2])) ! schars.append(curchar) ! octdigits = [] ! schars.append(char) ! else: ! schars.append(char) ! escape = 0 ! return "".join(schars) ! lst = map(convertEscapes, lst) return lst *************** *** 541,545 **** object.""" ! if value == None: return value --- 645,649 ---- object.""" ! if value is None: return value *************** *** 554,572 **** if _ftv == PG_INT2: ! if type(value) == PgInt2Type: return value else: return PgInt2(value) elif _ftv == PG_INT4 or _ftv == ROWID: ! if type(value) == IntType: return value else: return int(value) elif _ftv == PG_INT8: ! if type(PgInt8) == ClassType: if isinstance(value, PgInt8): return value else: ! if type(value) == PgInt8Type: return value return PgInt8(value) --- 658,676 ---- if _ftv == PG_INT2: ! if type(value) is PgInt2Type: return value else: return PgInt2(value) elif _ftv == PG_INT4 or _ftv == ROWID: ! if type(value) is IntType: return value else: return int(value) elif _ftv == PG_INT8: ! if type(PgInt8) is ClassType: if isinstance(value, PgInt8): return value else: ! if type(value) is PgInt8Type: return value return PgInt8(value) *************** *** 582,593 **** return PgMoney(value) elif _ftv == DATETIME: ! if type(value) in [ DateTimeType, DateTimeDeltaType ]: return value else: return DateTime.ISO.ParseAny(value) elif _ftv == BINARY: ! if isinstance(value, PgBytea) or type(value) == PgLargeObjectType: return value ! elif type(value) == IntType: return PgLargeObject(self.conn, value) else: --- 686,697 ---- return PgMoney(value) elif _ftv == DATETIME: ! if type(value) in [DateTimeType, DateTimeDeltaType]: return value else: return DateTime.ISO.ParseAny(value) elif _ftv == BINARY: ! if isinstance(value, PgBytea) or type(value) is PgLargeObjectType: return value ! elif type(value) is IntType: return PgLargeObject(self.conn, value) else: *************** *** 614,618 **** for _i in range(len(lst)): ! if type(lst[_i]) == ListType: lst[_i] = self.handleArray(colinfo, lst[_i]) elif _ftv == PG_INT4 or _ftv == ROWID: --- 718,722 ---- for _i in range(len(lst)): ! if type(lst[_i]) is ListType: lst[_i] = self.handleArray(colinfo, lst[_i]) elif _ftv == PG_INT4 or _ftv == ROWID: *************** *** 674,679 **** # Description: A Python wrapper class for the PostgreSQL types that do | # not (yet) have an implementation in python. The number | ! # of types in this catagory will shrink as more wrappers | ! # are implementated. | # | # Note: A Python String is used to store the PostgreSQL type in | --- 778,783 ---- # Description: A Python wrapper class for the PostgreSQL types that do | # not (yet) have an implementation in python. The number | ! # of types in this category will shrink as more wrappers | ! # are implemented. | # | # Note: A Python String is used to store the PostgreSQL type in | *************** *** 683,687 **** class PgOther: def __init__(self, value): ! if type(value) != StringType: raise TypeError, "argument must be a string." --- 787,791 ---- class PgOther: def __init__(self, value): ! if type(value) is not StringType: raise TypeError, "argument must be a string." *************** *** 737,741 **** class PgBytea: def __init__(self, value): ! if type(value) != StringType: raise TypeError, "argument must be a string." --- 841,845 ---- class PgBytea: def __init__(self, value): ! if type(value) is not StringType: raise TypeError, "argument must be a string." *************** *** 789,798 **** class PgNumeric: def __init__(self, value, prec=None, scale=None): ! if type(value) == LongType or type(value) == IntType or value == None: ! if prec == None or scale == None: raise TypeError, \ "you must supply precision and scale when value is a " \ "integer, long, or None" ! if value == None: self.__v = value else: --- 893,902 ---- class PgNumeric: def __init__(self, value, prec=None, scale=None): ! if type(value) is LongType or type(value) is IntType or value is None: ! if prec is None or scale is None: raise TypeError, \ "you must supply precision and scale when value is a " \ "integer, long, or None" ! if value is None: self.__v = value else: *************** *** 802,806 **** return ! if type(value) != StringType: raise TypeError, "value must be a string." --- 906,910 ---- return ! if type(value) is not StringType: raise TypeError, "value must be a string." *************** *** 866,870 **** # a trailing 'L', if so, remove it. Python 1.5 has the trailing 'L', # Python 1.6 does not. ! if value == None: _v = str(self.__v) else: --- 970,974 ---- # a trailing 'L', if so, remove it. Python 1.5 has the trailing 'L', # Python 1.6 does not. ! if value is None: _v = str(self.__v) else: *************** *** 900,904 **** if type(other) in [IntType, LongType]: _s = str(other) ! elif type(other) == FloatType: _s = str(long(((other * (10.0 ** self.__s)) + 0.5))) elif type(other) == type(self): --- 1004,1008 ---- if type(other) in [IntType, LongType]: _s = str(other) ! elif type(other) is FloatType: _s = str(long(((other * (10.0 ** self.__s)) + 0.5))) elif type(other) == type(self): *************** *** 1022,1026 **** class PgMoney: def __init__(self, value): ! if value == None: self.value = value return --- 1126,1130 ---- class PgMoney: def __init__(self, value): ! if value is None: self.value = value return *************** *** 1037,1044 **** def __coerce__(self, other): ! if other == None: return None res = coerce(self.value, other) ! if res == None: return None _s, _o = res --- 1141,1148 ---- def __coerce__(self, other): ! if other is None: return None res = coerce(self.value, other) ! if res is None: return None _s, _o = res *************** *** 1156,1160 **** class PgInt8: def __init__(self, value): ! if value == None: self.value = value return --- 1260,1264 ---- class PgInt8: def __init__(self, value): ! if value is None: self.value = value return *************** *** 1171,1178 **** def __coerce__(self, other): ! if other == None: return None res = coerce(self.value, other) ! if res == None: return None _s, _o = res --- 1275,1282 ---- def __coerce__(self, other): ! if other is None: return None res = coerce(self.value, other) ! if res is None: return None _s, _o = res *************** *** 1323,1327 **** # Now we set up attributes based on the column names in the result set self.__dict__['_xlatkey'] = {} ! if mapname == None: for _i in range(len(description)): self.__dict__['_xlatkey'][description[_i][0]] = _i --- 1427,1431 ---- # 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 *************** *** 1350,1359 **** def __getitem__(self, key): ! if type(key) == StringType: key = self._xlatkey[key] return self.baseObj[key] def __setitem__(self, key, value): ! if type(key) == StringType: key = self._xlatkey[key] self.baseObj[key] = value --- 1454,1463 ---- 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 *************** *** 1425,1429 **** # Define the PgSQL function calls: | # | ! # connect() -- connecnt to a PostgreSQL database. | # _handleArray() -- Transform a Python list into a string repre- | # senting a PostgreSQL array. | --- 1529,1533 ---- # Define the PgSQL function calls: | # | ! # connect() -- connect to a PostgreSQL database. | # _handleArray() -- Transform a Python list into a string repre- | # senting a PostgreSQL array. | *************** *** 1447,1451 **** # Try getting values from the DSN first. ! if dsn != None: try: params = string.split(dsn, ":") --- 1551,1555 ---- # Try getting values from the DSN first. ! if dsn is not None: try: params = string.split(dsn, ":") *************** *** 1461,1467 **** # Override from the keyword arguments, if needed. ! if (user != None): _d["user"] = user ! if (password != None): _d["password"] = password ! if (host != None): _d["host"] = host try: --- 1565,1571 ---- # Override from the keyword arguments, if needed. ! if (user is not None): _d["user"] = user ! if (password is not None): _d["password"] = password ! if (host is not None): _d["host"] = host try: *************** *** 1471,1478 **** except: pass ! if (database != None): _d["dbname"] = database ! if (port != None): _d["port"] = port ! if (options != None): _d["options"] = options ! if (tty != None): _d["tty"] = tty # Build up the connection info string passed to PQconnectdb --- 1575,1582 ---- except: pass ! if (database is not None): _d["dbname"] = database ! if (port is not None): _d["port"] = port ! if (options is not None): _d["options"] = options ! if (tty is not None): _d["tty"] = tty # Build up the connection info string passed to PQconnectdb *************** *** 1497,1511 **** _j = "'{" for _i in value: ! if type(_i) in [ListType, TupleType]: _v = list(_i) ! _j = _j + _handleArray(_v) + ',' elif hasattr(_i, '_quote'): _j = '%s%s,' % (_j, _i._quote(1)) elif type(_i) in [DateTime.DateTimeType, DateTime.DateTimeDeltaType]: _j = '%s"%s",' % (_j, _i) ! elif type(_i) == PgInt2Type or type(_i) == PgInt8Type: _j = '%s%s,' % (_j, str(_i)) else: ! _j = '%s%s,' % (_j, PgQuoteString(_i, 1)) return _j[:-1] + "}'" --- 1601,1617 ---- _j = "'{" for _i in value: ! if _i is None: ! _j += "," ! elif type(_i) in [ListType, TupleType]: _v = list(_i) ! _j = _j + _handleArray(_v)[1:-1] + ',' elif hasattr(_i, '_quote'): _j = '%s%s,' % (_j, _i._quote(1)) elif type(_i) in [DateTime.DateTimeType, DateTime.DateTimeDeltaType]: _j = '%s"%s",' % (_j, _i) ! elif type(_i) is PgInt2Type or type(_i) is PgInt8Type: _j = '%s%s,' % (_j, str(_i)) else: ! _j = '%s%s,' % (_j, PgQuoteString(str(_i), 1)) return _j[:-1] + "}'" *************** *** 1521,1525 **** quoting.""" ! if value == None: return 'NULL' --- 1627,1631 ---- quoting.""" ! if value is None: return 'NULL' *************** *** 1533,1537 **** return "'%s'" % value ! if type(value) == StringType: return PgQuoteString(value) --- 1639,1643 ---- return "'%s'" % value ! if type(value) is StringType: return PgQuoteString(value) *************** *** 1544,1556 **** insertion.""" ! if type(vdict) == DictType or isinstance(vdict, PgResultSet): t = {} for k, v in vdict.items(): t[k]=_quote(v) ! elif type(vdict) == StringType: # Note: a string is a SequenceType, but is treated as a single # entity, not a sequence of characters. t = (_quote(vdict), ) ! elif type(vdict)in [ListType, TupleType]: t = tuple(map(_quote, vdict)) else: --- 1650,1662 ---- insertion.""" ! if type(vdict) is DictType or isinstance(vdict, PgResultSet): t = {} for k, v in vdict.items(): t[k]=_quote(v) ! elif type(vdict) is StringType: # Note: a string is a SequenceType, but is treated as a single # entity, not a sequence of characters. t = (_quote(vdict), ) ! elif type(vdict) in [ListType, TupleType]: t = tuple(map(_quote, vdict)) else: *************** *** 1599,1606 **** def __setattr__(self, name, value): if name == "autocommit": ! if value == None: raise InterfaceError, \ "Can't delete the autocommit attribute." ! # Don't allow autocommit to change if there are any opened cursors # associated with this connection. if self.__anyLeft(): --- 1705,1712 ---- def __setattr__(self, name, value): if name == "autocommit": ! if value is None: raise InterfaceError, \ "Can't delete the autocommit attribute." ! # Don't allow autocommit to change if there are any opened cursor # associated with this connection. if self.__anyLeft(): *************** *** 1630,1634 **** self.__dict__[name] = 0 elif name == "TransactionLevel": ! if value == None: raise InterfaceError, \ "Can't delete the TransactinLevel attribute." --- 1736,1740 ---- self.__dict__[name] = 0 elif name == "TransactionLevel": ! if value is None: raise InterfaceError, \ "Can't delete the TransactinLevel attribute." *************** *** 1656,1660 **** self.rollback() ! if type(value) != StringType: raise ValueError, "TransactionLevel must be a string." --- 1762,1766 ---- self.rollback() ! if type(value) is not StringType: raise ValueError, "TransactionLevel must be a string." *************** *** 1845,1851 **** "unlink of a PostgreSQL Large Object in a transaction" ! if type(lobj) == IntType: oid = lobj ! elif type(lobj) == PgLargeObjectType: oid = lobj.oid --- 1951,1957 ---- "unlink of a PostgreSQL Large Object in a transaction" ! if type(lobj) is IntType: oid = lobj ! elif type(lobj) is PgLargeObjectType: oid = lobj.oid *************** *** 1873,1879 **** # Generate a unique name for the cursor is one is not given. ! if name == None: name = "PgSQL_%08X" % id(self) ! elif type(name) != StringType: raise TypeError, "Cursor name must be a string." --- 1979,1985 ---- # Generate a unique name for the cursor is one is not given. ! if name is None: name = "PgSQL_%08X" % id(self) ! elif type(name) is not StringType: raise TypeError, "Cursor name must be a string." *************** *** 2097,2101 **** raise InterfaceError, "callproc failed - the cursor is closed." ! if self.conn == None: raise Error, "connection is closed." --- 2203,2207 ---- raise InterfaceError, "callproc failed - the cursor is closed." ! if self.conn is None: raise Error, "connection is closed." *************** *** 2130,2134 **** self._rows_ = self.res.ntuples self._idx_ = 0 ! if type(self.res) != PgResultType: self.__dict__['rowcount'] = -1 else: --- 2236,2240 ---- self._rows_ = self.res.ntuples self._idx_ = 0 ! if type(self.res) is not PgResultType: self.__dict__['rowcount'] = -1 else: *************** *** 2191,2195 **** raise InterfaceError, "execute failed - the cursor is closed." ! if self.conn == None: raise Error, "connection is closed." --- 2297,2301 ---- raise InterfaceError, "execute failed - the cursor is closed." ! if self.conn is None: raise Error, "connection is closed." *************** *** 2262,2266 **** self._idx_ = 0 self.__dict__['rowcount'] = -1 # New query - no fetch occured yet. ! if type(self.res) != PgResultType: self.__dict__['rowcount'] = -1 else: --- 2368,2372 ---- self._idx_ = 0 self.__dict__['rowcount'] = -1 # New query - no fetch occured yet. ! if type(self.res) is not PgResultType: self.__dict__['rowcount'] = -1 else: *************** *** 2315,2319 **** raise InterfaceError, "executemany failed - the cursor is closed." ! if self.conn == None: raise Error, "connection is closed." --- 2421,2425 ---- raise InterfaceError, "executemany failed - the cursor is closed." ! if self.conn is None: raise Error, "connection is closed." *************** *** 2325,2336 **** raise InterfaceError, "fetchone failed - the cursor is closed." ! if self.conn == None: raise Error, "connection is closed." ! if self.res == None: raise Error, \ "fetchone() failed - cursor does not contain a result." elif self.res.resultType != RESULT_DQL: ! if self.closed == None: raise Error, \ "fetchone() Failed - cursor does not contain any rows." --- 2431,2442 ---- raise InterfaceError, "fetchone failed - the cursor is closed." ! if self.conn is None: raise Error, "connection is closed." ! if self.res is None: raise Error, \ "fetchone() failed - cursor does not contain a result." elif self.res.resultType != RESULT_DQL: ! if self.closed is None: raise Error, \ "fetchone() Failed - cursor does not contain any rows." *************** *** 2355,2370 **** raise InterfaceError, "fetchmany failed - the cursor is closed." ! if self.conn == None: raise Error, "connection is closed." ! if self.res == None: raise Error, \ "fetchmany() failed - cursor does not contain a result." elif self.res.resultType != RESULT_DQL: ! if self.close == None: raise Error, \ "fetchmany() Failed - cursor does not contain any rows." ! if sz == None: sz = self.arraysize else: --- 2461,2476 ---- raise InterfaceError, "fetchmany failed - the cursor is closed." ! if self.conn is None: raise Error, "connection is closed." ! if self.res is None: raise Error, \ "fetchmany() failed - cursor does not contain a result." elif self.res.resultType != RESULT_DQL: ! if self.close is None: raise Error, \ "fetchmany() Failed - cursor does not contain any rows." ! if sz is None: sz = self.arraysize else: *************** *** 2402,2413 **** raise InterfaceError, "fetchall failed - the cursor is closed." ! if self.conn == None: raise Error, "connection is closed." ! if self.res == None: raise Error, \ "fetchall() failed - cursor does not contain a result." elif self.res.resultType != RESULT_DQL: ! if self.closed == None: raise Error, \ "fetchall() Failed - cursor does not contain any rows." --- 2508,2519 ---- raise InterfaceError, "fetchall failed - the cursor is closed." ! if self.conn is None: raise Error, "connection is closed." ! if self.res is None: raise Error, \ "fetchall() failed - cursor does not contain a result." elif self.res.resultType != RESULT_DQL: ! if self.closed is None: raise Error, \ "fetchall() Failed - cursor does not contain any rows." *************** *** 2438,2448 **** raise InterfaceError, "rewind failed - the cursor is closed." ! if self.conn == None: raise Error, "connection is closed." ! if self.res == None: raise Error, "rewind() failed - cursor does not contain a result." elif self.res.resultType != RESULT_DQL: ! if self.closed == None: raise Error, \ "rewind() Failed - cursor does not contain any rows." --- 2544,2554 ---- raise InterfaceError, "rewind failed - the cursor is closed." ! if self.conn is None: raise Error, "connection is closed." ! if self.res is None: raise Error, "rewind() failed - cursor does not contain a result." elif self.res.resultType != RESULT_DQL: ! if self.closed is None: raise Error, \ "rewind() Failed - cursor does not contain any rows." |