From a4a09a687a2030c5eb30e03151379f91cec74e97 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Sat, 25 Sep 2010 18:38:01 -0400 Subject: [PATCH] - Fixed recursion overflow which could occur when operating with two expressions both of type "NullType", but not the singleton NULLTYPE instance. [ticket:1907] --- CHANGES | 4 ++++ lib/sqlalchemy/types.py | 2 +- test/sql/test_types.py | 39 +++++++++++++++++++++++++-------------- 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/CHANGES b/CHANGES index d714977957..58d95ec541 100644 --- a/CHANGES +++ b/CHANGES @@ -128,6 +128,10 @@ CHANGES which contains a Column that is not yet named. [ticket:1862] + - Fixed recursion overflow which could occur when operating + with two expressions both of type "NullType", but + not the singleton NULLTYPE instance. [ticket:1907] + - declarative - @classproperty (soon/now @mapperproperty) takes effect for __mapper_args__, __table_args__, __tablename__ on diff --git a/lib/sqlalchemy/types.py b/lib/sqlalchemy/types.py index af7ef22e69..46e5901a31 100644 --- a/lib/sqlalchemy/types.py +++ b/lib/sqlalchemy/types.py @@ -639,7 +639,7 @@ class NullType(TypeEngine): __visit_name__ = 'null' def _adapt_expression(self, op, othertype): - if othertype is NULLTYPE or not operators.is_commutative(op): + if isinstance(othertype, NullType) or not operators.is_commutative(op): return op, self else: return othertype._adapt_expression(op, self) diff --git a/test/sql/test_types.py b/test/sql/test_types.py index af460628ea..d7caae6003 100644 --- a/test/sql/test_types.py +++ b/test/sql/test_types.py @@ -738,10 +738,10 @@ class ExpressionTest(TestBase, AssertsExecutionResults, AssertsCompiledSQL): meta.create_all() test_table.insert().execute({ - 'id':1, - 'data':'somedata', - 'atimestamp':datetime.date(2007, 10, 15), - 'avalue':25, 'bvalue':'foo'}) + 'id':1, + 'data':'somedata', + 'atimestamp':datetime.date(2007, 10, 15), + 'avalue':25, 'bvalue':'foo'}) @classmethod def teardown_class(cls): @@ -752,7 +752,8 @@ class ExpressionTest(TestBase, AssertsExecutionResults, AssertsCompiledSQL): eq_( test_table.select().execute().fetchall(), - [(1, 'somedata', datetime.date(2007, 10, 15), 25, "BIND_INfooBIND_OUT")] + [(1, 'somedata', datetime.date(2007, 10, 15), 25, + 'BIND_INfooBIND_OUT')] ) def test_bind_adapt(self): @@ -762,9 +763,9 @@ class ExpressionTest(TestBase, AssertsExecutionResults, AssertsCompiledSQL): eq_( testing.db.execute( - select([test_table.c.id, test_table.c.data, test_table.c.atimestamp]) - .where(expr), - {"thedate":datetime.date(2007, 10, 15)}).fetchall(), + select([test_table.c.id, test_table.c.data, test_table.c.atimestamp]) + .where(expr), + {"thedate":datetime.date(2007, 10, 15)}).fetchall(), [(1, 'somedata', datetime.date(2007, 10, 15))] ) @@ -772,21 +773,25 @@ class ExpressionTest(TestBase, AssertsExecutionResults, AssertsCompiledSQL): eq_(expr.right.type._type_affinity, MyCustomType) eq_( - testing.db.execute(test_table.select().where(expr), {"somevalue":25}).fetchall(), - [(1, 'somedata', datetime.date(2007, 10, 15), 25, 'BIND_INfooBIND_OUT')] + testing.db.execute(test_table.select().where(expr), + {'somevalue': 25}).fetchall(), + [(1, 'somedata', datetime.date(2007, 10, 15), 25, + 'BIND_INfooBIND_OUT')] ) expr = test_table.c.bvalue == bindparam("somevalue") eq_(expr.right.type._type_affinity, String) eq_( - testing.db.execute(test_table.select().where(expr), {"somevalue":"foo"}).fetchall(), - [(1, 'somedata', datetime.date(2007, 10, 15), 25, 'BIND_INfooBIND_OUT')] + testing.db.execute(test_table.select().where(expr), + {"somevalue":"foo"}).fetchall(), + [(1, 'somedata', + datetime.date(2007, 10, 15), 25, 'BIND_INfooBIND_OUT')] ) def test_literal_adapt(self): - # literals get typed based on the types dictionary, unless compatible - # with the left side type + # literals get typed based on the types dictionary, unless + # compatible with the left side type expr = column('foo', String) == 5 eq_(expr.right.type._type_affinity, Integer) @@ -933,7 +938,13 @@ class ExpressionTest(TestBase, AssertsExecutionResults, AssertsCompiledSQL): ) assert isinstance(expr.type, types.Numeric) + def test_null_comparison(self): + eq_( + str(column('a', types.NullType()) + column('b', types.NullType())), + "a + b" + ) + def test_expression_typing(self): expr = column('bar', Integer) - 3 -- 2.47.2