summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/sql
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy/sql')
-rw-r--r--lib/sqlalchemy/sql/compiler.py36
-rw-r--r--lib/sqlalchemy/sql/default_comparator.py1
-rw-r--r--lib/sqlalchemy/sql/operators.py29
-rw-r--r--lib/sqlalchemy/sql/sqltypes.py5
4 files changed, 66 insertions, 5 deletions
diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py
index 28c1bf069..5f6ee5f41 100644
--- a/lib/sqlalchemy/sql/compiler.py
+++ b/lib/sqlalchemy/sql/compiler.py
@@ -177,7 +177,6 @@ OPERATORS = {
operators.mul: " * ",
operators.sub: " - ",
operators.mod: " % ",
- operators.truediv: " / ",
operators.neg: "-",
operators.lt: " < ",
operators.le: " <= ",
@@ -1923,6 +1922,41 @@ class SQLCompiler(Compiled):
"Unary expression has no operator or modifier"
)
+ def visit_truediv_binary(self, binary, operator, **kw):
+ if self.dialect.div_is_floordiv:
+ return (
+ self.process(binary.left, **kw)
+ + " / "
+ # TODO: would need a fast cast again here,
+ # unless we want to use an implicit cast like "+ 0.0"
+ + self.process(
+ elements.Cast(binary.right, sqltypes.Numeric()), **kw
+ )
+ )
+ else:
+ return (
+ self.process(binary.left, **kw)
+ + " / "
+ + self.process(binary.right, **kw)
+ )
+
+ def visit_floordiv_binary(self, binary, operator, **kw):
+ if (
+ self.dialect.div_is_floordiv
+ and binary.right.type._type_affinity is sqltypes.Integer
+ ):
+ return (
+ self.process(binary.left, **kw)
+ + " / "
+ + self.process(binary.right, **kw)
+ )
+ else:
+ return "FLOOR(%s)" % (
+ self.process(binary.left, **kw)
+ + " / "
+ + self.process(binary.right, **kw)
+ )
+
def visit_is_true_unary_operator(self, element, operator, **kw):
if (
element._is_implicitly_boolean
diff --git a/lib/sqlalchemy/sql/default_comparator.py b/lib/sqlalchemy/sql/default_comparator.py
index 036a96e9f..2bbead673 100644
--- a/lib/sqlalchemy/sql/default_comparator.py
+++ b/lib/sqlalchemy/sql/default_comparator.py
@@ -310,6 +310,7 @@ operator_lookup = {
"div": (_binary_operate,),
"mod": (_binary_operate,),
"truediv": (_binary_operate,),
+ "floordiv": (_binary_operate,),
"custom_op": (_custom_op_operate,),
"json_path_getitem_op": (_binary_operate,),
"json_getitem_op": (_binary_operate,),
diff --git a/lib/sqlalchemy/sql/operators.py b/lib/sqlalchemy/sql/operators.py
index 6d45cd033..74eb73e46 100644
--- a/lib/sqlalchemy/sql/operators.py
+++ b/lib/sqlalchemy/sql/operators.py
@@ -14,6 +14,7 @@ from operator import add
from operator import and_
from operator import contains
from operator import eq
+from operator import floordiv
from operator import ge
from operator import getitem
from operator import gt
@@ -1220,7 +1221,12 @@ class ColumnOperators(Operators):
def __truediv__(self, other):
"""Implement the ``/`` operator.
- In a column context, produces the clause ``a / b``.
+ In a column context, produces the clause ``a / b``, and
+ considers the result type to be numeric.
+
+ .. versionchanged:: 2.0 The truediv operator against two integers
+ is now considered to return a numeric value. Behavior on specific
+ backends may vary.
"""
return self.operate(truediv, other)
@@ -1233,6 +1239,26 @@ class ColumnOperators(Operators):
"""
return self.reverse_operate(truediv, other)
+ def __floordiv__(self, other):
+ """Implement the ``//`` operator.
+
+ In a column context, produces the clause ``a / b``,
+ which is the same as "truediv", but considers the result
+ type to be integer.
+
+ .. versionadded:: 2.0
+
+ """
+ return self.operate(floordiv, other)
+
+ def __rfloordiv__(self, other):
+ """Implement the ``//`` operator in reverse.
+
+ See :meth:`.ColumnOperators.__floordiv__`.
+
+ """
+ return self.reverse_operate(floordiv, other)
+
_commutative = {eq, ne, add, mul}
_comparison = {eq, ne, lt, gt, ge, le}
@@ -1588,6 +1614,7 @@ _PRECEDENCE = {
json_path_getitem_op: 15,
mul: 8,
truediv: 8,
+ floordiv: 8,
mod: 8,
neg: 8,
add: 7,
diff --git a/lib/sqlalchemy/sql/sqltypes.py b/lib/sqlalchemy/sql/sqltypes.py
index e65fa3c14..f035284f4 100644
--- a/lib/sqlalchemy/sql/sqltypes.py
+++ b/lib/sqlalchemy/sql/sqltypes.py
@@ -310,8 +310,6 @@ class Integer(_LookupExpressionAdapter, TypeEngine):
@util.memoized_property
def _expression_adaptations(self):
- # TODO: need a dictionary object that will
- # handle operators generically here, this is incomplete
return {
operators.add: {
Date: Date,
@@ -323,7 +321,8 @@ class Integer(_LookupExpressionAdapter, TypeEngine):
Integer: self.__class__,
Numeric: Numeric,
},
- operators.truediv: {Integer: self.__class__, Numeric: Numeric},
+ operators.truediv: {Integer: Numeric, Numeric: Numeric},
+ operators.floordiv: {Integer: self.__class__, Numeric: Numeric},
operators.sub: {Integer: self.__class__, Numeric: Numeric},
}