From: Michael Trier Date: Sat, 17 Jan 2009 20:57:18 +0000 (+0000) Subject: Corrected handling of large decimal values on mssql. Added more robust tests. X-Git-Tag: rel_0_5_1~1 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=27c4e7aade7d98f909dfb362bead0e38528213eb;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git 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 --- diff --git a/CHANGES b/CHANGES index bccb5e7c20..183edbdc0f 100644 --- a/CHANGES +++ b/CHANGES @@ -128,6 +128,9 @@ CHANGES 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. diff --git a/lib/sqlalchemy/databases/mssql.py b/lib/sqlalchemy/databases/mssql.py index 7d23c5b273..24296c329b 100644 --- a/lib/sqlalchemy/databases/mssql.py +++ b/lib/sqlalchemy/databases/mssql.py @@ -332,16 +332,17 @@ class MSNumeric(sqltypes.Numeric): # 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) - return value + 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 str(value) + return value + return process def get_col_spec(self): @@ -358,14 +359,6 @@ class MSFloat(sqltypes.Float): 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.""" @@ -380,14 +373,6 @@ class MSReal(MSFloat): 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" diff --git a/test/dialect/mssql.py b/test/dialect/mssql.py index b7bc9a6096..f0b0bec76f 100755 --- a/test/dialect/mssql.py +++ b/test/dialect/mssql.py @@ -473,32 +473,51 @@ class TypesTest(TestBase): 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) + + for value in select([numeric_table.c.numericcol]).execute(): + self.assertTrue(value[0] in test_items, "%s not in test_items" % value[0]) - def tearDown(self): - numeric_table.delete().execute() + except Exception, e: + raise e - def test_decimal_e_notation(self): - from decimal import Decimal + 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