]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
document Oracle FLOAT/DOUBLE and binary variants
authorMike Bayer <mike_mp@zzzcomputing.com>
Mon, 23 Dec 2024 16:46:57 +0000 (11:46 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Mon, 23 Dec 2024 16:47:30 +0000 (11:47 -0500)
Fixes: #9704
Change-Id: Id11722d32eeb2a8582348aa5846eefb19d7c83c7
(cherry picked from commit e182255e24500f4c0a101af5fee6b73e98149104)

lib/sqlalchemy/dialects/oracle/base.py
lib/sqlalchemy/dialects/oracle/types.py

index b0b9032c00d3685b90c9966764f2498e32d14ee7..e012fccdf0b12193dc1ed3c1f36f818a8236f939 100644 (file)
@@ -462,6 +462,49 @@ the ``exclude_tablespaces`` parameter::
         exclude_tablespaces=["SYSAUX", "SOME_TABLESPACE"],
     )
 
+.. _oracle_float_support:
+
+FLOAT / DOUBLE Support and Behaviors
+------------------------------------
+
+The SQLAlchemy :class:`.Float` and :class:`.Double` datatypes are generic
+datatypes that resolve to the "least surprising" datatype for a given backend.
+For Oracle Database, this means they resolve to the ``FLOAT`` and ``DOUBLE``
+types::
+
+    >>> from sqlalchemy import cast, literal, Float
+    >>> from sqlalchemy.dialects import oracle
+    >>> float_datatype = Float()
+    >>> print(cast(literal(5.0), float_datatype).compile(dialect=oracle.dialect()))
+    CAST(:param_1 AS FLOAT)
+
+Oracle's ``FLOAT`` / ``DOUBLE`` datatypes are aliases for ``NUMBER``.   Oracle
+Database stores ``NUMBER`` values with full precision, not floating point
+precision, which means that ``FLOAT`` / ``DOUBLE`` do not actually behave like
+native FP values. Oracle Database instead offers special datatypes
+``BINARY_FLOAT`` and ``BINARY_DOUBLE`` to deliver real 4- and 8- byte FP
+values.
+
+SQLAlchemy supports these datatypes directly using :class:`.BINARY_FLOAT` and
+:class:`.BINARY_DOUBLE`.   To use the :class:`.Float` or :class:`.Double`
+datatypes in a database agnostic way, while allowing Oracle backends to utilize
+one of these types, use the :meth:`.TypeEngine.with_variant` method to set up a
+variant::
+
+    >>> from sqlalchemy import cast, literal, Float
+    >>> from sqlalchemy.dialects import oracle
+    >>> float_datatype = Float().with_variant(oracle.BINARY_FLOAT(), "oracle")
+    >>> print(cast(literal(5.0), float_datatype).compile(dialect=oracle.dialect()))
+    CAST(:param_1 AS BINARY_FLOAT)
+
+E.g. to use this datatype in a :class:`.Table` definition::
+
+    my_table = Table(
+        "my_table", metadata,
+        Column("fp_data", Float().with_variant(oracle.BINARY_FLOAT(), "oracle"))
+    )
+
+
 DateTime Compatibility
 ----------------------
 
index 2f84415ea8f7b10787cc3de81ffc0566f08dba7f..539b2107076f2931bc6eafb18094ed8ceba6e69c 100644 (file)
@@ -111,10 +111,36 @@ class FLOAT(sqltypes.FLOAT):
 
 
 class BINARY_DOUBLE(sqltypes.Double):
+    """Implement the Oracle ``BINARY_DOUBLE`` datatype.
+
+    This datatype differs from the Oracle ``DOUBLE`` datatype in that it
+    delivers a true 4-byte FP value.   The datatype may be combined with a
+    generic :class:`.Double` datatype using :meth:`.TypeEngine.with_variant`.
+
+    .. seealso::
+
+        :ref:`oracle_float_support`
+
+
+    """
+
     __visit_name__ = "BINARY_DOUBLE"
 
 
 class BINARY_FLOAT(sqltypes.Float):
+    """Implement the Oracle ``BINARY_FLOAT`` datatype.
+
+    This datatype differs from the Oracle ``FLOAT`` datatype in that it
+    delivers a true 4-byte FP value.   The datatype may be combined with a
+    generic :class:`.Float` datatype using :meth:`.TypeEngine.with_variant`.
+
+    .. seealso::
+
+        :ref:`oracle_float_support`
+
+
+    """
+
     __visit_name__ = "BINARY_FLOAT"