features.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. import operator
  2. import platform
  3. from django.db import transaction
  4. from django.db.backends.base.features import BaseDatabaseFeatures
  5. from django.db.utils import OperationalError
  6. from django.utils.functional import cached_property
  7. from .base import Database
  8. class DatabaseFeatures(BaseDatabaseFeatures):
  9. # SQLite can read from a cursor since SQLite 3.6.5, subject to the caveat
  10. # that statements within a connection aren't isolated from each other. See
  11. # https://sqlite.org/isolation.html.
  12. can_use_chunked_reads = True
  13. test_db_allows_multiple_connections = False
  14. supports_unspecified_pk = True
  15. supports_timezones = False
  16. max_query_params = 999
  17. supports_mixed_date_datetime_comparisons = False
  18. supports_transactions = True
  19. atomic_transactions = False
  20. can_rollback_ddl = True
  21. can_create_inline_fk = False
  22. supports_paramstyle_pyformat = False
  23. can_clone_databases = True
  24. supports_temporal_subtraction = True
  25. ignores_table_name_case = True
  26. supports_cast_with_precision = False
  27. time_cast_precision = 3
  28. can_release_savepoints = True
  29. # Is "ALTER TABLE ... RENAME COLUMN" supported?
  30. can_alter_table_rename_column = Database.sqlite_version_info >= (3, 25, 0)
  31. supports_parentheses_in_compound = False
  32. # Deferred constraint checks can be emulated on SQLite < 3.20 but not in a
  33. # reasonably performant way.
  34. supports_pragma_foreign_key_check = Database.sqlite_version_info >= (3, 20, 0)
  35. can_defer_constraint_checks = supports_pragma_foreign_key_check
  36. supports_functions_in_partial_indexes = Database.sqlite_version_info >= (3, 15, 0)
  37. supports_over_clause = Database.sqlite_version_info >= (3, 25, 0)
  38. supports_frame_range_fixed_distance = Database.sqlite_version_info >= (3, 28, 0)
  39. supports_aggregate_filter_clause = Database.sqlite_version_info >= (3, 30, 1)
  40. supports_order_by_nulls_modifier = Database.sqlite_version_info >= (3, 30, 0)
  41. order_by_nulls_first = True
  42. supports_json_field_contains = False
  43. test_collations = {
  44. 'ci': 'nocase',
  45. 'cs': 'binary',
  46. 'non_default': 'nocase',
  47. }
  48. @cached_property
  49. def django_test_skips(self):
  50. skips = {
  51. 'SQLite stores values rounded to 15 significant digits.': {
  52. 'model_fields.test_decimalfield.DecimalFieldTests.test_fetch_from_db_without_float_rounding',
  53. },
  54. 'SQLite naively remakes the table on field alteration.': {
  55. 'schema.tests.SchemaTests.test_unique_no_unnecessary_fk_drops',
  56. 'schema.tests.SchemaTests.test_unique_and_reverse_m2m',
  57. 'schema.tests.SchemaTests.test_alter_field_default_doesnt_perform_queries',
  58. 'schema.tests.SchemaTests.test_rename_column_renames_deferred_sql_references',
  59. },
  60. "SQLite doesn't have a constraint.": {
  61. 'model_fields.test_integerfield.PositiveIntegerFieldTests.test_negative_values',
  62. },
  63. }
  64. if Database.sqlite_version_info < (3, 27):
  65. skips.update({
  66. 'Nondeterministic failure on SQLite < 3.27.': {
  67. 'expressions_window.tests.WindowFunctionTests.test_subquery_row_range_rank',
  68. },
  69. })
  70. if self.connection.is_in_memory_db():
  71. skips.update({
  72. "the sqlite backend's close() method is a no-op when using an "
  73. "in-memory database": {
  74. 'servers.test_liveserverthread.LiveServerThreadTest.test_closes_connections',
  75. },
  76. })
  77. return skips
  78. @cached_property
  79. def supports_atomic_references_rename(self):
  80. # SQLite 3.28.0 bundled with MacOS 10.15 does not support renaming
  81. # references atomically.
  82. if platform.mac_ver()[0].startswith('10.15.') and Database.sqlite_version_info == (3, 28, 0):
  83. return False
  84. return Database.sqlite_version_info >= (3, 26, 0)
  85. @cached_property
  86. def introspected_field_types(self):
  87. return{
  88. **super().introspected_field_types,
  89. 'BigAutoField': 'AutoField',
  90. 'DurationField': 'BigIntegerField',
  91. 'GenericIPAddressField': 'CharField',
  92. 'SmallAutoField': 'AutoField',
  93. }
  94. @cached_property
  95. def supports_json_field(self):
  96. with self.connection.cursor() as cursor:
  97. try:
  98. with transaction.atomic(self.connection.alias):
  99. cursor.execute('SELECT JSON(\'{"a": "b"}\')')
  100. except OperationalError:
  101. return False
  102. return True
  103. can_introspect_json_field = property(operator.attrgetter('supports_json_field'))
  104. has_json_object_function = property(operator.attrgetter('supports_json_field'))