.. changelog::
:version: 1.2.0b1
+ .. change:: 3873
+ :tags: bug, sql
+ :tickets: 3873
+
+ Repaired issue where the type of an expression that used
+ :meth:`.ColumnOperators.is_` or similar would not be a "boolean" type,
+ instead the type would be "nulltype", as well as when using custom
+ comparison operators against an untyped expression. This typing can
+ impact how the expression behaves in larger contexts as well as
+ in result-row-handling.
+
.. change:: 3969
:tags: bug, sql
:tickets: 3969
if op in (operators.eq, operators.is_):
return BinaryExpression(expr, _const_expr(obj),
operators.is_,
- negate=operators.isnot)
+ negate=operators.isnot,
+ type_=result_type
+ )
elif op in (operators.ne, operators.isnot):
return BinaryExpression(expr, _const_expr(obj),
operators.isnot,
- negate=operators.is_)
+ negate=operators.is_,
+ type_=result_type
+ )
else:
raise exc.ArgumentError(
"Only '=', '!=', 'is_()', 'isnot()', "
_commutative = {eq, ne, add, mul}
-_comparison = {eq, ne, lt, gt, ge, le, between_op, like_op}
+_comparison = {eq, ne, lt, gt, ge, le, between_op, like_op, is_,
+ isnot, is_distinct_from, isnot_distinct_from}
def is_comparison(op):
class Comparator(TypeEngine.Comparator):
def _adapt_expression(self, op, other_comparator):
- if isinstance(other_comparator, NullType.Comparator) or \
+ if operators.is_comparison(op):
+ return op, BOOLEANTYPE
+ elif isinstance(other_comparator, NullType.Comparator) or \
not operators.is_commutative(op):
return op, self.expr.type
else:
from sqlalchemy.testing import assert_raises_message
from sqlalchemy.sql import column, desc, asc, literal, collate, null, \
true, false, any_, all_
+from sqlalchemy.sql import sqltypes
from sqlalchemy.sql.expression import BinaryExpression, \
ClauseList, Grouping, \
UnaryExpression, select, union, func, tuple_
self._loop_test(operator, right)
+ if operators.is_comparison(operator):
+ is_(
+ left.comparator.operate(operator, right).type,
+ sqltypes.BOOLEANTYPE
+ )
+
def _loop_test(self, operator, *arg):
loop = LoopOperate()
is_(
assert operators.is_comparison(op1)
assert not operators.is_comparison(op2)
+ expr = c.op('$', is_comparison=True)(None)
+ is_(expr.type, sqltypes.BOOLEANTYPE)
+
class TupleTypingTest(fixtures.TestBase):