Fixed #6767: changed the way the Oracle backend fetches numbers to prevent decimals being returned as floats.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@9750 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Ian Kelly 2009-01-15 20:39:09 +00:00
parent f60d0f597a
commit acfe5cc880
2 changed files with 46 additions and 3 deletions

View File

@ -46,6 +46,7 @@ class MeasureBase(object):
"""
val = 0.0
for unit, value in kwargs.iteritems():
if not isinstance(value, float): value = float(value)
if unit in self.UNITS:
val += self.UNITS[unit] * value
default_unit = unit

View File

@ -7,6 +7,7 @@ Requires cx_Oracle: http://cx-oracle.sourceforge.net/
import os
import datetime
import time
from decimal import Decimal
# Oracle takes client-side character set encoding from the environment.
os.environ['NLS_LANG'] = '.UTF8'
@ -287,6 +288,8 @@ class DatabaseWrapper(BaseDatabaseWrapper):
pass
if not cursor:
cursor = FormatStylePlaceholderCursor(self.connection)
# Necessary to retrieve decimal values without rounding error.
cursor.numbersAsStrings = True
# Default arraysize of 1 is highly sub-optimal.
cursor.arraysize = 100
return cursor
@ -390,18 +393,57 @@ class FormatStylePlaceholderCursor(Database.Cursor):
row = Database.Cursor.fetchone(self)
if row is None:
return row
return tuple([to_unicode(e) for e in row])
return self._rowfactory(row)
def fetchmany(self, size=None):
if size is None:
size = self.arraysize
return tuple([tuple([to_unicode(e) for e in r])
return tuple([self._rowfactory(r)
for r in Database.Cursor.fetchmany(self, size)])
def fetchall(self):
return tuple([tuple([to_unicode(e) for e in r])
return tuple([self._rowfactory(r)
for r in Database.Cursor.fetchall(self)])
def _rowfactory(self, row):
# Cast numeric values as the appropriate Python type based upon the
# cursor description, and convert strings to unicode.
casted = []
for value, desc in zip(row, self.description):
if value is not None and desc[1] is Database.NUMBER:
precision, scale = desc[4:6]
if scale == -127:
if precision == 0:
# NUMBER column: decimal-precision floating point
# This will normally be an integer from a sequence,
# but it could be a decimal value.
if '.' in value:
value = Decimal(value)
else:
value = int(value)
else:
# FLOAT column: binary-precision floating point.
# This comes from FloatField columns.
value = float(value)
elif precision > 0:
# NUMBER(p,s) column: decimal-precision fixed point.
# This comes from IntField and DecimalField columns.
if scale == 0:
value = int(value)
else:
value = Decimal(value)
elif '.' in value:
# No type information. This normally comes from a
# mathematical expression in the SELECT list. Guess int
# or Decimal based on whether it has a decimal point.
value = Decimal(value)
else:
value = int(value)
else:
value = to_unicode(value)
casted.append(value)
return tuple(casted)
def to_unicode(s):
"""