Commit acfe5cc8 authored by Ian Kelly's avatar Ian Kelly
Browse files

Fixed #6767: changed the way the Oracle backend fetches numbers to prevent...

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
parent f60d0f59
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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
+45 −3
Original line number Diff line number Diff line
@@ -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):
    """