mirror of
https://github.com/django/django.git
synced 2025-10-31 09:41:08 +00:00
Fixed #30375 -- Added FOR NO KEY UPDATE support to QuerySet.select_for_update() on PostgreSQL.
This commit is contained in:
committed by
Mariusz Felisiak
parent
0e893248b2
commit
a4e6030904
@@ -38,6 +38,7 @@ class BaseDatabaseFeatures:
|
||||
has_select_for_update_nowait = False
|
||||
has_select_for_update_skip_locked = False
|
||||
has_select_for_update_of = False
|
||||
has_select_for_no_key_update = False
|
||||
# Does the database's SELECT FOR UPDATE OF syntax require a column rather
|
||||
# than a table?
|
||||
select_for_update_of_column = False
|
||||
|
||||
@@ -207,11 +207,12 @@ class BaseDatabaseOperations:
|
||||
"""
|
||||
return []
|
||||
|
||||
def for_update_sql(self, nowait=False, skip_locked=False, of=()):
|
||||
def for_update_sql(self, nowait=False, skip_locked=False, of=(), no_key=False):
|
||||
"""
|
||||
Return the FOR UPDATE SQL clause to lock rows for an update operation.
|
||||
"""
|
||||
return 'FOR UPDATE%s%s%s' % (
|
||||
return 'FOR%s UPDATE%s%s%s' % (
|
||||
' NO KEY' if no_key else '',
|
||||
' OF %s' % ', '.join(of) if of else '',
|
||||
' NOWAIT' if nowait else '',
|
||||
' SKIP LOCKED' if skip_locked else '',
|
||||
|
||||
@@ -18,6 +18,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
||||
has_select_for_update_nowait = True
|
||||
has_select_for_update_of = True
|
||||
has_select_for_update_skip_locked = True
|
||||
has_select_for_no_key_update = True
|
||||
can_release_savepoints = True
|
||||
supports_tablespaces = True
|
||||
supports_transactions = True
|
||||
|
||||
@@ -1018,7 +1018,7 @@ class QuerySet:
|
||||
return self
|
||||
return self._combinator_query('difference', *other_qs)
|
||||
|
||||
def select_for_update(self, nowait=False, skip_locked=False, of=()):
|
||||
def select_for_update(self, nowait=False, skip_locked=False, of=(), no_key=False):
|
||||
"""
|
||||
Return a new QuerySet instance that will select objects with a
|
||||
FOR UPDATE lock.
|
||||
@@ -1031,6 +1031,7 @@ class QuerySet:
|
||||
obj.query.select_for_update_nowait = nowait
|
||||
obj.query.select_for_update_skip_locked = skip_locked
|
||||
obj.query.select_for_update_of = of
|
||||
obj.query.select_for_no_key_update = no_key
|
||||
return obj
|
||||
|
||||
def select_related(self, *fields):
|
||||
|
||||
@@ -546,19 +546,26 @@ class SQLCompiler:
|
||||
nowait = self.query.select_for_update_nowait
|
||||
skip_locked = self.query.select_for_update_skip_locked
|
||||
of = self.query.select_for_update_of
|
||||
# If it's a NOWAIT/SKIP LOCKED/OF query but the backend
|
||||
# doesn't support it, raise NotSupportedError to prevent a
|
||||
# possible deadlock.
|
||||
no_key = self.query.select_for_no_key_update
|
||||
# If it's a NOWAIT/SKIP LOCKED/OF/NO KEY query but the
|
||||
# backend doesn't support it, raise NotSupportedError to
|
||||
# prevent a possible deadlock.
|
||||
if nowait and not self.connection.features.has_select_for_update_nowait:
|
||||
raise NotSupportedError('NOWAIT is not supported on this database backend.')
|
||||
elif skip_locked and not self.connection.features.has_select_for_update_skip_locked:
|
||||
raise NotSupportedError('SKIP LOCKED is not supported on this database backend.')
|
||||
elif of and not self.connection.features.has_select_for_update_of:
|
||||
raise NotSupportedError('FOR UPDATE OF is not supported on this database backend.')
|
||||
elif no_key and not self.connection.features.has_select_for_no_key_update:
|
||||
raise NotSupportedError(
|
||||
'FOR NO KEY UPDATE is not supported on this '
|
||||
'database backend.'
|
||||
)
|
||||
for_update_part = self.connection.ops.for_update_sql(
|
||||
nowait=nowait,
|
||||
skip_locked=skip_locked,
|
||||
of=self.get_select_for_update_of_arguments(),
|
||||
no_key=no_key,
|
||||
)
|
||||
|
||||
if for_update_part and self.connection.features.for_update_after_from:
|
||||
|
||||
@@ -189,6 +189,7 @@ class Query(BaseExpression):
|
||||
self.select_for_update_nowait = False
|
||||
self.select_for_update_skip_locked = False
|
||||
self.select_for_update_of = ()
|
||||
self.select_for_no_key_update = False
|
||||
|
||||
self.select_related = False
|
||||
# Arbitrary limit for select_related to prevents infinite recursion.
|
||||
|
||||
Reference in New Issue
Block a user