:ticket:`7490`
+.. _change_5465_oracle:
+
+New Oracle FLOAT type with binary precision; decimal precision not accepted directly
+------------------------------------------------------------------------------------
+
+A new datatype :class:`_oracle.FLOAT` has been added to the Oracle dialect, to
+accompany the addition of :class:`_sqltypes.Double` and database-specific
+:class:`_sqltypes.DOUBLE`, :class:`_sqltypes.DOUBLE_PRECISION` and
+:class:`_sqltypes.REAL` datatypes. Oracle's ``FLOAT`` accepts a so-called
+"binary precision" parameter that per Oracle documentation is roughly a
+standard "precision" value divided by 0.3103::
+
+ from sqlalchemy.dialects import oracle
+
+ Table(
+ "some_table", metadata,
+ Column("value", oracle.FLOAT(126))
+ )
+
+A binary precision value of 126 is synonymous with using the
+:class:`_sqltypes.DOUBLE_PRECISION` datatype, and a value of 63 is equivalent
+to using the :class:`_sqltypes.REAL` datatype. Other precision values are
+specific to the :class:`_oracle.FLOAT` type itself.
+
+The SQLAlchemy :class:`_sqltypes.Float` datatype also accepts a "precision"
+parameter, but this is decimal precision which is not accepted by
+Oracle. Rather than attempting to guess the conversion, the Oracle dialect
+will now raise an informative error if :class:`_sqltypes.Float` is used with
+a precision value against the Oracle backend. To specify a
+:class:`_sqltypes.Float` datatype with an explicit precision value for
+supporting backends, while also supporting other backends, use
+the :meth:`_types.TypeEngine.with_variant` method as follows::
+
+ from sqlalchemy.types import Float
+ from sqlalchemy.dialects import oracle
+
+ Table(
+ "some_table", metadata,
+ Column("value", Float(5).with_variant(oracle.FLOAT(16), "oracle"))
+ )
+
+
+
.. _migration_20_overview:
1.x -> 2.x Migration Overview
--- /dev/null
+.. change::
+ :tags: feature, types
+ :tickets: 5465
+
+ Added :class:`.Double`, :class:`.DOUBLE`, :class:`.DOUBLE_PRECISION`
+ datatypes to the base ``sqlalchemy.`` module namespace, for explicit use of
+ double/double precision as well as generic "double" datatypes. Use
+ :class:`.Double` for generic support that will resolve to DOUBLE/DOUBLE
+ PRECISION/FLOAT as needed for different backends.
+
+
+.. change::
+ :tags: feature, oracle
+ :tickets: 5465
+
+ Implemented DDL and reflection support for ``FLOAT`` datatypes which
+ include an explicit "binary_precision" value. Using the Oracle-specific
+ :class:`_oracle.FLOAT` datatype, the new parameter
+ :paramref:`_oracle.FLOAT.binary_precision` may be specified which will
+ render Oracle's precision for floating point types directly. This value is
+ interpreted during reflection. Upon reflecting back a ``FLOAT`` datatype,
+ the datatype returned is one of :class:`_types.DOUBLE_PRECISION` for a
+ ``FLOAT`` for a precision of 126 (this is also Oracle's default precision
+ for ``FLOAT``), :class:`_types.REAL` for a precision of 63, and
+ :class:`_oracle.FLOAT` for a custom precision, as per Oracle documentation.
+
+ As part of this change, the generic :paramref:`_sqltypes.Float.precision`
+ value is explicitly rejected when generating DDL for Oracle, as this
+ precision cannot be accurately converted to "binary precision"; instead, an
+ error message encourages the use of
+ :meth:`_sqltypes.TypeEngine.with_variant` so that Oracle's specific form of
+ precision may be chosen exactly. This is a backwards-incompatible change in
+ behavior, as the previous "precision" value was silently ignored for
+ Oracle.
+
+ .. seealso::
+
+ :ref:`change_5465_oracle`
\ No newline at end of file
"_row": "sqlalchemy.engine",
"_schema": "sqlalchemy.schema",
"_types": "sqlalchemy.types",
+ "_sqltypes": "sqlalchemy.types",
"_asyncio": "sqlalchemy.ext.asyncio",
"_expression": "sqlalchemy.sql.expression",
"_sql": "sqlalchemy.sql.expression",
.. autoclass:: Enum
:members: __init__, create, drop
+.. autoclass:: Double
+ :members:
+
.. autoclass:: Float
:members:
.. autoclass:: DECIMAL
+.. autoclass:: DOUBLE
+
+.. autoclass:: DOUBLE_PRECISION
.. autoclass:: FLOAT
.. autoclass:: DATE
:members: __init__
-.. autoclass:: DOUBLE_PRECISION
+.. autoclass:: FLOAT
:members: __init__
-
.. autoclass:: INTERVAL
:members: __init__
-
.. autoclass:: NCLOB
:members: __init__
-
.. autoclass:: NUMBER
:members: __init__
-
.. autoclass:: LONG
:members: __init__
-
.. autoclass:: RAW
:members: __init__
from .types import DATETIME as DATETIME
from .types import DateTime as DateTime
from .types import DECIMAL as DECIMAL
+from .types import DOUBLE as DOUBLE
+from .types import Double as Double
+from .types import DOUBLE_PRECISION as DOUBLE_PRECISION
from .types import Enum as Enum
from .types import FLOAT as FLOAT
from .types import Float as Float
_FloatType: _FloatType,
sqltypes.Numeric: NUMERIC,
sqltypes.Float: FLOAT,
+ sqltypes.Double: DOUBLE,
sqltypes.Time: TIME,
sqltypes.Enum: ENUM,
sqltypes.MatchType: _MatchType,
)
-class DOUBLE(_FloatType):
+class DOUBLE(_FloatType, sqltypes.DOUBLE):
"""MySQL DOUBLE type."""
__visit_name__ = "DOUBLE"
from .base import NVARCHAR
from .base import NVARCHAR2
from .base import RAW
+from .base import REAL
from .base import ROWID
from .base import TIMESTAMP
from .base import VARCHAR
from ...types import BLOB
from ...types import CHAR
from ...types import CLOB
+from ...types import DOUBLE_PRECISION
from ...types import FLOAT
from ...types import INTEGER
from ...types import NCHAR
from ...types import NVARCHAR
+from ...types import REAL
from ...types import TIMESTAMP
from ...types import VARCHAR
return sqltypes.Integer
-class DOUBLE_PRECISION(sqltypes.Float):
- __visit_name__ = "DOUBLE_PRECISION"
+class FLOAT(sqltypes.FLOAT):
+ """Oracle FLOAT.
+
+ This is the same as :class:`_sqltypes.FLOAT` except that
+ an Oracle-specific :paramref:`_oracle.FLOAT.binary_precision`
+ parameter is accepted, and
+ the :paramref:`_sqltypes.Float.precision` parameter is not accepted.
+
+ Oracle FLOAT types indicate precision in terms of "binary precision", which
+ defaults to 126. For a REAL type, the value is 63. This parameter does not
+ cleanly map to a specific number of decimal places but is roughly
+ equivalent to the desired number of decimal places divided by 0.3103.
+
+ .. versionadded:: 2.0
+
+ """
+
+ __visit_name__ = "FLOAT"
+
+ def __init__(
+ self,
+ binary_precision=None,
+ asdecimal=False,
+ decimal_return_scale=None,
+ ):
+ r"""
+ Construct a FLOAT
+
+ :param binary_precision: Oracle binary precision value to be rendered
+ in DDL. This may be approximated to the number of decimal characters
+ using the formula "decimal precision = 0.30103 * binary precision".
+ The default value used by Oracle for FLOAT / DOUBLE PRECISION is 126.
+
+ :param asdecimal: See :paramref:`_sqltypes.Float.asdecimal`
+
+ :param decimal_return_scale: See
+ :paramref:`_sqltypes.Float.decimal_return_scale`
+
+ """
+ super().__init__(
+ asdecimal=asdecimal, decimal_return_scale=decimal_return_scale
+ )
+ self.binary_precision = binary_precision
class BINARY_DOUBLE(sqltypes.Float):
"RAW": RAW,
"FLOAT": FLOAT,
"DOUBLE PRECISION": DOUBLE_PRECISION,
+ "REAL": REAL,
"LONG": LONG,
"BINARY_DOUBLE": BINARY_DOUBLE,
"BINARY_FLOAT": BINARY_FLOAT,
def visit_float(self, type_, **kw):
return self.visit_FLOAT(type_, **kw)
+ def visit_double(self, type_, **kw):
+ return self.visit_DOUBLE_PRECISION(type_, **kw)
+
def visit_unicode(self, type_, **kw):
if self.dialect._use_nchar_for_unicode:
return self.visit_NVARCHAR2(type_, **kw)
return self._generate_numeric(type_, "BINARY_FLOAT", **kw)
def visit_FLOAT(self, type_, **kw):
- # don't support conversion between decimal/binary
- # precision yet
- kw["no_precision"] = True
+ kw["_requires_binary_precision"] = True
return self._generate_numeric(type_, "FLOAT", **kw)
def visit_NUMBER(self, type_, **kw):
return self._generate_numeric(type_, "NUMBER", **kw)
def _generate_numeric(
- self, type_, name, precision=None, scale=None, no_precision=False, **kw
+ self,
+ type_,
+ name,
+ precision=None,
+ scale=None,
+ _requires_binary_precision=False,
+ **kw,
):
if precision is None:
- precision = type_.precision
+
+ precision = getattr(type_, "precision", None)
+
+ if _requires_binary_precision:
+ binary_precision = getattr(type_, "binary_precision", None)
+
+ if precision and binary_precision is None:
+ # https://www.oracletutorial.com/oracle-basics/oracle-float/
+ estimated_binary_precision = int(precision / 0.30103)
+ raise exc.ArgumentError(
+ "Oracle FLOAT types use 'binary precision', which does "
+ "not convert cleanly from decimal 'precision'. Please "
+ "specify "
+ f"this type with a separate Oracle variant, such as "
+ f"{type_.__class__.__name__}(precision={precision})."
+ f"with_variant(oracle.FLOAT"
+ f"(binary_precision="
+ f"{estimated_binary_precision}), 'oracle'), so that the "
+ "Oracle specific 'binary_precision' may be specified "
+ "accurately."
+ )
+ else:
+ precision = binary_precision
if scale is None:
scale = getattr(type_, "scale", None)
- if no_precision or precision is None:
+ if precision is None:
return name
elif scale is None:
n = "%(name)s(%(precision)s)"
else:
coltype = NUMBER(precision, scale)
elif coltype == "FLOAT":
- # TODO: support "precision" here as "binary_precision"
- coltype = FLOAT()
+ # https://docs.oracle.com/cd/B14117_01/server.101/b10758/sqlqr06.htm
+ if precision == 126:
+ # The DOUBLE PRECISION datatype is a floating-point
+ # number with binary precision 126.
+ coltype = DOUBLE_PRECISION()
+ elif precision == 63:
+ # The REAL datatype is a floating-point number with a
+ # binary precision of 63, or 18 decimal.
+ coltype = REAL()
+ else:
+ # non standard precision
+ coltype = FLOAT(binary_precision=precision)
+
elif coltype in ("VARCHAR2", "NVARCHAR2", "CHAR", "NCHAR"):
coltype = self.ischema_names.get(coltype)(length)
elif "WITH TIME ZONE" in coltype:
from ...types import BOOLEAN
from ...types import CHAR
from ...types import DATE
+from ...types import DOUBLE_PRECISION
from ...types import FLOAT
from ...types import INTEGER
from ...types import NUMERIC
__visit_name__ = "BYTEA"
-class DOUBLE_PRECISION(sqltypes.Float):
- __visit_name__ = "DOUBLE_PRECISION"
-
-
class INET(sqltypes.TypeEngine):
__visit_name__ = "INET"
else:
return "FLOAT(%(precision)s)" % {"precision": type_.precision}
- def visit_DOUBLE_PRECISION(self, type_, **kw):
- return "DOUBLE PRECISION"
+ def visit_double(self, type_, **kw):
+ return self.visit_DOUBLE_PRECISION(type, **kw)
def visit_BIGINT(self, type_, **kw):
return "BIGINT"
"DATE_CHAR": sqltypes.DATE,
"DATETIME": sqltypes.DATETIME,
"DATETIME_CHAR": sqltypes.DATETIME,
- "DOUBLE": sqltypes.FLOAT,
+ "DOUBLE": sqltypes.DOUBLE,
"DECIMAL": sqltypes.DECIMAL,
"FLOAT": sqltypes.FLOAT,
"INT": sqltypes.INTEGER,
def visit_FLOAT(self, type_, **kw):
return "FLOAT"
+ def visit_DOUBLE(self, type_, **kw):
+ return "DOUBLE"
+
+ def visit_DOUBLE_PRECISION(self, type_, **kw):
+ return "DOUBLE PRECISION"
+
def visit_REAL(self, type_, **kw):
return "REAL"
def visit_float(self, type_, **kw):
return self.visit_FLOAT(type_, **kw)
+ def visit_double(self, type_, **kw):
+ return self.visit_DOUBLE(type_, **kw)
+
def visit_numeric(self, type_, **kw):
return self.visit_NUMERIC(type_, **kw)
Construct a Float.
:param precision: the numeric precision for use in DDL ``CREATE
- TABLE``.
+ TABLE``. Backends **should** attempt to ensure this precision
+ indicates a number of digits for the generic
+ :class:`_sqltypes.Float` datatype.
+
+ .. note:: For the Oracle backend, the
+ :paramref:`_sqltypes.Float.precision` parameter is not accepted
+ when rendering DDL, as Oracle does not support float precision
+ specified as a number of decimal places. Instead, use the
+ Oracle-specific :class:`_oracle.FLOAT` datatype and specify the
+ :paramref:`_oracle.FLOAT.binary_precision` parameter. This is new
+ in version 2.0 of SQLAlchemy.
+
+ To create a database agnostic :class:`_types.Float` that
+ separately specifies binary precision for Oracle, use
+ :meth:`_types.TypeEngine.with_variant` as follows::
+
+ from sqlalchemy import Column
+ from sqlalchemy import Float
+ from sqlalchemy.dialects import oracle
+
+ Column(
+ "float_data",
+ Float(5).with_variant(oracle.FLOAT(binary_precision=16), "oracle")
+ )
:param asdecimal: the same flag as that of :class:`.Numeric`, but
defaults to ``False``. Note that setting this flag to ``True``
.. versionadded:: 0.9.0
- """
+ """ # noqa: E501
self.precision = precision
self.asdecimal = asdecimal
self.decimal_return_scale = decimal_return_scale
return None
+class Double(Float):
+ """A type for double ``FLOAT`` floating point types.
+
+ Typically generates a ``DOUBLE`` or ``DOUBLE_PRECISION`` in DDL,
+ and otherwise acts like a normal :class:`.Float` on the Python
+ side.
+
+ .. versionadded:: 2.0
+
+ """
+
+ __visit_name__ = "double"
+
+
class DateTime(_LookupExpressionAdapter, TypeEngine[dt.datetime]):
"""A type for ``datetime.datetime()`` objects.
class REAL(Float):
- """The SQL REAL type."""
+ """The SQL REAL type.
+
+ .. seealso::
+
+ :class:`_types.Float` - documentation for the base type.
+
+ """
__visit_name__ = "REAL"
class FLOAT(Float):
- """The SQL FLOAT type."""
+ """The SQL FLOAT type.
+
+ .. seealso::
+
+ :class:`_types.Float` - documentation for the base type.
+
+ """
__visit_name__ = "FLOAT"
+class DOUBLE(Double):
+ """The SQL DOUBLE type.
+
+ .. versionadded:: 2.0
+
+ .. seealso::
+
+ :class:`_types.Double` - documentation for the base type.
+
+ """
+
+ __visit_name__ = "DOUBLE"
+
+
+class DOUBLE_PRECISION(Double):
+ """The SQL DOUBLE PRECISION type.
+
+ .. versionadded:: 2.0
+
+ .. seealso::
+
+ :class:`_types.Double` - documentation for the base type.
+
+ """
+
+ __visit_name__ = "DOUBLE_PRECISION"
+
+
class NUMERIC(Numeric):
- """The SQL NUMERIC type."""
+ """The SQL NUMERIC type.
+
+ .. seealso::
+
+ :class:`_types.Numeric` - documentation for the base type.
+
+ """
__visit_name__ = "NUMERIC"
class DECIMAL(Numeric):
- """The SQL DECIMAL type."""
+ """The SQL DECIMAL type.
+
+ .. seealso::
+
+ :class:`_types.Numeric` - documentation for the base type.
+
+ """
__visit_name__ = "DECIMAL"
class INTEGER(Integer):
- """The SQL INT or INTEGER type."""
+ """The SQL INT or INTEGER type.
+
+ .. seealso::
+
+ :class:`_types.Integer` - documentation for the base type.
+
+ """
__visit_name__ = "INTEGER"
class SMALLINT(SmallInteger):
- """The SQL SMALLINT type."""
+ """The SQL SMALLINT type.
+
+ .. seealso::
+
+ :class:`_types.SmallInteger` - documentation for the base type.
+
+ """
__visit_name__ = "SMALLINT"
class BIGINT(BigInteger):
- """The SQL BIGINT type."""
+ """The SQL BIGINT type.
+
+ .. seealso::
+
+ :class:`_types.BigInteger` - documentation for the base type.
+
+ """
__visit_name__ = "BIGINT"
metadata,
Column("user_id", sa.INT, primary_key=True),
Column("test1", sa.CHAR(5), nullable=False),
- Column("test2", sa.Float(5), nullable=False),
+ Column("test2", sa.Float(), nullable=False),
Column(
"parent_user_id",
sa.Integer,
metadata,
Column("user_id", sa.INT, primary_key=True),
Column("test1", sa.CHAR(5), nullable=False),
- Column("test2", sa.Float(5), nullable=False),
+ Column("test2", sa.Float(), nullable=False),
schema=schema,
test_needs_fk=True,
)
def test_render_literal_float(self, literal_round_trip):
literal_round_trip(
- Float(4),
+ Float(),
[15.7563, decimal.Decimal("15.7563")],
[15.7563],
filter_=lambda n: n is not None and round(n, 5) or None,
@testing.requires.floats_to_four_decimals
def test_float_as_decimal(self, do_numeric_test):
do_numeric_test(
- Float(precision=8, asdecimal=True),
- [15.7563, decimal.Decimal("15.7563"), None],
- [decimal.Decimal("15.7563"), None],
+ Float(asdecimal=True),
+ [15.756, decimal.Decimal("15.756"), None],
+ [decimal.Decimal("15.756"), None],
filter_=lambda n: n is not None and round(n, 4) or None,
)
def test_float_as_float(self, do_numeric_test):
do_numeric_test(
- Float(precision=8),
- [15.7563, decimal.Decimal("15.7563")],
- [15.7563],
+ Float(),
+ [15.756, decimal.Decimal("15.756")],
+ [15.756],
filter_=lambda n: n is not None and round(n, 5) or None,
)
from .sql.sqltypes import DATETIME
from .sql.sqltypes import DateTime
from .sql.sqltypes import DECIMAL
+from .sql.sqltypes import DOUBLE
+from .sql.sqltypes import Double
+from .sql.sqltypes import DOUBLE_PRECISION
from .sql.sqltypes import Enum
from .sql.sqltypes import FLOAT
from .sql.sqltypes import Float
"BigInteger",
"Numeric",
"Float",
+ "Double",
+ "DOUBLE",
+ "DOUBLE_PRECISION",
"DateTime",
"Date",
"Time",
from sqlalchemy import DATETIME
from sqlalchemy import DateTime
from sqlalchemy import DECIMAL
+from sqlalchemy import DOUBLE
+from sqlalchemy import Double
from sqlalchemy import exc
from sqlalchemy import extract
from sqlalchemy import FLOAT
(Float, "t.col"),
(m.MSFloat, "t.col"),
(m.MSDouble, "t.col"),
+ (DOUBLE, "t.col"),
+ (Double, "t.col"),
(m.MSReal, "t.col"),
(m.MSYear, "t.col"),
(m.MSYear(2), "t.col"),
(m.FLOAT, "CAST(t.col AS FLOAT)"),
(Float, "CAST(t.col AS FLOAT)"),
(FLOAT, "CAST(t.col AS FLOAT)"),
+ (Double, "CAST(t.col AS DOUBLE)"),
+ (DOUBLE, "CAST(t.col AS DOUBLE)"),
(m.DOUBLE, "CAST(t.col AS DOUBLE)"),
(m.FLOAT, "CAST(t.col AS FLOAT)"),
argnames="type_,expected",
# coding: utf-8
from sqlalchemy import and_
from sqlalchemy import bindparam
+from sqlalchemy import cast
from sqlalchemy import Computed
from sqlalchemy import exc
from sqlalchemy import except_
from sqlalchemy import text
from sqlalchemy import type_coerce
from sqlalchemy import TypeDecorator
+from sqlalchemy import types as sqltypes
from sqlalchemy import union
from sqlalchemy.dialects.oracle import base as oracle
from sqlalchemy.dialects.oracle import cx_oracle
dialect=dd,
)
+ def test_double_to_oracle_double(self):
+ """test #5465"""
+ d1 = sqltypes.Double
+
+ self.assert_compile(
+ cast(column("foo"), d1), "CAST(foo AS DOUBLE PRECISION)"
+ )
+
class SequenceTest(fixtures.TestBase, AssertsCompiledSQL):
def test_basic(self):
# coding: utf-8
+from sqlalchemy import Double
from sqlalchemy import exc
from sqlalchemy import FLOAT
+from sqlalchemy import Float
from sqlalchemy import ForeignKey
from sqlalchemy import ForeignKeyConstraint
from sqlalchemy import func
from sqlalchemy import text
from sqlalchemy import Unicode
from sqlalchemy import UniqueConstraint
+from sqlalchemy.dialects import oracle
from sqlalchemy.dialects.oracle.base import BINARY_DOUBLE
from sqlalchemy.dialects.oracle.base import BINARY_FLOAT
from sqlalchemy.dialects.oracle.base import DOUBLE_PRECISION
from sqlalchemy.dialects.oracle.base import NUMBER
+from sqlalchemy.dialects.oracle.base import REAL
from sqlalchemy.testing import assert_warns
from sqlalchemy.testing import AssertsCompiledSQL
from sqlalchemy.testing import eq_
connection,
):
specs = [
- (DOUBLE_PRECISION(), FLOAT()),
- # when binary_precision is supported
- # (DOUBLE_PRECISION(), oracle.FLOAT(binary_precision=126)),
+ (DOUBLE_PRECISION(), DOUBLE_PRECISION()),
+ (Double(), DOUBLE_PRECISION()),
+ (REAL(), REAL()),
(BINARY_DOUBLE(), BINARY_DOUBLE()),
(BINARY_FLOAT(), BINARY_FLOAT()),
- (FLOAT(5), FLOAT()),
- # when binary_precision is supported
- # (FLOAT(5), oracle.FLOAT(binary_precision=5),),
- (FLOAT(), FLOAT()),
- # when binary_precision is supported
- # (FLOAT(5), oracle.FLOAT(binary_precision=126),),
+ (oracle.FLOAT(5), oracle.FLOAT(5)),
+ (
+ Float(5).with_variant(
+ oracle.FLOAT(binary_precision=16), "oracle"
+ ),
+ oracle.FLOAT(16),
+ ), # using conversion
+ (FLOAT(), DOUBLE_PRECISION()),
+ # from https://docs.oracle.com/cd/B14117_01/server.101/b10758/sqlqr06.htm # noqa E501
+ # DOUBLE PRECISION == precision 126
+ # REAL == precision 63
+ (oracle.FLOAT(126), DOUBLE_PRECISION()),
+ (oracle.FLOAT(63), REAL()),
]
self._run_test(metadata, connection, specs, ["precision"])
from sqlalchemy import DATE
from sqlalchemy import Date
from sqlalchemy import DateTime
+from sqlalchemy import Double
+from sqlalchemy import DOUBLE_PRECISION
from sqlalchemy import event
+from sqlalchemy import exc
from sqlalchemy import FLOAT
from sqlalchemy import Float
from sqlalchemy import Integer
from sqlalchemy.testing import assert_raises_message
from sqlalchemy.testing import AssertsCompiledSQL
from sqlalchemy.testing import eq_
+from sqlalchemy.testing import expect_raises_message
from sqlalchemy.testing import fixtures
from sqlalchemy.testing import is_
from sqlalchemy.testing import mock
datetime.timedelta(days=35, seconds=5743),
)
+ def test_no_decimal_float_precision(self):
+ with expect_raises_message(
+ exc.ArgumentError,
+ "Oracle FLOAT types use 'binary precision', which does not "
+ "convert cleanly from decimal 'precision'. Please specify this "
+ "type with a separate Oracle variant, such as "
+ r"FLOAT\(precision=5\).with_variant\(oracle.FLOAT\("
+ r"binary_precision=16\), 'oracle'\), so that the Oracle "
+ "specific 'binary_precision' may be specified accurately.",
+ ):
+ FLOAT(5).compile(dialect=oracle.dialect())
+
def test_numerics(self, metadata, connection):
m = metadata
t1 = Table(
Column("numericcol", Numeric(precision=9, scale=2)),
Column("floatcol1", Float()),
Column("floatcol2", FLOAT()),
- Column("doubleprec", oracle.DOUBLE_PRECISION),
+ Column("doubleprec1", DOUBLE_PRECISION),
+ Column("doubleprec2", Double()),
Column("numbercol1", oracle.NUMBER(9)),
Column("numbercol2", oracle.NUMBER(9, 3)),
Column("numbercol3", oracle.NUMBER),
numericcol=5.2,
floatcol1=6.5,
floatcol2=8.5,
- doubleprec=9.5,
+ doubleprec1=9.5,
+ doubleprec2=14.5,
numbercol1=12,
numbercol2=14.85,
numbercol3=15.76,
(6.5, float),
(8.5, float),
(9.5, float),
+ (14.5, float),
(12, int),
(decimal.Decimal("14.85"), decimal.Decimal),
(15.76, float),
(SmallInteger, 25, int, False),
(Integer, 25, int, False),
(Numeric(10, 8), decimal.Decimal("25.34534"), None, False),
- (Float(15), 25.34534, None, False),
+ (oracle.FLOAT(15), 25.34534, None, False),
(oracle.BINARY_DOUBLE, 25.34534, "NATIVE_FLOAT", False),
(oracle.BINARY_FLOAT, 25.34534, "NATIVE_FLOAT", False),
(oracle.DOUBLE_PRECISION, 25.34534, None, False),
"CAST(bar AS someschema.somename) AS bar",
)
+ def test_cast_double_pg_double(self):
+ """test #5465:
+
+ test sqlalchemy Double/DOUBLE to PostgreSQL DOUBLE PRECISION
+ """
+ d1 = sqltypes.Double
+
+ stmt = select(cast(column("foo"), d1))
+ self.assert_compile(
+ stmt, "SELECT CAST(foo AS DOUBLE PRECISION) AS foo"
+ )
+
def test_cast_enum_schema_translate(self):
"""test #6739"""
e1 = Enum("x", "y", "z", name="somename")
from sqlalchemy import Column
from sqlalchemy import column
from sqlalchemy import DateTime
+from sqlalchemy import Double
from sqlalchemy import Enum
from sqlalchemy import exc
from sqlalchemy import Float
Column("x", postgresql.ARRAY(Float)),
Column("y", postgresql.ARRAY(REAL)),
Column("z", postgresql.ARRAY(postgresql.DOUBLE_PRECISION)),
+ Column("w", postgresql.ARRAY(Double)),
Column("q", postgresql.ARRAY(Numeric)),
)
metadata.create_all(connection)
connection.execute(
- t1.insert(), dict(x=[5], y=[5], z=[6], q=[decimal.Decimal("6.4")])
+ t1.insert(),
+ dict(x=[5], y=[5], z=[6], w=[7], q=[decimal.Decimal("6.4")]),
)
row = connection.execute(t1.select()).first()
- eq_(row, ([5], [5], [6], [decimal.Decimal("6.4")]))
+ eq_(row, ([5], [5], [6], [7], [decimal.Decimal("6.4")]))
def test_arrays_base(self, connection, metadata):
t1 = Table(
Column("x", sqltypes.ARRAY(Float)),
Column("y", sqltypes.ARRAY(REAL)),
Column("z", sqltypes.ARRAY(postgresql.DOUBLE_PRECISION)),
+ Column("w", sqltypes.ARRAY(Double)),
Column("q", sqltypes.ARRAY(Numeric)),
)
metadata.create_all(connection)
connection.execute(
- t1.insert(), dict(x=[5], y=[5], z=[6], q=[decimal.Decimal("6.4")])
+ t1.insert(),
+ dict(x=[5], y=[5], z=[6], w=[7], q=[decimal.Decimal("6.4")]),
)
row = connection.execute(t1.select()).first()
- eq_(row, ([5], [5], [6], [decimal.Decimal("6.4")]))
+ eq_(row, ([5], [5], [6], [7], [decimal.Decimal("6.4")]))
class EnumTest(fixtures.TestBase, AssertsExecutionResults):
Column("user_id", sa.INT, primary_key=True),
Column("user_name", sa.VARCHAR(20), nullable=False),
Column("test1", sa.CHAR(5), nullable=False),
- Column("test2", sa.Float(5), nullable=False),
+ Column("test2", sa.Float(), nullable=False),
Column("test3", sa.Text),
Column("test4", sa.Numeric(10, 2), nullable=False),
Column("test5", sa.Date),
Column("user_id", sa.INT, primary_key=True),
Column("user_name", sa.VARCHAR(20), nullable=False),
Column("test1", sa.CHAR(5), nullable=False),
- Column("test2", sa.Float(5), nullable=False),
+ Column("test2", sa.Float(), nullable=False),
Column("test3", sa.Text),
Column("test4", sa.Numeric(10, 2), nullable=False),
Column("test5", sa.Date),
from sqlalchemy import DECIMAL
from sqlalchemy import dialects
from sqlalchemy import distinct
+from sqlalchemy import Double
from sqlalchemy import Enum
from sqlalchemy import exc
from sqlalchemy import FLOAT
eq_(types.Numeric(asdecimal=False).python_type, float)
eq_(types.LargeBinary().python_type, bytes)
eq_(types.Float().python_type, float)
+ eq_(types.Double().python_type, float)
eq_(types.Interval().python_type, datetime.timedelta)
eq_(types.Date().python_type, datetime.date)
eq_(types.DateTime().python_type, datetime.datetime)
dialects.postgresql.FLOAT(), "FLOAT", allow_dialect_select=True
)
+ def test_default_compile_double(self):
+ self.assert_compile(Double(), "DOUBLE")
+
def test_default_compile_mysql_integer(self):
self.assert_compile(
dialects.mysql.INTEGER(display_width=5),