Plain is headed towards 1.0! Subscribe for development updates →

  1from plain.models.db import ProgrammingError
  2from plain.utils.functional import cached_property
  3
  4
  5class BaseDatabaseFeatures:
  6    # An optional tuple indicating the minimum supported database version.
  7    minimum_database_version = None
  8    gis_enabled = False
  9    # Oracle can't group by LOB (large object) data types.
 10    allows_group_by_lob = True
 11    allows_group_by_selected_pks = False
 12    allows_group_by_select_index = True
 13    empty_fetchmany_value = []
 14    update_can_self_select = True
 15
 16    # Does the backend distinguish between '' and None?
 17    interprets_empty_strings_as_nulls = False
 18
 19    # Does the backend allow inserting duplicate NULL rows in a nullable
 20    # unique field? All core backends implement this correctly, but other
 21    # databases such as SQL Server do not.
 22    supports_nullable_unique_constraints = True
 23
 24    # Does the backend support initially deferrable unique constraints?
 25    supports_deferrable_unique_constraints = False
 26
 27    can_use_chunked_reads = True
 28    can_return_columns_from_insert = False
 29    can_return_rows_from_bulk_insert = False
 30    has_bulk_insert = True
 31    uses_savepoints = True
 32    can_release_savepoints = False
 33
 34    # If True, don't use integer foreign keys referring to, e.g., positive
 35    # integer primary keys.
 36    related_fields_match_type = False
 37    allow_sliced_subqueries_with_in = True
 38    has_select_for_update = False
 39    has_select_for_update_nowait = False
 40    has_select_for_update_skip_locked = False
 41    has_select_for_update_of = False
 42    has_select_for_no_key_update = False
 43    # Does the database's SELECT FOR UPDATE OF syntax require a column rather
 44    # than a table?
 45    select_for_update_of_column = False
 46
 47    # Does the default test database allow multiple connections?
 48    # Usually an indication that the test database is in-memory
 49    test_db_allows_multiple_connections = True
 50
 51    # Can an object be saved without an explicit primary key?
 52    supports_unspecified_pk = False
 53
 54    # Can a fixture contain forward references? i.e., are
 55    # FK constraints checked at the end of transaction, or
 56    # at the end of each save operation?
 57    supports_forward_references = True
 58
 59    # Does the backend truncate names properly when they are too long?
 60    truncates_names = False
 61
 62    # Is there a REAL datatype in addition to floats/doubles?
 63    has_real_datatype = False
 64    supports_subqueries_in_group_by = True
 65
 66    # Does the backend ignore unnecessary ORDER BY clauses in subqueries?
 67    ignores_unnecessary_order_by_in_subqueries = True
 68
 69    # Is there a true datatype for uuid?
 70    has_native_uuid_field = False
 71
 72    # Is there a true datatype for timedeltas?
 73    has_native_duration_field = False
 74
 75    # Does the database driver supports same type temporal data subtraction
 76    # by returning the type used to store duration field?
 77    supports_temporal_subtraction = False
 78
 79    # Does the __regex lookup support backreferencing and grouping?
 80    supports_regex_backreferencing = True
 81
 82    # Can date/datetime lookups be performed using a string?
 83    supports_date_lookup_using_string = True
 84
 85    # Can datetimes with timezones be used?
 86    supports_timezones = True
 87
 88    # Does the database have a copy of the zoneinfo database?
 89    has_zoneinfo_database = True
 90
 91    # When performing a GROUP BY, is an ORDER BY NULL required
 92    # to remove any ordering?
 93    requires_explicit_null_ordering_when_grouping = False
 94
 95    # Does the backend order NULL values as largest or smallest?
 96    nulls_order_largest = False
 97
 98    # Does the backend support NULLS FIRST and NULLS LAST in ORDER BY?
 99    supports_order_by_nulls_modifier = True
100
101    # Does the backend orders NULLS FIRST by default?
102    order_by_nulls_first = False
103
104    # The database's limit on the number of query parameters.
105    max_query_params = None
106
107    # Can an object have an autoincrement primary key of 0?
108    allows_auto_pk_0 = True
109
110    # Do we need to NULL a ForeignKey out, or can the constraint check be
111    # deferred
112    can_defer_constraint_checks = False
113
114    # Does the backend support tablespaces? Default to False because it isn't
115    # in the SQL standard.
116    supports_tablespaces = False
117
118    # Does the backend reset sequences between tests?
119    supports_sequence_reset = True
120
121    # Can the backend introspect the default value of a column?
122    can_introspect_default = True
123
124    # Confirm support for introspected foreign keys
125    # Every database can do this reliably, except MySQL,
126    # which can't do it for MyISAM tables
127    can_introspect_foreign_keys = True
128
129    # Map fields which some backends may not be able to differentiate to the
130    # field it's introspected as.
131    introspected_field_types = {
132        "AutoField": "AutoField",
133        "BigAutoField": "BigAutoField",
134        "BigIntegerField": "BigIntegerField",
135        "BinaryField": "BinaryField",
136        "BooleanField": "BooleanField",
137        "CharField": "CharField",
138        "DurationField": "DurationField",
139        "GenericIPAddressField": "GenericIPAddressField",
140        "IntegerField": "IntegerField",
141        "PositiveBigIntegerField": "PositiveBigIntegerField",
142        "PositiveIntegerField": "PositiveIntegerField",
143        "PositiveSmallIntegerField": "PositiveSmallIntegerField",
144        "SmallAutoField": "SmallAutoField",
145        "SmallIntegerField": "SmallIntegerField",
146        "TimeField": "TimeField",
147    }
148
149    # Can the backend introspect the column order (ASC/DESC) for indexes?
150    supports_index_column_ordering = True
151
152    # Does the backend support introspection of materialized views?
153    can_introspect_materialized_views = False
154
155    # Support for the DISTINCT ON clause
156    can_distinct_on_fields = False
157
158    # Does the backend prevent running SQL queries in broken transactions?
159    atomic_transactions = True
160
161    # Can we roll back DDL in a transaction?
162    can_rollback_ddl = False
163
164    schema_editor_uses_clientside_param_binding = False
165
166    # Does it support operations requiring references rename in a transaction?
167    supports_atomic_references_rename = True
168
169    # Can we issue more than one ALTER COLUMN clause in an ALTER TABLE?
170    supports_combined_alters = False
171
172    # Does it support foreign keys?
173    supports_foreign_keys = True
174
175    # Can it create foreign key constraints inline when adding columns?
176    can_create_inline_fk = True
177
178    # Can an index be renamed?
179    can_rename_index = False
180
181    # Does it automatically index foreign keys?
182    indexes_foreign_keys = True
183
184    # Does it support CHECK constraints?
185    supports_column_check_constraints = True
186    supports_table_check_constraints = True
187    # Does the backend support introspection of CHECK constraints?
188    can_introspect_check_constraints = True
189
190    # Does the backend support 'pyformat' style ("... %(name)s ...", {'name': value})
191    # parameter passing? Note this can be provided by the backend even if not
192    # supported by the Python driver
193    supports_paramstyle_pyformat = True
194
195    # Does the backend require literal defaults, rather than parameterized ones?
196    requires_literal_defaults = False
197
198    # Does the backend require a connection reset after each material schema change?
199    connection_persists_old_columns = False
200
201    # What kind of error does the backend throw when accessing closed cursor?
202    closed_cursor_error_class = ProgrammingError
203
204    # Does 'a' LIKE 'A' match?
205    has_case_insensitive_like = False
206
207    # Suffix for backends that don't support "SELECT xxx;" queries.
208    bare_select_suffix = ""
209
210    # If NULL is implied on columns without needing to be explicitly specified
211    implied_column_null = False
212
213    # Does the backend support "select for update" queries with limit (and offset)?
214    supports_select_for_update_with_limit = True
215
216    # Does the backend ignore null expressions in GREATEST and LEAST queries unless
217    # every expression is null?
218    greatest_least_ignores_nulls = False
219
220    # Can the backend clone databases for parallel test execution?
221    # Defaults to False to allow third-party backends to opt-in.
222    can_clone_databases = False
223
224    # Does the backend consider table names with different casing to
225    # be equal?
226    ignores_table_name_case = False
227
228    # Place FOR UPDATE right after FROM clause. Used on MSSQL.
229    for_update_after_from = False
230
231    # Combinatorial flags
232    supports_select_union = True
233    supports_select_intersection = True
234    supports_select_difference = True
235    supports_slicing_ordering_in_compound = False
236    supports_parentheses_in_compound = True
237    requires_compound_order_by_subquery = False
238
239    # Does the database support SQL 2003 FILTER (WHERE ...) in aggregate
240    # expressions?
241    supports_aggregate_filter_clause = False
242
243    # Does the backend support indexing a TextField?
244    supports_index_on_text_field = True
245
246    # Does the backend support window expressions (expression OVER (...))?
247    supports_over_clause = False
248    supports_frame_range_fixed_distance = False
249    only_supports_unbounded_with_preceding_and_following = False
250
251    # Does the backend support CAST with precision?
252    supports_cast_with_precision = True
253
254    # How many second decimals does the database return when casting a value to
255    # a type with time?
256    time_cast_precision = 6
257
258    # SQL to create a procedure for use by the Plain test suite. The
259    # functionality of the procedure isn't important.
260    create_test_procedure_without_params_sql = None
261    create_test_procedure_with_int_param_sql = None
262
263    # SQL to create a table with a composite primary key for use by the Plain
264    # test suite.
265    create_test_table_with_composite_primary_key = None
266
267    # Does the backend support keyword parameters for cursor.callproc()?
268    supports_callproc_kwargs = False
269
270    # What formats does the backend EXPLAIN syntax support?
271    supported_explain_formats = set()
272
273    # Does the backend support the default parameter in lead() and lag()?
274    supports_default_in_lead_lag = True
275
276    # Does the backend support ignoring constraint or uniqueness errors during
277    # INSERT?
278    supports_ignore_conflicts = True
279    # Does the backend support updating rows on constraint or uniqueness errors
280    # during INSERT?
281    supports_update_conflicts = False
282    supports_update_conflicts_with_target = False
283
284    # Does this backend require casting the results of CASE expressions used
285    # in UPDATE statements to ensure the expression has the correct type?
286    requires_casted_case_in_updates = False
287
288    # Does the backend support partial indexes (CREATE INDEX ... WHERE ...)?
289    supports_partial_indexes = True
290    supports_functions_in_partial_indexes = True
291    # Does the backend support covering indexes (CREATE INDEX ... INCLUDE ...)?
292    supports_covering_indexes = False
293    # Does the backend support indexes on expressions?
294    supports_expression_indexes = True
295    # Does the backend treat COLLATE as an indexed expression?
296    collate_as_index_expression = False
297
298    # Does the backend support boolean expressions in SELECT and GROUP BY
299    # clauses?
300    supports_boolean_expr_in_select_clause = True
301    # Does the backend support comparing boolean expressions in WHERE clauses?
302    # Eg: WHERE (price > 0) IS NOT NULL
303    supports_comparing_boolean_expr = True
304
305    # Does the backend support JSONField?
306    supports_json_field = True
307    # Can the backend introspect a JSONField?
308    can_introspect_json_field = True
309    # Does the backend support primitives in JSONField?
310    supports_primitives_in_json_field = True
311    # Is there a true datatype for JSON?
312    has_native_json_field = False
313    # Does the backend use PostgreSQL-style JSON operators like '->'?
314    has_json_operators = False
315    # Does the backend support __contains and __contained_by lookups for
316    # a JSONField?
317    supports_json_field_contains = True
318    # Does value__d__contains={'f': 'g'} (without a list around the dict) match
319    # {'d': [{'f': 'g'}]}?
320    json_key_contains_list_matching_requires_list = False
321    # Does the backend support JSONObject() database function?
322    has_json_object_function = True
323
324    # Does the backend support column collations?
325    supports_collation_on_charfield = True
326    supports_collation_on_textfield = True
327    # Does the backend support non-deterministic collations?
328    supports_non_deterministic_collations = True
329
330    # Does the backend support column and table comments?
331    supports_comments = False
332    # Does the backend support column comments in ADD COLUMN statements?
333    supports_comments_inline = False
334
335    # Does the backend support the logical XOR operator?
336    supports_logical_xor = False
337
338    # Set to (exception, message) if null characters in text are disallowed.
339    prohibits_null_characters_in_text_exception = None
340
341    # Does the backend support unlimited character columns?
342    supports_unlimited_charfield = False
343
344    # Collation names for use by the Plain test suite.
345    test_collations = {
346        "ci": None,  # Case-insensitive.
347        "cs": None,  # Case-sensitive.
348        "non_default": None,  # Non-default.
349        "swedish_ci": None,  # Swedish case-insensitive.
350    }
351    # SQL template override for tests.aggregation.tests.NowUTC
352    test_now_utc_template = None
353
354    def __init__(self, connection):
355        self.connection = connection
356
357    @cached_property
358    def supports_explaining_query_execution(self):
359        """Does this backend support explaining query execution?"""
360        return self.connection.ops.explain_prefix is not None
361
362    @cached_property
363    def supports_transactions(self):
364        """Confirm support for transactions."""
365        with self.connection.cursor() as cursor:
366            cursor.execute("CREATE TABLE ROLLBACK_TEST (X INT)")
367            self.connection.set_autocommit(False)
368            cursor.execute("INSERT INTO ROLLBACK_TEST (X) VALUES (8)")
369            self.connection.rollback()
370            self.connection.set_autocommit(True)
371            cursor.execute("SELECT COUNT(X) FROM ROLLBACK_TEST")
372            (count,) = cursor.fetchone()
373            cursor.execute("DROP TABLE ROLLBACK_TEST")
374        return count == 0
375
376    def allows_group_by_selected_pks_on_model(self, model):
377        if not self.allows_group_by_selected_pks:
378            return False
379        return model._meta.managed