You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

203 lines
6.9 KiB

  1. """
  2. Classes that represent database functions.
  3. """
  4. from django.db.models import (
  5. DateTimeField, Func, IntegerField, Transform, Value,
  6. )
  7. class Coalesce(Func):
  8. """
  9. Chooses, from left to right, the first non-null expression and returns it.
  10. """
  11. function = 'COALESCE'
  12. def __init__(self, *expressions, **extra):
  13. if len(expressions) < 2:
  14. raise ValueError('Coalesce must take at least two expressions')
  15. super(Coalesce, self).__init__(*expressions, **extra)
  16. def as_oracle(self, compiler, connection):
  17. # we can't mix TextField (NCLOB) and CharField (NVARCHAR), so convert
  18. # all fields to NCLOB when we expect NCLOB
  19. if self.output_field.get_internal_type() == 'TextField':
  20. class ToNCLOB(Func):
  21. function = 'TO_NCLOB'
  22. expressions = [
  23. ToNCLOB(expression) for expression in self.get_source_expressions()]
  24. self.set_source_expressions(expressions)
  25. return super(Coalesce, self).as_sql(compiler, connection)
  26. class ConcatPair(Func):
  27. """
  28. A helper class that concatenates two arguments together. This is used
  29. by `Concat` because not all backend databases support more than two
  30. arguments.
  31. """
  32. function = 'CONCAT'
  33. def __init__(self, left, right, **extra):
  34. super(ConcatPair, self).__init__(left, right, **extra)
  35. def as_sqlite(self, compiler, connection):
  36. coalesced = self.coalesce()
  37. coalesced.arg_joiner = ' || '
  38. coalesced.template = '%(expressions)s'
  39. return super(ConcatPair, coalesced).as_sql(compiler, connection)
  40. def as_mysql(self, compiler, connection):
  41. # Use CONCAT_WS with an empty separator so that NULLs are ignored.
  42. self.function = 'CONCAT_WS'
  43. self.template = "%(function)s('', %(expressions)s)"
  44. return super(ConcatPair, self).as_sql(compiler, connection)
  45. def coalesce(self):
  46. # null on either side results in null for expression, wrap with coalesce
  47. c = self.copy()
  48. expressions = [
  49. Coalesce(expression, Value('')) for expression in c.get_source_expressions()
  50. ]
  51. c.set_source_expressions(expressions)
  52. return c
  53. class Concat(Func):
  54. """
  55. Concatenates text fields together. Backends that result in an entire
  56. null expression when any arguments are null will wrap each argument in
  57. coalesce functions to ensure we always get a non-null result.
  58. """
  59. function = None
  60. template = "%(expressions)s"
  61. def __init__(self, *expressions, **extra):
  62. if len(expressions) < 2:
  63. raise ValueError('Concat must take at least two expressions')
  64. paired = self._paired(expressions)
  65. super(Concat, self).__init__(paired, **extra)
  66. def _paired(self, expressions):
  67. # wrap pairs of expressions in successive concat functions
  68. # exp = [a, b, c, d]
  69. # -> ConcatPair(a, ConcatPair(b, ConcatPair(c, d))))
  70. if len(expressions) == 2:
  71. return ConcatPair(*expressions)
  72. return ConcatPair(expressions[0], self._paired(expressions[1:]))
  73. class Greatest(Func):
  74. """
  75. Chooses the maximum expression and returns it.
  76. If any expression is null the return value is database-specific:
  77. On Postgres, the maximum not-null expression is returned.
  78. On MySQL, Oracle, and SQLite, if any expression is null, null is returned.
  79. """
  80. function = 'GREATEST'
  81. def __init__(self, *expressions, **extra):
  82. if len(expressions) < 2:
  83. raise ValueError('Greatest must take at least two expressions')
  84. super(Greatest, self).__init__(*expressions, **extra)
  85. def as_sqlite(self, compiler, connection):
  86. """Use the MAX function on SQLite."""
  87. return super(Greatest, self).as_sql(compiler, connection, function='MAX')
  88. class Least(Func):
  89. """
  90. Chooses the minimum expression and returns it.
  91. If any expression is null the return value is database-specific:
  92. On Postgres, the minimum not-null expression is returned.
  93. On MySQL, Oracle, and SQLite, if any expression is null, null is returned.
  94. """
  95. function = 'LEAST'
  96. def __init__(self, *expressions, **extra):
  97. if len(expressions) < 2:
  98. raise ValueError('Least must take at least two expressions')
  99. super(Least, self).__init__(*expressions, **extra)
  100. def as_sqlite(self, compiler, connection):
  101. """Use the MIN function on SQLite."""
  102. return super(Least, self).as_sql(compiler, connection, function='MIN')
  103. class Length(Transform):
  104. """Returns the number of characters in the expression"""
  105. function = 'LENGTH'
  106. lookup_name = 'length'
  107. def __init__(self, expression, **extra):
  108. output_field = extra.pop('output_field', IntegerField())
  109. super(Length, self).__init__(expression, output_field=output_field, **extra)
  110. def as_mysql(self, compiler, connection):
  111. self.function = 'CHAR_LENGTH'
  112. return super(Length, self).as_sql(compiler, connection)
  113. class Lower(Transform):
  114. function = 'LOWER'
  115. lookup_name = 'lower'
  116. def __init__(self, expression, **extra):
  117. super(Lower, self).__init__(expression, **extra)
  118. class Now(Func):
  119. template = 'CURRENT_TIMESTAMP'
  120. def __init__(self, output_field=None, **extra):
  121. if output_field is None:
  122. output_field = DateTimeField()
  123. super(Now, self).__init__(output_field=output_field, **extra)
  124. def as_postgresql(self, compiler, connection):
  125. # Postgres' CURRENT_TIMESTAMP means "the time at the start of the
  126. # transaction". We use STATEMENT_TIMESTAMP to be cross-compatible with
  127. # other databases.
  128. self.template = 'STATEMENT_TIMESTAMP()'
  129. return self.as_sql(compiler, connection)
  130. class Substr(Func):
  131. function = 'SUBSTRING'
  132. def __init__(self, expression, pos, length=None, **extra):
  133. """
  134. expression: the name of a field, or an expression returning a string
  135. pos: an integer > 0, or an expression returning an integer
  136. length: an optional number of characters to return
  137. """
  138. if not hasattr(pos, 'resolve_expression'):
  139. if pos < 1:
  140. raise ValueError("'pos' must be greater than 0")
  141. pos = Value(pos)
  142. expressions = [expression, pos]
  143. if length is not None:
  144. if not hasattr(length, 'resolve_expression'):
  145. length = Value(length)
  146. expressions.append(length)
  147. super(Substr, self).__init__(*expressions, **extra)
  148. def as_sqlite(self, compiler, connection):
  149. self.function = 'SUBSTR'
  150. return super(Substr, self).as_sql(compiler, connection)
  151. def as_oracle(self, compiler, connection):
  152. self.function = 'SUBSTR'
  153. return super(Substr, self).as_sql(compiler, connection)
  154. class Upper(Transform):
  155. function = 'UPPER'
  156. lookup_name = 'upper'
  157. def __init__(self, expression, **extra):
  158. super(Upper, self).__init__(expression, **extra)