compiler.py 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. from django.core.exceptions import FieldError
  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, from_params = self.get_from_clause()
  38. result.extend(from_sql)
  39. where_sql, where_params = self.compile(where)
  40. if where_sql:
  41. result.append("WHERE %s" % where_sql)
  42. return " ".join(result), tuple(from_params) + tuple(where_params)
  43. class SQLUpdateCompiler(compiler.SQLUpdateCompiler, SQLCompiler):
  44. def as_sql(self):
  45. update_query, update_params = super().as_sql()
  46. # MySQL and MariaDB support UPDATE ... ORDER BY syntax.
  47. if self.query.order_by:
  48. order_by_sql = []
  49. order_by_params = []
  50. db_table = self.query.get_meta().db_table
  51. try:
  52. for resolved, (sql, params, _) in self.get_order_by():
  53. if (
  54. isinstance(resolved.expression, Col)
  55. and resolved.expression.alias != db_table
  56. ):
  57. # Ignore ordering if it contains joined fields, because
  58. # they cannot be used in the ORDER BY clause.
  59. raise FieldError
  60. order_by_sql.append(sql)
  61. order_by_params.extend(params)
  62. update_query += " ORDER BY " + ", ".join(order_by_sql)
  63. update_params += tuple(order_by_params)
  64. except FieldError:
  65. # Ignore ordering if it contains annotations, because they're
  66. # removed in .update() and cannot be resolved.
  67. pass
  68. return update_query, update_params
  69. class SQLAggregateCompiler(compiler.SQLAggregateCompiler, SQLCompiler):
  70. pass