summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/sql/compiler.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2021-11-05 10:18:42 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2021-11-05 11:55:24 -0400
commit9ee47d90d804dc815685d42913ad170e04c38659 (patch)
tree5d89c1ac21811b11d404b8a23c01bca545e10eda /lib/sqlalchemy/sql/compiler.py
parent7166159bffc30f3dbb3da8495cc5756c29b9a457 (diff)
downloadsqlalchemy-9ee47d90d804dc815685d42913ad170e04c38659.tar.gz
use tuple expansion if type._is_tuple, test for Sequence if no type
Fixed regression where the row objects returned for ORM queries, which are now the normal :class:`_sql.Row` objects, would not be interpreted by the :meth:`_sql.ColumnOperators.in_` operator as tuple values to be broken out into individual bound parameters, and would instead pass them as single values to the driver leading to failures. The change to the "expanding IN" system now accommodates for the expression already being of type :class:`.TupleType` and treats values accordingly if so. In the uncommon case of using "tuple-in" with an untyped statement such as a textual statement with no typing information, a tuple value is detected for values that implement ``collections.abc.Sequence``, but that are not ``str`` or ``bytes``, as always when testing for ``Sequence``. Added :class:`.TupleType` to the top level ``sqlalchemy`` import namespace. Fixes: #7292 Change-Id: I8286387e3b3c3752b3bd4ae3560d4f31172acc22 (cherry picked from commit 0c44a1e77cfde0f841a4a64140314c6b833efdab)
Diffstat (limited to 'lib/sqlalchemy/sql/compiler.py')
-rw-r--r--lib/sqlalchemy/sql/compiler.py21
1 files changed, 15 insertions, 6 deletions
diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py
index 266452851..7db8d6b5d 100644
--- a/lib/sqlalchemy/sql/compiler.py
+++ b/lib/sqlalchemy/sql/compiler.py
@@ -2025,8 +2025,14 @@ class SQLCompiler(Compiled):
[parameter.type], parameter.expand_op
)
- elif isinstance(values[0], (tuple, list)):
- assert typ_dialect_impl._is_tuple_type
+ elif typ_dialect_impl._is_tuple_type or (
+ typ_dialect_impl._isnull
+ and isinstance(values[0], util.collections_abc.Sequence)
+ and not isinstance(
+ values[0], util.string_types + util.binary_types
+ )
+ ):
+
replacement_expression = (
"VALUES " if self.dialect.tuple_in_values else ""
) + ", ".join(
@@ -2042,7 +2048,6 @@ class SQLCompiler(Compiled):
for i, tuple_element in enumerate(values)
)
else:
- assert not typ_dialect_impl._is_tuple_type
replacement_expression = ", ".join(
self.render_literal_value(value, parameter.type)
for value in values
@@ -2071,10 +2076,14 @@ class SQLCompiler(Compiled):
[parameter.type], parameter.expand_op
)
- elif (
- isinstance(values[0], (tuple, list))
- and not typ_dialect_impl._is_array
+ elif typ_dialect_impl._is_tuple_type or (
+ typ_dialect_impl._isnull
+ and isinstance(values[0], util.collections_abc.Sequence)
+ and not isinstance(
+ values[0], util.string_types + util.binary_types
+ )
):
+ assert not typ_dialect_impl._is_array
to_update = [
("%s_%s_%s" % (name, i, j), value)
for i, tuple_element in enumerate(values, 1)