From: Billy G. A. <bal...@us...> - 2002-08-12 03:05:10
|
Update of /cvsroot/pypgsql/pypgsql/pyPgSQL In directory usw-pr-cvs1:/tmp/cvs-serv12330/pyPgSQL Modified Files: PgSQL.py Log Message: 11AUG2002 bga Fixed various problems with the PgNumeric type: - Added code to allow a float as an argument to the PgNumeric constructor. - You can now change the precision/scale of a PgNumeric by: a = PgNumeric(pgnumeric, new prec, new scale). This can be used to 'cast' a PgNumeric to the proper precision and scale before storing it in a field. - The arithmatic routines (__add__, __radd__, etc) now ensure that the arguments are properly coerced to the correct types. - Added support for the augmented arithmatic operations (__iadd__, etc). - The math routines would lose precision becuase the precision/ scale were set to be the same as the first operand. This is no longer the case all precision is retained for the +, -, and * operations. Index: PgSQL.py =================================================================== RCS file: /cvsroot/pypgsql/pypgsql/pyPgSQL/PgSQL.py,v retrieving revision 1.13 retrieving revision 1.14 diff -C2 -d -r1.13 -r1.14 *** PgSQL.py 3 Aug 2002 06:03:39 -0000 1.13 --- PgSQL.py 12 Aug 2002 03:05:03 -0000 1.14 *************** *** 30,33 **** --- 30,49 ---- # Date Ini Description | # --------- --- ------------------------------------------------------- | + # 11AUG2002 bga Fixed various problems with the PgNumeric type: | + # - Added code to allow a float as an argument to the | + # PgNumeric constructor. | + # - You can now change the precision/scale of a PgNumeric | + # by: a = PgNumeric(pgnumeric, new prec, new scale). | + # This can be used to 'cast' a PgNumeric to the proper | + # precision and scale before storing it in a field. | + # - The arithmatic routines (__add__, __radd__, etc) now | + # ensure that the arguments are properly coerced to the | + # correct types. | + # - Added support for the augmented arithmatic operations | + # (__iadd__, etc). | + # - The math routines would lose precision becuase the | + # precision/scale were set to be the same as the first | + # operand. This is no longer the case all precision is | + # retained for the +, -, and * operations. | # 03AUG2002 gh Fixed problem that occurs when a query on an OID field | # doesn't return any rows. [Bug #589370]. | *************** *** 905,909 **** 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, \ --- 921,925 ---- class PgNumeric: def __init__(self, value, prec=None, scale=None): ! if type(value) in [IntType, LongType] or value is None: if prec is None or scale is None: raise TypeError, \ *************** *** 916,980 **** self.__p = prec self.__s = scale ! return ! ! if type(value) is not StringType: ! raise TypeError, "value must be a string." ! ! _v = value.split() ! if len(_v) == 0 or len(_v) > 1: ! raise ValueError, \ ! "invalid literal for PgNumeric: %s" % value ! _v = _v[0] ! ! # At this point _v is value with leading and trailing blanks ! # removed. Initalize the precision and scale values. They will be ! # determined from the input string (value) is prec and scale are ! # None. ! ! _vs = value.rfind('.') # Get the location of the decimal point. ! # It's used to determine the precision and ! if prec: # scale if they aren't passed in, and to ! self.__p = prec # adjust the input string to match the passed ! else: # in scale. ! self.__p = len(value) ! if _vs >= 0: ! self.__p = self.__p - 1 ! # Calculate the scale of the passed in string. _vs will contain the ! # calulated scale. ! if _vs >= 0: ! _vs = len(value) - _vs - 1 ! else: ! _vs = 0 ! if scale: ! self.__s = scale ! else: ! self.__s = _vs ! # Calculate the number of character to add/remove from the end of ! # the input string in order to have it match the given scale. _sd ! # will contain the number of characters to add (>0) or remove (<0). ! _sd = self.__s - _vs ! if _sd == 0: ! pass # No change to value needed. ! elif _sd > 0: ! _v = _v + ('0' * _sd) # Add needed zeros to the end of value ! else: ! _v = _v[:_sd] # Remove excess digits from the end. ! if self.__s: ! _s = _v[:-(self.__s + 1)] + _v[-self.__s:] ! else: ! _s = _v ! try: ! self.__v = long(_s) ! except: ! raise ValueError, \ ! "invalid literal for PgNumeric: %s" % value def __fmtNumeric(self, value=None): --- 932,1043 ---- self.__p = prec self.__s = scale ! elif type(value) is FloatType: ! _s = repr(value) ! _d = _s.rfind('.') ! _e = _s.rfind('e') ! _exp = 0 ! if (_e >= 0): ! _exp = int(_s[_e+1:]) ! _s = _s[:_e] ! if _exp > 31: ! raise OverflowError, "float too large for PgNumeric" ! if _exp < -31: ! raise OverflowError, "float too small for PgNumeric" ! _s = _s[:_d] + _s[_d+1:] ! if _exp == 0: ! _sc = len(_s) - _d ! elif _exp > 0: ! _s = _s + ("0" * (_exp - len(_s) + 1)) ! _sc = 0 ! else: ! _sc = -_exp + len(_s) - 1 ! self.__v = long(_s) ! self.__p = len(_s) ! if self.__p < _sc: ! self.__p = _sc ! self.__s = _sc ! elif type(value) is StringType: ! _v = value.split() ! if len(_v) == 0 or len(_v) > 1: ! raise ValueError, \ ! "invalid literal for PgNumeric: %s" % value ! _v = _v[0] ! # At this point _v is value with leading and trailing blanks ! # removed. Initalize the precision and scale values. They will be ! # determined from the input string (value) is prec and scale are ! # None. ! _vs = value.rfind('.') # Get the location of the decimal point. ! # It's used to determine the precision and ! if prec: # scale if they aren't passed in, and to ! self.__p = prec # adjust the input string to match the ! else: # passed in scale. ! self.__p = len(value) ! if _vs >= 0: ! self.__p = self.__p - 1 ! # Calculate the scale of the passed in string. _vs will contain the ! # calulated scale. ! if _vs >= 0: ! _vs = len(value) - _vs - 1 ! else: ! _vs = 0 ! ! if scale: ! self.__s = scale ! else: ! self.__s = _vs ! # Calculate the number of character to add/remove from the end of ! # the input string in order to have it match the given scale. _sd ! # will contain the number of characters to add (>0) or remove (<0). ! _sd = self.__s - _vs ! if _sd == 0: ! pass # No change to value needed. ! elif _sd > 0: ! _v = _v + ('0' * _sd) # Add needed zeros to the end of value ! else: ! _v = _v[:_sd] # Remove excess digits from the end. ! if self.__s: ! _s = _v[:-(self.__s + 1)] + _v[-self.__s:] ! else: ! _s = _v ! ! try: ! self.__v = long(_s) ! except: ! raise ValueError, \ ! "invalid literal for PgNumeric: %s" % value ! elif isinstance(value, PgNumeric): ! # This is used to "cast" a PgNumeric to the specified precision ! # and scale. It can also make a copy of a PgNumeric. ! self.__v = value.__v ! if scale: ! self.__s = scale ! _ds = scale - value.__s ! else: ! self.__s = value.__s ! _ds = 0 ! if prec: ! self.__p = prec ! else: ! self.__p = value.__p ! # Now we adjust the value to reflect the new scaling factor. ! if _ds > 0: ! if _ds == 1: ! self.__v = self.__v * 10 ! else: ! self.__v = self.__v * (10L ** _ds) ! elif _ds < 0: ! self.__v = self._round(self.__v, abs(_ds)) ! if self.__v > (10L ** self.__p): ! raise OverflowError, "result exceeds precision of %d" % self.__p ! else: ! raise TypeError, "value can not be converted to a PgNumeric." def __fmtNumeric(self, value=None): *************** *** 1013,1053 **** def __coerce__(self, other): ! _s = None ! 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): ! return (self, other) ! else: ! _s = None ! ! if _s: if _s[-1:] == 'L': _s = _s[:-1] # Work around v1.5/1.6 differences ! _s = "%s.%s" % (_s, ("0" * self.__s)) ! if len(_s) > self.__p: ! return None ! else: ! return (self, PgNumeric(_s, self.__p, self.__s)) ! ! return None def _round(self, value, drop): ! if drop > 0: return (((value / (10L ** (drop - 1))) + 5L) / 10L) return value def __mul__(self, other): ! _p = self._round((self.__v * other.__v), other.__s ) ! return PgNumeric(_p, self.__p, self.__s) ! def __rmul__(other, self): ! _p = self._round((self.__v * other.__v), other.__s ) ! return PgNumeric(_p, self.__p, self.__s) def __div__(self, other): _n = (self.__v * (10L ** (other.__s + 1))) _d = other.__v --- 1076,1218 ---- def __coerce__(self, other): ! if isinstance(other, PgNumeric): ! return self, other ! elif type(other) in [IntType, LongType]: ! _s = str(other) if _s[-1:] == 'L': _s = _s[:-1] # Work around v1.5/1.6 differences ! return (self, PgNumeric(_s)) ! elif type(other) == FloatType: ! return (self, PgNumeric(other)) ! return None def _round(self, value, drop): ! if drop == 1: ! return ((value + 5L) / 10L) ! elif drop > 1: return (((value / (10L ** (drop - 1))) + 5L) / 10L) return value + def __add__(self, other): + _c = self.__coerce__(other) + if _c is None: + return None + self, other = _c + if self.__s < other.__s: + _sc = other.__s + _ds = other.__s - self.__s + _s = self.__v * (10L ** _ds) + _o = other.__v + elif self.__s > other.__s: + _sc = self.__s + _ds = self.__s - other.__s + _s = self.__v + _o = other.__v * (10L ** _ds) + else: + _sc = self.__s + _s = self.__v + _o = other.__v + if (self.__p - self.__s) >= (other.__p - other.__s): + _pr = self.__p - self.__s + _sc + else: + _pr = other.__p - other.__s + sc + + return PgNumeric((_s + _o), _pr, _sc) + + def __radd__(self, other): + return __add__(self, other) + + def __iadd__(self, other): + _r = self.__add__(other) + if _r is None: + return None + self.__v = _r.__v + self.__p = _r.__p + self.__s = _r.__s + return self + + def __sub__(self, other): + _c = self.__coerce__(other) + if _c is None: + return None + self, other = _c + if self.__s < other.__s: + _sc = other.__s + _ds = other.__s - self.__s + _s = self.__v * (10L ** _ds) + _o = other.__v + elif self.__s > other.__s: + _sc = self.__s + _ds = self.__s - other.__s + _s = self.__v + _o = other.__v * (10L ** _ds) + else: + _sc = self.__s + _s = self.__v + _o = other.__v + if (self.__p - self.__s) >= (other.__p - other.__s): + _pr = self.__p - self.__s + _sc + else: + _pr = other.__p - other.__s + sc + + return PgNumeric((_s - _o), _pr, _sc) + + def __rsub__(self, other): + if self.__s < other.__s: + _sc = other.__s + _ds = other.__s - self.__s + _s = self.__v * (10L ** _ds) + _o = other.__v + elif self.__s > other.__s: + _sc = self.__s + _ds = self.__s - other.__s + _s = self.__v + _o = other.__v * (10L ** _ds) + else: + _sc = self.__s + _s = self.__v + _o = other.__v + if (self.__p - self.__s) >= (other.__p - other.__s): + _pr = self.__p - self.__s + _sc + else: + _pr = other.__p - other.__s + sc + + return PgNumeric((_o - _s), _pr, _sc) + + def __isub__(self, other): + _r = self.__sub__(other) + if _r is None: + return None + self.__v = _r.__v + self.__p = _r.__p + self.__s = _r.__s + return self + def __mul__(self, other): ! _c = self.__coerce__(other) ! if _c is None: ! return None ! self, other = _c ! _p = self.__v * other.__v ! return PgNumeric(_p, self.__p + other.__p, self.__s + other.__s) ! def __rmul__(self, other): ! return self.__mul__(self, other) + def __imul__(self, other): + _r = self.__mul__(other) + if _r is None: + return None + self.__v = _r.__v + self.__p = _r.__p + self.__s = _r.__s + return self def __div__(self, other): + _c = self.__coerce__(other) + if _c is None: + return None + self, other = _c _n = (self.__v * (10L ** (other.__s + 1))) _d = other.__v *************** *** 1055,1065 **** return PgNumeric(self._round(_q, 1), self.__p, self.__s) ! def __rdiv__(other, self): ! _n = (self.__v * (10L ** (other.__s + 1))) ! _d = other.__v _q = (_n / _d) ! return PgNumeric(self._round(_q, 1), self.__p, self.__s) def __cmp__(self, other): if self.__s < other.__s: _d = other.__s - self.__s --- 1220,1249 ---- return PgNumeric(self._round(_q, 1), self.__p, self.__s) ! def __rdiv__(self, other): ! _c = self.__coerce__(other) ! if _c is None: ! return None ! self, other = _c ! _n = (other.__v * (10L ** (self.__s + 1))) ! _d = self.__v _q = (_n / _d) ! return PgNumeric(self._round(_q, 1), other.__p, other.__s) ! ! def __idiv__(self, other): ! _r = self.__div__(other) ! if _r is None: ! return None ! self.__v = _r.__v ! self.__p = _r.__p ! self.__s = _r.__s ! return self def __cmp__(self, other): + if other == None: + return 1 + _c = self.__coerce__(other) + if _c is None: + return None + self, other = _c if self.__s < other.__s: _d = other.__s - self.__s *************** *** 1089,1120 **** else: return -self - - def __add__(self, other): - if self.__s < other.__s: - _d = other.__s - self.__s - _s = self._round(((self.__v * (10L ** _d)) + other.__v), _d) - elif self.__s > other.__s: - _d = self.__s - other.__s - _s = self._round((self.__v + (other.__v * (10L ** _d))), _d) - else: - _s = self.__v + other.__v - return PgNumeric(_s, self.__p, self.__s) - - def __radd__(self, other): - return __add__(other, self) - - def __sub__(self, other): - if self.__s < other.__s: - _d = other.__s - self.__s - _s = self._round(((self.__v * (10L ** _d)) - other.__v), _d) - elif self.__s > other.__s: - _d = self.__s - other.__s - _s = self._round((self.__v - (other.__v * (10L ** _d))), _d) - else: - _s = self.__v - other.__v - return PgNumeric(_s, self.__p, self.__s) - - def __rsub__(self, other): - return __sub__(other, self) def _quote(self, forArray=0): --- 1273,1276 ---- |