summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2015-07-19 10:00:13 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2015-07-19 10:00:13 -0400
commit41aead96cdfd581c053a395992e1a3cf0b6a5572 (patch)
treefceafc25ac4ae48d181f5d34a45d5b49149e381e
parent18a078654da286c0adf51a20a21398e357ed12ed (diff)
downloadsqlalchemy-41aead96cdfd581c053a395992e1a3cf0b6a5572.tar.gz
- 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
-rw-r--r--doc/build/changelog/changelog_10.rst9
-rw-r--r--lib/sqlalchemy/sql/elements.py9
-rw-r--r--test/sql/test_functions.py16
3 files changed, 31 insertions, 3 deletions
diff --git a/doc/build/changelog/changelog_10.rst b/doc/build/changelog/changelog_10.rst
index 48626a525..c4d9ab448 100644
--- a/doc/build/changelog/changelog_10.rst
+++ b/doc/build/changelog/changelog_10.rst
@@ -20,6 +20,15 @@
.. 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
Fixed bug where the modulus SQL operator wouldn't work in reverse
diff --git a/lib/sqlalchemy/sql/elements.py b/lib/sqlalchemy/sql/elements.py
index 27ecce2b0..41dfcf147 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 ec8d9b5c0..ccc9b2dcd 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):