add base float coercion to float

Issue #4020 resolved
Mike Bayer repo owner created an issue

e.g. on MySQL, and possibly others in some cases, the driver may not be able to distinguish "float" from "numeric" and even though we know we want "float", Float currently assumes no result processing:

from sqlalchemy import *

e = create_engine("mysql://scott:tiger@localhost/test", echo=True)

print repr(e.scalar(select([literal(4.5, Float)])))

output:

Decimal('4.5')

change would be:

diff --git a/lib/sqlalchemy/sql/sqltypes.py b/lib/sqlalchemy/sql/sqltypes.py
index 7a3c505..1bf75c7 100644
--- a/lib/sqlalchemy/sql/sqltypes.py
+++ b/lib/sqlalchemy/sql/sqltypes.py
@@ -700,6 +700,8 @@ class Float(Numeric):
             return processors.to_decimal_processor_factory(
                 decimal.Decimal,
                 self._effective_decimal_return_scale)
+        elif dialect.supports_native_decimal:
+            return processors.to_float
         else:
             return None

the concern of course would be the extra fn call, however it does not seem to non-negligble overhead. Oddly, the pure Python version is faster than the c processor one so we might want to consider simplfying that:

from sqlalchemy import processors
import timeit


def go1():
    row = []
    for fl in [3.4, 5.10, 23.235, 7.0, 18.999999]:
        row.append(fl)

proc = processors.to_float


def go2():
    row = []
    for fl in [3.4, 5.10, 23.235, 7.0, 18.999999]:
        row.append(proc(fl))

print timeit.timeit("go1", "from __main__ import go1", number=10000000)

print timeit.timeit("go2", "from __main__ import go2", number=10000000)

cprocessors:

0.227154016495
0.238603830338

non cprocessors:

0.226067066193
0.226836919785

Comments (1)

  1. Mike Bayer reporter

    Coerce to float for Float with all native decimal backends

    The result processor for the :class:.Float type now unconditionally runs values through the float() processor if the dialect specifies that it also supports "native decimal" mode. While most backends will deliver Python float objects for a floating point datatype, the MySQL backends in some cases lack the typing information in order to provide this and return Decimal unless the float conversion is done.

    Change-Id: I638f1480fb00a507036efaf0e0080f26893d98ad Fixes: #4020

    → <<cset 563180f7d46b>>

  2. Log in to comment