Commits

Michael Trier  committed 66b33e4

Corrected handling of large decimal values on mssql. Added more robust tests.

- Removed string manipulation on floats. Float types are now passed through
to mssql as is.
- Fixes #1280

  • Participants
  • Parent commits 45a5b6f

Comments (0)

Files changed (3)

       properly.
 
 - mssql
+    - Corrected handling of large decimal values with more robust
+      tests. Removed string manipulation on floats. [ticket:1280]
+
     - Modified the do_begin handling in mssql to use the Cursor not
       the Connection so it is DBAPI compatible.
 

File lib/sqlalchemy/databases/mssql.py

                 # Not sure that this exception is needed
                 return value
             else:
-                # FIXME: this will not correct a situation where a float
-                # gets converted to e-notation.
-                if isinstance(value, decimal.Decimal) and value._exp < -6:
-                    value = ((value < 0 and '-' or '')
-                        + '0.'
-                        + '0' * -(value._exp+1)
-                        + value._int)
+                if isinstance(value, decimal.Decimal):
+                    sign = (value < 0 and '-' or '') 
+                    if value._exp > -1:
+                        return float(sign + value._int + '0' * value._exp)
+                    else:
+                        s = value._int.zfill(-value._exp+1)
+                        pos = len(s) + value._exp
+                        return sign + s[:pos] + '.' + s[pos:]
+                else:
                     return value
-                else:
-                    return str(value)
+
         return process
 
     def get_col_spec(self):
         else:
             return "FLOAT(%(precision)s)" % {'precision': self.precision}
 
-    def bind_processor(self, dialect):
-        def process(value):
-            """By converting to string, we can use Decimal types round-trip."""
-            if not value is None:
-                return str(value)
-            return None
-        return process
-
 
 class MSReal(MSFloat):
     """A type for ``real`` numbers."""
     def adapt(self, impltype):
         return impltype()
 
-    def bind_processor(self, dialect):
-        def process(value):
-            if value is not None:
-                return float(value)
-            else:
-                return value
-        return process
-
     def get_col_spec(self):
         return "REAL"
 

File test/dialect/mssql.py

     def setUpAll(self):
         global numeric_table, metadata
         metadata = MetaData(testing.db)
+
+    def tearDown(self):
+        metadata.drop_all()
+
+    def test_decimal_notation(self):
+        import decimal
         numeric_table = Table('numeric_table', metadata,
             Column('id', Integer, Sequence('numeric_id_seq', optional=True), primary_key=True),
-            Column('numericcol', Numeric(asdecimal=False))
+            Column('numericcol', Numeric(precision=38, scale=20, asdecimal=True))
         )
         metadata.create_all()
 
-    def tearDownAll(self):
-        metadata.drop_all()
+        try:
+            test_items = [decimal.Decimal(d) for d in '1500000.00000000000000000000',
+                          '-1500000.00000000000000000000', '1500000',
+                          '0.0000000000000000002', '0.2', '-0.0000000000000000002',
+                          '156666.458923543', '-156666.458923543', '1', '-1', '1234',
+                          '2E-12', '4E8', '3E-6', '3E-7', '4.1', '1E-1', '1E-2', '1E-3',
+                          '1E-4', '1E-5', '1E-6', '1E-7', '1E-8']
+            for value in test_items:
+                numeric_table.insert().execute(numericcol=value)
 
-    def tearDown(self):
-        numeric_table.delete().execute()
+            for value in select([numeric_table.c.numericcol]).execute():
+                self.assertTrue(value[0] in test_items, "%s not in test_items" % value[0])
 
-    def test_decimal_e_notation(self):
-        from decimal import Decimal
+        except Exception, e:
+            raise e
+
+    def test_float(self):
+        float_table = Table('float_table', metadata,
+            Column('id', Integer, Sequence('numeric_id_seq', optional=True), primary_key=True),
+            Column('floatcol', Float())
+        )
+        metadata.create_all()
 
         try:
-            numeric_table.insert().execute(numericcol=Decimal('4.1'))
-            numeric_table.insert().execute(numericcol=Decimal('1E-1'))
-            numeric_table.insert().execute(numericcol=Decimal('1E-2'))
-            numeric_table.insert().execute(numericcol=Decimal('1E-3'))
-            numeric_table.insert().execute(numericcol=Decimal('1E-4'))
-            numeric_table.insert().execute(numericcol=Decimal('1E-5'))
-            numeric_table.insert().execute(numericcol=Decimal('1E-6'))
-            numeric_table.insert().execute(numericcol=Decimal('1E-7'))
-            numeric_table.insert().execute(numericcol=Decimal('1E-8'))
-            numeric_table.insert().execute(numericcol=10000)
+            test_items = [float(d) for d in '1500000.00000000000000000000',
+                          '-1500000.00000000000000000000', '1500000',
+                          '0.0000000000000000002', '0.2', '-0.0000000000000000002',
+                          '156666.458923543', '-156666.458923543', '1', '-1', '1234',
+                          '2E-12', '4E8', '3E-6', '3E-7', '4.1', '1E-1', '1E-2', '1E-3',
+                          '1E-4', '1E-5', '1E-6', '1E-7', '1E-8']
+            for value in test_items:
+                float_table.insert().execute(floatcol=value)
+
         except Exception, e:
             raise e