summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--django/db/backends/oracle/features.py6
-rw-r--r--django/db/backends/sqlite3/features.py1
-rw-r--r--django/db/models/fields/tuple_lookups.py11
3 files changed, 16 insertions, 2 deletions
diff --git a/django/db/backends/oracle/features.py b/django/db/backends/oracle/features.py
index b6980ad1a5..559a36bfed 100644
--- a/django/db/backends/oracle/features.py
+++ b/django/db/backends/oracle/features.py
@@ -80,7 +80,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
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).
@@ -217,3 +216,8 @@ class DatabaseFeatures(BaseDatabaseFeatures):
@cached_property
def bare_select_suffix(self):
return "" if self.connection.oracle_version >= (23,) else " FROM DUAL"
+
+ @cached_property
+ def supports_tuple_lookups(self):
+ # Support is known to be missing on 23.2 but available on 23.4.
+ return self.connection.oracle_version >= (23, 4)
diff --git a/django/db/backends/sqlite3/features.py b/django/db/backends/sqlite3/features.py
index 6ab6308ece..60893561df 100644
--- a/django/db/backends/sqlite3/features.py
+++ b/django/db/backends/sqlite3/features.py
@@ -61,7 +61,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
insert_test_table_with_defaults = 'INSERT INTO {} ("null") VALUES (1)'
supports_default_keyword_in_insert = False
supports_unlimited_charfield = True
- supports_tuple_lookups = False
@cached_property
def django_test_skips(self):
diff --git a/django/db/models/fields/tuple_lookups.py b/django/db/models/fields/tuple_lookups.py
index 1e77f095c8..b45bcaf2cd 100644
--- a/django/db/models/fields/tuple_lookups.py
+++ b/django/db/models/fields/tuple_lookups.py
@@ -27,6 +27,17 @@ class Tuple(Func):
def __iter__(self):
return iter(self.source_expressions)
+ def as_sqlite(self, compiler, connection):
+ if connection.get_database_version() < (3, 37) and isinstance(
+ first_expr := self.source_expressions[0], Tuple
+ ):
+ first_expr = first_expr.copy()
+ first_expr.function = "VALUES"
+ return Tuple(first_expr, *self.source_expressions[1:]).as_sql(
+ compiler, connection
+ )
+ return self.as_sql(compiler, connection)
+
class TupleLookupMixin:
allows_composite_expressions = True