features.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. import operator
  2. from django.db import transaction
  3. from django.db.backends.base.features import BaseDatabaseFeatures
  4. from django.db.utils import OperationalError
  5. from django.utils.functional import cached_property
  6. from .base import Database
  7. class DatabaseFeatures(BaseDatabaseFeatures):
  8. test_db_allows_multiple_connections = False
  9. supports_unspecified_pk = True
  10. supports_timezones = False
  11. max_query_params = 999
  12. supports_transactions = True
  13. atomic_transactions = False
  14. can_rollback_ddl = True
  15. can_create_inline_fk = False
  16. supports_paramstyle_pyformat = False
  17. requires_literal_defaults = True
  18. can_clone_databases = True
  19. supports_temporal_subtraction = True
  20. ignores_table_name_case = True
  21. supports_cast_with_precision = False
  22. time_cast_precision = 3
  23. can_release_savepoints = True
  24. has_case_insensitive_like = True
  25. # Is "ALTER TABLE ... RENAME COLUMN" supported?
  26. can_alter_table_rename_column = Database.sqlite_version_info >= (3, 25, 0)
  27. supports_parentheses_in_compound = False
  28. # Deferred constraint checks can be emulated on SQLite < 3.20 but not in a
  29. # reasonably performant way.
  30. supports_pragma_foreign_key_check = Database.sqlite_version_info >= (3, 20, 0)
  31. can_defer_constraint_checks = supports_pragma_foreign_key_check
  32. supports_functions_in_partial_indexes = Database.sqlite_version_info >= (3, 15, 0)
  33. supports_over_clause = Database.sqlite_version_info >= (3, 25, 0)
  34. supports_frame_range_fixed_distance = Database.sqlite_version_info >= (3, 28, 0)
  35. supports_aggregate_filter_clause = Database.sqlite_version_info >= (3, 30, 1)
  36. supports_order_by_nulls_modifier = Database.sqlite_version_info >= (3, 30, 0)
  37. order_by_nulls_first = True
  38. supports_json_field_contains = False
  39. supports_update_conflicts = Database.sqlite_version_info >= (3, 24, 0)
  40. supports_update_conflicts_with_target = supports_update_conflicts
  41. test_collations = {
  42. "ci": "nocase",
  43. "cs": "binary",
  44. "non_default": "nocase",
  45. }
  46. django_test_expected_failures = {
  47. # The django_format_dtdelta() function doesn't properly handle mixed
  48. # Date/DateTime fields and timedeltas.
  49. "expressions.tests.FTimeDeltaTests.test_mixed_comparisons1",
  50. }
  51. @cached_property
  52. def django_test_skips(self):
  53. skips = {
  54. "SQLite stores values rounded to 15 significant digits.": {
  55. "model_fields.test_decimalfield.DecimalFieldTests."
  56. "test_fetch_from_db_without_float_rounding",
  57. },
  58. "SQLite naively remakes the table on field alteration.": {
  59. "schema.tests.SchemaTests.test_unique_no_unnecessary_fk_drops",
  60. "schema.tests.SchemaTests.test_unique_and_reverse_m2m",
  61. "schema.tests.SchemaTests."
  62. "test_alter_field_default_doesnt_perform_queries",
  63. "schema.tests.SchemaTests."
  64. "test_rename_column_renames_deferred_sql_references",
  65. },
  66. "SQLite doesn't support negative precision for ROUND().": {
  67. "db_functions.math.test_round.RoundTests."
  68. "test_null_with_negative_precision",
  69. "db_functions.math.test_round.RoundTests."
  70. "test_decimal_with_negative_precision",
  71. "db_functions.math.test_round.RoundTests."
  72. "test_float_with_negative_precision",
  73. "db_functions.math.test_round.RoundTests."
  74. "test_integer_with_negative_precision",
  75. },
  76. }
  77. if Database.sqlite_version_info < (3, 27):
  78. skips.update(
  79. {
  80. "Nondeterministic failure on SQLite < 3.27.": {
  81. "expressions_window.tests.WindowFunctionTests."
  82. "test_subquery_row_range_rank",
  83. },
  84. }
  85. )
  86. if self.connection.is_in_memory_db():
  87. skips.update(
  88. {
  89. "the sqlite backend's close() method is a no-op when using an "
  90. "in-memory database": {
  91. "servers.test_liveserverthread.LiveServerThreadTest."
  92. "test_closes_connections",
  93. "servers.tests.LiveServerTestCloseConnectionTest."
  94. "test_closes_connections",
  95. },
  96. }
  97. )
  98. return skips
  99. @cached_property
  100. def supports_atomic_references_rename(self):
  101. return Database.sqlite_version_info >= (3, 26, 0)
  102. @cached_property
  103. def introspected_field_types(self):
  104. return {
  105. **super().introspected_field_types,
  106. "BigAutoField": "AutoField",
  107. "DurationField": "BigIntegerField",
  108. "GenericIPAddressField": "CharField",
  109. "SmallAutoField": "AutoField",
  110. }
  111. @cached_property
  112. def supports_json_field(self):
  113. with self.connection.cursor() as cursor:
  114. try:
  115. with transaction.atomic(self.connection.alias):
  116. cursor.execute('SELECT JSON(\'{"a": "b"}\')')
  117. except OperationalError:
  118. return False
  119. return True
  120. can_introspect_json_field = property(operator.attrgetter("supports_json_field"))
  121. has_json_object_function = property(operator.attrgetter("supports_json_field"))
  122. @cached_property
  123. def can_return_columns_from_insert(self):
  124. return Database.sqlite_version_info >= (3, 35)
  125. can_return_rows_from_bulk_insert = property(
  126. operator.attrgetter("can_return_columns_from_insert")
  127. )