]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Fix unique constraints reflection in PostgreSQL
authorRoman Podolyaka <roman.podolyaka@gmail.com>
Sat, 22 Jun 2013 12:57:03 +0000 (15:57 +0300)
committerRoman Podolyaka <roman.podolyaka@gmail.com>
Sun, 23 Jun 2013 10:35:19 +0000 (13:35 +0300)
Reflection of unique constraints must preserve the order of columns.

lib/sqlalchemy/dialects/postgresql/base.py
lib/sqlalchemy/testing/suite/test_reflection.py

index 16ace0583e2d0a873196cb1ce174ccb1a690d6c2..9d89fe160fde1feb7b20a1e6030afe705b85b0d2 100644 (file)
@@ -205,6 +205,7 @@ underlying CREATE INDEX command, so it *must* be a valid index type for your
 version of PostgreSQL.
 
 """
+from collections import defaultdict
 import re
 
 from ... import sql, schema, exc, util
@@ -2010,25 +2011,31 @@ class PGDialect(default.DefaultDialect):
         UNIQUE_SQL = """
             SELECT
                 cons.conname as name,
-                ARRAY_AGG(a.attname) as column_names
+                cons.conkey as key,
+                a.attnum as col_num,
+                a.attname as col_name
             FROM
                 pg_catalog.pg_constraint cons
-                left outer join pg_attribute a
-                    on cons.conrelid = a.attrelid and a.attnum = ANY(cons.conkey)
+                join pg_attribute a
+                  on cons.conrelid = a.attrelid AND a.attnum = ANY(cons.conkey)
             WHERE
                 cons.conrelid = :table_oid AND
                 cons.contype = 'u'
-            GROUP BY
-                cons.conname
         """
 
-        t = sql.text(UNIQUE_SQL,
-                     typemap={'column_names': ARRAY(sqltypes.Unicode)})
+        t = sql.text(UNIQUE_SQL, typemap={'col_name': sqltypes.Unicode})
         c = connection.execute(t, table_oid=table_oid)
 
+        uniques = defaultdict(lambda: defaultdict(dict))
+        for row in c.fetchall():
+            uc = uniques[row.name]
+            uc["key"] = row.key
+            uc["cols"][row.col_num] = row.col_name
+
         return [
-            {'name': row.name, 'column_names': row.column_names}
-            for row in c.fetchall()
+            {'name': name,
+             'column_names': [uc["cols"][i] for i in uc["key"]]}
+            for name, uc in uniques.items()
         ]
 
     def _load_enums(self, connection):
index 7ab4097a11f9f59dc10b36882b23a3ce2084f23c..255fd559516f290f89ebad5d295b2a2163427d97 100644 (file)
@@ -370,9 +370,9 @@ class ComponentReflectionTest(fixtures.TablesTest):
     def _test_get_unique_constraints(self, schema=None):
         uniques = sorted(
             [
+                {'name': 'unique_a', 'column_names': ['a']},
                 {'name': 'unique_a_b_c', 'column_names': ['a', 'b', 'c']},
-                {'name': 'unique_a_c', 'column_names': ['a', 'c']},
-                {'name': 'unique_b_c', 'column_names': ['b', 'c']},
+                {'name': 'unique_c_a_b', 'column_names': ['c', 'a', 'b']},
                 {'name': 'unique_asc_key', 'column_names': ['asc', 'key']},
             ],
             key=operator.itemgetter('name')