]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Fix mssql index column order
authorAllen Chen <e2ne00@gmail.com>
Fri, 3 Oct 2025 02:53:34 +0000 (22:53 -0400)
committerFederico Caselli <cfederico87@gmail.com>
Thu, 9 Oct 2025 18:32:51 +0000 (20:32 +0200)
Fixed issue where the index reflection for SQL Server would
not correctly return the order of the column inside an index
when the order of the columns in the index did not match the
order of the columns in the table.
Pull request courtesy of Allen Chen.

Fixes: #12894
Closes: #12895
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/12895
Pull-request-sha: bd9bd43219f35a29eaeee81fedea452afc64eb5d

Change-Id: I45ed30bbd0fcfd4f67cb2b682ecb3a18029be2b7
(cherry picked from commit 3dc9720c365a8d03e7c173874db74a080752d24e)

doc/build/changelog/unreleased_20/12894.rst [new file with mode: 0644]
lib/sqlalchemy/dialects/mssql/base.py
lib/sqlalchemy/testing/requirements.py
lib/sqlalchemy/testing/suite/test_reflection.py
test/dialect/mssql/test_reflection.py
test/requirements.py

diff --git a/doc/build/changelog/unreleased_20/12894.rst b/doc/build/changelog/unreleased_20/12894.rst
new file mode 100644 (file)
index 0000000..43cbd74
--- /dev/null
@@ -0,0 +1,9 @@
+.. change::
+    :tags: bug, mssql
+    :tickets: 12894
+
+    Fixed issue where the index reflection for SQL Server would
+    not correctly return the order of the column inside an index
+    when the order of the columns in the index did not match the
+    order of the columns in the table.
+    Pull request courtesy of Allen Chen.
index fed174070352a105918658cba7c3844137630e94..d422ad8c3d930e04da4159ffaa3e8ed1e59aea6d 100644 (file)
@@ -3503,6 +3503,9 @@ join sys.schemas as sch on
 where
     tab.name = :tabname
     and sch.name = :schname
+order by
+    ind_col.index_id,
+    ind_col.key_ordinal
             """
             )
             .bindparams(
index b90e8363af4c3189c39879e823b8bfa7b9fdb654..9719106b338b52af5c594a769f010e63701facbd 100644 (file)
@@ -796,6 +796,11 @@ class SuiteRequirements(Requirements):
         ASC/DESC but reflects them as expressions (like oracle)."""
         return exclusions.closed()
 
+    @property
+    def indexes_check_column_order(self):
+        """target database supports CREATE INDEX with column order check."""
+        return exclusions.closed()
+
     @property
     def indexes_with_expressions(self):
         """target database supports CREATE INDEX against SQL expressions."""
index 12ac5df1c5ef5f56bc5b69e20f4102ad22601de2..b701de126b680e5b4b8bac01175d919c241300d3 100644 (file)
@@ -2698,6 +2698,26 @@ class ComponentReflectionTestExtra(ComparesIndexes, fixtures.TestBase):
             ],
         )
 
+    @testing.requires.indexes_check_column_order
+    def test_index_column_order(self, metadata, inspect_for_table):
+        """test for #12894"""
+        with inspect_for_table("sa_multi_index") as (schema, inspector):
+            test_table = Table(
+                "sa_multi_index",
+                metadata,
+                Column("Column1", Integer, primary_key=True),
+                Column("Column2", Integer),
+                Column("Column3", Integer),
+            )
+            Index(
+                "Index_Example",
+                test_table.c.Column3,
+                test_table.c.Column1,
+                test_table.c.Column2,
+            )
+        indexes = inspector.get_indexes("sa_multi_index")
+        eq_(indexes[0]["column_names"], ["Column3", "Column1", "Column2"])
+
     @testing.requires.indexes_with_expressions
     def test_reflect_expression_based_indexes(self, metadata, connection):
         t = Table(
index 733f29fef07014ddceb5720aedef82f9dcb7535d..4569a5249fc028b670616d8f1f7730f367145b84 100644 (file)
@@ -750,6 +750,27 @@ class ReflectionTest(fixtures.TestBase, ComparesTables, AssertsCompiledSQL):
             CreateIndex(idx), "CREATE NONCLUSTERED INDEX idx_x ON t (x)"
         )
 
+    def test_index_column_order_clustered(self, metadata, connection):
+        """test for #12894"""
+        test_table = Table(
+            "t",
+            metadata,
+            Column("id", Integer, primary_key=True),
+            Column("x", Integer),
+            Column("y", Integer),
+            PrimaryKeyConstraint("id", mssql_clustered=False),
+        )
+        Index(
+            "idx_x",
+            test_table.c.y,
+            test_table.c.id,
+            test_table.c.x,
+            mssql_clustered=True,
+        )
+        metadata.create_all(connection)
+        indexes = testing.db.dialect.get_indexes(connection, "t", None)
+        eq_(indexes[0]["column_names"], ["y", "id", "x"])
+
     @testing.only_if("mssql>=12")
     def test_index_reflection_colstore_clustered(self, metadata, connection):
         t1 = Table(
index 16d4db465e5b4d8530f3f797c11b568a630595e8..56087b6c8476ba85d10defa868124f2ae11836ff 100644 (file)
@@ -673,6 +673,10 @@ class DefaultRequirements(SuiteRequirements):
             ]
         )
 
+    @property
+    def indexes_check_column_order(self):
+        return exclusions.open()
+
     @property
     def indexes_with_expressions(self):
         return only_on(["postgresql", "sqlite>=3.9.0", "oracle"])