diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2018-10-03 10:40:38 -0400 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2018-10-03 10:40:38 -0400 |
| commit | aa2128427064a2bdeaeff5dc946ecbb3727c90aa (patch) | |
| tree | 62e207bb41e8569727153c144f4d650d4981d02c /lib/sqlalchemy/sql | |
| parent | ffd27cef48241e39725c4e9cd13fd744a2806bdd (diff) | |
| download | sqlalchemy-aa2128427064a2bdeaeff5dc946ecbb3727c90aa.tar.gz | |
Support tuples of heterogeneous types for empty expanding IN
Pass a list of all the types for the left side of an
IN expression to the visit_empty_set_expr() method, so that
the "empty expanding IN" can produce clauses for each element.
Fixes: #4271
Change-Id: I2738b9df2292ac01afda37f16d4fa56ae7bf9147
Diffstat (limited to 'lib/sqlalchemy/sql')
| -rw-r--r-- | lib/sqlalchemy/sql/compiler.py | 2 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/default_comparator.py | 11 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/elements.py | 10 |
3 files changed, 21 insertions, 2 deletions
diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py index 2f68b7e2e..27ee4afc6 100644 --- a/lib/sqlalchemy/sql/compiler.py +++ b/lib/sqlalchemy/sql/compiler.py @@ -1056,7 +1056,7 @@ class SQLCompiler(Compiled): self._emit_empty_in_warning() return self.process(binary.left == binary.left) - def visit_empty_set_expr(self, type_): + def visit_empty_set_expr(self, element_types): raise NotImplementedError( "Dialect '%s' does not support empty set expression." % self.dialect.name diff --git a/lib/sqlalchemy/sql/default_comparator.py b/lib/sqlalchemy/sql/default_comparator.py index 5d02f65a1..8149f9731 100644 --- a/lib/sqlalchemy/sql/default_comparator.py +++ b/lib/sqlalchemy/sql/default_comparator.py @@ -15,7 +15,8 @@ from .elements import BindParameter, True_, False_, BinaryExpression, \ Null, _const_expr, _clause_element_as_expr, \ ClauseList, ColumnElement, TextClause, UnaryExpression, \ collate, _is_literal, _literal_as_text, ClauseElement, and_, or_, \ - Slice, Visitable, _literal_as_binds, CollectionAggregate + Slice, Visitable, _literal_as_binds, CollectionAggregate, \ + Tuple from .selectable import SelectBase, Alias, Selectable, ScalarSelect @@ -145,6 +146,14 @@ def _in_impl(expr, op, seq_or_selectable, negate_op, **kw): elif isinstance(seq_or_selectable, ClauseElement): if isinstance(seq_or_selectable, BindParameter) and \ seq_or_selectable.expanding: + + if isinstance(expr, Tuple): + seq_or_selectable = ( + seq_or_selectable._with_expanding_in_types( + [elem.type for elem in expr] + ) + ) + return _boolean_compare( expr, op, seq_or_selectable, diff --git a/lib/sqlalchemy/sql/elements.py b/lib/sqlalchemy/sql/elements.py index dd16b6862..de3b7992a 100644 --- a/lib/sqlalchemy/sql/elements.py +++ b/lib/sqlalchemy/sql/elements.py @@ -865,6 +865,7 @@ class BindParameter(ColumnElement): __visit_name__ = 'bindparam' _is_crud = False + _expanding_in_types = () def __init__(self, key, value=NO_ARG, type_=None, unique=False, required=NO_ARG, @@ -1134,6 +1135,15 @@ class BindParameter(ColumnElement): else: self.type = type_ + def _with_expanding_in_types(self, types): + """Return a copy of this :class:`.BindParameter` in + the context of an expanding IN against a tuple. + + """ + cloned = self._clone() + cloned._expanding_in_types = types + return cloned + def _with_value(self, value): """Return a copy of this :class:`.BindParameter` with the given value set. |
