@@ -332,4 +332,102 @@ public void testGetTableMetaOriginalTableNamePreserved() throws SQLException {
332332 Assertions .assertNotNull (tableMeta );
333333 Assertions .assertEquals (originalName , tableMeta .getOriginalTableName ());
334334 }
335+
336+ @ Test
337+ public void testCompositeIndexWithDifferentColumnOrder () throws SQLException {
338+ // Regression test for a bug fix: different column order caused List.equals to fail, which could lead to
339+ // failing to recognize a primary key index.
340+ // Scenario: composite primary key (ID, USER_ID) while a unique index lists the same columns in reverse order
341+ // (USER_ID, ID).
342+ // Before the fix: List.equals returned FALSE because of the different order, causing the primary key index to
343+ // be unrecognized.
344+ // After the fix: using Set.equals should return TRUE and correctly identify the index as PRIMARY.
345+
346+ Object [][] compositeIndexDiffOrder = new Object [][] {
347+ new Object [] {"idx_id_userid" , "id" , false , "" , 3 , 1 , "A" , 34 }, // column order 1
348+ new Object [] {"idx_id_userid" , "user_id" , false , "" , 3 , 2 , "A" , 34 } // column order 2
349+ };
350+ Object [][] compositePKMetas = new Object [][] {
351+ new Object [] {"user_id" }, // PK column order 1 (intentionally different from index order)
352+ new Object [] {"id" } // PK column order 2
353+ };
354+ Object [][] compositeColumnMetas = new Object [][] {
355+ new Object [] {"" , "" , "dt2" , "id" , Types .INTEGER , "INTEGER" , 64 , 0 , 10 , 1 , "" , "" , 0 , 0 , 64 , 1 , "NO" , "YES"
356+ },
357+ new Object [] {
358+ "" , "" , "dt2" , "user_id" , Types .INTEGER , "INTEGER" , 64 , 0 , 10 , 0 , "" , "" , 0 , 0 , 64 , 2 , "YES" , "NO"
359+ }
360+ };
361+ Object [][] compositeTableMetas = new Object [][] {new Object [] {"" , "t" , "dt2" }};
362+
363+ MockDriver mockDriver =
364+ new MockDriver (compositeColumnMetas , compositeIndexDiffOrder , compositePKMetas , compositeTableMetas );
365+ DruidDataSource dataSource = new DruidDataSource ();
366+ dataSource .setUrl ("jdbc:mock:dm" );
367+ dataSource .setDriver (mockDriver );
368+
369+ DataSourceProxy proxy = DataSourceProxyTest .getDataSourceProxy (dataSource );
370+ TableMetaCache tableMetaCache = TableMetaCacheFactory .getTableMetaCache (JdbcConstants .DM );
371+
372+ TableMeta tableMeta = tableMetaCache .getTableMeta (proxy .getPlainConnection (), "t.dt2" , proxy .getResourceId ());
373+
374+ Assertions .assertNotNull (tableMeta );
375+ IndexMeta compositeIndex = tableMeta .getAllIndexes ().get ("idx_id_userid" );
376+ Assertions .assertNotNull (compositeIndex );
377+ // Key assertion: should be recognized as PRIMARY (after the fix), not mistakenly treated as UNIQUE
378+ Assertions .assertEquals (
379+ IndexType .PRIMARY ,
380+ compositeIndex .getIndextype (),
381+ "Composite index with different column order should be recognized as PRIMARY" );
382+ }
383+
384+ @ Test
385+ public void testCompositeIndexWithExtraColumnsNotMarkedAsPrimary () throws SQLException {
386+ // Regression test for a bug fix: a composite unique index that contains primary key columns plus extra columns
387+ // should NOT be marked as PRIMARY.
388+ // Scenario: primary key (ID), unique index (ID, NAME) — unique index contains PK column but has extra NAME.
389+ // Before the fix: the previous DM implementation matched by count (matchCols == pkcol.size()) and could misidentify
390+ // PRIMARY.
391+ // After the fix: using Set equality ({ID, NAME} != {ID}) prevents the index from being marked as PRIMARY
392+
393+ Object [][] mixedIndexMetas = new Object [][] {
394+ new Object [] {"idx_id" , "id" , false , "" , 3 , 1 , "A" , 34 },
395+ new Object [] {"uk_id_name" , "id" , false , "" , 3 , 1 , "A" , 34 }, // unique index contains the primary key column
396+ new Object [] {"uk_id_name" , "name1" , false , "" , 3 , 2 , "A" , 34 } // but it also has extra columns
397+ };
398+
399+ // Use a dedicated table name to avoid cache hits from earlier tests
400+ Object [][] extraColumnMetas = new Object [][] {
401+ new Object [] {"" , "" , "dt3" , "id" , Types .INTEGER , "INTEGER" , 64 , 0 , 10 , 1 , "" , "" , 0 , 0 , 64 , 1 , "NO" , "YES"
402+ },
403+ new Object [] {
404+ "" , "" , "dt3" , "name1" , Types .VARCHAR , "VARCHAR" , 64 , 0 , 10 , 0 , "" , "" , 0 , 0 , 64 , 2 , "YES" , "NO"
405+ }
406+ };
407+ Object [][] extraPkMetas = new Object [][] {new Object [] {"id" }};
408+ Object [][] extraTableMetas = new Object [][] {new Object [] {"" , "t" , "dt3" }};
409+
410+ MockDriver mockDriver = new MockDriver (extraColumnMetas , mixedIndexMetas , extraPkMetas , extraTableMetas );
411+ DruidDataSource dataSource = new DruidDataSource ();
412+ dataSource .setUrl ("jdbc:mock:dm" );
413+ dataSource .setDriver (mockDriver );
414+
415+ DataSourceProxy proxy = DataSourceProxyTest .getDataSourceProxy (dataSource );
416+ TableMetaCache tableMetaCache = TableMetaCacheFactory .getTableMetaCache (JdbcConstants .DM );
417+
418+ TableMeta tableMeta = tableMetaCache .getTableMeta (proxy .getPlainConnection (), "t.dt3" , proxy .getResourceId ());
419+
420+ Assertions .assertNotNull (tableMeta );
421+ IndexMeta pkIndex = tableMeta .getAllIndexes ().get ("idx_id" );
422+ Assertions .assertNotNull (pkIndex );
423+ Assertions .assertEquals (IndexType .PRIMARY , pkIndex .getIndextype (), "Single column PK index should be PRIMARY" );
424+
425+ IndexMeta mixedIndex = tableMeta .getAllIndexes ().get ("uk_id_name" );
426+ Assertions .assertNotNull (mixedIndex );
427+ // Key assertion: should remain UNIQUE (should not be misidentified as PRIMARY)
428+ Assertions .assertEquals (
429+ IndexType .UNIQUE ,
430+ mixedIndex .getIndextype (),
431+ "Composite index with extra columns should NOT be marked as PRIMARY" );
432+ }
335433}
0 commit comments