Changeset 5013
- Timestamp:
- 04/16/07 17:31:55 (2 years ago)
- Files:
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/branches/boulder-oracle-sprint/django/db/backends/oracle/base.py
r5002 r5013 297 297 # 2. convert NCLOBs 298 298 299 def resolve_cols(row):300 for field in row:301 value = field302 if isinstance(field, Database.LOB):303 value = field.read()304 # cx_Oracle always returns datetime.datetime objects for305 # DATE and TIMESTAMP columns, but Django wants to see a306 # python datetime.date, .time, or .datetime.307 # As a workaround, we cast to date if all the time-related308 # fields are 0, or to time if the date is 1/1/1900.309 # A better fix would involve either patching cx_Oracle310 # or checking the Model here, neither of which is good.311 elif isinstance(field, datetime.datetime):312 if field.hour == field.minute == field.second == field.microsecond == 0:313 value = field.date()314 elif field.year == 1900 and field.month == field.day == 1:315 value = field.time()316 # In Python 2.3, the cx_Oracle driver returns its own317 # Timestamp object that we must convert to a datetime class.318 elif isinstance(field, Database.Timestamp):319 if field.hour == field.minute == field.second == field.fsecond == 0:320 value = datetime.date(field.year, field.month, field.day)321 elif field.year == 1900 and field.month == field.day == 1:322 value = datetime.time(field.hour, field.minute, field.second, field.fsecond)323 else:324 value = datetime.datetime(field.year, field.month, field.day, field.hour,325 field.minute, field.second, field.fsecond)326 # Since Oracle won't distinguish between NULL and an empty327 # string (''), we store empty strings as a space. Here is328 # where we undo that treachery.329 if value == ' ':330 value = ''331 yield value332 333 299 while 1: 334 300 rows = cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE) … … 336 302 raise StopIteration 337 303 for row in rows: 338 row = list(resolve_cols(row))304 row = self.resolve_columns(row) 339 305 if fill_cache: 340 306 obj, index_end = get_cached_row(klass=self.model, row=row, … … 480 446 return select, " ".join(sql), params 481 447 448 def resolve_columns(self, row, fields=()): 449 from django.db.models.fields import DateField, DateTimeField, TimeField 450 values = [] 451 for value, field in map(None, row, fields): 452 if isinstance(value, Database.LOB): 453 value = value.read() 454 # Since Oracle won't distinguish between NULL and an empty 455 # string (''), we store empty strings as a space. Here is 456 # where we undo that treachery. 457 if value == ' ': 458 value = '' 459 # cx_Oracle always returns datetime.datetime objects for 460 # DATE and TIMESTAMP columns, but Django wants to see a 461 # python datetime.date, .time, or .datetime. We use the type 462 # of the Field to determine which to cast to, but it's not 463 # always available. 464 # As a workaround, we cast to date if all the time-related 465 # values are 0, or to time if the date is 1/1/1900. 466 # This could be cleaned a bit by adding a method to the Field 467 # classes to normalize values from the database (the to_python 468 # method is used for validation and isn't what we want here). 469 elif isinstance(value, Database.Timestamp): 470 # In Python 2.3, the cx_Oracle driver returns its own 471 # Timestamp object that we must convert to a datetime class. 472 if not isinstance(value, datetime.datetime): 473 value = datetime.datetime(value.year, value.month, value.day, value.hour, 474 value.minute, value.second, value.fsecond) 475 if isinstance(field, DateTimeField): 476 pass # DateTimeField subclasses DateField so must be checked first. 477 elif isinstance(field, DateField): 478 value = value.date() 479 elif isinstance(field, TimeField): 480 value = value.time() 481 elif value.hour == value.minute == value.second == value.microsecond == 0: 482 value = value.date() 483 elif value.year == 1900 and value.month == value.day == 1: 484 value = value.time() 485 values.append(value) 486 return values 487 482 488 return OracleQuerySet 483 489 django/branches/boulder-oracle-sprint/django/db/models/query.py
r4990 r5013 185 185 fill_cache = self._select_related 186 186 index_end = len(self.model._meta.fields) 187 has_resolve_columns = hasattr(self, 'resolve_columns') 187 188 while 1: 188 189 rows = cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE) … … 190 191 raise StopIteration 191 192 for row in rows: 193 if has_resolve_columns: 194 row = self.resolve_columns(row) 192 195 if fill_cache: 193 196 obj, index_end = get_cached_row(klass=self.model, row=row, … … 574 577 # self._fields is a list of field names to fetch. 575 578 if self._fields: 576 columns = [self.model._meta.get_field(f, many_to_many=False).column for f in self._fields] 577 field_names = self._fields 579 fields = [self.model._meta.get_field(f, many_to_many=False) for f in self._fields] 578 580 else: # Default to all fields. 579 columns = [f.column for f in self.model._meta.fields] 580 field_names = [f.attname for f in self.model._meta.fields] 581 fields = self.model._meta.fields 582 columns = [f.column for f in fields] 583 field_names = [f.attname for f in fields] 581 584 582 585 select = ['%s.%s' % (backend.quote_name(self.model._meta.db_table), backend.quote_name(c)) for c in columns] 583 586 cursor = connection.cursor() 584 587 cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params) 588 589 has_resolve_columns = hasattr(self, 'resolve_columns') 585 590 while 1: 586 591 rows = cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE) … … 588 593 raise StopIteration 589 594 for row in rows: 595 if has_resolve_columns: 596 row = self.resolve_columns(row, fields) 590 597 yield dict(zip(field_names, row)) 591 598 … … 598 605 def iterator(self): 599 606 from django.db.backends.util import typecast_timestamp 607 from django.db.models.fields import DateTimeField 600 608 self._order_by = () # Clear this because it'll mess things up otherwise. 601 609 if self._field.null: … … 621 629 cursor = connection.cursor() 622 630 cursor.execute(sql, params) 623 if backend.needs_datetime_string_cast: 624 return [typecast_timestamp(str(row[0])) for row in cursor.fetchall()] 625 else: 626 return [row[0] for row in cursor.fetchall()] 631 632 has_resolve_columns = hasattr(self, 'resolve_columns') 633 needs_datetime_string_cast = backend.needs_datetime_string_cast 634 dates = [] 635 # It would be better to use self._field here instead of DateTimeField(), 636 # but in Oracle that will result in a list of datetime.date instead of 637 # datetime.datetime. 638 fields = [DateTimeField()] 639 while 1: 640 rows = cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE) 641 if not rows: 642 return dates 643 for row in rows: 644 date = row[0] 645 if has_resolve_columns: 646 date = self.resolve_columns([date], fields)[0] 647 elif needs_datetime_string_cast: 648 date = typecast_timestamp(str(date)) 649 dates.append(date) 627 650 628 651 def _clone(self, klass=None, **kwargs):
