]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
change float -> Double in the _type_map.
authorMike Bayer <mike_mp@zzzcomputing.com>
Tue, 20 Jan 2026 14:45:25 +0000 (09:45 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Wed, 21 Jan 2026 01:31:41 +0000 (20:31 -0500)
The :class:`.Double` type is now used when a Python float value is detected
as a literal value to be sent as a bound parameter, rather than the
:class:`.Float` type.  :class:`.Double` has the same implementation as
:class:`.Float`, but when rendered in a CAST, produces ``DOUBLE`` or
``DOUBLE PRECISION`` rather than ``FLOAT``.   The former better matches
Python's ``float`` datatype which uses 8-byte double-precision storage.
Third party dialects which don't support the :class:`.Double` type directly
may need adjustment so that they render an appropriate keyword (e.g.
``FLOAT``) when the :class:`.Double` datatype is encountered.

Fixes: #10300
Change-Id: I6d221ca9206a10c73fefad55f7ab7a6da5c81d6b

doc/build/changelog/migration_21.rst
doc/build/changelog/unreleased_21/10300.rst [new file with mode: 0644]
lib/sqlalchemy/sql/sqltypes.py
test/ext/test_hybrid.py
test/sql/test_types.py

index 67a979d589fcaab7bed491aff6a976253e726889..bfc259e62b085764a7f6b83f74299772af111c38 100644 (file)
@@ -1183,6 +1183,61 @@ raise an error, directing users to use :class:`_sql.FrameClause` instead.
 
 :ticket:`12596`
 
+.. _change_10300:
+
+Python float literals now render as DOUBLE in CAST expressions
+---------------------------------------------------------------
+
+When Python ``float`` values are used as literal bound parameters in SQL
+expressions, in the absence of an explicit type being passed to the bound
+parameter expression, they now use the :class:`.Double` type instead of
+:class:`.Float`. This change affects the SQL keyword that is rendered when
+these values appear in CAST expressions.
+
+The :class:`.Double` and :class:`.Float` types have identical implementations
+and behavior at runtime. The only difference is in DDL and CAST rendering:
+:class:`.Double` renders as ``DOUBLE`` or ``DOUBLE PRECISION``, while
+:class:`.Float` renders as ``FLOAT``. The ``DOUBLE`` keyword better matches
+Python's ``float`` datatype, which uses 8-byte double-precision storage.
+
+This change is most visible in division operations, where a float divisor is
+automatically cast to ensure proper floating-point division::
+
+    from sqlalchemy import table, column, Integer, select
+
+    t = table("t", column("x", Integer))
+
+    stmt = select(t.c.x / 5.0)
+
+The above statement will now render with a DOUBLE CAST on most backends:
+
+.. sourcecode:: sql
+
+    SELECT t.x / CAST(:x_1 AS DOUBLE) AS anon_1 FROM t
+
+Previously, this would have rendered as ``CAST(:x_1 AS FLOAT)``.
+
+Notes for Third-Party Dialects
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Third-party dialect implementations that don't support the ``DOUBLE`` keyword
+will need to ensure they have a ``visit_double()`` method in their type compiler
+to render an appropriate alternative keyword for the target database.
+
+For example, a dialect for a database that doesn't support ``DOUBLE`` might
+map it to ``FLOAT``::
+
+    class MyDialectTypeCompiler(GenericTypeCompiler):
+        def visit_double(self, type_, **kw):
+            # Map double to FLOAT for databases that don't support DOUBLE
+            return "FLOAT"
+
+The built-in SQLAlchemy dialects (PostgreSQL, MySQL, Oracle, SQL Server,
+SQLite) all handle ``visit_double()`` by rendering either ``DOUBLE`` or
+``DOUBLE PRECISION``.
+
+:ticket:`10300`
+
 
 PostgreSQL
 ==========
diff --git a/doc/build/changelog/unreleased_21/10300.rst b/doc/build/changelog/unreleased_21/10300.rst
new file mode 100644 (file)
index 0000000..edc14fa
--- /dev/null
@@ -0,0 +1,17 @@
+.. change::
+    :tags: bug, sql
+    :tickets: 10300
+
+    The :class:`.Double` type is now used when a Python float value is detected
+    as a literal value to be sent as a bound parameter, rather than the
+    :class:`.Float` type.  :class:`.Double` has the same implementation as
+    :class:`.Float`, but when rendered in a CAST, produces ``DOUBLE`` or
+    ``DOUBLE PRECISION`` rather than ``FLOAT``.   The former better matches
+    Python's ``float`` datatype which uses 8-byte double-precision storage.
+    Third party dialects which don't support the :class:`.Double` type directly
+    may need adjustment so that they render an appropriate keyword (e.g.
+    ``FLOAT``) when the :class:`.Double` datatype is encountered.
+
+    .. seealso::
+
+        :ref:`change_10300`
index 9a43056cdbf9a9774526e7f4872ef24e2a4e4a19..6308f3014d0ee1cd0d244d836e5f77de3d76fce4 100644 (file)
@@ -3992,7 +3992,7 @@ _UNICODE = Unicode()
 
 _type_map: Dict[Type[Any], TypeEngine[Any]] = {
     int: Integer(),
-    float: Float(),
+    float: Double(),
     bool: BOOLEANTYPE,
     _python_UUID: Uuid(),
     decimal.Decimal: Numeric(),
index a18419541716c312dd733ff4063caf7d93be25f8..162331906b0fd8f706b3e12c4d951e088714061c 100644 (file)
@@ -1879,7 +1879,7 @@ class DMLTest(
                 }
             ),
             "INSERT INTO a (amount, rate) VALUES "
-            "((:param_1 / CAST(:rate AS FLOAT)), :rate)",
+            "((:param_1 / CAST(:rate AS DOUBLE)), :rate)",
             checkparams={"param_1": 25, "rate": 1.5},
         )
 
@@ -1904,7 +1904,7 @@ class DMLTest(
                         ): 25,
                     }
                 ),
-                "UPDATE a SET amount=(:param_1 / CAST(:rate AS FLOAT)), "
+                "UPDATE a SET amount=(:param_1 / CAST(:rate AS DOUBLE)), "
                 "rate=:rate",
                 checkparams={"param_1": 25, "rate": 1.5},
             )
@@ -1921,7 +1921,7 @@ class DMLTest(
                         ): 25
                     }
                 ),
-                "UPDATE a SET amount=(:param_1 / CAST(a.rate AS FLOAT))",
+                "UPDATE a SET amount=(:param_1 / CAST(a.rate AS DOUBLE))",
                 checkparams={"param_1": 25},
             )
 
index 44792d135ae7bfbdcefa1fe47232692f377da0dd..826a6f2ec4b9919f0445c1ab220f883764244116 100644 (file)
@@ -3699,7 +3699,7 @@ class ExpressionTest(
 
     @testing.combinations(
         (5, Integer),
-        (2.65, Float),
+        (2.65, Double),
         (True, Boolean),
         (decimal.Decimal("2.65"), Numeric),
         (datetime.date(2015, 7, 20), Date),