diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2021-12-08 08:57:44 -0500 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2021-12-26 19:32:53 -0500 |
commit | 6d589ffbb5fe04a4ee606819e948974045f62b80 (patch) | |
tree | 95fc3ac54ae23945e3bf810f85294193f4fbbd82 /test/sql/test_operators.py | |
parent | 2bb6cfc7c9b8f09eaa4efeffc337a1162993979c (diff) | |
download | sqlalchemy-6d589ffbb5fe04a4ee606819e948974045f62b80.tar.gz |
consider truediv as truediv; support floordiv operator
Implemented full support for "truediv" and "floordiv" using the
"/" and "//" operators. A "truediv" operation between two expressions
using :class:`_types.Integer` now considers the result to be
:class:`_types.Numeric`, and the dialect-level compilation will cast
the right operand to a numeric type on a dialect-specific basis to ensure
truediv is achieved. For floordiv, conversion is also added for those
databases that don't already do floordiv by default (MySQL, Oracle) and
the ``FLOOR()`` function is rendered in this case, as well as for
cases where the right operand is not an integer (needed for PostgreSQL,
others).
The change resolves issues both with inconsistent behavior of the
division operator on different backends and also fixes an issue where
integer division on Oracle would fail to be able to fetch a result due
to inappropriate outputtypehandlers.
Fixes: #4926
Change-Id: Id54cc018c1fb7a49dd3ce1216d68d40f43fe2659
Diffstat (limited to 'test/sql/test_operators.py')
-rw-r--r-- | test/sql/test_operators.py | 93 |
1 files changed, 77 insertions, 16 deletions
diff --git a/test/sql/test_operators.py b/test/sql/test_operators.py index 6e943d236..9e47f217f 100644 --- a/test/sql/test_operators.py +++ b/test/sql/test_operators.py @@ -1621,66 +1621,87 @@ class OperatorAssociativityTest(fixtures.TestBase, testing.AssertsCompiledSQL): def test_associativity_7(self): f = column("f") # because - less precedent than / - self.assert_compile(f / (f - f), "f / (f - f)") + self.assert_compile(f / (f - f), "f / CAST((f - f) AS NUMERIC)") def test_associativity_8(self): f = column("f") - self.assert_compile(f / (f - f).label("foo"), "f / (f - f)") + self.assert_compile( + f / (f - f).label("foo"), "f / CAST((f - f) AS NUMERIC)" + ) def test_associativity_9(self): f = column("f") - self.assert_compile(f / f - f, "f / f - f") + self.assert_compile(f / f - f, "f / CAST(f AS NUMERIC) - f") def test_associativity_10(self): f = column("f") - self.assert_compile((f / f) - f, "f / f - f") + self.assert_compile((f / f) - f, "f / CAST(f AS NUMERIC) - f") def test_associativity_11(self): f = column("f") - self.assert_compile((f / f).label("foo") - f, "f / f - f") + self.assert_compile( + (f / f).label("foo") - f, "f / CAST(f AS NUMERIC) - f" + ) def test_associativity_12(self): f = column("f") # because / more precedent than - - self.assert_compile(f - (f / f), "f - f / f") + self.assert_compile(f - (f / f), "f - f / CAST(f AS NUMERIC)") def test_associativity_13(self): f = column("f") - self.assert_compile(f - (f / f).label("foo"), "f - f / f") + self.assert_compile( + f - (f / f).label("foo"), "f - f / CAST(f AS NUMERIC)" + ) def test_associativity_14(self): f = column("f") - self.assert_compile(f - f / f, "f - f / f") + self.assert_compile(f - f / f, "f - f / CAST(f AS NUMERIC)") def test_associativity_15(self): f = column("f") - self.assert_compile((f - f) / f, "(f - f) / f") + self.assert_compile((f - f) / f, "(f - f) / CAST(f AS NUMERIC)") def test_associativity_16(self): f = column("f") - self.assert_compile(((f - f) / f) - f, "(f - f) / f - f") + self.assert_compile( + ((f - f) / f) - f, "(f - f) / CAST(f AS NUMERIC) - f" + ) def test_associativity_17(self): f = column("f") # - lower precedence than / - self.assert_compile((f - f) / (f - f), "(f - f) / (f - f)") + self.assert_compile( + (f - f) / (f - f), "(f - f) / CAST((f - f) AS NUMERIC)" + ) def test_associativity_18(self): f = column("f") # / higher precedence than - - self.assert_compile((f / f) - (f / f), "f / f - f / f") + self.assert_compile( + (f / f) - (f / f), + "f / CAST(f AS NUMERIC) - f / CAST(f AS NUMERIC)", + ) def test_associativity_19(self): f = column("f") - self.assert_compile((f / f) - (f - f), "f / f - (f - f)") + self.assert_compile( + (f / f) - (f - f), "f / CAST(f AS NUMERIC) - (f - f)" + ) def test_associativity_20(self): f = column("f") - self.assert_compile((f / f) / (f - f), "(f / f) / (f - f)") + self.assert_compile( + (f / f) / (f - f), + "(f / CAST(f AS NUMERIC)) / CAST((f - f) AS NUMERIC)", + ) def test_associativity_21(self): f = column("f") - self.assert_compile(f / (f / (f - f)), "f / (f / (f - f))") + self.assert_compile( + f / (f / (f - f)), + "f / CAST((f / CAST((f - f) AS NUMERIC)) AS NUMERIC)", + ) def test_associativity_22(self): f = column("f") @@ -2195,7 +2216,6 @@ class MathOperatorTest(fixtures.TestBase, testing.AssertsCompiledSQL): ("add", operator.add, "+"), ("mul", operator.mul, "*"), ("sub", operator.sub, "-"), - ("div", operator.truediv, "/"), ("mod", operator.mod, "%"), id_="iaa", ) @@ -2216,6 +2236,17 @@ class MathOperatorTest(fixtures.TestBase, testing.AssertsCompiledSQL): ): self.assert_compile(py_op(lhs, rhs), res % sql_op) + def test_truediv_op_integer(self): + self.assert_compile( + 5 / literal(5), ":param_1 / CAST(:param_2 AS NUMERIC)" + ) + + def test_floordiv_op_integer(self): + self.assert_compile(5 // literal(5), ":param_1 / :param_2") + + def test_floordiv_op_numeric(self): + self.assert_compile(5.10 // literal(5.5), "FLOOR(:param_1 / :param_2)") + @testing.combinations( ("format", "mytable.myid %% %s"), ("qmark", "mytable.myid % ?"), @@ -2231,6 +2262,36 @@ class MathOperatorTest(fixtures.TestBase, testing.AssertsCompiledSQL): dialect=default.DefaultDialect(paramstyle=paramstyle), ) + @testing.combinations( + (operator.add,), + (operator.mul,), + (operator.sub,), + (operator.floordiv), + ) + def test_integer_integer_coercion_to_integer(self, op): + expr = op(column("bar", Integer()), column("foo", Integer())) + assert isinstance(expr.type, Integer) + + @testing.combinations( + (operator.add,), + (operator.mul,), + (operator.sub,), + (operator.truediv,), + ) + def test_integer_numeric_coercion_to_numeric(self, op): + expr = op(column("bar", Integer()), column("foo", Numeric(10, 2))) + assert isinstance(expr.type, Numeric) + expr = op(column("foo", Numeric(10, 2)), column("bar", Integer())) + assert isinstance(expr.type, Numeric) + + def test_integer_truediv(self): + expr = column("bar", Integer()) / column("foo", Integer) + assert isinstance(expr.type, Numeric) + + def test_integer_floordiv(self): + expr = column("bar", Integer()) // column("foo", Integer) + assert isinstance(expr.type, Integer) + class ComparisonOperatorTest(fixtures.TestBase, testing.AssertsCompiledSQL): __dialect__ = "default" |