Repository: privacyidea/privacyidea

Issue:
Database migration to PI 3.0.1 fails with postgres db
When the db upgrade script creates a new table with a postgres backend, the required sequence will not be added, instead a default sequence is created which breaks further use of the table.
We also need to make sure, that the corresponding dialect supports sequences before creating them.
Actually this breaks all upgrades with postgres where tables are created in the migration script (or if tables are created before we added sequences to the tables).


Discussion:

Resolving patch:
diff --git a/migrations/versions/48ee74b8a7c8_.py b/migrations/versions/48ee74b8a7c8_.py
--- a/migrations/versions/48ee74b8a7c8_.py
+++ b/migrations/versions/48ee74b8a7c8_.py
@@ -11,12 +11,12 @@
 down_revision = 'cb6d7b7bae63'
 
 
-from alembic import op
+from alembic import op, context
 import sqlalchemy as sa
 from sqlalchemy.ext.declarative import declarative_base
-from sqlalchemy.schema import Sequence
+from sqlalchemy.schema import Sequence, CreateSequence
 from sqlalchemy import orm
-from privacyidea.models import ResolverRealm, TokenRealm, Resolver
+from privacyidea.models import TokenRealm, Resolver
 import sys
 
 Base = declarative_base()
@@ -61,19 +61,36 @@ class Token(Base):
                        default=u'', index=True)
 
 
+# Check if the SQL dialect uses sequences
+# (from https://stackoverflow.com/a/17196812/7036742)
+def dialect_supports_sequences():
+    migration_context = context.get_context()
+    return migration_context.dialect.supports_sequences
+
+
+def create_seq(seq):
+    if dialect_supports_sequences():
+        op.execute(CreateSequence(seq))
+
+
 def upgrade():
     try:
+        seq = Sequence('tokenowner_seq')
+        try:
+            create_seq(seq)
+        except Exception as _e:
+            pass
         op.create_table('tokenowner',
-        sa.Column('id', sa.Integer()),
-        sa.Column('token_id', sa.Integer(), nullable=True),
-        sa.Column('resolver', sa.Unicode(length=120), nullable=True),
-        sa.Column('user_id', sa.Unicode(length=320), nullable=True),
-        sa.Column('realm_id', sa.Integer(), nullable=True),
-        sa.ForeignKeyConstraint(['realm_id'], ['realm.id'], ),
-        sa.ForeignKeyConstraint(['token_id'], ['token.id'], ),
-        sa.PrimaryKeyConstraint('id'),
-        mysql_row_format='DYNAMIC'
-        )
+                        sa.Column('id', sa.Integer(), seq, primary_key=True),
+                        sa.Column('token_id', sa.Integer(), nullable=True),
+                        sa.Column('resolver', sa.Unicode(length=120), nullable=True),
+                        sa.Column('user_id', sa.Unicode(length=320), nullable=True),
+                        sa.Column('realm_id', sa.Integer(), nullable=True),
+                        sa.ForeignKeyConstraint(['realm_id'], ['realm.id'], ),
+                        sa.ForeignKeyConstraint(['token_id'], ['token.id'], ),
+                        sa.PrimaryKeyConstraint('id'),
+                        mysql_row_format='DYNAMIC'
+                        )
         op.create_index(op.f('ix_tokenowner_resolver'), 'tokenowner', ['resolver'], unique=False)
         op.create_index(op.f('ix_tokenowner_user_id'), 'tokenowner', ['user_id'], unique=False)
     except Exception as exx:


Test patch: