compiler.py 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. # coding=utf-8
  2. """
  3. @project: maxkb
  4. @Author:虎
  5. @file: compiler.py
  6. @date:2023/10/7 10:53
  7. @desc:
  8. """
  9. from django.core.exceptions import EmptyResultSet, FullResultSet
  10. from django.db import NotSupportedError
  11. from django.db.models.sql.compiler import SQLCompiler
  12. from django.db.transaction import TransactionManagementError
  13. class AppSQLCompiler(SQLCompiler):
  14. def __init__(self, query, connection, using, elide_empty=True, field_replace_dict=None):
  15. super().__init__(query, connection, using, elide_empty)
  16. if field_replace_dict is None:
  17. field_replace_dict = {}
  18. self.field_replace_dict = field_replace_dict
  19. def get_query_str(self, with_limits=True, with_table_name=False, with_col_aliases=False):
  20. refcounts_before = self.query.alias_refcount.copy()
  21. try:
  22. combinator = self.query.combinator
  23. extra_select, order_by, group_by = self.pre_sql_setup(
  24. with_col_aliases=with_col_aliases or bool(combinator),
  25. )
  26. for_update_part = None
  27. # Is a LIMIT/OFFSET clause needed?
  28. with_limit_offset = with_limits and self.query.is_sliced
  29. combinator = self.query.combinator
  30. features = self.connection.features
  31. if combinator:
  32. if not getattr(features, "supports_select_{}".format(combinator)):
  33. raise NotSupportedError(
  34. "{} is not supported on this database backend.".format(
  35. combinator
  36. )
  37. )
  38. result, params = self.get_combinator_sql(
  39. combinator, self.query.combinator_all
  40. )
  41. elif self.qualify:
  42. result, params = self.get_qualify_sql()
  43. order_by = None
  44. else:
  45. distinct_fields, distinct_params = self.get_distinct()
  46. # This must come after 'select', 'ordering', and 'distinct'
  47. # (see docstring of get_from_clause() for details).
  48. from_, f_params = self.get_from_clause()
  49. try:
  50. where, w_params = (
  51. self.compile(self.where) if self.where is not None else ("", [])
  52. )
  53. except EmptyResultSet:
  54. if self.elide_empty:
  55. raise
  56. # Use a predicate that's always False.
  57. where, w_params = "0 = 1", []
  58. except FullResultSet:
  59. where, w_params = "", []
  60. try:
  61. having, h_params = (
  62. self.compile(self.having)
  63. if self.having is not None
  64. else ("", [])
  65. )
  66. except FullResultSet:
  67. having, h_params = "", []
  68. result = []
  69. params = []
  70. if self.query.distinct:
  71. distinct_result, distinct_params = self.connection.ops.distinct_sql(
  72. distinct_fields,
  73. distinct_params,
  74. )
  75. result += distinct_result
  76. params += distinct_params
  77. out_cols = []
  78. for _, (s_sql, s_params), alias in self.select + extra_select:
  79. if alias:
  80. s_sql = "%s AS %s" % (
  81. s_sql,
  82. self.connection.ops.quote_name(alias),
  83. )
  84. params.extend(s_params)
  85. out_cols.append(s_sql)
  86. params.extend(f_params)
  87. if self.query.select_for_update and features.has_select_for_update:
  88. if (
  89. self.connection.get_autocommit()
  90. # Don't raise an exception when database doesn't
  91. # support transactions, as it's a noop.
  92. and features.supports_transactions
  93. ):
  94. raise TransactionManagementError(
  95. "select_for_update cannot be used outside of a transaction."
  96. )
  97. if (
  98. with_limit_offset
  99. and not features.supports_select_for_update_with_limit
  100. ):
  101. raise NotSupportedError(
  102. "LIMIT/OFFSET is not supported with "
  103. "select_for_update on this database backend."
  104. )
  105. nowait = self.query.select_for_update_nowait
  106. skip_locked = self.query.select_for_update_skip_locked
  107. of = self.query.select_for_update_of
  108. no_key = self.query.select_for_no_key_update
  109. # If it's a NOWAIT/SKIP LOCKED/OF/NO KEY query but the
  110. # backend doesn't support it, raise NotSupportedError to
  111. # prevent a possible deadlock.
  112. if nowait and not features.has_select_for_update_nowait:
  113. raise NotSupportedError(
  114. "NOWAIT is not supported on this database backend."
  115. )
  116. elif skip_locked and not features.has_select_for_update_skip_locked:
  117. raise NotSupportedError(
  118. "SKIP LOCKED is not supported on this database backend."
  119. )
  120. elif of and not features.has_select_for_update_of:
  121. raise NotSupportedError(
  122. "FOR UPDATE OF is not supported on this database backend."
  123. )
  124. elif no_key and not features.has_select_for_no_key_update:
  125. raise NotSupportedError(
  126. "FOR NO KEY UPDATE is not supported on this "
  127. "database backend."
  128. )
  129. for_update_part = self.connection.ops.for_update_sql(
  130. nowait=nowait,
  131. skip_locked=skip_locked,
  132. of=self.get_select_for_update_of_arguments(),
  133. no_key=no_key,
  134. )
  135. if for_update_part and features.for_update_after_from:
  136. result.append(for_update_part)
  137. if where:
  138. result.append("WHERE %s" % where)
  139. params.extend(w_params)
  140. grouping = []
  141. for g_sql, g_params in group_by:
  142. grouping.append(g_sql)
  143. params.extend(g_params)
  144. if grouping:
  145. if distinct_fields:
  146. raise NotImplementedError(
  147. "annotate() + distinct(fields) is not implemented."
  148. )
  149. order_by = order_by or self.connection.ops.force_no_ordering()
  150. result.append("GROUP BY %s" % ", ".join(grouping))
  151. if self._meta_ordering:
  152. order_by = None
  153. if having:
  154. result.append("HAVING %s" % having)
  155. params.extend(h_params)
  156. if self.query.explain_info:
  157. result.insert(
  158. 0,
  159. self.connection.ops.explain_query_prefix(
  160. self.query.explain_info.format,
  161. **self.query.explain_info.options,
  162. ),
  163. )
  164. if order_by:
  165. ordering = []
  166. for _, (o_sql, o_params, _) in order_by:
  167. ordering.append(o_sql)
  168. params.extend(o_params)
  169. order_by_sql = "ORDER BY %s" % ", ".join(ordering)
  170. if combinator and features.requires_compound_order_by_subquery:
  171. result = ["SELECT * FROM (", *result, ")", order_by_sql]
  172. else:
  173. result.append(order_by_sql)
  174. if with_limit_offset:
  175. result.append(
  176. self.connection.ops.limit_offset_sql(
  177. self.query.low_mark, self.query.high_mark
  178. )
  179. )
  180. if for_update_part and not features.for_update_after_from:
  181. result.append(for_update_part)
  182. from_, f_params = self.get_from_clause()
  183. sql = " ".join(result)
  184. if not with_table_name:
  185. for table_name in from_:
  186. sql = sql.replace(table_name + ".", "")
  187. for key in self.field_replace_dict.keys():
  188. value = self.field_replace_dict.get(key)
  189. sql = sql.replace(key, value)
  190. return sql, tuple(params)
  191. finally:
  192. # Finally do cleanup - get rid of the joins we created above.
  193. self.query.reset_refcounts(refcounts_before)
  194. def as_sql(self, with_limits=True, with_col_aliases=False, select_string=None):
  195. if select_string is None:
  196. return super().as_sql(with_limits, with_col_aliases)
  197. else:
  198. sql, params = self.get_query_str(with_table_name=False)
  199. return (select_string + " " + sql), params