From: Mike Bayer Date: Sat, 6 Oct 2007 16:12:58 +0000 (+0000) Subject: - oracle does not implicitly convert to unicode for non-typed result X-Git-Tag: rel_0_4_0~68 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=29291f4c326086a413064bc8e32acad911a33910;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - oracle does not implicitly convert to unicode for non-typed result sets (i.e. when no TypeEngine/String/Unicode type is even being used; previously it was detecting DBAPI types and converting regardless). should fix [ticket:800] - fixed oracle out_parameters, likely broke in beta6 - fixed oracle _normalize_case for encoded names, gets unicode reflection test to work - a few extra tests tweaked/unsupported for oracle --- diff --git a/CHANGES b/CHANGES index 4c1c8b8d9d..72bcbc56d2 100644 --- a/CHANGES +++ b/CHANGES @@ -37,6 +37,11 @@ CHANGES - null foreign key on a m2o doesn't trigger a lazyload [ticket:803] +- oracle does not implicitly convert to unicode for non-typed result + sets (i.e. when no TypeEngine/String/Unicode type is even being used; + previously it was detecting DBAPI types and converting regardless). + should fix [ticket:800] + 0.4.0beta6 ---------- diff --git a/lib/sqlalchemy/databases/oracle.py b/lib/sqlalchemy/databases/oracle.py index 1a3a0c0344..951f97e38d 100644 --- a/lib/sqlalchemy/databases/oracle.py +++ b/lib/sqlalchemy/databases/oracle.py @@ -203,21 +203,21 @@ class OracleExecutionContext(default.DefaultExecutionContext): super(OracleExecutionContext, self).pre_exec() if self.dialect.auto_setinputsizes: self.set_input_sizes() - if self.compiled_parameters is not None and not isinstance(self.compiled_parameters, list): - for key in self.compiled_parameters: - (bindparam, name, value) = self.compiled_parameters.get_parameter(key) + if self.compiled_parameters is not None and len(self.compiled_parameters) == 1: + for key in self.compiled_parameters[0]: + (bindparam, name, value) = self.compiled_parameters[0].get_parameter(key) if bindparam.isoutparam: dbtype = bindparam.type.dialect_impl(self.dialect).get_dbapi_type(self.dialect.dbapi) if not hasattr(self, 'out_parameters'): self.out_parameters = {} self.out_parameters[name] = self.cursor.var(dbtype) - self.parameters[name] = self.out_parameters[name] + self.parameters[0][name] = self.out_parameters[name] def get_result_proxy(self): if hasattr(self, 'out_parameters'): - if self.compiled_parameters is not None: + if self.compiled_parameters is not None and len(self.compiled_parameters) == 1: for k in self.out_parameters: - type = self.compiled_parameters.get_type(k) + type = self.compiled_parameters[0].get_type(k) self.out_parameters[k] = type.dialect_impl(self.dialect).result_processor(self.dialect)(self.out_parameters[k].getvalue()) else: for k in self.out_parameters: @@ -257,14 +257,13 @@ class OracleDialect(default.DefaultDialect): if self.dbapi is None or not self.auto_convert_lobs: return {} else: + # only use this for LOB objects. using it for strings, dates + # etc. leads to a little too much magic, reflection doesn't know if it should + # expect encoded strings or unicodes, etc. return { - self.dbapi.NUMBER: OracleInteger(), self.dbapi.CLOB: OracleText(), self.dbapi.BLOB: OracleBinary(), - self.dbapi.STRING: OracleString(), - self.dbapi.TIMESTAMP: OracleTimestamp(), self.dbapi.BINARY: OracleRaw(), - datetime.datetime: OracleDate() } def dbapi(cls): @@ -408,18 +407,18 @@ class OracleDialect(default.DefaultDialect): def _normalize_name(self, name): if name is None: return None - elif name.upper() == name and not self.identifier_preparer._requires_quotes(name.lower()): - return name.lower() + elif name.upper() == name and not self.identifier_preparer._requires_quotes(name.lower().decode(self.encoding)): + return name.lower().decode(self.encoding) else: - return name + return name.decode(self.encoding) def _denormalize_name(self, name): if name is None: return None elif name.lower() == name and not self.identifier_preparer._requires_quotes(name.lower()): - return name.upper() + return name.upper().encode(self.encoding) else: - return name + return name.encode(self.encoding) def table_names(self, connection, schema): # note that table_names() isnt loading DBLINKed or synonym'ed tables diff --git a/test/engine/reflection.py b/test/engine/reflection.py index 74984399e3..8ce3c51a10 100644 --- a/test/engine/reflection.py +++ b/test/engine/reflection.py @@ -507,6 +507,7 @@ class ReflectionTest(PersistTest): finally: table.drop() + @testing.unsupported('oracle') def testreserved(self): # check a table that uses an SQL reserved name doesn't cause an error meta = MetaData(testbase.db) @@ -689,7 +690,10 @@ class CreateDropTest(PersistTest): class UnicodeTest(PersistTest): def test_basic(self): try: - bind = engines.utf8_engine() + # the 'convert_unicode' should not get in the way of the reflection + # process. reflecttable for oracle, postgres (others?) expect non-unicode + # strings in result sets/bind params + bind = engines.utf8_engine(options={'convert_unicode':True}) metadata = MetaData(bind) names = set([u'plain', u'Unit\u00e9ble', u'\u6e2c\u8a66']) diff --git a/test/sql/testtypes.py b/test/sql/testtypes.py index 72a696c962..1a6fa7563d 100644 --- a/test/sql/testtypes.py +++ b/test/sql/testtypes.py @@ -264,6 +264,7 @@ class UnicodeTest(AssertMixin): else: self.assert_(not isinstance(x['plain_varchar'], unicode) and x['plain_varchar'] == rawdata) + @testing.unsupported('oracle') def testblanks(self): unicode_table.insert().execute(unicode_varchar=u'') assert select([unicode_table.c.unicode_varchar]).scalar() == u'' @@ -454,9 +455,9 @@ class DateTest(AssertMixin): self.assert_(isinstance(x[0][0], datetime.datetime)) x = testbase.db.text( - "select * from query_users_with_date where user_datetime=:date", - bindparams=[bindparam('date', type_=types.DateTime)]).execute( - date=datetime.datetime(2005, 11, 10, 11, 52, 35)).fetchall() + "select * from query_users_with_date where user_datetime=:somedate", + bindparams=[bindparam('somedate', type_=types.DateTime)]).execute( + somedate=datetime.datetime(2005, 11, 10, 11, 52, 35)).fetchall() print repr(x) def testdate2(self):