Ticket #2705: for_update_8031.2.patch

File for_update_8031.2.patch, 7.9 KB (added by anih, 7 years ago)

patch against r8031

  • django/db/models/sql/query.py

     
    7070        self.order_by = []
    7171        self.low_mark, self.high_mark = 0, None  # Used for offset/limit
    7272        self.distinct = False
     73        self.select_for_update = False
     74        self.select_for_update_nowait = False
    7375        self.select_related = False
    7476        self.related_select_cols = []
    7577
     
    177179        obj.order_by = self.order_by[:]
    178180        obj.low_mark, obj.high_mark = self.low_mark, self.high_mark
    179181        obj.distinct = self.distinct
     182        obj.select_for_update = self.select_for_update
     183        obj.select_for_update_nowait = self.select_for_update_nowait
    180184        obj.select_related = self.select_related
    181185        obj.related_select_cols = []
    182186        obj.max_depth = self.max_depth
     
    215219        obj = self.clone()
    216220        obj.clear_ordering(True)
    217221        obj.clear_limits()
     222        obj.select_for_update = False
    218223        obj.select_related = False
    219224        obj.related_select_cols = []
    220225        obj.related_select_fields = []
     
    293298                        result.append('LIMIT %d' % val)
    294299                result.append('OFFSET %d' % self.low_mark)
    295300
     301        if self.select_for_update:
     302            result.append("%s" % self.connection.ops.for_update_sql(nowait=self.select_for_update_nowait))
     303
    296304        params.extend(self.extra_params)
    297305        return ' '.join(result), tuple(params)
    298306
  • django/db/models/manager.py

     
    108108    def order_by(self, *args, **kwargs):
    109109        return self.get_query_set().order_by(*args, **kwargs)
    110110
     111    def select_for_update(self, *args, **kwargs):
     112        return self.get_query_set().select_for_update(*args, **kwargs)
     113       
    111114    def select_related(self, *args, **kwargs):
    112115        return self.get_query_set().select_related(*args, **kwargs)
    113116
  • django/db/models/query.py

     
    372372        del_query = self._clone()
    373373
    374374        # Disable non-supported fields.
     375        del_query.query.select_for_update = False
    375376        del_query.query.select_related = False
    376377        del_query.query.clear_ordering()
    377378
     
    514515        else:
    515516            return self._filter_or_exclude(None, **filter_obj)
    516517
     518    def select_for_update(self, **kwargs):
     519        """
     520        Returns a new QuerySet instance that will select objects with a
     521        FOR UPDATE lock.
     522        """
     523        # Default to false for nowait
     524        nowait = kwargs.pop('nowait', False)
     525        obj = self._clone()
     526        obj.query.select_for_update = True
     527        obj.query.select_for_update_nowait = nowait
     528        return obj
     529
    517530    def select_related(self, *fields, **kwargs):
    518531        """
    519532        Returns a new QuerySet instance that will select related objects.
  • django/db/backends/sqlite3/base.py

     
    5757        # function django_date_trunc that's registered in connect().
    5858        return 'django_date_trunc("%s", %s)' % (lookup_type.lower(), field_name)
    5959
     60    def for_update_sql(self):
     61        # sqlite does not support FOR UPDATE
     62        return ''
     63
    6064    def drop_foreignkey_sql(self):
    6165        return ""
    6266
     
    179183        return bool(re.search(re_pattern, re_string))
    180184    except:
    181185        return False
     186
  • django/db/backends/mysql/base.py

     
    8989    def fulltext_search_sql(self, field_name):
    9090        return 'MATCH (%s) AGAINST (%%s IN BOOLEAN MODE)' % field_name
    9191
     92    def for_update_sql(self, nowait=False):
     93        """
     94        Return FOR UPDATE SQL clause to lock row for update
     95        Currently mysql ignores NOWAIT
     96        """
     97        if nowait:
     98            raise NotImplementedError("NOWAIT option for SELECT ... FOR UPDATE not implemented with mysql");
     99        BaseDatabaseWrapper.for_update_sql(self,nowait=False)
     100
     101
    92102    def no_limit_value(self):
    93103        # 2**64 - 1, as recommended by the MySQL documentation
    94104        return 18446744073709551615L
  • django/db/backends/__init__.py

     
    123123        """
    124124        return '%s'
    125125
     126    def for_update_sql(self, nowait=False):
     127        """
     128        Return FOR UPDATE SQL clause to lock row for update
     129        """
     130        if nowait:
     131            nowaitstr = ' NOWAIT'
     132        else:
     133            nowaitstr = ''
     134        return 'FOR UPDATE' + nowaitstr
     135
    126136    def fulltext_search_sql(self, field_name):
    127137        """
    128138        Returns the SQL WHERE clause to use in order to perform a full-text
  • tests/regressiontests/queries/models.py

     
    726726>>> Item.objects.exclude(~Q(tags__name='t1', name='one'), name='two')
    727727[<Item: four>, <Item: one>, <Item: three>]
    728728
     729Bug #2075
     730Added FOR UPDATE functionality
     731>>> from django.db import transaction
     732>>> @transaction.commit_manually
     733>>> def test_for_update():
     734>>>     t = Tag(name='for update test')
     735>>>     t.save()
     736>>>     transaction.commit()
     737>>>     tfound = Tag.objects.select_for_update().get(pk=t.id)
     738>>>     tfound.name = 'for update test 2'
     739>>>     tfound.save()
     740>>>     transaction.commit()
     741>>> test_for_update()
     742
    729743Bug #7095
    730744Updates that are filtered on the model being updated are somewhat tricky to get
    731745in MySQL. This exercises that case.
  • docs/db-api.txt

     
    10711071``extra()`` is new. Previously, you could attempt to pass parameters for
    10721072``select`` in the ``params`` argument, but it worked very unreliably.
    10731073
     1074select_for_update
     1075~~~~~~~~~~~~~~~~~
     1076
     1077**New in Django development version:**
     1078
     1079Lock rows returned from a query. Most databases allow you to exclusively
     1080lock rows with ``select_for_update()``. To do this call the method
     1081``select_for_update()`` to lock all retrieved objects::
     1082
     1083    entry = Entry.objects.select_for_update().get(pk=1)
     1084    ...
     1085    entry.save()
     1086
     1087All objects returned using ``select_for_update()`` will be locked with an
     1088exclusive lock which will remain locked until the transaction has finished.
     1089In the case of using middleware, the locks will be released when the view
     1090returns and the transaction is committed or rolled back. SQLite does not
     1091support an exclusive lock so this is simply ignored for SQLite. Other
     1092databases issue a ``FOR UPDATE``.
     1093
     1094If you would not like to wait for the lock then set the parameter nowait to
     1095True. In this case, it will grab the lock if it isn't already locked. If
     1096it is locked then it will throw an exception. This is not supported
     1097with mysql. Doing this with mysql will raise a ``NotImplemented`` exception.
     1098
     1099Note that all rows returned are locked.  If you retrieve multiple objects,
     1100all objects will be locked until the transaction is committed. Another
     1101process which does a ``select_for_update()`` on the same rows will wait until
     1102the transaction which has the locks is finished.
     1103
    10741104QuerySet methods that do not return QuerySets
    10751105---------------------------------------------
    10761106
Back to Top