File: features.py

package info (click to toggle)
python-django 3%3A5.2.5-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 61,236 kB
  • sloc: python: 361,585; javascript: 19,250; xml: 211; makefile: 182; sh: 28
file content (223 lines) | stat: -rw-r--r-- 9,336 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
from django.db import DatabaseError, InterfaceError
from django.db.backends.base.features import BaseDatabaseFeatures
from django.db.backends.oracle.oracledb_any import is_oracledb
from django.utils.functional import cached_property


class DatabaseFeatures(BaseDatabaseFeatures):
    minimum_database_version = (19,)
    # Oracle crashes with "ORA-00932: inconsistent datatypes: expected - got
    # BLOB" when grouping by LOBs (#24096).
    allows_group_by_lob = False
    # Although GROUP BY select index is supported by Oracle 23c+, it requires
    # GROUP_BY_POSITION_ENABLED to be enabled to avoid backward compatibility
    # issues. Introspection of this settings is not straightforward.
    allows_group_by_select_index = False
    interprets_empty_strings_as_nulls = True
    has_select_for_update = True
    has_select_for_update_nowait = True
    has_select_for_update_skip_locked = True
    has_select_for_update_of = True
    select_for_update_of_column = True
    can_return_columns_from_insert = True
    supports_subqueries_in_group_by = False
    ignores_unnecessary_order_by_in_subqueries = False
    supports_transactions = True
    supports_timezones = False
    has_native_duration_field = True
    can_defer_constraint_checks = True
    supports_partially_nullable_unique_constraints = False
    supports_deferrable_unique_constraints = True
    truncates_names = True
    supports_comments = True
    supports_tablespaces = True
    supports_sequence_reset = False
    can_introspect_materialized_views = True
    atomic_transactions = False
    nulls_order_largest = True
    requires_literal_defaults = True
    supports_default_keyword_in_bulk_insert = False
    closed_cursor_error_class = InterfaceError
    # Select for update with limit can be achieved on Oracle, but not with the
    # current backend.
    supports_select_for_update_with_limit = False
    supports_temporal_subtraction = True
    # Oracle doesn't ignore quoted identifiers case but the current backend
    # does by uppercasing all identifiers.
    ignores_table_name_case = True
    supports_index_on_text_field = False
    create_test_procedure_without_params_sql = """
        CREATE PROCEDURE "TEST_PROCEDURE" AS
            V_I INTEGER;
        BEGIN
            V_I := 1;
        END;
    """
    create_test_procedure_with_int_param_sql = """
        CREATE PROCEDURE "TEST_PROCEDURE" (P_I INTEGER) AS
            V_I INTEGER;
        BEGIN
            V_I := P_I;
        END;
    """
    supports_callproc_kwargs = True
    supports_over_clause = True
    supports_frame_range_fixed_distance = True
    supports_ignore_conflicts = False
    max_query_params = 2**16 - 1
    supports_partial_indexes = False
    supports_stored_generated_columns = False
    supports_virtual_generated_columns = True
    can_rename_index = True
    supports_slicing_ordering_in_compound = True
    requires_compound_order_by_subquery = True
    allows_multiple_constraints_on_same_fields = False
    supports_json_field_contains = False
    supports_collation_on_textfield = False
    supports_tuple_lookups = False
    test_now_utc_template = "CURRENT_TIMESTAMP AT TIME ZONE 'UTC'"
    django_test_expected_failures = {
        # A bug in Django/oracledb with respect to string handling (#23843).
        "annotations.tests.NonAggregateAnnotationTestCase.test_custom_functions",
        "annotations.tests.NonAggregateAnnotationTestCase."
        "test_custom_functions_can_ref_other_functions",
    }
    insert_test_table_with_defaults = (
        "INSERT INTO {} VALUES (DEFAULT, DEFAULT, DEFAULT)"
    )

    @cached_property
    def django_test_skips(self):
        skips = {
            "Oracle doesn't support SHA224.": {
                "db_functions.text.test_sha224.SHA224Tests.test_basic",
                "db_functions.text.test_sha224.SHA224Tests.test_transform",
            },
            "Oracle doesn't correctly calculate ISO 8601 week numbering before "
            "1583 (the Gregorian calendar was introduced in 1582).": {
                "db_functions.datetime.test_extract_trunc.DateFunctionTests."
                "test_trunc_week_before_1000",
                "db_functions.datetime.test_extract_trunc."
                "DateFunctionWithTimeZoneTests.test_trunc_week_before_1000",
            },
            "Oracle doesn't support bitwise XOR.": {
                "expressions.tests.ExpressionOperatorTests.test_lefthand_bitwise_xor",
                "expressions.tests.ExpressionOperatorTests."
                "test_lefthand_bitwise_xor_null",
                "expressions.tests.ExpressionOperatorTests."
                "test_lefthand_bitwise_xor_right_null",
            },
            "Oracle requires ORDER BY in row_number, ANSI:SQL doesn't.": {
                "expressions_window.tests.WindowFunctionTests."
                "test_row_number_no_ordering",
                "prefetch_related.tests.PrefetchLimitTests.test_empty_order",
            },
            "Oracle doesn't support changing collations on indexed columns (#33671).": {
                "migrations.test_operations.OperationTests."
                "test_alter_field_pk_fk_db_collation",
            },
            "Oracle doesn't support comparing NCLOB to NUMBER.": {
                "generic_relations_regress.tests.GenericRelationTests."
                "test_textlink_filter",
            },
            "Oracle doesn't support casting filters to NUMBER.": {
                "lookup.tests.LookupQueryingTests.test_aggregate_combined_lookup",
            },
        }
        if self.connection.oracle_version < (23,):
            skips.update(
                {
                    "Raises ORA-00600 on Oracle < 23c: internal error code.": {
                        "model_fields.test_jsonfield.TestQuerying."
                        "test_usage_in_subquery",
                    },
                }
            )
        if self.connection.is_pool:
            skips.update(
                {
                    "Pooling does not support persistent connections": {
                        "backends.base.test_base.ConnectionHealthChecksTests."
                        "test_health_checks_enabled",
                        "backends.base.test_base.ConnectionHealthChecksTests."
                        "test_health_checks_enabled_errors_occurred",
                        "backends.base.test_base.ConnectionHealthChecksTests."
                        "test_health_checks_disabled",
                        "backends.base.test_base.ConnectionHealthChecksTests."
                        "test_set_autocommit_health_checks_enabled",
                        "servers.tests.LiveServerTestCloseConnectionTest."
                        "test_closes_connections",
                        "backends.oracle.tests.TransactionalTests."
                        "test_password_with_at_sign",
                    },
                }
            )
        if is_oracledb and self.connection.oracledb_version >= (2, 1, 2):
            skips.update(
                {
                    "python-oracledb 2.1.2+ no longer hides 'ORA-1403: no data found' "
                    "exceptions raised in database triggers.": {
                        "backends.oracle.tests.TransactionalTests."
                        "test_hidden_no_data_found_exception"
                    },
                },
            )
        return skips

    @cached_property
    def introspected_field_types(self):
        return {
            **super().introspected_field_types,
            "GenericIPAddressField": "CharField",
            "PositiveBigIntegerField": "BigIntegerField",
            "PositiveIntegerField": "IntegerField",
            "PositiveSmallIntegerField": "IntegerField",
            "SmallIntegerField": "IntegerField",
            "TimeField": "DateTimeField",
        }

    @cached_property
    def test_collations(self):
        return {
            "ci": "BINARY_CI",
            "cs": "BINARY",
            "non_default": "SWEDISH_CI",
            "swedish_ci": "SWEDISH_CI",
            "virtual": "SWEDISH_CI" if self.supports_collation_on_charfield else None,
        }

    @cached_property
    def supports_collation_on_charfield(self):
        sql = "SELECT CAST('a' AS VARCHAR2(4001))" + self.bare_select_suffix
        with self.connection.cursor() as cursor:
            try:
                cursor.execute(sql)
            except DatabaseError as e:
                if e.args[0].code == 910:
                    return False
                raise
            return True

    @cached_property
    def supports_primitives_in_json_field(self):
        return self.connection.oracle_version >= (21,)

    @cached_property
    def supports_frame_exclusion(self):
        return self.connection.oracle_version >= (21,)

    @cached_property
    def supports_boolean_expr_in_select_clause(self):
        return self.connection.oracle_version >= (23,)

    @cached_property
    def supports_comparing_boolean_expr(self):
        return self.connection.oracle_version >= (23,)

    @cached_property
    def supports_aggregation_over_interval_types(self):
        return self.connection.oracle_version >= (23,)

    @cached_property
    def bare_select_suffix(self):
        return "" if self.connection.oracle_version >= (23,) else " FROM DUAL"