Odoo Commit 每日一读/5 - 56588e8

PostgreSQL 10.0最近发布了,Odoo对该版本的数据库是完全支持的,不过最近发现了一个 问题- issue 20269,这个问题跟Odoo的序列号相关 。V11分支中的提交: 56588e8解决了该问题。

问题说明

在本提交之前,如果数据库运行PG 10.0在访问Settings→Sequence & Idendifiers→Sequence菜单项时,会显示如下图错误:

Sequence Error when using Pg10 before commit 56588e8

问题原因

这是因为PostgreSQL 10 将sequence相关的元数据字段移到了pg_sequence系统表 里,对sequence关联表的查询目前只能返回3个字段的信息,其中不包括Odoo序列号所 需的increment_by字段的信息。

解决方法

def _predict_nextval(self, seq_id): (1)
    """Predict next value for PostgreSQL sequence without consuming it"""
    # Cannot use currval() as it requires prior call to nextval()
    query = """SELECT last_value,
                      (SELECT increment_by  (2)
                       FROM pg_sequences
                       WHERE sequencename = 'ir_sequence_%(seq_id)s'),
                      is_called
               FROM ir_sequence_%(seq_id)s"""
    if self.env.cr._cnx.server_version < 100000: (3)
        query = "SELECT last_value, increment_by, is_called FROM ir_sequence_%(seq_id)s"
1 构造了一个新的Predict_nextval函数来获取seqence数据
2 如果是PG 10 以上的数据库,对pg_sequences表查询以获得increment_by字段 数据
3 通过self.env.cr._cnx.server_version来获得postgreSQL数据库的版本,若小于 V10则直接对关联sequence做查询获取数据。

原始提交信息

commit 56588e8d447a188f730ecfc62b451dba046e81ef
Author: Olivier Dony <odo@openerp.com>
Date:   Sat Nov 11 01:13:25 2017 +0100

    [FIX] ir_sequence: add support for PG 10

    PostgreSQL 10 move sequences' metadata fields into a new `pg_sequence`
    system catalog. As a result, selecting from a sequence relation now
    only return three fields, and does not include the `increment_by`
    metadata field anymore.

    This patch obtains the `increment_by` value from the new system catalog
    for PostgreSQL server versions >= 10.

    Fixes #20269

diff --git a/odoo/addons/base/ir/ir_sequence.py b/odoo/addons/base/ir/ir_sequence.py
index f1005cc6c44..70d70b536ef 100644
--- a/odoo/addons/base/ir/ir_sequence.py
+++ b/odoo/addons/base/ir/ir_sequence.py
@@ -54,6 +54,24 @@ def _update_nogap(self, number_increment):
     self.invalidate_cache(['number_next'], [self.id])
     return number_next

+def _predict_nextval(self, seq_id):
+    """Predict next value for PostgreSQL sequence without consuming it"""
+    # Cannot use currval() as it requires prior call to nextval()
+    query = """SELECT last_value,
+                      (SELECT increment_by
+                       FROM pg_sequences
+                       WHERE sequencename = 'ir_sequence_%(seq_id)s'),
+                      is_called
+               FROM ir_sequence_%(seq_id)s"""
+    if self.env.cr._cnx.server_version < 100000:
+        query = "SELECT last_value, increment_by, is_called FROM ir_sequence_%(seq_id)s"
+    self.env.cr.execute(query % {'seq_id': seq_id})
+    (last_value, increment_by, is_called) = self.env.cr.fetchone()
+    if is_called:
+        return last_value + increment_by
+    # sequence has just been RESTARTed to return last_value next time
+    return last_value
+

 class IrSequence(models.Model):
     """ Sequence model.
@@ -73,15 +91,8 @@ class IrSequence(models.Model):
             if seq.implementation != 'standard':
                 seq.number_next_actual = seq.number_next
             else:
-                # get number from postgres sequence. Cannot use currval, because that might give an error when
-                # not having used nextval before.
-                query = "SELECT last_value, increment_by, is_called FROM ir_sequence_%03d" % seq.id
-                self._cr.execute(query)
-                (last_value, increment_by, is_called) = self._cr.fetchone()
-                if is_called:
-                    seq.number_next_actual = last_value + increment_by
-                else:
-                    seq.number_next_actual = last_value
+                seq_id = "%03d" % seq.id
+                seq.number_next_actual = _predict_nextval(self, seq_id)

     def _set_number_next_actual(self):
         for seq in self:
@@ -311,14 +322,8 @@ class IrSequenceDateRange(models.Model):
             if seq.sequence_id.implementation != 'standard':
                 seq.number_next_actual = seq.number_next
             else:
-                # get number from postgres sequence. Cannot use currval, because that might give an error when
-                # not having used nextval before.
-                self._cr.execute("SELECT last_value, increment_by, is_called FROM ir_sequence_%03d_%03d" % (seq.sequence_id.id, seq.id))
-                (last_value, increment_by, is_called) = self._cr.fetchone()
-                if is_called:
-                    seq.number_next_actual = last_value + increment_by
-                else:
-                    seq.number_next_actual = last_value
+                seq_id = "%03d_%03d" % (seq.sequence_id.id, seq.id)
+                seq.number_next_actual = _predict_nextval(self, seq_id)

     def _set_number_next_actual(self):
         for seq in self: