]> 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:33:46 +0000 (20:33 +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

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 96d4b520bc915f2ee67c3e37efb3c7a1f2fe217f..001c0768339e302ecc542f9ea0141d120f96dca2 100644 (file)
@@ -3479,6 +3479,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 580579a2d962ff63003c855f3708accb19a78805..d4828712a66d8e7ef6c47f3812084b2726b1e6b1 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 aa1a4e90a8419395de8612321aeab085e25c59dd..b4fc34a4767cfdd87c958bae5e71f97b8d12fbe0 100644 (file)
@@ -2699,6 +2699,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 29051536d3e4303723ccbe62a321373e609e2a55..cf1c0f382530c3311852e175e68dfe35dff8fef6 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"])