summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2010-03-12 21:05:53 +0000
committerMike Bayer <mike_mp@zzzcomputing.com>2010-03-12 21:05:53 +0000
commit022e8124ca6e1d032b7ac370692a0c7027aa8bdc (patch)
treec39b52ec634b6516284ff815e18f638b488c31a9 /lib
parent1b169548642b4ced5b25510d35fdd28af0c06c7e (diff)
downloadsqlalchemy-022e8124ca6e1d032b7ac370692a0c7027aa8bdc.tar.gz
- Added preliminary support for Oracle's WITH_UNICODE
mode. At the very least this establishes initial support for cx_Oracle with Python 3. [ticket:1670]
Diffstat (limited to 'lib')
-rw-r--r--lib/sqlalchemy/dialects/oracle/base.py29
-rw-r--r--lib/sqlalchemy/dialects/oracle/cx_oracle.py45
-rw-r--r--lib/sqlalchemy/engine/default.py10
-rw-r--r--lib/sqlalchemy/test/config.py1
4 files changed, 67 insertions, 18 deletions
diff --git a/lib/sqlalchemy/dialects/oracle/base.py b/lib/sqlalchemy/dialects/oracle/base.py
index 3107c8b6c..ffadc84f8 100644
--- a/lib/sqlalchemy/dialects/oracle/base.py
+++ b/lib/sqlalchemy/dialects/oracle/base.py
@@ -590,22 +590,31 @@ 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().decode(self.encoding))):
- return name.lower().decode(self.encoding)
+ # Py2K
+ if isinstance(name, str):
+ name = name.decode(self.encoding)
+ # end Py2K
+ if name.upper() == name and \
+ not self.identifier_preparer._requires_quotes(name.lower()):
+ return name.lower()
else:
- return name.decode(self.encoding)
+ return name
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().encode(self.encoding)
+ name = name.upper()
+ # Py2K
+ if not self.supports_unicode_binds:
+ name = name.encode(self.encoding)
else:
- return name.encode(self.encoding)
+ name = unicode(name)
+ # end Py2K
+ return name
def _get_default_schema_name(self, connection):
- return self.normalize_name(connection.execute('SELECT USER FROM DUAL').scalar())
+ return self.normalize_name(connection.execute(u'SELECT USER FROM DUAL').scalar())
def table_names(self, connection, schema):
# note that table_names() isnt loading DBLINKed or synonym'ed tables
@@ -664,7 +673,11 @@ class OracleDialect(default.DefaultDialect):
resolve_synonyms=False, dblink='', **kw):
if resolve_synonyms:
- actual_name, owner, dblink, synonym = self._resolve_synonym(connection, desired_owner=self.denormalize_name(schema), desired_synonym=self.denormalize_name(table_name))
+ actual_name, owner, dblink, synonym = self._resolve_synonym(
+ connection,
+ desired_owner=self.denormalize_name(schema),
+ desired_synonym=self.denormalize_name(table_name)
+ )
else:
actual_name, owner, dblink, synonym = None, None, None, None
if not actual_name:
diff --git a/lib/sqlalchemy/dialects/oracle/cx_oracle.py b/lib/sqlalchemy/dialects/oracle/cx_oracle.py
index f4c2e295f..c5e24cbb3 100644
--- a/lib/sqlalchemy/dialects/oracle/cx_oracle.py
+++ b/lib/sqlalchemy/dialects/oracle/cx_oracle.py
@@ -119,7 +119,9 @@ class _NativeUnicodeMixin(object):
def result_processor(self, dialect, coltype):
# if we know cx_Oracle will return unicode,
# don't process results
- if self.convert_unicode != 'force' and \
+ if dialect._cx_oracle_with_unicode:
+ return None
+ elif self.convert_unicode != 'force' and \
dialect._cx_oracle_native_nvarchar and \
coltype == dialect.dbapi.UNICODE:
return None
@@ -227,9 +229,8 @@ class Oracle_cx_oracleExecutionContext(OracleExecutionContext):
# on String, including that outparams/RETURNING
# breaks for varchars
self.set_input_sizes(quoted_bind_names,
- exclude_types=[
- self.dialect.dbapi.STRING,
- self.dialect.dbapi.UNICODE])
+ exclude_types=self.dialect._cx_oracle_string_types
+ )
if len(self.compiled_parameters) == 1:
for key in self.compiled.binds:
@@ -266,7 +267,7 @@ class Oracle_cx_oracleExecutionContext(OracleExecutionContext):
if self.cursor.description is not None:
for column in self.cursor.description:
type_code = column[1]
- if type_code in self.dialect.ORACLE_BINARY_TYPES:
+ if type_code in self.dialect._cx_oracle_binary_types:
result = base.BufferedColumnResultProxy(self)
if result is None:
@@ -347,10 +348,26 @@ class Oracle_cx_oracle(OracleDialect):
cx_oracle_ver = vers(self.dbapi.version)
self.supports_unicode_binds = cx_oracle_ver >= (5, 0)
self._cx_oracle_native_nvarchar = cx_oracle_ver >= (5, 0)
-
- if self.dbapi is None or not self.auto_convert_lobs or not 'CLOB' in self.dbapi.__dict__:
+
+ if self.dbapi is not None and not hasattr(self.dbapi, 'UNICODE'):
+ # cx_Oracle WITH_UNICODE mode. *only* python
+ # unicode objects accepted for anything
+ self._cx_oracle_string_types = set([self.dbapi.STRING])
+ self.supports_unicode_statements = True
+ self.supports_unicode_binds = True
+ self._cx_oracle_with_unicode = True
+ else:
+ self._cx_oracle_with_unicode = False
+ if self.dbapi is not None:
+ self._cx_oracle_string_types = set([self.dbapi.UNICODE, self.dbapi.STRING])
+ else:
+ self._cx_oracle_string_types = set()
+
+ if self.dbapi is None or \
+ not self.auto_convert_lobs or \
+ not hasattr(self.dbapi, 'CLOB'):
self.dbapi_type_map = {}
- self.ORACLE_BINARY_TYPES = []
+ self._cx_oracle_binary_types = set()
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
@@ -361,7 +378,9 @@ class Oracle_cx_oracle(OracleDialect):
self.dbapi.BLOB: oracle.BLOB(),
self.dbapi.BINARY: oracle.RAW(),
}
- self.ORACLE_BINARY_TYPES = [getattr(self.dbapi, k) for k in ["BFILE", "CLOB", "NCLOB", "BLOB"] if hasattr(self.dbapi, k)]
+ self._cx_oracle_binary_types = set([getattr(self.dbapi, k) for k in
+ ["BFILE", "CLOB", "NCLOB", "BLOB"]
+ if hasattr(self.dbapi, k)])
@classmethod
def dbapi(cls):
@@ -395,6 +414,14 @@ class Oracle_cx_oracle(OracleDialect):
threaded=self.threaded,
twophase=self.allow_twophase,
)
+
+ # Py2K
+ if self._cx_oracle_with_unicode:
+ for k, v in opts.items():
+ if isinstance(v, str):
+ opts[k] = unicode(v)
+ # end Py2K
+
if 'mode' in url.query:
opts['mode'] = url.query['mode']
if isinstance(opts['mode'], basestring):
diff --git a/lib/sqlalchemy/engine/default.py b/lib/sqlalchemy/engine/default.py
index 077627949..cfab01dc4 100644
--- a/lib/sqlalchemy/engine/default.py
+++ b/lib/sqlalchemy/engine/default.py
@@ -138,9 +138,17 @@ class DefaultDialect(base.Dialect):
def _check_unicode_returns(self, connection):
cursor = connection.connection.cursor()
+ # Py2K
+ if self.supports_unicode_statements:
+ cast_to = unicode
+ else:
+ cast_to = str
+ # end Py2K
+ # Py3K
+ #cast_to = str
def check_unicode(type_):
cursor.execute(
- str(
+ cast_to(
expression.select(
[expression.cast(
expression.literal_column("'test unicode returns'"), type_)
diff --git a/lib/sqlalchemy/test/config.py b/lib/sqlalchemy/test/config.py
index eec962d80..efbe00fef 100644
--- a/lib/sqlalchemy/test/config.py
+++ b/lib/sqlalchemy/test/config.py
@@ -1,5 +1,6 @@
import optparse, os, sys, re, ConfigParser, time, warnings
+
# 2to3
import StringIO