|
@@ -96,9 +96,20 @@ class TupleLookupMixin:
|
|
|
)
|
|
|
return "(%s)" % sql, params
|
|
|
|
|
|
+ def get_fallback_sql(self, compiler, connection):
|
|
|
+ raise NotImplementedError(
|
|
|
+ f"{self.__class__.__name__}.get_fallback_sql() must be implemented "
|
|
|
+ f"for backends that don't have the supports_tuple_lookups feature enabled."
|
|
|
+ )
|
|
|
+
|
|
|
+ def as_sql(self, compiler, connection):
|
|
|
+ if not connection.features.supports_tuple_lookups:
|
|
|
+ return self.get_fallback_sql(compiler, connection)
|
|
|
+ return super().as_sql(compiler, connection)
|
|
|
+
|
|
|
|
|
|
class TupleExact(TupleLookupMixin, Exact):
|
|
|
- def as_oracle(self, compiler, connection):
|
|
|
+ def get_fallback_sql(self, compiler, connection):
|
|
|
# Process right-hand-side to trigger sanitization.
|
|
|
self.process_rhs(compiler, connection)
|
|
|
# e.g.: (a, b, c) == (x, y, z) as SQL:
|
|
@@ -132,7 +143,7 @@ class TupleIsNull(TupleLookupMixin, IsNull):
|
|
|
|
|
|
|
|
|
class TupleGreaterThan(TupleLookupMixin, GreaterThan):
|
|
|
- def as_oracle(self, compiler, connection):
|
|
|
+ def get_fallback_sql(self, compiler, connection):
|
|
|
# Process right-hand-side to trigger sanitization.
|
|
|
self.process_rhs(compiler, connection)
|
|
|
# e.g.: (a, b, c) > (x, y, z) as SQL:
|
|
@@ -160,7 +171,7 @@ class TupleGreaterThan(TupleLookupMixin, GreaterThan):
|
|
|
|
|
|
|
|
|
class TupleGreaterThanOrEqual(TupleLookupMixin, GreaterThanOrEqual):
|
|
|
- def as_oracle(self, compiler, connection):
|
|
|
+ def get_fallback_sql(self, compiler, connection):
|
|
|
# Process right-hand-side to trigger sanitization.
|
|
|
self.process_rhs(compiler, connection)
|
|
|
# e.g.: (a, b, c) >= (x, y, z) as SQL:
|
|
@@ -188,7 +199,7 @@ class TupleGreaterThanOrEqual(TupleLookupMixin, GreaterThanOrEqual):
|
|
|
|
|
|
|
|
|
class TupleLessThan(TupleLookupMixin, LessThan):
|
|
|
- def as_oracle(self, compiler, connection):
|
|
|
+ def get_fallback_sql(self, compiler, connection):
|
|
|
# Process right-hand-side to trigger sanitization.
|
|
|
self.process_rhs(compiler, connection)
|
|
|
# e.g.: (a, b, c) < (x, y, z) as SQL:
|
|
@@ -216,7 +227,7 @@ class TupleLessThan(TupleLookupMixin, LessThan):
|
|
|
|
|
|
|
|
|
class TupleLessThanOrEqual(TupleLookupMixin, LessThanOrEqual):
|
|
|
- def as_oracle(self, compiler, connection):
|
|
|
+ def get_fallback_sql(self, compiler, connection):
|
|
|
# Process right-hand-side to trigger sanitization.
|
|
|
self.process_rhs(compiler, connection)
|
|
|
# e.g.: (a, b, c) <= (x, y, z) as SQL:
|
|
@@ -315,17 +326,19 @@ class TupleIn(TupleLookupMixin, In):
|
|
|
|
|
|
return compiler.compile(Tuple(*result))
|
|
|
|
|
|
- def as_sql(self, compiler, connection):
|
|
|
- if not self.rhs_is_direct_value():
|
|
|
- return self.as_subquery(compiler, connection)
|
|
|
- return super().as_sql(compiler, connection)
|
|
|
+ def as_subquery_sql(self, compiler, connection):
|
|
|
+ lhs = self.lhs
|
|
|
+ rhs = self.rhs
|
|
|
+ if isinstance(lhs, ColPairs):
|
|
|
+ rhs = rhs.clone()
|
|
|
+ rhs.set_values([source.name for source in lhs.sources])
|
|
|
+ lhs = Tuple(lhs)
|
|
|
+ return compiler.compile(In(lhs, rhs))
|
|
|
|
|
|
- def as_sqlite(self, compiler, connection):
|
|
|
+ def get_fallback_sql(self, compiler, connection):
|
|
|
rhs = self.rhs
|
|
|
if not rhs:
|
|
|
raise EmptyResultSet
|
|
|
- if not self.rhs_is_direct_value():
|
|
|
- return self.as_subquery(compiler, connection)
|
|
|
|
|
|
# e.g.: (a, b, c) in [(x1, y1, z1), (x2, y2, z2)] as SQL:
|
|
|
# WHERE (a = x1 AND b = y1 AND c = z1) OR (a = x2 AND b = y2 AND c = z2)
|
|
@@ -338,14 +351,10 @@ class TupleIn(TupleLookupMixin, In):
|
|
|
|
|
|
return root.as_sql(compiler, connection)
|
|
|
|
|
|
- def as_subquery(self, compiler, connection):
|
|
|
- lhs = self.lhs
|
|
|
- rhs = self.rhs
|
|
|
- if isinstance(lhs, ColPairs):
|
|
|
- rhs = rhs.clone()
|
|
|
- rhs.set_values([source.name for source in lhs.sources])
|
|
|
- lhs = Tuple(lhs)
|
|
|
- return compiler.compile(In(lhs, rhs))
|
|
|
+ def as_sql(self, compiler, connection):
|
|
|
+ if not self.rhs_is_direct_value():
|
|
|
+ return self.as_subquery_sql(compiler, connection)
|
|
|
+ return super().as_sql(compiler, connection)
|
|
|
|
|
|
|
|
|
tuple_lookups = {
|