Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
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.

indexes.py 8.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. from django.db import NotSupportedError
  2. from django.db.models import Func, Index
  3. from django.utils.functional import cached_property
  4. __all__ = [
  5. "BloomIndex",
  6. "BrinIndex",
  7. "BTreeIndex",
  8. "GinIndex",
  9. "GistIndex",
  10. "HashIndex",
  11. "SpGistIndex",
  12. ]
  13. class PostgresIndex(Index):
  14. @cached_property
  15. def max_name_length(self):
  16. # Allow an index name longer than 30 characters when the suffix is
  17. # longer than the usual 3 character limit. The 30 character limit for
  18. # cross-database compatibility isn't applicable to PostgreSQL-specific
  19. # indexes.
  20. return Index.max_name_length - len(Index.suffix) + len(self.suffix)
  21. def create_sql(self, model, schema_editor, using="", **kwargs):
  22. self.check_supported(schema_editor)
  23. statement = super().create_sql(
  24. model, schema_editor, using=" USING %s" % (using or self.suffix), **kwargs
  25. )
  26. with_params = self.get_with_params()
  27. if with_params:
  28. statement.parts["extra"] = " WITH (%s)%s" % (
  29. ", ".join(with_params),
  30. statement.parts["extra"],
  31. )
  32. return statement
  33. def check_supported(self, schema_editor):
  34. pass
  35. def get_with_params(self):
  36. return []
  37. class BloomIndex(PostgresIndex):
  38. suffix = "bloom"
  39. def __init__(self, *expressions, length=None, columns=(), **kwargs):
  40. super().__init__(*expressions, **kwargs)
  41. if len(self.fields) > 32:
  42. raise ValueError("Bloom indexes support a maximum of 32 fields.")
  43. if not isinstance(columns, (list, tuple)):
  44. raise ValueError("BloomIndex.columns must be a list or tuple.")
  45. if len(columns) > len(self.fields):
  46. raise ValueError("BloomIndex.columns cannot have more values than fields.")
  47. if not all(0 < col <= 4095 for col in columns):
  48. raise ValueError(
  49. "BloomIndex.columns must contain integers from 1 to 4095.",
  50. )
  51. if length is not None and not 0 < length <= 4096:
  52. raise ValueError(
  53. "BloomIndex.length must be None or an integer from 1 to 4096.",
  54. )
  55. self.length = length
  56. self.columns = columns
  57. def deconstruct(self):
  58. path, args, kwargs = super().deconstruct()
  59. if self.length is not None:
  60. kwargs["length"] = self.length
  61. if self.columns:
  62. kwargs["columns"] = self.columns
  63. return path, args, kwargs
  64. def get_with_params(self):
  65. with_params = []
  66. if self.length is not None:
  67. with_params.append("length = %d" % self.length)
  68. if self.columns:
  69. with_params.extend(
  70. "col%d = %d" % (i, v) for i, v in enumerate(self.columns, start=1)
  71. )
  72. return with_params
  73. class BrinIndex(PostgresIndex):
  74. suffix = "brin"
  75. def __init__(
  76. self, *expressions, autosummarize=None, pages_per_range=None, **kwargs
  77. ):
  78. if pages_per_range is not None and pages_per_range <= 0:
  79. raise ValueError("pages_per_range must be None or a positive integer")
  80. self.autosummarize = autosummarize
  81. self.pages_per_range = pages_per_range
  82. super().__init__(*expressions, **kwargs)
  83. def deconstruct(self):
  84. path, args, kwargs = super().deconstruct()
  85. if self.autosummarize is not None:
  86. kwargs["autosummarize"] = self.autosummarize
  87. if self.pages_per_range is not None:
  88. kwargs["pages_per_range"] = self.pages_per_range
  89. return path, args, kwargs
  90. def get_with_params(self):
  91. with_params = []
  92. if self.autosummarize is not None:
  93. with_params.append(
  94. "autosummarize = %s" % ("on" if self.autosummarize else "off")
  95. )
  96. if self.pages_per_range is not None:
  97. with_params.append("pages_per_range = %d" % self.pages_per_range)
  98. return with_params
  99. class BTreeIndex(PostgresIndex):
  100. suffix = "btree"
  101. def __init__(self, *expressions, fillfactor=None, **kwargs):
  102. self.fillfactor = fillfactor
  103. super().__init__(*expressions, **kwargs)
  104. def deconstruct(self):
  105. path, args, kwargs = super().deconstruct()
  106. if self.fillfactor is not None:
  107. kwargs["fillfactor"] = self.fillfactor
  108. return path, args, kwargs
  109. def get_with_params(self):
  110. with_params = []
  111. if self.fillfactor is not None:
  112. with_params.append("fillfactor = %d" % self.fillfactor)
  113. return with_params
  114. class GinIndex(PostgresIndex):
  115. suffix = "gin"
  116. def __init__(
  117. self, *expressions, fastupdate=None, gin_pending_list_limit=None, **kwargs
  118. ):
  119. self.fastupdate = fastupdate
  120. self.gin_pending_list_limit = gin_pending_list_limit
  121. super().__init__(*expressions, **kwargs)
  122. def deconstruct(self):
  123. path, args, kwargs = super().deconstruct()
  124. if self.fastupdate is not None:
  125. kwargs["fastupdate"] = self.fastupdate
  126. if self.gin_pending_list_limit is not None:
  127. kwargs["gin_pending_list_limit"] = self.gin_pending_list_limit
  128. return path, args, kwargs
  129. def get_with_params(self):
  130. with_params = []
  131. if self.gin_pending_list_limit is not None:
  132. with_params.append(
  133. "gin_pending_list_limit = %d" % self.gin_pending_list_limit
  134. )
  135. if self.fastupdate is not None:
  136. with_params.append("fastupdate = %s" % ("on" if self.fastupdate else "off"))
  137. return with_params
  138. class GistIndex(PostgresIndex):
  139. suffix = "gist"
  140. def __init__(self, *expressions, buffering=None, fillfactor=None, **kwargs):
  141. self.buffering = buffering
  142. self.fillfactor = fillfactor
  143. super().__init__(*expressions, **kwargs)
  144. def deconstruct(self):
  145. path, args, kwargs = super().deconstruct()
  146. if self.buffering is not None:
  147. kwargs["buffering"] = self.buffering
  148. if self.fillfactor is not None:
  149. kwargs["fillfactor"] = self.fillfactor
  150. return path, args, kwargs
  151. def get_with_params(self):
  152. with_params = []
  153. if self.buffering is not None:
  154. with_params.append("buffering = %s" % ("on" if self.buffering else "off"))
  155. if self.fillfactor is not None:
  156. with_params.append("fillfactor = %d" % self.fillfactor)
  157. return with_params
  158. def check_supported(self, schema_editor):
  159. if (
  160. self.include
  161. and not schema_editor.connection.features.supports_covering_gist_indexes
  162. ):
  163. raise NotSupportedError("Covering GiST indexes require PostgreSQL 12+.")
  164. class HashIndex(PostgresIndex):
  165. suffix = "hash"
  166. def __init__(self, *expressions, fillfactor=None, **kwargs):
  167. self.fillfactor = fillfactor
  168. super().__init__(*expressions, **kwargs)
  169. def deconstruct(self):
  170. path, args, kwargs = super().deconstruct()
  171. if self.fillfactor is not None:
  172. kwargs["fillfactor"] = self.fillfactor
  173. return path, args, kwargs
  174. def get_with_params(self):
  175. with_params = []
  176. if self.fillfactor is not None:
  177. with_params.append("fillfactor = %d" % self.fillfactor)
  178. return with_params
  179. class SpGistIndex(PostgresIndex):
  180. suffix = "spgist"
  181. def __init__(self, *expressions, fillfactor=None, **kwargs):
  182. self.fillfactor = fillfactor
  183. super().__init__(*expressions, **kwargs)
  184. def deconstruct(self):
  185. path, args, kwargs = super().deconstruct()
  186. if self.fillfactor is not None:
  187. kwargs["fillfactor"] = self.fillfactor
  188. return path, args, kwargs
  189. def get_with_params(self):
  190. with_params = []
  191. if self.fillfactor is not None:
  192. with_params.append("fillfactor = %d" % self.fillfactor)
  193. return with_params
  194. def check_supported(self, schema_editor):
  195. if (
  196. self.include
  197. and not schema_editor.connection.features.supports_covering_spgist_indexes
  198. ):
  199. raise NotSupportedError("Covering SP-GiST indexes require PostgreSQL 14+.")
  200. class OpClass(Func):
  201. template = "%(expressions)s %(name)s"
  202. def __init__(self, expression, name):
  203. super().__init__(expression, name=name)