Use SQL sequence on PostgreSQL for ir.sequence
Based on Openlabs module review79002
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
* Use SQL sequence on PostgreSQL for ir.sequence
|
||||
* Allow to specify more than one interface
|
||||
* Use unoconv for report format conversion
|
||||
* Allow to use any Opendocument as report template
|
||||
|
||||
@@ -2,6 +2,7 @@ Copyright (C) 2004-2008 Tiny SPRL.
|
||||
Copyright (C) 2007-2011 Cédric Krier.
|
||||
Copyright (C) 2007-2011 Bertrand Chenal.
|
||||
Copyright (C) 2008-2011 B2CK SPRL.
|
||||
Copyright (C) 2011 Openlabs Technologies & Consulting (P) Ltd.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
+130
-7
@@ -8,6 +8,10 @@ from trytond.tools import datetime_strftime
|
||||
from trytond.pyson import In, Eval, Not
|
||||
from trytond.transaction import Transaction
|
||||
from trytond.pool import Pool
|
||||
from trytond.config import CONFIG
|
||||
from trytond.backend import TableHandler
|
||||
|
||||
sql_sequence = CONFIG.options['db_type'] == 'postgresql'
|
||||
|
||||
|
||||
class SequenceType(ModelSQL, ModelView):
|
||||
@@ -24,6 +28,7 @@ class Sequence(ModelSQL, ModelView):
|
||||
"Sequence"
|
||||
_name = 'ir.sequence'
|
||||
_description = __doc__
|
||||
_strict = False
|
||||
name = fields.Char('Sequence Name', required=True, translate=True)
|
||||
code = fields.Selection('code_get', 'Sequence Code', required=True,
|
||||
states={
|
||||
@@ -37,10 +42,12 @@ class Sequence(ModelSQL, ModelView):
|
||||
('decimal timestamp', 'Decimal Timestamp'),
|
||||
('hexadecimal timestamp', 'Hexadecimal Timestamp'),
|
||||
], 'Type')
|
||||
number_next = fields.Integer('Next Number',
|
||||
number_next_internal = fields.Integer('Next Number',
|
||||
states={
|
||||
'invisible': Not(In(Eval('type'), ['incremental'])),
|
||||
}, depends=['type'])
|
||||
number_next = fields.Function(number_next_internal, 'get_number_next',
|
||||
'set_number_next')
|
||||
number_increment = fields.Integer('Increment Number',
|
||||
states={
|
||||
'invisible': Not(In(Eval('type'), ['incremental'])),
|
||||
@@ -77,6 +84,26 @@ class Sequence(ModelSQL, ModelView):
|
||||
'future_last_timestamp': 'Last Timestamp could not be in future!',
|
||||
})
|
||||
|
||||
def init(self, module_name):
|
||||
cursor = Transaction().cursor
|
||||
table = TableHandler(cursor, self, module_name)
|
||||
|
||||
# Migration from 2.0 rename number_next into number_next_internal
|
||||
table.column_rename('number_next', 'number_next_internal')
|
||||
|
||||
super(Sequence, self).init(module_name)
|
||||
|
||||
# Migration from 2.0 create sql_sequence
|
||||
if sql_sequence and not self._strict:
|
||||
sequence_ids = self.search([])
|
||||
for sequence in self.browse(sequence_ids):
|
||||
if sequence.type != 'incremental':
|
||||
continue
|
||||
if not TableHandler.sequence_exist(cursor,
|
||||
self._sql_sequence_name(sequence)):
|
||||
self.create_sql_sequence(sequence,
|
||||
sequence.number_next_internal)
|
||||
|
||||
def default_active(self):
|
||||
return True
|
||||
|
||||
@@ -104,6 +131,53 @@ class Sequence(ModelSQL, ModelView):
|
||||
def default_code(self):
|
||||
return Transaction().context.get('code', False)
|
||||
|
||||
def get_number_next(self, ids, name):
|
||||
cursor = Transaction().cursor
|
||||
result = {}
|
||||
for sequence in self.browse(ids):
|
||||
sql_name = self._sql_sequence_name(sequence)
|
||||
if sql_sequence and not self._strict:
|
||||
cursor.execute('SELECT '
|
||||
'CASE WHEN NOT is_called THEN last_value '
|
||||
'ELSE last_value + increment_by '
|
||||
'END FROM "%s"' % sql_name)
|
||||
value, = cursor.fetchone()
|
||||
else:
|
||||
value = sequence.number_next_internal
|
||||
result[sequence.id] = value
|
||||
return result
|
||||
|
||||
def set_number_next(self, ids, name, value):
|
||||
cursor = Transaction().cursor
|
||||
super(Sequence, self).write(ids, {
|
||||
'number_next_internal': value,
|
||||
})
|
||||
|
||||
def create(self, values):
|
||||
sequence_id = super(Sequence, self).create(values)
|
||||
if sql_sequence and not self._strict:
|
||||
sequence = self.browse(sequence_id)
|
||||
self.update_sql_sequence(sequence, values.get('number_next',
|
||||
self.default_number_next()))
|
||||
return sequence_id
|
||||
|
||||
def write(self, ids, values):
|
||||
result = super(Sequence, self).write(ids, values)
|
||||
if sql_sequence and not self._strict:
|
||||
ids = [ids] if isinstance(ids, (int, long)) else ids
|
||||
sequences = self.browse(ids)
|
||||
for sequence in sequences:
|
||||
self.update_sql_sequence(sequence, values.get('number_next'))
|
||||
return result
|
||||
|
||||
def delete(self, ids):
|
||||
if sql_sequence and not self._strict:
|
||||
ids = [ids] if isinstance(ids, (int, long)) else ids
|
||||
sequences = self.browse(ids)
|
||||
for sequence in sequences:
|
||||
self.delete_sql_sequence(sequence)
|
||||
return super(Sequence, self).delete(ids)
|
||||
|
||||
def code_get(self):
|
||||
pool = Pool()
|
||||
sequence_type_obj = pool.get('ir.sequence.type')
|
||||
@@ -131,6 +205,47 @@ class Sequence(ModelSQL, ModelView):
|
||||
return False
|
||||
return True
|
||||
|
||||
def _sql_sequence_name(self, sequence):
|
||||
'Return SQL sequence name'
|
||||
return '%s_%s' % (self._table, sequence.id)
|
||||
|
||||
def create_sql_sequence(self, sequence, number_next=None):
|
||||
'Create the SQL sequence'
|
||||
cursor = Transaction().cursor
|
||||
if sequence.type != 'incremental':
|
||||
return
|
||||
if number_next is None:
|
||||
number_next = sequence.number_next
|
||||
cursor.execute('CREATE SEQUENCE "' + self._sql_sequence_name(sequence)
|
||||
+ '" INCREMENT BY %s START WITH %s', (sequence.number_increment,
|
||||
number_next))
|
||||
|
||||
def update_sql_sequence(self, sequence, number_next=None):
|
||||
'Update the SQL sequence'
|
||||
cursor = Transaction().cursor
|
||||
exist = TableHandler.sequence_exist(cursor,
|
||||
self._sql_sequence_name(sequence))
|
||||
if sequence.type != 'incremental':
|
||||
if exist:
|
||||
self.delete_sql_sequence(sequence)
|
||||
return
|
||||
if not exist:
|
||||
self.create_sql_sequence(sequence, number_next)
|
||||
return
|
||||
if number_next is None:
|
||||
number_next = sequence.number_next
|
||||
cursor.execute('ALTER SEQUENCE "' + self._sql_sequence_name(sequence)
|
||||
+ '" INCREMENT BY %s RESTART WITH %s', (sequence.number_increment,
|
||||
number_next))
|
||||
|
||||
def delete_sql_sequence(self, sequence):
|
||||
'Delete the SQL sequence'
|
||||
cursor = Transaction().cursor
|
||||
if sequence.type != 'incremental':
|
||||
return
|
||||
cursor.execute('DROP SEQUENCE "%s"'
|
||||
% self._sql_sequence_name(sequence))
|
||||
|
||||
def _process(self, string, date=None):
|
||||
pool = Pool()
|
||||
date_obj = pool.get('ir.date')
|
||||
@@ -151,13 +266,20 @@ class Sequence(ModelSQL, ModelView):
|
||||
|
||||
def _get_sequence(self, sequence):
|
||||
if sequence.type == 'incremental':
|
||||
#Pre-fetch number_next
|
||||
number_next = sequence.number_next or 0
|
||||
if sql_sequence and not self._strict:
|
||||
cursor = Transaction().cursor
|
||||
cursor.execute('SELECT nextval(\'"%s"\')'
|
||||
% self._sql_sequence_name(sequence))
|
||||
number_next, = cursor.fetchone()
|
||||
else:
|
||||
#Pre-fetch number_next
|
||||
number_next = sequence.number_next_internal
|
||||
|
||||
with Transaction().set_user(0):
|
||||
self.write(sequence.id, {
|
||||
'number_next': number_next + sequence.number_increment,
|
||||
})
|
||||
with Transaction().set_user(0):
|
||||
self.write(sequence.id, {
|
||||
'number_next_internal': (number_next
|
||||
+ sequence.number_increment),
|
||||
})
|
||||
return '%%0%sd' % sequence.padding % number_next
|
||||
elif sequence.type in ('decimal timestamp', 'hexadecimal timestamp'):
|
||||
timestamp = sequence.last_timestamp
|
||||
@@ -209,6 +331,7 @@ class SequenceStrict(Sequence):
|
||||
"Sequence Strict"
|
||||
_name = 'ir.sequence.strict'
|
||||
_description = __doc__
|
||||
_strict = True
|
||||
|
||||
def get_id(self, clause):
|
||||
Transaction().cursor.lock(self._table)
|
||||
|
||||
Reference in New Issue
Block a user