- changed milestone to 0.7.0
boolean literals accepted for BooleanClause in 0.6, not in 0.7
Issue #2117
resolved
This code works on 0.6:
from sqlalchemy import *
t = Table('t', MetaData(), Column('id', Integer, primary_key=True))
and_(t.c.id == 3, False)
(although it compiles with a non-standard capitalized {{{False}}} in SQL)
It fails on 0.7 (current tip of default branch) with:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/gthb/extsvn/sqlalchemy/lib/sqlalchemy/sql/expression.py", line 409, in and_
return BooleanClauseList(operator=operators.and_, *clauses)
File "/Users/gthb/extsvn/sqlalchemy/lib/sqlalchemy/sql/expression.py", line 2919, in __init__
super(BooleanClauseList, self).__init__(*clauses, **kwargs)
File "/Users/gthb/extsvn/sqlalchemy/lib/sqlalchemy/sql/expression.py", line 2848, in __init__
for clause in clauses if clause is not None]
File "/Users/gthb/extsvn/sqlalchemy/lib/sqlalchemy/sql/expression.py", line 1189, in _literal_as_text
"SQL expression object or string expected."
sqlalchemy.exc.ArgumentError: SQL expression object or string expected.
Replacing {{{False}}} with {{{'false'}}} works (and it works in {{{rel_0_6}}} as well).
If it's an intentional change, it is not documented in 07Migration.
Comments (4)
-
repo owner -
repo owner here's test code from shazow. I want to break it into test_constants() and test_constant_coercion().
diff -r 5eee7e2eefb754ce998554993e26f8fa3c8428ee test/sql/test_compiler.py --- a/test/sql/test_compiler.py Fri Apr 08 16:44:15 2011 -0400 +++ b/test/sql/test_compiler.py Fri Apr 08 19:51:41 2011 -0700 @@ -2797,3 +2797,27 @@ "INSERT INTO remote_owner.remotetable (rem_id, datatype_id, value) VALUES " "(:rem_id, :datatype_id, :value)") + +class CoercionTest(fixtures.TestBase, AssertsCompiledSQL): + __dialect__ = 'default' + + def test_boolean(self): + m = MetaData() + foo = Table('foo', m, + Column('id', Integer)) + + self.assert_compile(and_(foo.c.id == 1, False), + "foo.id = :id_1 AND false") + + self.assert_compile(and_(foo.c.id == 1, True), + "foo.id = :id_1 AND true") + + self.assert_compile(and_(foo.c.id == None), + "foo.id IS NULL") + + self.assert_compile(and_(foo.c.id == 1, None), + "foo.id = :id_1 AND NULL") + + self.assert_compile(and_(foo.c.id == 1, null()), + "foo.id = :id_1 AND NULL") +
-
repo owner - changed status to resolved
-
repo owner - removed milestone
Removing milestone: 0.7.0 (automated comment)
- Log in to comment
So one thing to be aware of is that not every database understands the keyword "False", and the capitalized F makes it even less likely. So 0.6's behavior is not exactly a feature.
If the
False
is coerced to a literal, which would be the usual routine here, a database like Oracle, and probably others, would still reject it pretty harshly, i.e.x=3 AND :some_bind
. True/False are more like NULL anyway in that they are in theory constants.So in this case passing
False
would appear to be a sub-case of the "coerce text to SQL" and the patch below can address this. But its still not DB agnostic, even if we used "0" and "1" for those platforms that don't have a constant, it will probably still reject it.