]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- the string approach appears to be necessary for large numbers, however.
authorMike Bayer <mike_mp@zzzcomputing.com>
Fri, 19 Mar 2010 15:35:32 +0000 (11:35 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Fri, 19 Mar 2010 15:35:32 +0000 (11:35 -0400)
Don't know how to get large decimals through to Sybase.

lib/sqlalchemy/connectors/pyodbc.py
test/dialect/test_mssql.py
test/sql/test_types.py

index 5cfe4a1921b8c5918b5c8f753fc23a471cdb1490..82e510754db0c6bbfa5dc292f61f42b24ca8d1fe 100644 (file)
@@ -8,55 +8,43 @@ import decimal
 from sqlalchemy import processors, types as sqltypes
 
 class PyODBCNumeric(sqltypes.Numeric):
-    """Turns Decimals with adjusted() < -6 into floats."""
+    """Turns Decimals with adjusted() < -6 into floats, > 7 into strings"""
     
     def bind_processor(self, dialect):
         super_process = super(PyODBCNumeric, self).bind_processor(dialect)
         
         def process(value):
             if self.asdecimal and \
-                    isinstance(value, decimal.Decimal) and \
-                    value.adjusted() < -6:
-                return processors.to_float(value)
-            elif super_process:
+                    isinstance(value, decimal.Decimal):
+                
+                if value.adjusted() < -6:
+                    return processors.to_float(value)
+                elif value.adjusted() > 7:
+                    return self._large_dec_to_string(value)
+
+            if super_process:
                 return super_process(value)
             else:
                 return value
         return process
 
-    # This method turns the adjusted into a string.
-    # not sure if this has advantages over the simple float
-    # approach above.
-#    def bind_processor(self, dialect):
-#        def process(value):
-#            if isinstance(value, decimal.Decimal):
-#                if value.adjusted() < 0:
-#                    result = "%s0.%s%s" % (
-#                            (value < 0 and '-' or ''),
-#                            '0' * (abs(value.adjusted()) - 1),
-#                            "".join([str(nint) for nint in value._int]))
-#
-#                else:
-#                    if 'E' in str(value):
-#                        result = "%s%s%s" % (
-#                                (value < 0 and '-' or ''),
-#                                "".join([str(s) for s in value._int]),
-#                                "0" * (value.adjusted() - (len(value._int)-1)))
-#                    else:
-#                        if (len(value._int) - 1) > value.adjusted():
-#                            result = "%s%s.%s" % (
-#                                    (value < 0 and '-' or ''),
-#                                    "".join([str(s) for s in value._int][0:value.adjusted() + 1]),
-#                                    "".join([str(s) for s in value._int][value.adjusted() + 1:]))
-#                        else:
-#                            result = "%s%s" % (
-#                                    (value < 0 and '-' or ''),
-#                                    "".join([str(s) for s in value._int][0:value.adjusted() + 1]))
-#                return result
-#
-#            else:
-#                return value
-#        return process
+    def _large_dec_to_string(self, value):
+        if 'E' in str(value):
+            result = "%s%s%s" % (
+                    (value < 0 and '-' or ''),
+                    "".join([str(s) for s in value._int]),
+                    "0" * (value.adjusted() - (len(value._int)-1)))
+        else:
+            if (len(value._int) - 1) > value.adjusted():
+                result = "%s%s.%s" % (
+                        (value < 0 and '-' or ''),
+                        "".join([str(s) for s in value._int][0:value.adjusted() + 1]),
+                        "".join([str(s) for s in value._int][value.adjusted() + 1:]))
+            else:
+                result = "%s%s" % (
+                        (value < 0 and '-' or ''),
+                        "".join([str(s) for s in value._int][0:value.adjusted() + 1]))
+        return result
 
 class PyODBCConnector(Connector):
     driver='pyodbc'
index 07d195a435733b5c6463abce33b26fb98ded3efe..264636ba7a5df81c27e466b00973b5f8a547edea 100644 (file)
@@ -1030,11 +1030,11 @@ class TypesTest(TestBase, AssertsExecutionResults, ComparesTables):
 
         columns = [
             # column type, args, kwargs, expected ddl
-            (mssql.MSNumeric, [], {},
+            (types.NUMERIC, [], {},
              'NUMERIC'),
-            (mssql.MSNumeric, [None], {},
+            (types.NUMERIC, [None], {},
              'NUMERIC'),
-            (mssql.MSNumeric, [12, 4], {},
+            (types.NUMERIC, [12, 4], {},
              'NUMERIC(12, 4)'),
 
             (types.Float, [], {},
index 1aa75b7321c159d4f42f716b6f081e3cd06605e9..341e9516e3bbec4f338a86dd32d755b7a982b0e7 100644 (file)
@@ -1189,6 +1189,27 @@ class NumericTest(TestBase):
             numbers,
             numbers
         )
+    
+    @testing.fails_on("sybase+pyodbc", 
+                        "Don't know how do get these values through FreeTDS + Sybase")
+    @testing.fails_on('sqlite', 'The 319438... number fails.')
+    def test_enotation_decimal_large(self):
+        """test exceedingly large decimals.
+
+        """
+
+        numbers = set([
+            decimal.Decimal('4E+8'),
+            decimal.Decimal("31943874831932418390.01"),
+            decimal.Decimal("5748E+15"),
+            decimal.Decimal('1.521E+15'),
+            decimal.Decimal('00000000000000.1E+12'),
+        ])
+        self._do_test(
+            Numeric(precision=25, scale=2),
+            numbers,
+            numbers
+        )