diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2007-06-25 17:07:25 +0000 | 
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2007-06-25 17:07:25 +0000 | 
| commit | bc58df9c1f1f443b67a3312463df2c9425531503 (patch) | |
| tree | 51f4354e740700f911ba917cdd6c23818bac97bb /lib/sqlalchemy/sql.py | |
| parent | f9dc30f239d1aa13771f0e152af691a8ae56514b (diff) | |
| download | sqlalchemy-bc58df9c1f1f443b67a3312463df2c9425531503.tar.gz | |
- fixed precedence of operators so that parenthesis are correctly applied
[ticket:620]
- calling <column>.in_() (i.e. with no arguments) will return
"CASE WHEN (<column> IS NULL) THEN NULL ELSE 0 END = 1)", so that
NULL or False is returned in all cases, rather than throwing an error
[ticket:545]
Diffstat (limited to 'lib/sqlalchemy/sql.py')
| -rw-r--r-- | lib/sqlalchemy/sql.py | 54 | 
1 files changed, 38 insertions, 16 deletions
diff --git a/lib/sqlalchemy/sql.py b/lib/sqlalchemy/sql.py index 5ceb9bdea..9bea33946 100644 --- a/lib/sqlalchemy/sql.py +++ b/lib/sqlalchemy/sql.py @@ -40,22 +40,37 @@ __all__ = ['AbstractDialect', 'Alias', 'ClauseElement', 'ClauseParameters',             'subquery', 'table', 'text', 'union', 'union_all', 'update',]  # precedence ordering for common operators.  if an operator is not present in this list, -# its precedence is assumed to be '0' which will cause it to be parenthesized when grouped against other operators +# it will be parenthesized when grouped against other operators  PRECEDENCE = {      'FROM':15, -    'AS':15, -    'NOT':10, +    '*':7, +    '/':7, +	'%':7, +    '+':6, +    '-':6, +    'ILIKE':5, +    'NOT ILIKE':5, +    'LIKE':5, +    'NOT LIKE':5, +    'IN':5, +    'NOT IN':5, +    'IS':5, +    'IS NOT':5, +    '=':5, +    '!=':5, +    '>':5, +    '<':5, +    '>=':5, +    '<=':5, +    'NOT':4,      'AND':3, -    'OR':3, -    '=':7, -    '!=':7, -    '>':7, -    '<':7, -    '+':5, -    '-':5, -    '*':5, -    '/':5, -    ',':0 +    'OR':2, +    ',':-1, +    'AS':-1, +    'EXISTS':0, +    'BETWEEN':0, +    '_smallest': -1000, +    '_largest': 1000  }  def desc(column): @@ -1286,7 +1301,7 @@ class _CompareMixin(object):      def in_(self, *other):          """produce an ``IN`` clause."""          if len(other) == 0: -            return self.__eq__(None) +            return _Grouping(case([(self.__eq__(None), text('NULL'))], else_=text('0')).__eq__(text('1')))          elif len(other) == 1:              o = other[0]              if _is_literal(o) or isinstance( o, _CompareMixin): @@ -1965,7 +1980,7 @@ class ClauseList(ClauseElement):          return f      def self_group(self, against=None): -        if PRECEDENCE.get(self.operator, 0) <= PRECEDENCE.get(against, 0): +        if self.operator != against and PRECEDENCE.get(self.operator, PRECEDENCE['_smallest']) <= PRECEDENCE.get(against, PRECEDENCE['_largest']):              return _Grouping(self)          else:              return self @@ -2122,6 +2137,12 @@ class _UnaryExpression(ColumnElement):              return _UnaryExpression(self.element, operator=self.negate, negate=self.operator, modifier=self.modifier, type=self.type)          else:              return super(_UnaryExpression, self)._negate() +     +    def self_group(self, against): +        if self.operator and PRECEDENCE.get(self.operator, PRECEDENCE['_smallest']) <= PRECEDENCE.get(against, PRECEDENCE['_largest']): +            return _Grouping(self) +        else: +            return self  class _BinaryExpression(ColumnElement): @@ -2155,7 +2176,8 @@ class _BinaryExpression(ColumnElement):          )      def self_group(self, against=None): -        if PRECEDENCE.get(self.operator, 0) <= PRECEDENCE.get(against, 0): +        # use small/large defaults for comparison so that unknown operators are always parenthesized +        if self.operator != against and (PRECEDENCE.get(self.operator, PRECEDENCE['_smallest']) <= PRECEDENCE.get(against, PRECEDENCE['_largest'])):              return _Grouping(self)          else:              return self  | 
