compiler.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. from django.core.exceptions import FieldError, FullResultSet
  2. from django.db.models.expressions import Col
  3. from django.db.models.sql import compiler
  4. class SQLCompiler(compiler.SQLCompiler):
  5. def as_subquery_condition(self, alias, columns, compiler):
  6. qn = compiler.quote_name_unless_alias
  7. qn2 = self.connection.ops.quote_name
  8. sql, params = self.as_sql()
  9. return (
  10. "(%s) IN (%s)"
  11. % (
  12. ", ".join("%s.%s" % (qn(alias), qn2(column)) for column in columns),
  13. sql,
  14. ),
  15. params,
  16. )
  17. class SQLInsertCompiler(compiler.SQLInsertCompiler, SQLCompiler):
  18. pass
  19. class SQLDeleteCompiler(compiler.SQLDeleteCompiler, SQLCompiler):
  20. def as_sql(self):
  21. # Prefer the non-standard DELETE FROM syntax over the SQL generated by
  22. # the SQLDeleteCompiler's default implementation when multiple tables
  23. # are involved since MySQL/MariaDB will generate a more efficient query
  24. # plan than when using a subquery.
  25. where, having, qualify = self.query.where.split_having_qualify(
  26. must_group_by=self.query.group_by is not None
  27. )
  28. if self.single_alias or having or qualify:
  29. # DELETE FROM cannot be used when filtering against aggregates or
  30. # window functions as it doesn't allow for GROUP BY/HAVING clauses
  31. # and the subquery wrapping (necessary to emulate QUALIFY).
  32. return super().as_sql()
  33. result = [
  34. "DELETE %s FROM"
  35. % self.quote_name_unless_alias(self.query.get_initial_alias())
  36. ]
  37. from_sql, params = self.get_from_clause()
  38. result.extend(from_sql)
  39. try:
  40. where_sql, where_params = self.compile(where)
  41. except FullResultSet:
  42. pass
  43. else:
  44. result.append("WHERE %s" % where_sql)
  45. params.extend(where_params)
  46. return " ".join(result), tuple(params)
  47. class SQLUpdateCompiler(compiler.SQLUpdateCompiler, SQLCompiler):
  48. def as_sql(self):
  49. update_query, update_params = super().as_sql()
  50. # MySQL and MariaDB support UPDATE ... ORDER BY syntax.
  51. if self.query.order_by:
  52. order_by_sql = []
  53. order_by_params = []
  54. db_table = self.query.get_meta().db_table
  55. try:
  56. for resolved, (sql, params, _) in self.get_order_by():
  57. if (
  58. isinstance(resolved.expression, Col)
  59. and resolved.expression.alias != db_table
  60. ):
  61. # Ignore ordering if it contains joined fields, because
  62. # they cannot be used in the ORDER BY clause.
  63. raise FieldError
  64. order_by_sql.append(sql)
  65. order_by_params.extend(params)
  66. update_query += " ORDER BY " + ", ".join(order_by_sql)
  67. update_params += tuple(order_by_params)
  68. except FieldError:
  69. # Ignore ordering if it contains annotations, because they're
  70. # removed in .update() and cannot be resolved.
  71. pass
  72. return update_query, update_params
  73. class SQLAggregateCompiler(compiler.SQLAggregateCompiler, SQLCompiler):
  74. pass