Use SQL sequence on PostgreSQL for ir.sequence

Based on Openlabs module

review79002
This commit is contained in:
Cédric Krier
2011-08-09 12:35:32 +02:00
parent 18f69b825d
commit 5a192571d4
3 changed files with 132 additions and 7 deletions
+1
View File
@@ -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
+1
View File
@@ -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
View File
@@ -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)