mirror of https://github.com/django/django.git
Fixed #23147 -- Disabled a limit/offset on a query with select_for_update on Oracle.
Thanks Shai Berger and Tim Graham for the reviews.
This commit is contained in:
parent
08df3dd937
commit
695d4dd790
|
@ -1,3 +1,4 @@
|
||||||
|
from django.db import NotSupportedError
|
||||||
from django.db.models.sql import compiler
|
from django.db.models.sql import compiler
|
||||||
|
|
||||||
|
|
||||||
|
@ -17,6 +18,11 @@ class SQLCompiler(compiler.SQLCompiler):
|
||||||
do_offset = with_limits and (self.query.high_mark is not None or self.query.low_mark)
|
do_offset = with_limits and (self.query.high_mark is not None or self.query.low_mark)
|
||||||
if not do_offset:
|
if not do_offset:
|
||||||
sql, params = super().as_sql(with_limits=False, with_col_aliases=with_col_aliases)
|
sql, params = super().as_sql(with_limits=False, with_col_aliases=with_col_aliases)
|
||||||
|
elif not self.connection.features.supports_select_for_update_with_limit and self.query.select_for_update:
|
||||||
|
raise NotSupportedError(
|
||||||
|
'LIMIT/OFFSET not supported with select_for_update on this '
|
||||||
|
'database backend.'
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
sql, params = super().as_sql(with_limits=False, with_col_aliases=True)
|
sql, params = super().as_sql(with_limits=False, with_col_aliases=True)
|
||||||
# Wrap the base query in an outer SELECT * with boundaries on
|
# Wrap the base query in an outer SELECT * with boundaries on
|
||||||
|
|
|
@ -10,7 +10,7 @@ from django.db.models.sql.constants import (
|
||||||
)
|
)
|
||||||
from django.db.models.sql.query import Query, get_order_dir
|
from django.db.models.sql.query import Query, get_order_dir
|
||||||
from django.db.transaction import TransactionManagementError
|
from django.db.transaction import TransactionManagementError
|
||||||
from django.db.utils import DatabaseError
|
from django.db.utils import DatabaseError, NotSupportedError
|
||||||
|
|
||||||
FORCE = object()
|
FORCE = object()
|
||||||
|
|
||||||
|
@ -460,6 +460,11 @@ class SQLCompiler:
|
||||||
if self.connection.get_autocommit():
|
if self.connection.get_autocommit():
|
||||||
raise TransactionManagementError('select_for_update cannot be used outside of a transaction.')
|
raise TransactionManagementError('select_for_update cannot be used outside of a transaction.')
|
||||||
|
|
||||||
|
if with_limits and not self.connection.features.supports_select_for_update_with_limit:
|
||||||
|
raise NotSupportedError(
|
||||||
|
'LIMIT/OFFSET not supported with select_for_update'
|
||||||
|
' on this database backend.'
|
||||||
|
)
|
||||||
nowait = self.query.select_for_update_nowait
|
nowait = self.query.select_for_update_nowait
|
||||||
skip_locked = self.query.select_for_update_skip_locked
|
skip_locked = self.query.select_for_update_skip_locked
|
||||||
# If it's a NOWAIT/SKIP LOCKED query but the backend
|
# If it's a NOWAIT/SKIP LOCKED query but the backend
|
||||||
|
|
|
@ -5,7 +5,8 @@ from unittest import mock
|
||||||
from multiple_database.routers import TestRouter
|
from multiple_database.routers import TestRouter
|
||||||
|
|
||||||
from django.db import (
|
from django.db import (
|
||||||
DatabaseError, connection, connections, router, transaction,
|
DatabaseError, NotSupportedError, connection, connections, router,
|
||||||
|
transaction,
|
||||||
)
|
)
|
||||||
from django.test import (
|
from django.test import (
|
||||||
TransactionTestCase, override_settings, skipIfDBFeature,
|
TransactionTestCase, override_settings, skipIfDBFeature,
|
||||||
|
@ -179,6 +180,20 @@ class SelectForUpdateTests(TransactionTestCase):
|
||||||
with self.assertRaises(transaction.TransactionManagementError):
|
with self.assertRaises(transaction.TransactionManagementError):
|
||||||
list(people)
|
list(people)
|
||||||
|
|
||||||
|
@skipUnlessDBFeature('supports_select_for_update_with_limit')
|
||||||
|
def test_select_for_update_with_limit(self):
|
||||||
|
other = Person.objects.create(name='Grappeli')
|
||||||
|
with transaction.atomic():
|
||||||
|
qs = list(Person.objects.all().order_by('pk').select_for_update()[1:2])
|
||||||
|
self.assertEqual(qs[0], other)
|
||||||
|
|
||||||
|
@skipIfDBFeature('supports_select_for_update_with_limit')
|
||||||
|
def test_unsupported_select_for_update_with_limit(self):
|
||||||
|
msg = 'LIMIT/OFFSET not supported with select_for_update on this database backend.'
|
||||||
|
with self.assertRaisesMessage(NotSupportedError, msg):
|
||||||
|
with transaction.atomic():
|
||||||
|
list(Person.objects.all().order_by('pk').select_for_update()[1:2])
|
||||||
|
|
||||||
def run_select_for_update(self, status, **kwargs):
|
def run_select_for_update(self, status, **kwargs):
|
||||||
"""
|
"""
|
||||||
Utility method that runs a SELECT FOR UPDATE against all
|
Utility method that runs a SELECT FOR UPDATE against all
|
||||||
|
|
Loading…
Reference in New Issue