From: Mike Bayer Date: Sun, 19 Jul 2015 14:00:13 +0000 (-0400) Subject: - Fixed potential issue where a custom subclass X-Git-Tag: rel_1_0_7~7 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=41aead96cdfd581c053a395992e1a3cf0b6a5572;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - Fixed potential issue where a custom subclass of :class:`.FunctionElement` or other column element that incorrectly states 'None' or any other invalid object as the ``.type`` attribute will report this exception instead of recursion overflow. fixes #3485 --- diff --git a/doc/build/changelog/changelog_10.rst b/doc/build/changelog/changelog_10.rst index 48626a5253..c4d9ab4480 100644 --- a/doc/build/changelog/changelog_10.rst +++ b/doc/build/changelog/changelog_10.rst @@ -18,6 +18,15 @@ .. changelog:: :version: 1.0.7 + .. change:: + :tags: bug, sql + :tickets: 3485 + + Fixed potential issue where a custom subclass + of :class:`.FunctionElement` or other column element that incorrectly + states 'None' or any other invalid object as the ``.type`` + attribute will report this exception instead of recursion overflow. + .. change:: :tags: bug, sql :pullreq: github:188 diff --git a/lib/sqlalchemy/sql/elements.py b/lib/sqlalchemy/sql/elements.py index 27ecce2b0b..41dfcf1478 100644 --- a/lib/sqlalchemy/sql/elements.py +++ b/lib/sqlalchemy/sql/elements.py @@ -715,7 +715,14 @@ class ColumnElement(operators.ColumnOperators, ClauseElement): @util.memoized_property def comparator(self): - return self.type.comparator_factory(self) + try: + comparator_factory = self.type.comparator_factory + except AttributeError: + raise TypeError( + "Object %r associated with '.type' attribute " + "is not a TypeEngine class or object" % self.type) + else: + return comparator_factory(self) def __getattr__(self, key): try: diff --git a/test/sql/test_functions.py b/test/sql/test_functions.py index ec8d9b5c0d..ccc9b2dcdb 100644 --- a/test/sql/test_functions.py +++ b/test/sql/test_functions.py @@ -9,12 +9,12 @@ from sqlalchemy.sql.compiler import BIND_TEMPLATES from sqlalchemy.testing.engines import all_dialects from sqlalchemy import types as sqltypes from sqlalchemy.sql import functions -from sqlalchemy.sql.functions import GenericFunction +from sqlalchemy.sql.functions import GenericFunction, FunctionElement import decimal from sqlalchemy import testing from sqlalchemy.testing import fixtures, AssertsCompiledSQL, engines from sqlalchemy.dialects import sqlite, postgresql, mysql, oracle - +from sqlalchemy.testing import assert_raises_message table1 = table('mytable', column('myid', Integer), @@ -477,6 +477,18 @@ class CompileTest(fixtures.TestBase, AssertsCompiledSQL): "AS anon_1 FROM mytable" ) + def test_incorrect_none_type(self): + class MissingType(FunctionElement): + name = 'mt' + type = None + + assert_raises_message( + TypeError, + "Object None associated with '.type' attribute is " + "not a TypeEngine class or object", + MissingType().compile + ) + class ExecuteTest(fixtures.TestBase):