Fixed #7637 -- Added an extra parameterisation hook to the Oracle backend.

Required for some extension modules (in particular, geo-django). Patch from
Justin Bronn.


git-svn-id: http://code.djangoproject.com/svn/django/trunk@8145 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Malcolm Tredinnick 2008-07-30 01:29:31 +00:00
parent 726a24c609
commit 464a9c8ca4
1 changed files with 33 additions and 10 deletions

View File

@ -257,6 +257,26 @@ class DatabaseWrapper(BaseDatabaseWrapper):
cursor.arraysize = 100 cursor.arraysize = 100
return cursor return cursor
class OracleParam(object):
"""
Wrapper object for formatting parameters for Oracle. If the string
representation of the value is large enough (greater than 4000 characters)
the input size needs to be set as NCLOB. Alternatively, if the parameter has
an `input_size` attribute, then the value of the `input_size` attribute will
be used instead. Otherwise, no input size will be set for the parameter when
executing the query.
"""
def __init__(self, param, charset, strings_only=False):
self.smart_str = smart_str(param, charset, strings_only)
if hasattr(param, 'input_size'):
# If parameter has `input_size` attribute, use that.
self.input_size = param.input_size
elif isinstance(param, basestring) and len(param) > 4000:
# Mark any string parameter greater than 4000 characters as an NCLOB.
self.input_size = Database.NCLOB
else:
self.input_size = None
class FormatStylePlaceholderCursor(Database.Cursor): class FormatStylePlaceholderCursor(Database.Cursor):
""" """
Django uses "format" (e.g. '%s') style placeholders, but Oracle uses ":var" Django uses "format" (e.g. '%s') style placeholders, but Oracle uses ":var"
@ -271,15 +291,13 @@ class FormatStylePlaceholderCursor(Database.Cursor):
def _format_params(self, params): def _format_params(self, params):
if isinstance(params, dict): if isinstance(params, dict):
result = {} result = {}
charset = self.charset
for key, value in params.items(): for key, value in params.items():
result[smart_str(key, charset)] = smart_str(value, charset) result[smart_str(key, self.charset)] = OracleParam(param, self.charset)
return result return result
else: else:
return tuple([smart_str(p, self.charset, True) for p in params]) return tuple([OracleParam(p, self.charset, True) for p in params])
def _guess_input_sizes(self, params_list): def _guess_input_sizes(self, params_list):
# Mark any string parameter greater than 4000 characters as an NCLOB.
if isinstance(params_list[0], dict): if isinstance(params_list[0], dict):
sizes = {} sizes = {}
iterators = [params.iteritems() for params in params_list] iterators = [params.iteritems() for params in params_list]
@ -288,13 +306,18 @@ class FormatStylePlaceholderCursor(Database.Cursor):
iterators = [enumerate(params) for params in params_list] iterators = [enumerate(params) for params in params_list]
for iterator in iterators: for iterator in iterators:
for key, value in iterator: for key, value in iterator:
if isinstance(value, basestring) and len(value) > 4000: if value.input_size: sizes[key] = value.input_size
sizes[key] = Database.NCLOB
if isinstance(sizes, dict): if isinstance(sizes, dict):
self.setinputsizes(**sizes) self.setinputsizes(**sizes)
else: else:
self.setinputsizes(*sizes) self.setinputsizes(*sizes)
def _param_generator(self, params):
if isinstance(params, dict):
return dict([(k, p.smart_str) for k, p in params.iteritems()])
else:
return [p.smart_str for p in params]
def execute(self, query, params=None): def execute(self, query, params=None):
if params is None: if params is None:
params = [] params = []
@ -309,7 +332,7 @@ class FormatStylePlaceholderCursor(Database.Cursor):
query = query[:-1] query = query[:-1]
query = smart_str(query, self.charset) % tuple(args) query = smart_str(query, self.charset) % tuple(args)
self._guess_input_sizes([params]) self._guess_input_sizes([params])
return Database.Cursor.execute(self, query, params) return Database.Cursor.execute(self, query, self._param_generator(params))
def executemany(self, query, params=None): def executemany(self, query, params=None):
try: try:
@ -324,9 +347,9 @@ class FormatStylePlaceholderCursor(Database.Cursor):
if query.endswith(';') or query.endswith('/'): if query.endswith(';') or query.endswith('/'):
query = query[:-1] query = query[:-1]
query = smart_str(query, self.charset) % tuple(args) query = smart_str(query, self.charset) % tuple(args)
new_param_list = [self._format_params(i) for i in params] formatted = [self._format_params(i) for i in params]
self._guess_input_sizes(new_param_list) self._guess_input_sizes(formatted)
return Database.Cursor.executemany(self, query, new_param_list) return Database.Cursor.executemany(self, query, [self._param_generator(p) for p in formatted])
def fetchone(self): def fetchone(self):
row = Database.Cursor.fetchone(self) row = Database.Cursor.fetchone(self)