# Copyright (c) 2018 Mathias Behrle <mbehrle@m9s.biz>
diff --git a/trytond/backend/database.py b/trytond/backend/database.py
index 22567cd61c7683ee88cb0e38c732a3a5ffb6b887..bff64d62fb45d0dbb45de5972375cb76414f1be4 100644
--- a/trytond/backend/database.py
+++ b/trytond/backend/database.py
@@ -172,3 +172,46 @@ class DatabaseInterface(object):
     def has_multirow_insert(self):
         'Return True if database supports multirow insert'
         return False
+
+    @classmethod
+    def has_sequence(cls):
+        "Return if database supports sequence querying and assignation"
+        return False
+
+    def sequence_exist(self, connection, name):
+        "Return if a sequence exists"
+        if not self.has_sequence():
+            return
+        raise NotImplementedError
+
+    def sequence_create(
+            self, connection, name, number_increment=1, start_value=1):
+        "Creates a sequence"
+        if not self.has_sequence():
+            return
+        raise NotImplementedError
+
+    def sequence_update(
+            self, connection, name, number_increment=1, start_value=1):
+        "Modifies a sequence"
+        if not self.has_sequence():
+            return
+        raise NotImplementedError
+
+    def sequence_rename(self, connection, old_name, new_name):
+        "Renames a sequence"
+        if not self.has_sequence():
+            return
+        raise NotImplementedError
+
+    def sequence_delete(self, connection, name):
+        "Removes a sequence"
+        if not self.has_sequence():
+            return
+        raise NotImplementedError
+
+    def sequence_next_number(self, connection, name):
+        "Gets the next number of a sequence"
+        if not self.has_sequence():
+            return
+        raise NotImplementedError
diff --git a/trytond/backend/mysql/table.py b/trytond/backend/mysql/table.py
index bfe6031250787a0ed0d593dd4822ec25bb596b55..c09065f37ccf2c242007e69a44bf111e4e1e8632 100644
--- a/trytond/backend/mysql/table.py
+++ b/trytond/backend/mysql/table.py
@@ -75,14 +75,6 @@ class TableHandler(TableHandlerInterface):
             cursor.execute('ALTER TABLE `%s` RENAME TO `%s`'
                 % (old_history, new_history))
 
-    @staticmethod
-    def sequence_exist(sequence_name):
-        return True
-
-    @staticmethod
-    def sequence_rename(old_name, new_name):
-        pass
-
     def column_exist(self, column_name):
         return column_name in self._columns
 
diff --git a/trytond/backend/postgresql/database.py b/trytond/backend/postgresql/database.py
index 505973a8785ca5c11889aa757222a9242acb182a..6967b7d28c73d1968b216d57814a604f5af10199 100644
--- a/trytond/backend/postgresql/database.py
+++ b/trytond/backend/postgresql/database.py
@@ -2,7 +2,6 @@
 # this repository contains the full copyright notices and license terms.
 import time
 import logging
-import re
 import os
 import urllib
 from decimal import Decimal
@@ -34,8 +33,6 @@ __all__ = ['Database', 'DatabaseIntegrityError', 'DatabaseOperationalError']
 
 logger = logging.getLogger(__name__)
 
-RE_VERSION = re.compile(r'\S+ (\d+)\.(\d+)')
-
 os.environ['PGTZ'] = os.environ.get('TZ', '')
 
 
@@ -131,10 +128,11 @@ class Database(DatabaseInterface):
     def get_version(self, connection):
         if self.name not in self._version_cache:
             cursor = connection.cursor()
-            cursor.execute('SELECT version()')
+            cursor.execute('SHOW server_version_num')
             version, = cursor.fetchone()
-            self._version_cache[self.name] = tuple(map(int,
-                RE_VERSION.search(version).groups()))
+            major, rest = divmod(int(version), 10000)
+            minor, patch = divmod(rest, 100)
+            self._version_cache[self.name] = (major, minor, patch)
         return self._version_cache[self.name]
 
     @staticmethod
@@ -353,6 +351,80 @@ class Database(DatabaseInterface):
                 self.put_connection(connection)
         return self._search_path
 
+    @classmethod
+    def has_sequence(cls):
+        return True
+
+    def sequence_exist(self, connection, name):
+        cursor = connection.cursor()
+        for schema in self.search_path:
+            cursor.execute('SELECT 1 '
+                'FROM information_schema.sequences '
+                'WHERE sequence_name = %s AND sequence_schema = %s',
+                (name, schema))
+            if cursor.rowcount:
+                return True
+        return False
+
+    def sequence_create(
+            self, connection, name, number_increment=1, start_value=1):
+        cursor = connection.cursor()
+
+        param = self.flavor.param
+        cursor.execute(
+            'CREATE SEQUENCE "%s" '
+            'INCREMENT BY %s '
+            'START WITH %s'
+            % (name, param, param),
+            (number_increment, start_value))
+
+    def sequence_update(
+            self, connection, name, number_increment=1, start_value=1):
+        cursor = connection.cursor()
+        param = self.flavor.param
+        cursor.execute(
+            'ALTER SEQUENCE "%s" '
+            'INCREMENT BY %s '
+            'RESTART WITH %s'
+            % (name, param, param),
+            (number_increment, start_value))
+
+    def sequence_rename(self, connection, old_name, new_name):
+        cursor = connection.cursor()
+        if (self.sequence_exist(connection, old_name)
+                and not self.sequence_exist(connection, new_name)):
+            cursor.execute('ALTER TABLE "%s" RENAME TO "%s"'
+                % (old_name, new_name))
+
+    def sequence_delete(self, connection, name):
+        cursor = connection.cursor()
+        cursor.execute('DROP SEQUENCE "%s"' % name)
+
+    def sequence_next_number(self, connection, name):
+        cursor = connection.cursor()
+        version = self.get_version(connection)
+        if version >= (10, 0):
+            cursor.execute(
+                'SELECT increment_by '
+                'FROM pg_sequences '
+                'WHERE sequencename=%s '
+                % self.flavor.param,
+                (name,))
+            increment, = cursor.fetchone()
+            cursor.execute(
+                'SELECT CASE WHEN NOT is_called THEN last_value '
+                            'ELSE last_value + %s '
+                        'END '
+                'FROM "%s"' % (self.flavor.param, name),
+                (increment,))
+        else:
+            cursor.execute(
+                'SELECT CASE WHEN NOT is_called THEN last_value '
+                            'ELSE last_value + increment_by '
+                       'END '
+                'FROM "%s"' % name)
+        return cursor.fetchone()[0]
+
 register_type(UNICODE)
 if PYDATE:
     register_type(PYDATE)
diff --git a/trytond/backend/postgresql/table.py b/trytond/backend/postgresql/table.py
index a3323041c98be880cf9053b98589dc78e16265b5..8cae6ca12fcacf5a5cdd924416f26ef0ca7ca7bf 100644
--- a/trytond/backend/postgresql/table.py
+++ b/trytond/backend/postgresql/table.py
@@ -22,8 +22,10 @@ class TableHandler(TableHandlerInterface):
         transaction = Transaction()
         cursor = transaction.connection.cursor()
         # Create sequence if necessary
-        if not self.sequence_exist(self.sequence_name):
-            cursor.execute('CREATE SEQUENCE "%s"' % self.sequence_name)
+        if not transaction.database.sequence_exist(
+                transaction.connection, self.sequence_name):
+            transaction.database.sequence_create(
+                transaction.connection, self.sequence_name)
 
         # Create new table if necessary
         if not self.table_exist(self.table_name):
@@ -81,7 +83,8 @@ class TableHandler(TableHandlerInterface):
 
     @staticmethod
     def table_rename(old_name, new_name):
-        cursor = Transaction().connection.cursor()
+        transaction = Transaction()
+        cursor = transaction.connection.cursor()
         # Rename table
         if (TableHandler.table_exist(old_name)
                 and not TableHandler.table_exist(new_name)):
@@ -90,7 +93,8 @@ class TableHandler(TableHandlerInterface):
         # Rename sequence
         old_sequence = old_name + '_id_seq'
         new_sequence = new_name + '_id_seq'
-        TableHandler.sequence_rename(old_sequence, new_sequence)
+        transaction.database.sequence_rename(
+            transaction.connection, old_sequence, new_sequence)
         # Rename history table
         old_history = old_name + "__history"
         new_history = new_name + "__history"
@@ -99,30 +103,6 @@ class TableHandler(TableHandlerInterface):
             cursor.execute('ALTER TABLE "%s" RENAME TO "%s"'
                 % (old_history, new_history))
 
-    @classmethod
-    def sequence_schema(cls, sequence_name):
-        transaction = Transaction()
-        cursor = transaction.connection.cursor()
-        for schema in transaction.database.search_path:
-            cursor.execute('SELECT 1 '
-                'FROM information_schema.sequences '
-                'WHERE sequence_name = %s AND sequence_schema = %s',
-                (sequence_name, schema))
-            if cursor.rowcount:
-                return schema
-
-    @classmethod
-    def sequence_exist(cls, sequence_name):
-        return bool(cls.sequence_schema(sequence_name))
-
-    @staticmethod
-    def sequence_rename(old_name, new_name):
-        cursor = Transaction().connection.cursor()
-        if (TableHandler.sequence_exist(old_name)
-                and not TableHandler.sequence_exist(new_name)):
-            cursor.execute('ALTER TABLE "%s" RENAME TO "%s"'
-                % (old_name, new_name))
-
     def column_exist(self, column_name):
         return column_name in self._columns
 
diff --git a/trytond/backend/table.py b/trytond/backend/table.py
index 887d415af80a3f69061808797b70621f73c0108d..853c51918e0b918f0aa9ad392eac7d22697990dd 100644
--- a/trytond/backend/table.py
+++ b/trytond/backend/table.py
@@ -46,26 +46,6 @@ class TableHandlerInterface(object):
         '''
         raise NotImplementedError
 
-    @staticmethod
-    def sequence_exist(sequence_name):
-        '''
-        Sequence exist
-
-        :param sequence_name: the sequence name
-        :return: a boolean
-        '''
-        raise NotImplementedError
-
-    @staticmethod
-    def sequence_rename(old_name, new_name):
-        '''
-        Rename sequence
-
-        :param old_name: the old sequence name
-        :param new_name: the new sequence name
-        '''
-        raise NotImplementedError
-
     def column_exist(self, column_name):
         '''
         Column exist
diff --git a/trytond/ir/sequence.py b/trytond/ir/sequence.py
index 21bc3c12ee62990ce91fe675520582e3db8c41a8..f6791cf692fb6f9161d7a8607c01f638a576309d 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 Literal, For
 
 from ..model import ModelView, ModelSQL, fields, Check
 from ..tools import datetime_strftime
@@ -16,7 +16,7 @@ __all__ = [
     'SequenceType', 'Sequence', 'SequenceStrict',
     ]
 
-sql_sequence = backend.name() == 'postgresql'
+sql_sequence = backend.get('Database').has_sequence()
 
 
 class SequenceType(ModelSQL, ModelView):
@@ -104,6 +104,7 @@ class Sequence(ModelSQL, ModelView):
     def __register__(cls, module_name):
         TableHandler = backend.get('TableHandler')
         table = TableHandler(cls, module_name)
+        transaction = Transaction()
 
         # Migration from 2.0 rename number_next into number_next_internal
         table.column_rename('number_next', 'number_next_internal')
@@ -116,8 +117,8 @@ class Sequence(ModelSQL, ModelView):
             for sequence in sequences:
                 if sequence.type != 'incremental':
                     continue
-                if not TableHandler.sequence_exist(
-                        sequence._sql_sequence_name):
+                if not transaction.database.sequence_exist(
+                        transaction.connection, sequence._sql_sequence_name):
                     sequence.create_sql_sequence(sequence.number_next_internal)
 
     @staticmethod
@@ -159,14 +160,11 @@ class Sequence(ModelSQL, ModelView):
     def get_number_next(self, name):
         if self.type != 'incremental':
             return
-        cursor = Transaction().connection.cursor()
-        sql_name = self._sql_sequence_name
+
+        transaction = Transaction()
         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)
-            return cursor.fetchone()[0]
+            return transaction.database.sequence_next_number(
+                transaction.connection, self._sql_sequence_name)
         else:
             return self.number_next_internal
 
@@ -260,22 +258,22 @@ class Sequence(ModelSQL, ModelView):
 
     def create_sql_sequence(self, number_next=None):
         'Create the SQL sequence'
-        cursor = Transaction().connection.cursor()
-        param = Flavor.get().param
+        transaction = Transaction()
+
         if self.type != 'incremental':
             return
         if number_next is None:
             number_next = self.number_next
-        cursor.execute('CREATE SEQUENCE "' + self._sql_sequence_name
-            + '" INCREMENT BY ' + param + ' START WITH ' + param,
-            (self.number_increment, number_next))
+        if sql_sequence:
+            transaction.database.sequence_create(transaction.connection,
+                self._sql_sequence_name, self.number_increment, number_next)
 
     def update_sql_sequence(self, number_next=None):
         'Update the SQL sequence'
-        TableHandler = backend.get('TableHandler')
-        cursor = Transaction().connection.cursor()
-        param = Flavor.get().param
-        exist = TableHandler.sequence_exist(self._sql_sequence_name)
+        transaction = Transaction()
+
+        exist = transaction.database.sequence_exist(
+            transaction.connection, self._sql_sequence_name)
         if self.type != 'incremental':
             if exist:
                 self.delete_sql_sequence()
@@ -285,17 +283,16 @@ class Sequence(ModelSQL, ModelView):
             return
         if number_next is None:
             number_next = self.number_next
-        cursor.execute('ALTER SEQUENCE "' + self._sql_sequence_name
-            + '" INCREMENT BY ' + param + ' RESTART WITH ' + param,
-            (self.number_increment, number_next))
+        transaction.database.sequence_update(transaction.connection,
+            self._sql_sequence_name, self.number_increment, number_next)
 
     def delete_sql_sequence(self):
         'Delete the SQL sequence'
-        cursor = Transaction().connection.cursor()
+        transaction = Transaction()
         if self.type != 'incremental':
             return
-        cursor.execute('DROP SEQUENCE "%s"'
-            % self._sql_sequence_name)
+        transaction.database.sequence_delete(
+            transaction.connection, self._sql_sequence_name)
 
     @staticmethod
     def _process(string, date=None):
diff --git a/trytond/res/ir.py b/trytond/res/ir.py
index 754a6226a6b5e1d7aca4b5575ed8232f9525eb2a..0265c46e4e6857753613a27d6a44575d003c4718 100644
--- a/trytond/res/ir.py
+++ b/trytond/res/ir.py
@@ -3,6 +3,7 @@
 from ..model import ModelSQL, fields
 from .. import backend
 from ..pool import Pool, PoolMeta
+from ..transaction import Transaction
 
 __all__ = [
     'UIMenuGroup', 'ActionGroup', 'ModelFieldGroup', 'ModelButtonGroup',
@@ -23,10 +24,11 @@ class UIMenuGroup(ModelSQL):
     @classmethod
     def __register__(cls, module_name):
         TableHandler = backend.get('TableHandler')
+        transaction = Transaction()
         # Migration from 1.0 table name change
         TableHandler.table_rename('ir_ui_menu_group_rel', cls._table)
-        TableHandler.sequence_rename('ir_ui_menu_group_rel_id_seq',
-            cls._table + '_id_seq')
+        transaction.database.sequence_rename(transaction.connection,
+            'ir_ui_menu_group_rel_id_seq', cls._table + '_id_seq')
         # Migration from 2.0 menu_id and gid renamed into menu group
         table = TableHandler(cls, module_name)
         table.column_rename('menu_id', 'menu')
@@ -64,10 +66,11 @@ class ActionGroup(ModelSQL):
     @classmethod
     def __register__(cls, module_name):
         TableHandler = backend.get('TableHandler')
+        transaction = Transaction()
         # Migration from 1.0 table name change
         TableHandler.table_rename('ir_action_group_rel', cls._table)
-        TableHandler.sequence_rename('ir_action_group_rel_id_seq',
-            cls._table + '_id_seq')
+        transaction.database.sequence_rename(transaction.connection,
+            'ir_action_group_rel_id_seq', cls._table + '_id_seq')
         # Migration from 2.0 action_id and gid renamed into action and group
         table = TableHandler(cls, module_name)
         table.column_rename('action_id', 'action')
@@ -118,10 +121,12 @@ class ModelFieldGroup(ModelSQL):
     @classmethod
     def __register__(cls, module_name):
         TableHandler = backend.get('TableHandler')
+        database = Transaction().database
+        transaction = Transaction()
         # Migration from 1.0 table name change
         TableHandler.table_rename('ir_model_field_group_rel', cls._table)
-        TableHandler.sequence_rename('ir_model_field_group_rel_id_seq',
-            cls._table + '_id_seq')
+        transaction.database.sequence_rename(transaction.connection,
+            'ir_model_field_group_rel_id_seq', cls._table + '_id_seq')
         table = TableHandler(cls, module_name)
         # Migration from 2.6: field_id and group_id renamed to field and group
         table.column_rename('field_id', 'field')
@@ -176,10 +181,11 @@ class RuleGroupGroup(ModelSQL):
     @classmethod
     def __register__(cls, module_name):
         TableHandler = backend.get('TableHandler')
+        transaction = Transaction()
         # Migration from 1.0 table name change
         TableHandler.table_rename('group_rule_group_rel', cls._table)
-        TableHandler.sequence_rename('group_rule_group_rel_id_seq',
-            cls._table + '_id_seq')
+        transaction.database.sequence_rename(transaction.connection,
+            'group_rule_group_rel_id_seq', cls._table + '_id_seq')
         # Migration from 2.0 rule_group_id and group_id renamed into rule_group
         # and group
         table = TableHandler(cls, module_name)
@@ -199,10 +205,11 @@ class RuleGroupUser(ModelSQL):
     @classmethod
     def __register__(cls, module_name):
         TableHandler = backend.get('TableHandler')
+        transaction = Transaction()
         # Migration from 1.0 table name change
         TableHandler.table_rename('user_rule_group_rel', cls._table)
-        TableHandler.sequence_rename('user_rule_group_rel_id_seq',
-            cls._table + '_id_seq')
+        transaction.database.sequence_rename(transaction.connection,
+            'user_rule_group_rel_id_seq', cls._table + '_id_seq')
         # Migration from 2.0 rule_group_id and user_id renamed into rule_group
         # and user
         table = TableHandler(cls, module_name)
diff --git a/trytond/res/user.py b/trytond/res/user.py
index ac539065b01127b77540c4f3dbdca9b3383d8978..dd13df43b05f9f243d9e1e29573252c0640b7122 100644
--- a/trytond/res/user.py
+++ b/trytond/res/user.py
@@ -645,10 +645,12 @@ class UserGroup(ModelSQL):
     @classmethod
     def __register__(cls, module_name):
         TableHandler = backend.get('TableHandler')
+        transaction = Transaction()
+
         # Migration from 1.0 table name change
         TableHandler.table_rename('res_group_user_rel', cls._table)
-        TableHandler.sequence_rename('res_group_user_rel_id_seq',
-            cls._table + '_id_seq')
+        transaction.database.sequence_rename(transaction.connection,
+            'res_group_user_rel_id_seq', cls._table + '_id_seq')
         # Migration from 2.0 uid and gid rename into user and group
         table = TableHandler(cls, module_name)
         table.column_rename('uid', 'user')