filter(or_(False)) throws exception

Issue #3490 resolved
Tim Tisdall created an issue

Let's just say upfront that this seems like an extreme edge-case so I'm okay if this ignored...

I'm currently developing a search API and am translating query terms into SQLA filters. I then compile the filters together and make an SQL query. Sometimes elements of the filter are or_'ed together. I found that SQLA was smart enough that when an or_ received a single filter it understood and removed the "OR" component of the query.

So, I could do the following with no issues: filter(or_(*or_filters))

Sometimes I find that I get query terms that should basically cause the whole query to fail so I do that by inserting a False into the filter. Doing a filter(False, ..snip.. ) works fine.

Since those two aspects work, I was surprised when doing filter(or_(False)) gave me an exception.

  File "/sites/metrics_dev/env/lib/python3.4/site-packages/sqlalchemy/sql/elements.py", line 1941, in or_
    return cls._construct(operators.or_, False_, True_, *clauses)
  File "/sites/metrics_dev/env/lib/python3.4/site-packages/sqlalchemy/sql/elements.py", line 1857, in _construct
    return clauses[0].self_group(against=operators._asbool)
AttributeError: 'bool' object has no attribute 'self_group'

This is in SQLA 1.0.6

Comments (5)

  1. Tim Tisdall reporter

    As I said "extreme edge-case"... :)

    What I'm doing is filters(or_(*subfilters)), and that fails only if subfilters == [False].

    I'll try sqlalchemy.false() instead as right now what I'm doing is testing if the length of subfilters is greater than 1 before using the or_.

  2. Mike Bayer repo owner
    • changed milestone to 1.0.7
    • changed component to sql

    we should be able to go with this:

    diff --git a/lib/sqlalchemy/sql/elements.py b/lib/sqlalchemy/sql/elements.py
    index 27ecce2..d3f5a73 100644
    --- a/lib/sqlalchemy/sql/elements.py
    +++ b/lib/sqlalchemy/sql/elements.py
    @@ -1840,9 +1840,12 @@ class BooleanClauseList(ClauseList, ColumnElement):
         def _construct(cls, operator, continue_on, skip_on, *clauses, **kw):
             convert_clauses = []
    
    -        clauses = util.coerce_generator_arg(clauses)
    +        clauses = [
    +            _expression_literal_as_text(clause)
    +            for clause in
    +            util.coerce_generator_arg(clauses)
    +        ]
             for clause in clauses:
    -            clause = _expression_literal_as_text(clause)
    
                 if isinstance(clause, continue_on):
                     continue
    
  3. Log in to comment