Pārlūkot izejas kodu

Updated DatabaseFeatures.bare_select_suffix on Oracle 23c.

https://docs.oracle.com/en/database/oracle/oracle-database/23/nfcoa/application-development.html#GUID-4EB70EB9-4EE3-4FE2-99C4-86F7AAC60F12
Nick Pope 1 gadu atpakaļ
vecāks
revīzija
c72001644f

+ 6 - 2
django/db/backends/oracle/features.py

@@ -37,7 +37,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
     requires_literal_defaults = True
     supports_default_keyword_in_bulk_insert = False
     closed_cursor_error_class = InterfaceError
-    bare_select_suffix = " FROM DUAL"
     # Select for update with limit can be achieved on Oracle, but not with the
     # current backend.
     supports_select_for_update_with_limit = False
@@ -159,9 +158,10 @@ class DatabaseFeatures(BaseDatabaseFeatures):
 
     @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("SELECT CAST('a' AS VARCHAR2(4001)) FROM dual")
+                cursor.execute(sql)
             except DatabaseError as e:
                 if e.args[0].code == 910:
                     return False
@@ -183,3 +183,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
     @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"

+ 5 - 2
django/db/backends/oracle/operations.py

@@ -54,7 +54,7 @@ BEGIN
     SELECT NVL(last_number - cache_size, 0) INTO seq_value FROM user_sequences
            WHERE sequence_name = seq_name;
     WHILE table_value > seq_value LOOP
-        EXECUTE IMMEDIATE 'SELECT "'||seq_name||'".nextval FROM DUAL'
+        EXECUTE IMMEDIATE 'SELECT "'||seq_name||'".nextval%(suffix)s'
         INTO seq_value;
     END LOOP;
 END;
@@ -527,6 +527,7 @@ END;
                 "column": column,
                 "table_name": strip_quotes(table),
                 "column_name": strip_quotes(column),
+                "suffix": self.connection.features.bare_select_suffix,
             }
             sql.append(query)
         return sql
@@ -550,6 +551,7 @@ END;
                             "column": column,
                             "table_name": strip_quotes(table),
                             "column_name": strip_quotes(column),
+                            "suffix": self.connection.features.bare_select_suffix,
                         }
                     )
                     # Only one AutoField is allowed per model, so don't
@@ -683,7 +685,8 @@ END;
                 if not query:
                     placeholder = "%s col_%s" % (placeholder, i)
                 select.append(placeholder)
-            query.append("SELECT %s FROM DUAL" % ", ".join(select))
+            suffix = self.connection.features.bare_select_suffix
+            query.append(f"SELECT %s{suffix}" % ", ".join(select))
         # Bulk insert to tables with Oracle identity columns causes Oracle to
         # add sequence.nextval to it. Sequence.nextval cannot be used with the
         # UNION operator. To prevent incorrect SQL, move UNION to a subquery.

+ 3 - 2
django/db/models/functions/text.py

@@ -261,13 +261,14 @@ class Reverse(Transform):
     def as_oracle(self, compiler, connection, **extra_context):
         # REVERSE in Oracle is undocumented and doesn't support multi-byte
         # strings. Use a special subquery instead.
+        suffix = connection.features.bare_select_suffix
         sql, params = super().as_sql(
             compiler,
             connection,
             template=(
                 "(SELECT LISTAGG(s) WITHIN GROUP (ORDER BY n DESC) FROM "
-                "(SELECT LEVEL n, SUBSTR(%(expressions)s, LEVEL, 1) s "
-                "FROM DUAL CONNECT BY LEVEL <= LENGTH(%(expressions)s)) "
+                f"(SELECT LEVEL n, SUBSTR(%(expressions)s, LEVEL, 1) s{suffix} "
+                "CONNECT BY LEVEL <= LENGTH(%(expressions)s)) "
                 "GROUP BY %(expressions)s)"
             ),
             **extra_context,

+ 2 - 1
tests/backends/oracle/tests.py

@@ -43,8 +43,9 @@ class Tests(TestCase):
         An 'almost right' datetime works with configured NLS parameters
         (#18465).
         """
+        suffix = connection.features.bare_select_suffix
         with connection.cursor() as cursor:
-            query = "select 1 from dual where '1936-12-29 00:00' < sysdate"
+            query = f"SELECT 1{suffix} WHERE '1936-12-29 00:00' < SYSDATE"
             # The query succeeds without errors - pre #18465 this
             # wasn't the case.
             cursor.execute(query)