summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2013-04-22 19:13:00 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2013-04-22 19:13:00 -0400
commit600b4bc1a2ac093af5797ecd8717bbc038f1e5c1 (patch)
treeed8a37934eb00d4c01bfeec117ea7b1bb980db68
parentb6c523d25550cfa01cbe7e9dd24dd1179a32eae8 (diff)
parent5884c2e7e5b46cee29b90aa3f7161e7380e3e2a5 (diff)
downloadsqlalchemy-600b4bc1a2ac093af5797ecd8717bbc038f1e5c1.tar.gz
merge default
-rw-r--r--doc/build/changelog/changelog_08.rst12
-rw-r--r--lib/sqlalchemy/sql/expression.py46
-rw-r--r--test/sql/test_operators.py29
3 files changed, 74 insertions, 13 deletions
diff --git a/doc/build/changelog/changelog_08.rst b/doc/build/changelog/changelog_08.rst
index 489cad582..1f8998452 100644
--- a/doc/build/changelog/changelog_08.rst
+++ b/doc/build/changelog/changelog_08.rst
@@ -7,6 +7,18 @@
:version: 0.8.1
.. change::
+ :tags: bug, sql, mysql
+ :tickets: 2682
+
+ Fully implemented the IS and IS NOT operators with
+ regards to the True/False constants. An expression like
+ ``col.is_(True)`` will now render ``col IS true``
+ on the target platform, rather than converting the True/
+ False constant to an integer bound parameter.
+ This allows the ``is_()`` operator to work on MySQL when
+ given True/False constants.
+
+ .. change::
:tags: bug, postgresql
:tickets: 2681
diff --git a/lib/sqlalchemy/sql/expression.py b/lib/sqlalchemy/sql/expression.py
index 28b1c6ddd..d2e644ce2 100644
--- a/lib/sqlalchemy/sql/expression.py
+++ b/lib/sqlalchemy/sql/expression.py
@@ -1591,7 +1591,9 @@ def _interpret_as_from(element):
def _const_expr(element):
- if element is None:
+ if isinstance(element, (Null, False_, True_)):
+ return element
+ elif element is None:
return null()
elif element is False:
return false()
@@ -2011,18 +2013,33 @@ class _DefaultColumnComparator(operators.ColumnOperators):
return op, other_comparator.type
def _boolean_compare(self, expr, op, obj, negate=None, reverse=False,
- **kwargs
- ):
- if obj is None or isinstance(obj, Null):
- if op in (operators.eq, operators.is_):
- return BinaryExpression(expr, null(), operators.is_,
- negate=operators.isnot)
- elif op in (operators.ne, operators.isnot):
- return BinaryExpression(expr, null(), operators.isnot,
- negate=operators.is_)
+ **kwargs):
+ if isinstance(obj, (util.NoneType, bool, Null, True_, False_)):
+
+ # allow x ==/!= True/False to be treated as a literal.
+ # this comes out to "== / != true/false" or "1/0" if those
+ # constants aren't supported and works on all platforms
+ if op in (operators.eq, operators.ne) and \
+ isinstance(obj, (bool, True_, False_)):
+ return BinaryExpression(expr,
+ obj,
+ op,
+ type_=sqltypes.BOOLEANTYPE,
+ negate=negate, modifiers=kwargs)
else:
- raise exc.ArgumentError("Only '='/'!=' operators can "
- "be used with NULL")
+ # all other None/True/False uses IS, IS NOT
+ if op in (operators.eq, operators.is_):
+ return BinaryExpression(expr, _const_expr(obj),
+ operators.is_,
+ negate=operators.isnot)
+ elif op in (operators.ne, operators.isnot):
+ return BinaryExpression(expr, _const_expr(obj),
+ operators.isnot,
+ negate=operators.is_)
+ else:
+ raise exc.ArgumentError(
+ "Only '=', '!=', 'is_()', 'isnot()' operators can "
+ "be used with None/True/False")
else:
obj = self._check_literal(expr, op, obj)
@@ -3253,6 +3270,8 @@ class False_(ColumnElement):
def __init__(self):
self.type = sqltypes.BOOLEANTYPE
+ def compare(self, other):
+ return isinstance(other, False_)
class True_(ColumnElement):
"""Represent the ``true`` keyword in a SQL statement.
@@ -3266,6 +3285,9 @@ class True_(ColumnElement):
def __init__(self):
self.type = sqltypes.BOOLEANTYPE
+ def compare(self, other):
+ return isinstance(other, True_)
+
class ClauseList(ClauseElement):
"""Describe a list of clauses, separated by an operator.
diff --git a/test/sql/test_operators.py b/test/sql/test_operators.py
index 7215ae565..d1db733e0 100644
--- a/test/sql/test_operators.py
+++ b/test/sql/test_operators.py
@@ -1,7 +1,7 @@
from sqlalchemy.testing import fixtures, eq_, is_
from sqlalchemy import testing
from sqlalchemy.testing import assert_raises_message
-from sqlalchemy.sql import column, desc, asc, literal, collate
+from sqlalchemy.sql import column, desc, asc, literal, collate, null, true, false
from sqlalchemy.sql.expression import BinaryExpression, \
ClauseList, Grouping, \
UnaryExpression, select, union, func, tuple_
@@ -66,6 +66,33 @@ class DefaultColumnComparatorTest(fixtures.TestBase):
def test_isnot_null(self):
self._do_operate_test(operators.isnot, None)
+ def test_is_null_const(self):
+ self._do_operate_test(operators.is_, null())
+
+ def test_is_true_const(self):
+ self._do_operate_test(operators.is_, true())
+
+ def test_is_false_const(self):
+ self._do_operate_test(operators.is_, false())
+
+ def test_equals_true(self):
+ self._do_operate_test(operators.eq, True)
+
+ def test_notequals_true(self):
+ self._do_operate_test(operators.ne, True)
+
+ def test_is_true(self):
+ self._do_operate_test(operators.is_, True)
+
+ def test_isnot_true(self):
+ self._do_operate_test(operators.isnot, True)
+
+ def test_is_false(self):
+ self._do_operate_test(operators.is_, False)
+
+ def test_isnot_false(self):
+ self._do_operate_test(operators.isnot, False)
+
def test_like(self):
self._do_operate_test(operators.like_op)