]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
re-split PyODBCNumeric among Sybase and MS-SQL, they can't be shared.
authorMike Bayer <mike_mp@zzzcomputing.com>
Sat, 20 Mar 2010 01:37:42 +0000 (21:37 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sat, 20 Mar 2010 01:37:42 +0000 (21:37 -0400)
MS-SQL really needs the pure string approach else crashes occur on
windows.

lib/sqlalchemy/connectors/pyodbc.py
lib/sqlalchemy/dialects/mssql/pyodbc.py
lib/sqlalchemy/dialects/sybase/pyodbc.py

index 5cf00bc9233e079763621d1a6f10003126169c2c..b291f3e1695d235c40aeac87a669e4ec932c3f41 100644 (file)
@@ -5,49 +5,6 @@ import sys
 import re
 import urllib
 import decimal
-from sqlalchemy import processors, types as sqltypes
-
-class PyODBCNumeric(sqltypes.Numeric):
-    """Turns Decimals with adjusted() < -6 into floats, > 7 into strings"""
-    
-    convert_large_decimals_to_string = False
-    
-    def bind_processor(self, dialect):
-        super_process = super(PyODBCNumeric, self).bind_processor(dialect)
-        
-        def process(value):
-            if self.asdecimal and \
-                    isinstance(value, decimal.Decimal):
-                
-                if value.adjusted() < -6:
-                    return processors.to_float(value)
-                elif self.convert_large_decimals_to_string and \
-                    value.adjusted() > 7:
-                    return self._large_dec_to_string(value)
-
-            if super_process:
-                return super_process(value)
-            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 8e7e90629269673189c4407d62dbb627e21b5035..5625e3cd263ecab6b132037adcbc5789ab500291 100644 (file)
@@ -12,11 +12,61 @@ Connect strings are of the form::
 """
 
 from sqlalchemy.dialects.mssql.base import MSExecutionContext, MSDialect
-from sqlalchemy.connectors.pyodbc import PyODBCConnector, PyODBCNumeric
+from sqlalchemy.connectors.pyodbc import PyODBCConnector
 from sqlalchemy import types as sqltypes, util
+import decimal
 
-class _MSNumeric_pyodbc(PyODBCNumeric):
-    convert_large_decimals_to_string = True
+class _MSNumeric_pyodbc(sqltypes.Numeric):
+    """Turns Decimals with adjusted() < -6 or > 7 into strings.
+    
+    This is the only method that is proven to work with Pyodbc+MSSQL
+    without crashing (floats can be used but seem to cause sporadic
+    crashes).
+    
+    """
+
+    def bind_processor(self, dialect):
+        super_process = super(_MSNumeric_pyodbc, self).bind_processor(dialect)
+
+        def process(value):
+            if self.asdecimal and \
+                    isinstance(value, decimal.Decimal):
+                
+                adjusted = value.adjusted()
+                if adjusted < -6:
+                    return self._small_dec_to_string(value)
+                elif adjusted > 7:
+                    return self._large_dec_to_string(value)
+
+            if super_process:
+                return super_process(value)
+            else:
+                return value
+        return process
+    
+    def _small_dec_to_string(self, value):
+        return "%s0.%s%s" % (
+                    (value < 0 and '-' or ''),
+                    '0' * (abs(value.adjusted()) - 1),
+                    "".join([str(nint) for nint in value._int]))
+
+    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 MSExecutionContext_pyodbc(MSExecutionContext):
index 19ad70fe82fbad7b39f9b56b03462dce918c4215..e34f2605cbec460001984f40824d0e071032e24b 100644 (file)
@@ -29,12 +29,34 @@ Currently *not* supported are::
 """
 
 from sqlalchemy.dialects.sybase.base import SybaseDialect, SybaseExecutionContext
-from sqlalchemy.connectors.pyodbc import PyODBCConnector, PyODBCNumeric
+from sqlalchemy.connectors.pyodbc import PyODBCConnector
+import decimal
+from sqlalchemy import types as sqltypes, util, processors
 
-from sqlalchemy import types as sqltypes, util
+class _SybNumeric_pyodbc(sqltypes.Numeric):
+    """Turns Decimals with adjusted() < -6 into floats.
+    
+    It's not yet known how to get decimals with many 
+    significant digits or very large adjusted() into Sybase
+    via pyodbc.
+    
+    """
+
+    def bind_processor(self, dialect):
+        super_process = super(_SybNumeric_pyodbc, self).bind_processor(dialect)
+
+        def process(value):
+            if self.asdecimal and \
+                    isinstance(value, decimal.Decimal):
 
-class _SybNumeric_pyodbc(PyODBCNumeric):
-    convert_large_decimals_to_string = False
+                if value.adjusted() < -6:
+                    return processors.to_float(value)
+
+            if super_process:
+                return super_process(value)
+            else:
+                return value
+        return process
 
 class SybaseExecutionContext_pyodbc(SybaseExecutionContext):
     def set_ddl_autocommit(self, connection, value):
@@ -43,8 +65,6 @@ class SybaseExecutionContext_pyodbc(SybaseExecutionContext):
         else:
             connection.autocommit = False
 
-
-
 class SybaseDialect_pyodbc(PyODBCConnector, SybaseDialect):
     execution_ctx_cls = SybaseExecutionContext_pyodbc