From df078a6fb010e28cb14afa1f0947add1f60e0e52 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Wed, 7 Apr 2021 21:43:17 -0400 Subject: Infer types in BindParameter when expanding=True Enhanced the "expanding" feature used for :meth:`_sql.ColumnOperators.in_` operations to infer the type of expression from the right hand list of elements, if the left hand side does not have any explicit type set up. This allows the expression to support stringification among other things. In 1.3, "expanding" was not automatically used for :meth:`_sql.ColumnOperators.in_` expressions, so in that sense this change fixes a behavioral regression. Fixes: #6222 Change-Id: Icdfda1e2c226a21896cafd6d8f251547794451c2 --- lib/sqlalchemy/sql/elements.py | 15 +++++++++++++-- lib/sqlalchemy/sql/sqltypes.py | 12 ++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) (limited to 'lib/sqlalchemy/sql') diff --git a/lib/sqlalchemy/sql/elements.py b/lib/sqlalchemy/sql/elements.py index dfa6c0f8f..9e1b69088 100644 --- a/lib/sqlalchemy/sql/elements.py +++ b/lib/sqlalchemy/sql/elements.py @@ -1392,15 +1392,26 @@ class BindParameter(roles.InElementRole, ColumnElement): self.literal_execute = literal_execute if _is_crud: self._is_crud = True + if type_ is None: + if expanding and value: + check_value = value[0] + else: + check_value = value if _compared_to_type is not None: self.type = _compared_to_type.coerce_compared_value( - _compared_to_operator, value + _compared_to_operator, check_value ) else: - self.type = type_api._resolve_value_to_type(value) + self.type = type_api._resolve_value_to_type(check_value) elif isinstance(type_, type): self.type = type_() + elif type_._is_tuple_type: + if expanding and value: + check_value = value[0] + else: + check_value = value + self.type = type_._resolve_values_to_types(check_value) else: self.type = type_ diff --git a/lib/sqlalchemy/sql/sqltypes.py b/lib/sqlalchemy/sql/sqltypes.py index e57a14681..bdfb7d833 100644 --- a/lib/sqlalchemy/sql/sqltypes.py +++ b/lib/sqlalchemy/sql/sqltypes.py @@ -2912,8 +2912,20 @@ class TupleType(TypeEngine): _is_tuple_type = True def __init__(self, *types): + self._fully_typed = NULLTYPE not in types self.types = types + def _resolve_values_to_types(self, value): + if self._fully_typed: + return self + else: + return TupleType( + *[ + _resolve_value_to_type(elem) if typ is NULLTYPE else typ + for typ, elem in zip(self.types, value) + ] + ) + def result_processor(self, dialect, coltype): raise NotImplementedError( "The tuple type does not support being fetched " -- cgit v1.2.1