diff --git a/django/db/backends/oracle/base.py b/django/db/backends/oracle/base.py index cc85685e5b..42351480ff 100644 --- a/django/db/backends/oracle/base.py +++ b/django/db/backends/oracle/base.py @@ -514,58 +514,18 @@ class FormatStylePlaceholderCursor(object): row = self.cursor.fetchone() if row is None: return row - return self._rowfactory(row) + return _rowfactory(row, self.cursor) def fetchmany(self, size=None): if size is None: size = self.arraysize - return tuple([self._rowfactory(r) + return tuple([_rowfactory(r, self.cursor) for r in self.cursor.fetchmany(size)]) def fetchall(self): - return tuple([self._rowfactory(r) + return tuple([_rowfactory(r, self.cursor) for r in self.cursor.fetchall()]) - def _rowfactory(self, row): - # Cast numeric values as the appropriate Python type based upon the - # cursor description, and convert strings to unicode. - casted = [] - for value, desc in zip(row, self.cursor.description): - if value is not None and desc[1] is Database.NUMBER: - precision, scale = desc[4:6] - if scale == -127: - if precision == 0: - # NUMBER column: decimal-precision floating point - # This will normally be an integer from a sequence, - # but it could be a decimal value. - if '.' in value: - value = Decimal(value) - else: - value = int(value) - else: - # FLOAT column: binary-precision floating point. - # This comes from FloatField columns. - value = float(value) - elif precision > 0: - # NUMBER(p,s) column: decimal-precision fixed point. - # This comes from IntField and DecimalField columns. - if scale == 0: - value = int(value) - else: - value = Decimal(value) - elif '.' in value: - # No type information. This normally comes from a - # mathematical expression in the SELECT list. Guess int - # or Decimal based on whether it has a decimal point. - value = Decimal(value) - else: - value = int(value) - elif desc[1] in (Database.STRING, Database.FIXED_CHAR, - Database.LONG_STRING): - value = to_unicode(value) - casted.append(value) - return tuple(casted) - def __getattr__(self, attr): if attr in self.__dict__: return self.__dict__[attr] @@ -573,7 +533,63 @@ class FormatStylePlaceholderCursor(object): return getattr(self.cursor, attr) def __iter__(self): - return iter(self.cursor) + return CursorIterator(self.cursor) + + +class CursorIterator(object): + + """Cursor iterator wrapper that invokes our custom row factory.""" + + def __init__(self, cursor): + self.cursor = cursor + self.iter = iter(cursor) + + def __iter__(self): + return self + + def next(self): + return _rowfactory(self.iter.next(), self.cursor) + + +def _rowfactory(row, cursor): + # Cast numeric values as the appropriate Python type based upon the + # cursor description, and convert strings to unicode. + casted = [] + for value, desc in zip(row, cursor.description): + if value is not None and desc[1] is Database.NUMBER: + precision, scale = desc[4:6] + if scale == -127: + if precision == 0: + # NUMBER column: decimal-precision floating point + # This will normally be an integer from a sequence, + # but it could be a decimal value. + if '.' in value: + value = Decimal(value) + else: + value = int(value) + else: + # FLOAT column: binary-precision floating point. + # This comes from FloatField columns. + value = float(value) + elif precision > 0: + # NUMBER(p,s) column: decimal-precision fixed point. + # This comes from IntField and DecimalField columns. + if scale == 0: + value = int(value) + else: + value = Decimal(value) + elif '.' in value: + # No type information. This normally comes from a + # mathematical expression in the SELECT list. Guess int + # or Decimal based on whether it has a decimal point. + value = Decimal(value) + else: + value = int(value) + elif desc[1] in (Database.STRING, Database.FIXED_CHAR, + Database.LONG_STRING): + value = to_unicode(value) + casted.append(value) + return tuple(casted) def to_unicode(s): diff --git a/django/db/models/query.py b/django/db/models/query.py index 8799b4a93b..0b57b1e4bc 100644 --- a/django/db/models/query.py +++ b/django/db/models/query.py @@ -1210,10 +1210,11 @@ class RawQuerySet(object): A dict mapping column names to model field names. """ if not hasattr(self, '_model_fields'): + converter = connections[self.db].introspection.table_name_converter self._model_fields = {} for field in self.model._meta.fields: name, column = field.get_attname_column() - self._model_fields[column] = name + self._model_fields[converter(column)] = name return self._model_fields def transform_results(self, values): diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py index d821c0ee02..01706407af 100644 --- a/django/db/models/sql/query.py +++ b/django/db/models/sql/query.py @@ -42,7 +42,9 @@ class RawQuery(object): def get_columns(self): if self.cursor is None: self._execute_query() - return [column_meta[0] for column_meta in self.cursor.description] + converter = connections[self.using].introspection.table_name_converter + return [converter(column_meta[0]) + for column_meta in self.cursor.description] def validate_sql(self, sql): if not sql.lower().strip().startswith('select'): @@ -53,7 +55,7 @@ class RawQuery(object): # Always execute a new query for a new iterator. # This could be optomized with a cache at the expense of RAM. self._execute_query() - return self.cursor + return iter(self.cursor) def __repr__(self): return "" % (self.sql % self.params)