diff --git a/CHANGELOG b/CHANGELOG index a711135aa0..1e657e5939 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +* Add has_select_for on Database * Store custom report translation in separate module * Add form action keyword for set/synchronize translation on report and view * Add negative value for col attribute diff --git a/trytond/backend/database.py b/trytond/backend/database.py index d825c6be27..a2f0402782 100644 --- a/trytond/backend/database.py +++ b/trytond/backend/database.py @@ -151,3 +151,7 @@ class DatabaseInterface(object): def has_multirow_insert(self): 'Return True if database supports multirow insert' return False + + def has_select_for(self): + "Return if database supports FOR UPDATE/SHARE clause in SELECT." + return False diff --git a/trytond/backend/postgresql/database.py b/trytond/backend/postgresql/database.py index 2cb8d35c00..262bd8689b 100644 --- a/trytond/backend/postgresql/database.py +++ b/trytond/backend/postgresql/database.py @@ -295,6 +295,9 @@ class Database(DatabaseInterface): self.put_connection(connection) return self._has_returning + def has_select_for(self): + return True + register_type(UNICODE) if PYDATE: register_type(PYDATE) diff --git a/trytond/ir/sequence.py b/trytond/ir/sequence.py index 261f13f005..ca56adf3bf 100644 --- a/trytond/ir/sequence.py +++ b/trytond/ir/sequence.py @@ -3,7 +3,7 @@ from string import Template import time from itertools import izip -from sql import Flavor +from sql import Flavor, Literal, For from ..model import ModelView, ModelSQL, fields, Check from ..tools import datetime_strftime @@ -354,7 +354,7 @@ class Sequence(ModelSQL, ModelView): return '' @classmethod - def get_id(cls, domain): + def get_id(cls, domain, _lock=False): ''' Return sequence value for the domain ''' @@ -370,6 +370,19 @@ class Sequence(ModelSQL, ModelView): sequence, = cls.search(domain, limit=1) except TypeError: cls.raise_user_error('missing') + if _lock: + transaction = Transaction() + database = transaction.database + connection = transaction.connection + if not database.has_select_for(): + database.lock(connection, cls._table) + else: + table = cls.__table__() + query = table.select(Literal(1), + where=table.id == sequence.id, + for_=For('UPDATE', nowait=True)) + cursor = connection.cursor() + cursor.execute(*query) date = Transaction().context.get('date') return '%s%s%s' % ( cls._process(sequence.prefix, date=date), @@ -390,6 +403,4 @@ class SequenceStrict(Sequence): @classmethod def get_id(cls, clause): - transaction = Transaction() - transaction.database.lock(transaction.connection, cls._table) - return super(SequenceStrict, cls).get_id(clause) + return super(SequenceStrict, cls).get_id(clause, _lock=True) diff --git a/trytond/tests/test_sequence.py b/trytond/tests/test_sequence.py index e73aef715c..9091cd1eef 100644 --- a/trytond/tests/test_sequence.py +++ b/trytond/tests/test_sequence.py @@ -16,11 +16,15 @@ class SequenceTestCase(unittest.TestCase): def setUpClass(cls): activate_module('tests') + @staticmethod + def get_model(): + pool = Pool() + return pool.get('ir.sequence') + @with_transaction() def test_incremental(self): 'Test incremental' - pool = Pool() - Sequence = pool.get('ir.sequence') + Sequence = self.get_model() sequence, = Sequence.create([{ 'name': 'Test incremental', @@ -48,8 +52,7 @@ class SequenceTestCase(unittest.TestCase): @with_transaction() def test_decimal_timestamp(self): 'Test Decimal Timestamp' - pool = Pool() - Sequence = pool.get('ir.sequence') + Sequence = self.get_model() sequence, = Sequence.create([{ 'name': 'Test decimal timestamp', @@ -73,8 +76,7 @@ class SequenceTestCase(unittest.TestCase): @with_transaction() def test_hexadecimal_timestamp(self): 'Test Hexadecimal Timestamp' - pool = Pool() - Sequence = pool.get('ir.sequence') + Sequence = self.get_model() sequence, = Sequence.create([{ 'name': 'Test hexadecimal timestamp', @@ -99,8 +101,7 @@ class SequenceTestCase(unittest.TestCase): @with_transaction() def test_prefix_suffix(self): 'Test prefix/suffix' - pool = Pool() - Sequence = pool.get('ir.sequence') + Sequence = self.get_model() sequence, = Sequence.create([{ 'name': 'Test incremental', @@ -121,5 +122,19 @@ class SequenceTestCase(unittest.TestCase): '2010-08-15/2/15.08.2010') +class SequenceStrictTestCase(SequenceTestCase): + "Test Sequence Strict" + + @staticmethod + def get_model(): + pool = Pool() + return pool.get('ir.sequence.strict') + + def suite(): - return unittest.TestLoader().loadTestsFromTestCase(SequenceTestCase) + suite_ = unittest.TestSuite() + suite_.addTests(unittest.TestLoader().loadTestsFromTestCase( + SequenceTestCase)) + suite_.addTests(unittest.TestLoader().loadTestsFromTestCase( + SequenceStrictTestCase)) + return suite_