summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/sql
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2018-08-07 18:59:05 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2018-08-08 17:29:32 -0400
commitf03c7918796e1080d971a9c03943962478be4caf (patch)
tree1fc625022979151be27a9a3403726a4d2179f44d /lib/sqlalchemy/sql
parentb17fa2513e412b8f9aa1f62c0acc7fa3805e632b (diff)
downloadsqlalchemy-f03c7918796e1080d971a9c03943962478be4caf.tar.gz
Fixed issue with :meth:`.TypeEngine.bind_expression` and
:meth:`.TypeEngine.column_expression` methods where these methods would not work if the target type were part of a :class:`.Variant`, or other target type of a :class:`.TypeDecorator`. Additionally, the SQL compiler now calls upon the dialect-level implementation when it renders these methods so that dialects can now provide for SQL-level processing for built-in types. Change-Id: Ic7b39575184db582e628e6ecee48dcda7d03a817 Fixes: #3981
Diffstat (limited to 'lib/sqlalchemy/sql')
-rw-r--r--lib/sqlalchemy/sql/compiler.py23
-rw-r--r--lib/sqlalchemy/sql/type_api.py29
2 files changed, 43 insertions, 9 deletions
diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py
index 57da43217..5fbc7d87f 100644
--- a/lib/sqlalchemy/sql/compiler.py
+++ b/lib/sqlalchemy/sql/compiler.py
@@ -1237,10 +1237,17 @@ class SQLCompiler(Compiled):
literal_binds=False,
skip_bind_expression=False,
**kwargs):
- if not skip_bind_expression and bindparam.type._has_bind_expression:
- bind_expression = bindparam.type.bind_expression(bindparam)
- return self.process(bind_expression,
- skip_bind_expression=True)
+
+ if not skip_bind_expression:
+ impl = bindparam.type.dialect_impl(self.dialect)
+ if impl._has_bind_expression:
+ bind_expression = impl.bind_expression(bindparam)
+ return self.process(
+ bind_expression, skip_bind_expression=True,
+ within_columns_clause=within_columns_clause,
+ literal_binds=literal_binds,
+ **kwargs
+ )
if literal_binds or \
(within_columns_clause and
@@ -1510,10 +1517,12 @@ class SQLCompiler(Compiled):
within_columns_clause=True):
"""produce labeled columns present in a select()."""
- if column.type._has_column_expression and \
+ impl = column.type.dialect_impl(self.dialect)
+ if impl._has_column_expression and \
populate_result_map:
- col_expr = column.type.column_expression(column)
- add_to_result_map = lambda keyname, name, objects, type_: \
+ col_expr = impl.column_expression(column)
+
+ def add_to_result_map(keyname, name, objects, type_):
self._add_to_result_map(
keyname, name,
(column,) + objects, type_)
diff --git a/lib/sqlalchemy/sql/type_api.py b/lib/sqlalchemy/sql/type_api.py
index 6a323683b..a8dfa19be 100644
--- a/lib/sqlalchemy/sql/type_api.py
+++ b/lib/sqlalchemy/sql/type_api.py
@@ -1239,6 +1239,33 @@ class TypeDecorator(SchemaEventTarget, TypeEngine):
else:
return self.impl.result_processor(dialect, coltype)
+ @util.memoized_property
+ def _has_bind_expression(self):
+ return (
+ self.__class__.bind_expression.__code__
+ is not TypeDecorator.bind_expression.__code__
+ ) or self.impl._has_bind_expression
+
+ def bind_expression(self, bindparam):
+ return self.impl.bind_expression(bindparam)
+
+ @util.memoized_property
+ def _has_column_expression(self):
+ """memoized boolean, check if column_expression is implemented.
+
+ Allows the method to be skipped for the vast majority of expression
+ types that don't use this feature.
+
+ """
+
+ return (
+ self.__class__.column_expression.__code__
+ is not TypeDecorator.column_expression.__code__
+ ) or self.impl._has_column_expression
+
+ def column_expression(self, column):
+ return self.impl.column_expression(column)
+
def coerce_compared_value(self, op, value):
"""Suggest a type for a 'coerced' Python value in an expression.
@@ -1299,8 +1326,6 @@ class TypeDecorator(SchemaEventTarget, TypeEngine):
return util.generic_repr(self, to_inspect=self.impl)
-
-
class Variant(TypeDecorator):
"""A wrapping type that selects among a variety of
implementations based on dialect in use.