From: Mike Bayer Date: Mon, 1 Mar 2010 01:00:12 +0000 (+0000) Subject: - adjusted the literal coercion rules to take the left side's type into account,... X-Git-Tag: rel_0_6beta2~87 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=da1666cc18cebc485563332d2f1c3d3818affc1f;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - adjusted the literal coercion rules to take the left side's type into account, if it is compatible with what was found for the right, so that things like oracle CHAR conversions work. - oracle dialect specific tests pass again. --- diff --git a/CHANGES b/CHANGES index d7695c40f1..3a1376b328 100644 --- a/CHANGES +++ b/CHANGES @@ -151,8 +151,10 @@ CHANGES "literal" is first derived from the Python type of the literal, assuming standard native Python types + date types, before falling back to that of the known type - on the other side of the expression. Also part - of [ticket:1683]. + on the other side of the expression. If the + "fallback" type is compatible (i.e. CHAR from String), + the literal side will use that. Also part of + [ticket:1683]. - Made sqlalchemy.sql.expressions.Executable part of public API, used for any expression construct that can be sent to diff --git a/lib/sqlalchemy/sql/expression.py b/lib/sqlalchemy/sql/expression.py index f3a1562c55..1c3961f1f7 100644 --- a/lib/sqlalchemy/sql/expression.py +++ b/lib/sqlalchemy/sql/expression.py @@ -2155,6 +2155,8 @@ class _BindParamClause(ColumnElement): if type_ is None: self.type = sqltypes.type_map.get(type(value), _fallback_type or sqltypes.NULLTYPE) + if _fallback_type and _fallback_type._type_affinity == self.type._type_affinity: + self.type = _fallback_type elif isinstance(type_, type): self.type = type_() else: diff --git a/lib/sqlalchemy/types.py b/lib/sqlalchemy/types.py index 7f1e38003e..cdbf7927ef 100644 --- a/lib/sqlalchemy/types.py +++ b/lib/sqlalchemy/types.py @@ -704,7 +704,8 @@ class Unicode(String): """ kwargs.setdefault('convert_unicode', True) - super(Unicode, self).__init__(length=length, _warn_on_bytestring=True, **kwargs) + kwargs.setdefault('_warn_on_bytestring', True) + super(Unicode, self).__init__(length=length, **kwargs) class UnicodeText(Text): """An unbounded-length Unicode string. @@ -732,7 +733,8 @@ class UnicodeText(Text): """ kwargs.setdefault('convert_unicode', True) - super(UnicodeText, self).__init__(length=length, _warn_on_bytestring=True, **kwargs) + kwargs.setdefault('_warn_on_bytestring', True) + super(UnicodeText, self).__init__(length=length, **kwargs) class Integer(_DateAffinity, TypeEngine): @@ -838,7 +840,10 @@ class Numeric(_DateAffinity, TypeEngine): # try: # from fastdec import mpd as Decimal # except ImportError: - return processors.to_decimal_processor_factory(_python_Decimal, self.scale) + if self.scale is not None: + return processors.to_decimal_processor_factory(_python_Decimal, self.scale) + else: + return processors.to_decimal_processor_factory(_python_Decimal) else: return None diff --git a/test/sql/test_types.py b/test/sql/test_types.py index 29b337eda5..3ac8baf004 100644 --- a/test/sql/test_types.py +++ b/test/sql/test_types.py @@ -4,7 +4,7 @@ import decimal import datetime, os, re from sqlalchemy import * from sqlalchemy import exc, types, util, schema -from sqlalchemy.sql import operators +from sqlalchemy.sql import operators, column from sqlalchemy.test.testing import eq_ import sqlalchemy.engine.url as url from sqlalchemy.databases import * @@ -734,8 +734,9 @@ class ExpressionTest(TestBase, AssertsExecutionResults): ) def test_bind_adapt(self): + # test an untyped bind gets the left side's type expr = test_table.c.atimestamp == bindparam("thedate") - assert expr.right.type.__class__ == test_table.c.atimestamp.type.__class__ + eq_(expr.right.type._type_affinity, Date) eq_( testing.db.execute( @@ -745,13 +746,31 @@ class ExpressionTest(TestBase, AssertsExecutionResults): ) expr = test_table.c.avalue == bindparam("somevalue") - eq_(expr.right.type.__class__, test_table.c.avalue.type.__class__) + 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)] ) + + def test_literal_adapt(self): + # 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) + + expr = column('foo', String) == "asdf" + eq_(expr.right.type._type_affinity, String) + + expr = column('foo', CHAR) == 5 + eq_(expr.right.type._type_affinity, Integer) + expr = column('foo', CHAR) == "asdf" + eq_(expr.right.type.__class__, CHAR) + + + @testing.fails_on('firebird', 'Data type unknown on the parameter') def test_operator_adapt(self): """test type-based overloading of operators"""