From: Mike Bayer Date: Sun, 17 Jan 2010 21:12:47 +0000 (+0000) Subject: - remove the exclusion of cx_oracle.STRING from setinputsizes by X-Git-Tag: rel_0_6beta1~63 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=8f4871eaf25c2335823a4116d593e6782ff5d743;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - remove the exclusion of cx_oracle.STRING from setinputsizes by configuring cx_oracle.UNICODE on OracleNVarChar. Attempts were made to pass unicode data to/from a plain VARCHAR2 with cx_oracle, both with and without setinputsizes in use, but it doesn't appear to be possible - therefore users will need to use Unicode/UnicodeText with oracle if data contains non-ASCII info. [ticket:1517] - updated the Unicode/UnicodeText docs to reflect this, that convert_unicode might not be enough. - allowed convert_unicode='force' to be significant for bind parameters as well. --- diff --git a/lib/sqlalchemy/dialects/oracle/cx_oracle.py b/lib/sqlalchemy/dialects/oracle/cx_oracle.py index 44344d165b..5a94efccb1 100644 --- a/lib/sqlalchemy/dialects/oracle/cx_oracle.py +++ b/lib/sqlalchemy/dialects/oracle/cx_oracle.py @@ -118,6 +118,8 @@ class _OracleChar(sqltypes.CHAR): return dbapi.FIXED_CHAR class _OracleNVarChar(sqltypes.NVARCHAR): + def get_dbapi_type(self, dbapi): + return dbapi.UNICODE def result_processor(self, dialect, coltype): if dialect._cx_oracle_native_nvarchar: return None @@ -204,7 +206,7 @@ class Oracle_cx_oracleExecutionContext(OracleExecutionContext): del param[fromname] if self.dialect.auto_setinputsizes: - self.set_input_sizes(quoted_bind_names, exclude_types=(self.dialect.dbapi.STRING,)) + self.set_input_sizes(quoted_bind_names) if len(self.compiled_parameters) == 1: for key in self.compiled.binds: diff --git a/lib/sqlalchemy/types.py b/lib/sqlalchemy/types.py index f2e0481314..47cc37c2db 100644 --- a/lib/sqlalchemy/types.py +++ b/lib/sqlalchemy/types.py @@ -478,11 +478,19 @@ class String(Concatenable, TypeEngine): If False, may be overridden by :attr:`sqlalchemy.engine.base.Dialect.convert_unicode`. - If the dialect has been detected as returning unicode - strings from a VARCHAR result column, no unicode translation - will be done on results. To force unicode translation - for individual types regardless of dialect setting, - set convert_unicode='force'. + If the DBAPI in use has been detected to return unicode + strings from a VARCHAR result column, the String object will + assume all subsequent results are already unicode objects, and no + type detection will be done to verify this. The + rationale here is that isinstance() calls are enormously + expensive at the level of column-fetching. To + force the check to occur regardless, set + convert_unicode='force'. + + Similarly, if the dialect is known to accept bind parameters + as unicode objects, no translation from unicode to bytestring + is performed on binds. Again, encoding to a bytestring can be + forced for special circumstances by setting convert_unicode='force'. :param assert_unicode: @@ -523,7 +531,7 @@ class String(Concatenable, TypeEngine): raise exc.InvalidRequestError("Unicode type received non-unicode bind param value %r" % value) else: return value - elif dialect.supports_unicode_binds: + elif dialect.supports_unicode_binds and self.convert_unicode != 'force': return None else: def process(value): @@ -583,7 +591,15 @@ class Unicode(String): ``u'somevalue'``) into encoded bytestrings when passing the value to the database driver, and similarly decodes values from the database back into Python ``unicode`` objects. - + + It's roughly equivalent to using a ``String`` object with + ``convert_unicode=True`` and ``assert_unicode='warn'``, however + the type has other significances in that it implies the usage + of a unicode-capable type being used on the backend, such as NVARCHAR. + This may affect what type is emitted when issuing CREATE TABLE + and also may effect some DBAPI-specific details, such as type + information passed along to ``setinputsizes()``. + When using the ``Unicode`` type, it is only appropriate to pass Python ``unicode`` objects, and not plain ``str``. If a bytestring (``str``) is passed, a runtime warning is issued. If @@ -626,6 +642,9 @@ class UnicodeText(Text): See :class:`Unicode` for details on the unicode behavior of this object. + Like ``Unicode``, usage the ``UnicodeText`` type implies a + unicode-capable type being used on the backend, such as NCLOB. + """ __visit_name__ = 'unicode_text' diff --git a/test/sql/test_types.py b/test/sql/test_types.py index a332dc1bd3..065e272759 100644 --- a/test/sql/test_types.py +++ b/test/sql/test_types.py @@ -308,8 +308,10 @@ class UnicodeTest(TestBase, AssertsExecutionResults): ) x = unicode_table.select().execute().first() - self.assert_(isinstance(x['unicode_varchar'], unicode) and x['unicode_varchar'] == unicodedata) - self.assert_(isinstance(x['unicode_text'], unicode) and x['unicode_text'] == unicodedata) + assert isinstance(x['unicode_varchar'], unicode) + eq_(x['unicode_varchar'], unicodedata) + assert isinstance(x['unicode_text'], unicode) + eq_(x['unicode_text'], unicodedata) def test_union(self): """ensure compiler processing works for UNIONs"""