From: Mike Bayer Date: Sat, 20 Mar 2010 01:37:42 +0000 (-0400) Subject: re-split PyODBCNumeric among Sybase and MS-SQL, they can't be shared. X-Git-Tag: rel_0_6beta2~7 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1398268c42667d5feb148cf5f6e27aeaecfe35e9;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git re-split PyODBCNumeric among Sybase and MS-SQL, they can't be shared. MS-SQL really needs the pure string approach else crashes occur on windows. --- diff --git a/lib/sqlalchemy/connectors/pyodbc.py b/lib/sqlalchemy/connectors/pyodbc.py index 5cf00bc923..b291f3e169 100644 --- a/lib/sqlalchemy/connectors/pyodbc.py +++ b/lib/sqlalchemy/connectors/pyodbc.py @@ -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' diff --git a/lib/sqlalchemy/dialects/mssql/pyodbc.py b/lib/sqlalchemy/dialects/mssql/pyodbc.py index 8e7e906292..5625e3cd26 100644 --- a/lib/sqlalchemy/dialects/mssql/pyodbc.py +++ b/lib/sqlalchemy/dialects/mssql/pyodbc.py @@ -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): diff --git a/lib/sqlalchemy/dialects/sybase/pyodbc.py b/lib/sqlalchemy/dialects/sybase/pyodbc.py index 19ad70fe82..e34f2605cb 100644 --- a/lib/sqlalchemy/dialects/sybase/pyodbc.py +++ b/lib/sqlalchemy/dialects/sybase/pyodbc.py @@ -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