Float precision loss with pyformat

Issue #1804 resolved
Former user created an issue

I am using pymssql 1.0.2 and SQL Server 2005. SQLAlchemy creates the SQL statements using pyformat %%(%(name)s)s. This causes float values to be converted to string with str(), and that conversion causes precision loss even when both the server and Python could handle more precise floats. I switched the %%(%(name)s)s format to %%(%(name)s)r in sqlalchemy.sql.compiler.BIND_TEMPLATES, and got better results. Of course this is not the real solution since it breaks other string escapes.

Before switching to SQLAlchemy, I created my query statements manually and used simple type checking for bind values and added %(name)s, %(name)i and %(name)r formatting accordingly. Maybe SQLAlchemy could do the same?

Code example:

import sqlalchemy as sa
from sqlalchemy import orm

engine = sa.create_engine('mssql+pymssql:// ...')
metadata = sa.MetaData(bind=engine)

test_table = sa.Table('TEST', metadata,
    sa.Column('ID', sa.Integer, primary_key=True),
    sa.Column('FLT', sa.Float),
    )

class Foo(object):
    pass

orm.mapper(Foo, test_table)

Session = orm.sessionmaker(autoflush=False, autocommit=False)
session = Session()

Results with default SQLAlchemy 0.6:

>>> o = Foo()
>>> o.FLT = 12345678.123456789
>>> session.add(o)
>>> session.commit()
>>> o.FLT
12345678.123500001

After I changed the bind template:

>>> o = Foo()
>>> o.FLT = 12345678.123456789
>>> session.add(o)
>>> session.commit()
>>> o.FLT
12345678.123456787

I know Python's float isn't perfect, but str conversion loses too much precision in this case.

Comments (3)

  1. Mike Bayer repo owner

    I think there is a fundamental misunderstanding of DBAPI here. The "%(name)s" format in this case is specified by DBAPI, and only happens to match the Python syntax as a matter of convenience. "%(name)r" and such are not supported. That pymssql happens to be using "%(name)s" without any intelligence, but when the paramstyle is changed suddenly it works differently, is a (major) bug in pymssql. Please see "paramstyle" in http://www.python.org/dev/peps/pep-0249/ .

    SQLAlchemy makes no decisions here, we only use the default paramstyle format sent to us by the DBAPI. The only point in our source code where we are forced to deal with float formatting is for returning Decimal objects for DBAPIs that don't support it natively, but that is not taking place here.

  2. Log in to comment