summaryrefslogtreecommitdiff
path: root/test/sql/test_operators.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2021-12-08 08:57:44 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2021-12-26 19:32:53 -0500
commit6d589ffbb5fe04a4ee606819e948974045f62b80 (patch)
tree95fc3ac54ae23945e3bf810f85294193f4fbbd82 /test/sql/test_operators.py
parent2bb6cfc7c9b8f09eaa4efeffc337a1162993979c (diff)
downloadsqlalchemy-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.py93
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"