.. changelog::
:version: 0.9.2
+ .. change::
+ :tags: bug, sql
+ :tickets: 2927
+
+ Fixed regression whereby the "annotation" system used by the ORM was leaking
+ into the names used by standard functions in :mod:`sqlalchemy.sql.functions`,
+ such as ``func.coalesce()`` and ``func.max()``. Using these functions
+ in ORM attributes and thus producing annotated versions of them could
+ corrupt the actual function name rendered in the SQL.
+
.. change::
:tags: bug, sql
:tickets: 2924, 2848
from . import operators
from .visitors import VisitableType
from .. import util
+from . import annotation
_registry = util.defaultdict(dict)
_compared_to_type=self.type,
unique=True)
-
class _GenericMeta(VisitableType):
def __init__(cls, clsname, bases, clsdict):
- cls.name = name = clsdict.get('name', clsname)
- cls.identifier = identifier = clsdict.get('identifier', name)
- package = clsdict.pop('package', '_default')
- # legacy
- if '__return_type__' in clsdict:
- cls.type = clsdict['__return_type__']
- register_function(identifier, cls, package)
+ if annotation.Annotated not in cls.__mro__:
+ cls.name = name = clsdict.get('name', clsname)
+ cls.identifier = identifier = clsdict.get('identifier', name)
+ package = clsdict.pop('package', '_default')
+ # legacy
+ if '__return_type__' in clsdict:
+ cls.type = clsdict['__return_type__']
+ register_function(identifier, cls, package)
super(_GenericMeta, cls).__init__(clsname, bases, clsdict)
self.type = sqltypes.to_instance(
kwargs.pop("type_", None) or getattr(self, 'type', None))
-
register_function("cast", Cast)
register_function("extract", Extract)
checkparams={"name": "ed"}
)
+ def test_col_prop_builtin_function(self):
+ class Foo(object):
+ pass
+
+ mapper(Foo, self.tables.users, properties={
+ 'foob': column_property(func.coalesce(self.tables.users.c.name))
+ })
+
+ self.assert_compile(
+ select([Foo]).where(Foo.foob == 'somename').order_by(Foo.foob),
+ "SELECT users.id, users.name FROM users "
+ "WHERE coalesce(users.name) = :coalesce_1 ORDER BY coalesce(users.name)"
+ )
+
class GetTest(QueryTest):
def test_get(self):
User = self.classes.User
]:
self.assert_compile(func.random(), ret, dialect=dialect)
+ def test_generic_annotation(self):
+ fn = func.coalesce('x', 'y')._annotate({"foo": "bar"})
+ self.assert_compile(
+ fn, "coalesce(:param_1, :param_2)"
+ )
def test_custom_default_namespace(self):
class myfunc(GenericFunction):
pass