]> git.ipfire.org Git - thirdparty/sqlalchemy/alembic.git/commitdiff
- Postgresql "functional" indexes are necessarily skipped from the
authorMike Bayer <mike_mp@zzzcomputing.com>
Tue, 10 Mar 2015 15:26:43 +0000 (11:26 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Tue, 10 Mar 2015 15:26:43 +0000 (11:26 -0400)
autogenerate process, as the SQLAlchemy backend currently does not
support reflection of these structures.   A warning is emitted
both from the SQLAlchemy backend as well as from the Alembic
backend for Postgresql when such an index is detected.
fixes #282

alembic/ddl/postgresql.py
docs/build/changelog.rst
tests/test_autogen_indexes.py

index ac3a5f48d137991ba1eb042abdf316c8d750f3a0..10026876ad8157ab49a0eb27c97c0e3e6aecbb5a 100644 (file)
@@ -1,10 +1,17 @@
 import re
 
 from .. import compat
+from .. import util
 from .base import compiles, alter_table, format_table_name, RenameTable
 from .impl import DefaultImpl
 from sqlalchemy.dialects.postgresql import INTEGER, BIGINT
-from sqlalchemy import text, Numeric
+from sqlalchemy import text, Numeric, Column
+
+if compat.sqla_08:
+    from sqlalchemy.sql.expression import UnaryExpression
+else:
+    from sqlalchemy.sql.expression import _UnaryExpression as UnaryExpression
+
 import logging
 
 log = logging.getLogger(__name__)
@@ -97,6 +104,19 @@ class PostgresqlImpl(DefaultImpl):
         for name, (uq, ix) in doubled_constraints.items():
             conn_indexes.remove(ix)
 
+        for idx in list(metadata_indexes):
+            if compat.sqla_08:
+                exprs = idx.expressions
+            else:
+                exprs = idx.columns
+            for expr in exprs:
+                if not isinstance(expr, (Column, UnaryExpression)):
+                    util.warn(
+                        "autogenerate skipping functional index %s; "
+                        "not supported by SQLAlchemy reflection" % idx.name
+                    )
+                    metadata_indexes.discard(idx)
+
 
 @compiles(RenameTable, "postgresql")
 def visit_rename_table(element, compiler, **kw):
index 1d5fb935fd30dfa9687989a672e76ba836abd833..73a046f1f0709b43489837a4c6e2f14ed0e26490 100644 (file)
@@ -6,6 +6,16 @@ Changelog
 .. changelog::
     :version: 0.7.5
 
+    .. change::
+      :tags: bug, autogenerate, postgresql
+      :tickets: 282
+
+      Postgresql "functional" indexes are necessarily skipped from the
+      autogenerate process, as the SQLAlchemy backend currently does not
+      support reflection of these structures.   A warning is emitted
+      both from the SQLAlchemy backend as well as from the Alembic
+      backend for Postgresql when such an index is detected.
+
     .. change::
       :tags: bug, autogenerate, mysql
       :tickets: 276
index f798dd3c0536b7d6029c530ec69089cc6b00485e..1f92649c3de8683458961bac9a29b29972e9bc7f 100644 (file)
@@ -1,10 +1,11 @@
 import sys
 from alembic.testing import TestBase
 from alembic.testing import config
+from alembic.testing import assertions
 
 from sqlalchemy import MetaData, Column, Table, Integer, String, \
     Numeric, UniqueConstraint, Index, ForeignKeyConstraint,\
-    ForeignKey
+    ForeignKey, func
 from alembic.testing import engines
 from alembic.testing import eq_
 from alembic.testing.env import staging_env
@@ -639,6 +640,31 @@ class PGUniqueIndexTest(AutogenerateUniqueIndexTest):
         eq_(diffs[0][1].name, "uq_name")
         eq_(len(diffs), 1)
 
+    def test_functional_ix(self):
+        m1 = MetaData()
+        m2 = MetaData()
+
+        t1 = Table(
+            'foo', m1,
+            Column('id', Integer, primary_key=True),
+            Column('email', String(50))
+        )
+        Index("email_idx", func.lower(t1.c.email), unique=True)
+
+        t2 = Table(
+            'foo', m2,
+            Column('id', Integer, primary_key=True),
+            Column('email', String(50))
+        )
+        Index("email_idx", func.lower(t2.c.email), unique=True)
+
+        with assertions.expect_warnings(
+                "Skipped unsupported reflection",
+                "autogenerate skipping functional index"
+        ):
+            diffs = self._fixture(m1, m2)
+        eq_(diffs, [])
+
 
 class MySQLUniqueIndexTest(AutogenerateUniqueIndexTest):
     reports_unnamed_constraints = True