From 464a9c8ca482f4a96c9da66e791bd3fb646ffbd2 Mon Sep 17 00:00:00 2001 From: Malcolm Tredinnick Date: Wed, 30 Jul 2008 01:29:31 +0000 Subject: [PATCH] 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 --- django/db/backends/oracle/base.py | 43 ++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/django/db/backends/oracle/base.py b/django/db/backends/oracle/base.py index bcf141fd7e..bdb73b1864 100644 --- a/django/db/backends/oracle/base.py +++ b/django/db/backends/oracle/base.py @@ -257,6 +257,26 @@ class DatabaseWrapper(BaseDatabaseWrapper): cursor.arraysize = 100 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): """ 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): if isinstance(params, dict): result = {} - charset = self.charset 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 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): - # Mark any string parameter greater than 4000 characters as an NCLOB. if isinstance(params_list[0], dict): sizes = {} iterators = [params.iteritems() for params in params_list] @@ -288,13 +306,18 @@ class FormatStylePlaceholderCursor(Database.Cursor): iterators = [enumerate(params) for params in params_list] for iterator in iterators: for key, value in iterator: - if isinstance(value, basestring) and len(value) > 4000: - sizes[key] = Database.NCLOB + if value.input_size: sizes[key] = value.input_size if isinstance(sizes, dict): self.setinputsizes(**sizes) else: 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): if params is None: params = [] @@ -309,7 +332,7 @@ class FormatStylePlaceholderCursor(Database.Cursor): query = query[:-1] query = smart_str(query, self.charset) % tuple(args) 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): try: @@ -324,9 +347,9 @@ class FormatStylePlaceholderCursor(Database.Cursor): if query.endswith(';') or query.endswith('/'): query = query[:-1] query = smart_str(query, self.charset) % tuple(args) - new_param_list = [self._format_params(i) for i in params] - self._guess_input_sizes(new_param_list) - return Database.Cursor.executemany(self, query, new_param_list) + formatted = [self._format_params(i) for i in params] + self._guess_input_sizes(formatted) + return Database.Cursor.executemany(self, query, [self._param_generator(p) for p in formatted]) def fetchone(self): row = Database.Cursor.fetchone(self)