/doj/backends/zxjdbc/oracle/query.py

https://github.com/vitormazzi/django-jython
Python | 136 lines | 107 code | 10 blank | 19 comment | 5 complexity | ce50d40157f996d29dce38a181081488 MD5 | raw file
  1. """
  2. Custom Query class for Oracle.
  3. Derived from: django.db.models.sql.query.Query
  4. """
  5. import datetime
  6. from django.db.backends import util
  7. # Cache. Maps default query class to new Oracle query class.
  8. _classes = {}
  9. def query_class(QueryClass, Database):
  10. """
  11. Returns a custom django.db.models.sql.query.Query subclass that is
  12. appropriate for Oracle.
  13. The 'Database' module (cx_Oracle) is passed in here so that all the setup
  14. required to import it only needs to be done by the calling module.
  15. """
  16. global _classes
  17. try:
  18. return _classes[QueryClass]
  19. except KeyError:
  20. pass
  21. class OracleQuery(QueryClass):
  22. def resolve_columns(self, row, fields=()):
  23. index_start = len(self.extra_select.keys())
  24. values = [self.convert_values(v, type(v)) for v in row[:index_start]]
  25. for value, field in map(None, row[index_start:], fields):
  26. values.append(self.convert_values(value, field))
  27. return values
  28. def convert_values(self, value, field):
  29. from django.db.models.fields import DateField, DateTimeField, \
  30. TimeField, BooleanField, NullBooleanField, DecimalField, FloatField, Field
  31. # Oracle stores empty strings as null. We need to undo this in
  32. # order to adhere to the Django convention of using the empty
  33. # string instead of null, but only if the field accepts the
  34. # empty string.
  35. if value is None:
  36. pass
  37. elif value is None and isinstance(field, Field) and field.empty_strings_allowed:
  38. value = u''
  39. # Convert 1 or 0 to True or False
  40. elif isinstance(value, float):
  41. value = float(value)
  42. # Added 04-26-2009 to repair "Invalid literal for int() base 10" error
  43. elif isinstance(value,int):
  44. value = int(value)
  45. elif field is not None and field.get_internal_type() == 'AutoField':
  46. value = int(float(value))
  47. elif value in (1, 0) and field is not None and field.get_internal_type() in ('BooleanField', 'NullBooleanField'):
  48. value = bool(value)
  49. # Force floats to the correct type
  50. elif field is not None and field.get_internal_type() == 'FloatField':
  51. value = float(value)
  52. # Convert floats to decimals
  53. elif field is not None and field.get_internal_type() == 'DecimalField':
  54. value = util.typecast_decimal(field.format_number(value))
  55. elif field is not None and field.get_internal_type() == 'SmallIntegerField':
  56. value = util.typecast_decimal(field.format_number(value))
  57. return value
  58. def as_sql(self, with_limits=True, with_col_aliases=False):
  59. """
  60. Creates the SQL for this query. Returns the SQL string and list
  61. of parameters. This is overriden from the original Query class
  62. to handle the additional SQL Oracle requires to emulate LIMIT
  63. and OFFSET.
  64. If 'with_limits' is False, any limit/offset information is not
  65. included in the query.
  66. """
  67. # The `do_offset` flag indicates whether we need to construct
  68. # the SQL needed to use limit/offset with Oracle.
  69. do_offset = with_limits and (self.high_mark is not None
  70. or self.low_mark)
  71. if not do_offset:
  72. sql, params = super(OracleQuery, self).as_sql(with_limits=False,
  73. with_col_aliases=with_col_aliases)
  74. else:
  75. # `get_columns` needs to be called before `get_ordering` to
  76. # populate `_select_alias`.
  77. self.pre_sql_setup()
  78. self.get_columns()
  79. #ordering = self.get_ordering()
  80. #
  81. # Removed Ordering on 03/27/2009 as it caused error:
  82. # TypeError: sequence item 0: expected string, list found
  83. #
  84. ordering = False
  85. # Oracle's ROW_NUMBER() function requires an ORDER BY clause.
  86. if ordering:
  87. rn_orderby = ', '.join(ordering)
  88. else:
  89. # Create a default ORDER BY since none was specified.
  90. qn = self.quote_name_unless_alias
  91. opts = self.model._meta
  92. rn_orderby = '%s.%s' % (qn(opts.db_table),
  93. qn(opts.fields[0].db_column or opts.fields[0].column))
  94. # Ensure the base query SELECTs our special "_RN" column
  95. self.extra_select['_RN'] = ('ROW_NUMBER() OVER (ORDER BY %s)'
  96. % rn_orderby, '')
  97. sql, params = super(OracleQuery, self).as_sql(with_limits=False,
  98. with_col_aliases=True)
  99. # Wrap the base query in an outer SELECT * with boundaries on
  100. # the "_RN" column. This is the canonical way to emulate LIMIT
  101. # and OFFSET on Oracle.
  102. sql = 'SELECT * FROM (%s) WHERE "_RN" > %d' % (sql, self.low_mark)
  103. if self.high_mark is not None:
  104. sql = '%s AND "_RN" <= %d' % (sql, self.high_mark)
  105. return sql, params
  106. def set_limits(self, low=None, high=None):
  107. super(OracleQuery, self).set_limits(low, high)
  108. # We need to select the row number for the LIMIT/OFFSET sql.
  109. # A placeholder is added to extra_select now, because as_sql is
  110. # too late to be modifying extra_select. However, the actual sql
  111. # depends on the ordering, so that is generated in as_sql.
  112. self.extra_select['_RN'] = ('1', '')
  113. def clear_limits(self):
  114. super(OracleQuery, self).clear_limits()
  115. if '_RN' in self.extra_select:
  116. del self.extra_select['_RN']
  117. _classes[QueryClass] = OracleQuery
  118. return OracleQuery