Commits

adamv committed ee19ff1

* Applying Paul's fixes for issue 39

  • Participants
  • Parent commits 92e5642

Comments (0)

Files changed (3)

File source/sqlserver_ado/dbapi.py

 except ImportError:
     from django.utils import _decimal as decimal
 
+import pythoncom
 import win32com.client
 
-# AdamV todo - sort out decimal/currency/numeric support in SQL Server
-# The next two code lines request Decimal python types for
-# ADO currency values. This does not affect SQL decimal/numeric
-# types, which come back as strings.
-import pythoncom
-pythoncom.__future_currency__ = True
-
 from ado_consts import *
 
 # DB API default values
         p.AppendChunk(value)
 
     elif isinstance(value, decimal.Decimal):
-        s = str(value.quantize(decimal.Decimal('0')))
-
-        point = s.find('.')
-        if point == -1:
+        p.Value = value
+        exponent = value.as_tuple()[2]
+        digit_count = len(value.as_tuple()[1])
+        
+        if exponent == 0:
             p.NumericScale = 0
-        else:
-            p.NumericScale = len(s)-point
-
-        p.Precision = len(s)
-        p.Value = value
+            p.Precision =  digit_count
+        elif exponent < 0:
+            p.NumericScale = -exponent
+            p.Precision =  digit_count
+        elif exponent > 0:
+            p.NumericScale = 0
+            p.Precision = digit_count + exponent
 
     else:
         # For any other type, set the value and let pythoncom do the right thing.
         return None
     return _variantConversions[adType](variant)
 
-def _cvtCurrency((hi, lo), decimal_places=2):
-    if lo < 0:
-        lo += (2L ** 32)
-    return decimal.Decimal((long(hi) << 32) + lo)/decimal.Decimal(1000)
+def _cvtDecimal(variant):
+    return _convertNumberWithCulture(variant, decimal.Decimal)
 
 def _cvtFloat(variant):
     return _convertNumberWithCulture(variant, float)
 _variantConversions = MultiMap(
     {
         adoDateTimeTypes : _cvtComDate,
+        adoExactNumericTypes: _cvtDecimal,
         adoApproximateNumericTypes: _cvtFloat,
-        (adCurrency,): _cvtCurrency,
         (adBoolean,): bool,
         adoLongTypes+adoRowIdTypes : long,
         adoIntegerTypes: int,

File tests/test_main/regressiontests/models.py

             self.failUnless(isinstance(e, IntegrityError), 'Expected IntegrityError but got: %s' % type(e))
 
 class Bug38Table(models.Model):
-    """
-    Test adding decimals as strings with various formats.
-    
-    >>> Bug38Table(d=decimal.Decimal('0')).save()
-    >>> Bug38Table(d=decimal.Decimal('0e0')).save()
-    >>> Bug38Table(d=decimal.Decimal('0E0')).save()
-    >>> Bug38Table(d=decimal.Decimal('450')).save()
-    >>> Bug38Table(d=decimal.Decimal('450.0')).save()
-    >>> Bug38Table(d=decimal.Decimal('450.00')).save()
-    >>> Bug38Table(d=decimal.Decimal('450.000')).save()
-    >>> Bug38Table(d=decimal.Decimal('0450')).save()
-    >>> Bug38Table(d=decimal.Decimal('0450.0')).save()
-    >>> Bug38Table(d=decimal.Decimal('0450.00')).save()
-    >>> Bug38Table(d=decimal.Decimal('0450.000')).save()
-    >>> Bug38Table(d=decimal.Decimal('4.5e+2')).save()
-    >>> Bug38Table(d=decimal.Decimal('4.5E+2')).save()
-    >>> len(list(Bug38Table.objects.all()))
-    13
-    """
     d = models.DecimalField(max_digits=5, decimal_places=2)

File tests/test_main/regressiontests/tests.py

+import decimal
+from django.db import models
+from django.test import TestCase
+
+class Bug38Table(models.Model):
+    d = models.DecimalField(max_digits=5, decimal_places=2)
+
+
+class Bug38TestCase(TestCase):
+    def testInsertVariousFormats(self):
+        """
+        Test adding decimals as strings with various formats.
+        """
+        Bug38Table(d=decimal.Decimal('0')).save()
+        Bug38Table(d=decimal.Decimal('0e0')).save()
+        Bug38Table(d=decimal.Decimal('0E0')).save()
+        Bug38Table(d=decimal.Decimal('450')).save()
+        Bug38Table(d=decimal.Decimal('450.0')).save()
+        Bug38Table(d=decimal.Decimal('450.00')).save()
+        Bug38Table(d=decimal.Decimal('450.000')).save()
+        Bug38Table(d=decimal.Decimal('0450')).save()
+        Bug38Table(d=decimal.Decimal('0450.0')).save()
+        Bug38Table(d=decimal.Decimal('0450.00')).save()
+        Bug38Table(d=decimal.Decimal('0450.000')).save()
+        Bug38Table(d=decimal.Decimal('4.5e+2')).save()
+        Bug38Table(d=decimal.Decimal('4.5E+2')).save()
+        self.assertEquals(len(list(Bug38Table.objects.all())),13)
+
+    def testReturnsDecimal(self):
+        """
+        Test if return value is a python Decimal object 
+        when saving the model with a Decimal object as value 
+        """
+        Bug38Table(d=decimal.Decimal('0')).save()
+        d1 = Bug38Table.objects.all()[0]
+        self.assertEquals(decimal.Decimal, d1.d.__class__)
+
+    def testReturnsDecimalFromString(self):
+        """
+        Test if return value is a python Decimal object 
+        when saving the model with a unicode object as value.
+        """
+        Bug38Table(d=u'123').save()
+        d1 = Bug38Table.objects.all()[0]
+        self.assertEquals(decimal.Decimal, d1.d.__class__)        
+
+    def testSavesAfterDecimal(self):
+        """
+        Test if value is saved correctly when there are numbers 
+        to the right side of the decimal point 
+        """
+        Bug38Table(d=decimal.Decimal('450.1')).save()
+        d1 = Bug38Table.objects.all()[0]
+        self.assertEquals(decimal.Decimal('450.1'), d1.d)
+    
+    def testInsertWithMoreDecimals(self):
+        """
+        Test if numbers to the right side of the decimal point 
+        are saved correctly rounding to a decimal with the correct 
+        decimal places.
+        """
+        Bug38Table(d=decimal.Decimal('450.111')).save()
+        d1 = Bug38Table.objects.all()[0]
+        self.assertEquals(decimal.Decimal('450.11'), d1.d)    
+        
+    def testInsertWithLeadingZero(self):
+        """
+        Test if value is saved correctly with Decimals with a leading zero.
+        """
+        Bug38Table(d=decimal.Decimal('0450.0')).save()
+        d1 = Bug38Table.objects.all()[0]
+        self.assertEquals(decimal.Decimal('450.0'), d1.d)