Skip to content

Commit 6154840

Browse files
Fix bug when comparing the included columns in the indexes.
1 parent 2c6c9de commit 6154840

File tree

9 files changed

+115
-26
lines changed

9 files changed

+115
-26
lines changed

src/UnitTests.Databases.SqlServer/SqlServerDatabaseObjectExtensions.cs

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -351,28 +351,37 @@ private static async Task<ILookup<int, DataRow>> GetIndexesAsync(SqlServerDataba
351351
{
352352
const string sql = @"
353353
SELECT
354-
[t].[object_id] AS [TableId],
355-
[i].[name] AS [IndexName],
356-
[c].[name] AS [ColumnName],
357-
[ic].[key_ordinal] AS [Position],
358-
[i].[type_desc] AS [Type],
359-
[i].[is_unique] AS [IsUnique],
360-
[ic].[is_included_column] AS [IsIncludedColumn],
361-
[i].[filter_definition] AS [Filter]
362-
FROM
363-
[sys].[indexes] AS [i],
364-
[sys].[tables] AS [t],
365-
[sys].[index_columns] AS [ic],
366-
[sys].[columns] AS [c]
367-
WHERE
368-
[t].[name] NOT IN ('__EFMigrationsHistory')
369-
AND [t].[object_id] = [i].[object_id]
370-
AND [i].[is_unique_constraint] = 0
371-
AND [i].[object_id] = [ic].[object_id]
372-
AND [i].[index_id] = [ic].[index_id]
373-
AND [ic].[column_id] = [c].[column_id]
374-
AND [ic].[object_id] = [c].[object_id]
375-
ORDER BY [t].[name], [i].[name], [ic].[key_ordinal]";
354+
[t].[object_id] AS [TableId],
355+
[i].[name] AS [IndexName],
356+
[c].[name] AS [ColumnName],
357+
ROW_NUMBER() OVER(
358+
PARTITION BY [t].[object_id], [i].[index_id], [ic].[is_included_column]
359+
ORDER BY
360+
[ic].[is_included_column],
361+
CASE
362+
WHEN [ic].[is_included_column] = 0 THEN [ic].[key_ordinal]
363+
ELSE [ic].[index_column_id]
364+
END
365+
) AS [Position],
366+
[i].[type_desc] AS [Type],
367+
[i].[is_unique] AS [IsUnique],
368+
[ic].[is_included_column] AS [IsIncludedColumn],
369+
[i].[filter_definition] AS [Filter],
370+
[ic].*
371+
FROM
372+
[sys].[indexes] AS [i],
373+
[sys].[tables] AS [t],
374+
[sys].[index_columns] AS [ic],
375+
[sys].[columns] AS [c]
376+
WHERE
377+
[t].[name] NOT IN ('__EFMigrationsHistory')
378+
AND [t].[object_id] = [i].[object_id]
379+
AND [i].[is_unique_constraint] = 0
380+
AND [i].[object_id] = [ic].[object_id]
381+
AND [i].[index_id] = [ic].[index_id]
382+
AND [ic].[column_id] = [c].[column_id]
383+
AND [ic].[object_id] = [c].[object_id]
384+
ORDER BY [t].[name], [i].[name], [ic].[index_column_id]";
376385

377386
var result = await database.ExecuteQueryAsync(sql, cancellationToken);
378387

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
CREATE INDEX [IndexDifference]
22
ON [dbo].[TableDifference]
33
([ForeignKeyId], [Type])
4+
INCLUDE ([Precision], [Scale], [Identity])
45
WHERE [Type] = 1234
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
CREATE INDEX [IndexIdentical]
22
ON [dbo].[TableIdentical]
33
([ForeignKeyId])
4+
INCLUDE ([IncludeColumn])
45
WHERE [ForeignKeyId] > 0
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
CREATE INDEX [IndexSource]
22
ON [dbo].[TableSource]
33
([SourceName])
4+
INCLUDE ([SourceForeignKeyId])
45
WHERE [SourceName] = ''

tests/UnitTests.Databases.SqlServer.Tests.Source/Tables/TableIdentical.sql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@
22
(
33
[Id] INT NOT NULL,
44
[ForeignKeyId] INT NOT NULL,
5+
[IncludeColumn] INT NOT NULL,
56
)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
CREATE INDEX [IndexDifference]
22
ON [dbo].[TableDifference]
33
([Type], [ForeignKeyId])
4+
INCLUDE ([Scale], [Precision])
45
WHERE [Type] = 'Target'
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
CREATE INDEX [IndexTarget]
22
ON [dbo].[TableTarget]
33
([TargetName])
4+
INCLUDE ([TargetForeignKeyId])
45
WHERE [TargetName] = ''

tests/UnitTests.Databases.SqlServer.Tests/SqlServerDatabaseComparerTest.CompareAsync.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,16 @@
7676
* Position:
7777
Source: 1
7878
Target: 2
79+
------ Included columns ------
80+
- Scale
81+
* Position:
82+
Source: 2
83+
Target: 1
84+
- Precision
85+
* Position:
86+
Source: 1
87+
Target: 2
88+
- Identity (Missing in the target)
7989
- PrimaryKeyDifference
8090
* Type:
8191
Source: NONCLUSTERED

tests/UnitTests.Databases.SqlServer.Tests/SqlServerDatabaseComparerTest.cs

Lines changed: 68 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,13 @@ public async Task CompareAsync()
403403
differences.Tables[0].Source.Indexes[0].Columns[1].Name.Should().Be("Type");
404404
differences.Tables[0].Source.Indexes[0].Columns[1].Position.Should().Be(2);
405405
differences.Tables[0].Source.Indexes[0].Filter.Should().Be("([Type]=(1234))");
406-
differences.Tables[0].Source.Indexes[0].IncludedColumns.Should().HaveCount(0);
406+
differences.Tables[0].Source.Indexes[0].IncludedColumns.Should().HaveCount(3);
407+
differences.Tables[0].Source.Indexes[0].IncludedColumns[0].Name.Should().Be("Precision");
408+
differences.Tables[0].Source.Indexes[0].IncludedColumns[0].Position.Should().Be(1);
409+
differences.Tables[0].Source.Indexes[0].IncludedColumns[1].Name.Should().Be("Scale");
410+
differences.Tables[0].Source.Indexes[0].IncludedColumns[1].Position.Should().Be(2);
411+
differences.Tables[0].Source.Indexes[0].IncludedColumns[2].Name.Should().Be("Identity");
412+
differences.Tables[0].Source.Indexes[0].IncludedColumns[2].Position.Should().Be(3);
407413
differences.Tables[0].Source.Indexes[0].IsUnique.Should().BeFalse();
408414
differences.Tables[0].Source.Indexes[0].Name.Should().Be("IndexDifference");
409415
differences.Tables[0].Source.Indexes[0].Type.Should().Be("NONCLUSTERED");
@@ -425,7 +431,11 @@ public async Task CompareAsync()
425431
differences.Tables[0].Target.Indexes[0].Columns[1].Name.Should().Be("ForeignKeyId");
426432
differences.Tables[0].Target.Indexes[0].Columns[1].Position.Should().Be(2);
427433
differences.Tables[0].Target.Indexes[0].Filter.Should().Be("([Type]='Target')");
428-
differences.Tables[0].Target.Indexes[0].IncludedColumns.Should().HaveCount(0);
434+
differences.Tables[0].Target.Indexes[0].IncludedColumns.Should().HaveCount(2);
435+
differences.Tables[0].Target.Indexes[0].IncludedColumns[0].Name.Should().Be("Scale");
436+
differences.Tables[0].Target.Indexes[0].IncludedColumns[0].Position.Should().Be(1);
437+
differences.Tables[0].Target.Indexes[0].IncludedColumns[1].Name.Should().Be("Precision");
438+
differences.Tables[0].Target.Indexes[0].IncludedColumns[1].Position.Should().Be(2);
429439
differences.Tables[0].Target.Indexes[0].IsUnique.Should().BeFalse();
430440
differences.Tables[0].Target.Indexes[0].Name.Should().Be("IndexDifference");
431441
differences.Tables[0].Target.Indexes[0].Type.Should().Be("NONCLUSTERED");
@@ -442,6 +452,40 @@ public async Task CompareAsync()
442452

443453
differences.Tables[0].Indexes.Should().HaveCount(2);
444454

455+
differences.Tables[0].Indexes[0].Columns.Should().HaveCount(2);
456+
differences.Tables[0].Indexes[0].Columns[0].Properties.Should().HaveCount(1);
457+
differences.Tables[0].Indexes[0].Columns[0].Properties[0].Name.Should().Be("Position");
458+
differences.Tables[0].Indexes[0].Columns[0].Properties[0].Source.Should().Be(2);
459+
differences.Tables[0].Indexes[0].Columns[0].Properties[0].Target.Should().Be(1);
460+
differences.Tables[0].Indexes[0].Columns[0].Source.Should().BeSameAs(differences.Tables[0].Source.Indexes[0].Columns[1]);
461+
differences.Tables[0].Indexes[0].Columns[0].Target.Should().BeSameAs(differences.Tables[0].Target.Indexes[0].Columns[0]);
462+
differences.Tables[0].Indexes[0].Columns[0].Type.Should().Be(SqlObjectDifferenceType.Different);
463+
differences.Tables[0].Indexes[0].Columns[1].Properties.Should().HaveCount(1);
464+
differences.Tables[0].Indexes[0].Columns[1].Properties[0].Name.Should().Be("Position");
465+
differences.Tables[0].Indexes[0].Columns[1].Properties[0].Source.Should().Be(1);
466+
differences.Tables[0].Indexes[0].Columns[1].Properties[0].Target.Should().Be(2);
467+
differences.Tables[0].Indexes[0].Columns[1].Source.Should().BeSameAs(differences.Tables[0].Source.Indexes[0].Columns[0]);
468+
differences.Tables[0].Indexes[0].Columns[1].Target.Should().BeSameAs(differences.Tables[0].Target.Indexes[0].Columns[1]);
469+
differences.Tables[0].Indexes[0].Columns[1].Type.Should().Be(SqlObjectDifferenceType.Different);
470+
differences.Tables[0].Indexes[0].IncludedColumns.Should().HaveCount(3);
471+
differences.Tables[0].Indexes[0].IncludedColumns[0].Properties.Should().HaveCount(1);
472+
differences.Tables[0].Indexes[0].IncludedColumns[0].Properties[0].Name.Should().Be("Position");
473+
differences.Tables[0].Indexes[0].IncludedColumns[0].Properties[0].Source.Should().Be(2);
474+
differences.Tables[0].Indexes[0].IncludedColumns[0].Properties[0].Target.Should().Be(1);
475+
differences.Tables[0].Indexes[0].IncludedColumns[0].Source.Should().BeSameAs(differences.Tables[0].Source.Indexes[0].IncludedColumns[1]);
476+
differences.Tables[0].Indexes[0].IncludedColumns[0].Target.Should().BeSameAs(differences.Tables[0].Target.Indexes[0].IncludedColumns[0]);
477+
differences.Tables[0].Indexes[0].IncludedColumns[0].Type.Should().Be(SqlObjectDifferenceType.Different);
478+
differences.Tables[0].Indexes[0].IncludedColumns[1].Properties.Should().HaveCount(1);
479+
differences.Tables[0].Indexes[0].IncludedColumns[1].Properties[0].Name.Should().Be("Position");
480+
differences.Tables[0].Indexes[0].IncludedColumns[1].Properties[0].Source.Should().Be(1);
481+
differences.Tables[0].Indexes[0].IncludedColumns[1].Properties[0].Target.Should().Be(2);
482+
differences.Tables[0].Indexes[0].IncludedColumns[1].Source.Should().BeSameAs(differences.Tables[0].Source.Indexes[0].IncludedColumns[0]);
483+
differences.Tables[0].Indexes[0].IncludedColumns[1].Target.Should().BeSameAs(differences.Tables[0].Target.Indexes[0].IncludedColumns[1]);
484+
differences.Tables[0].Indexes[0].IncludedColumns[1].Type.Should().Be(SqlObjectDifferenceType.Different);
485+
differences.Tables[0].Indexes[0].IncludedColumns[2].Properties.Should().HaveCount(0);
486+
differences.Tables[0].Indexes[0].IncludedColumns[2].Source.Should().BeSameAs(differences.Tables[0].Source.Indexes[0].IncludedColumns[2]);
487+
differences.Tables[0].Indexes[0].IncludedColumns[2].Target.Should().BeNull();
488+
differences.Tables[0].Indexes[0].IncludedColumns[2].Type.Should().Be(SqlObjectDifferenceType.MissingInTarget);
445489
differences.Tables[0].Indexes[0].Properties.Should().HaveCount(1);
446490
differences.Tables[0].Indexes[0].Properties[0].Name.Should().Be("Filter");
447491
differences.Tables[0].Indexes[0].Properties[0].Source.Should().Be("([Type]=(1234))");
@@ -450,6 +494,22 @@ public async Task CompareAsync()
450494
differences.Tables[0].Indexes[0].Target.Should().BeSameAs(differences.Tables[0].Target.Indexes[0]);
451495
differences.Tables[0].Indexes[0].Type.Should().Be(SqlObjectDifferenceType.Different);
452496

497+
differences.Tables[0].Indexes[1].Columns.Should().HaveCount(2);
498+
differences.Tables[0].Indexes[1].Columns[0].Properties.Should().HaveCount(1);
499+
differences.Tables[0].Indexes[1].Columns[0].Properties[0].Name.Should().Be("Position");
500+
differences.Tables[0].Indexes[1].Columns[0].Properties[0].Source.Should().Be(2);
501+
differences.Tables[0].Indexes[1].Columns[0].Properties[0].Target.Should().Be(1);
502+
differences.Tables[0].Indexes[1].Columns[0].Source.Should().BeSameAs(differences.Tables[0].Source.Indexes[1].Columns[1]);
503+
differences.Tables[0].Indexes[1].Columns[0].Target.Should().BeSameAs(differences.Tables[0].Target.Indexes[1].Columns[0]);
504+
differences.Tables[0].Indexes[1].Columns[0].Type.Should().Be(SqlObjectDifferenceType.Different);
505+
differences.Tables[0].Indexes[1].Columns[1].Properties.Should().HaveCount(1);
506+
differences.Tables[0].Indexes[1].Columns[1].Properties[0].Name.Should().Be("Position");
507+
differences.Tables[0].Indexes[1].Columns[1].Properties[0].Source.Should().Be(1);
508+
differences.Tables[0].Indexes[1].Columns[1].Properties[0].Target.Should().Be(2);
509+
differences.Tables[0].Indexes[1].Columns[1].Source.Should().BeSameAs(differences.Tables[0].Source.Indexes[1].Columns[0]);
510+
differences.Tables[0].Indexes[1].Columns[1].Target.Should().BeSameAs(differences.Tables[0].Target.Indexes[1].Columns[1]);
511+
differences.Tables[0].Indexes[1].Columns[1].Type.Should().Be(SqlObjectDifferenceType.Different);
512+
differences.Tables[0].Indexes[1].IncludedColumns.Should().HaveCount(0);
453513
differences.Tables[0].Indexes[1].Properties.Should().HaveCount(1);
454514
differences.Tables[0].Indexes[1].Properties[0].Name.Should().Be("Type");
455515
differences.Tables[0].Indexes[1].Properties[0].Source.Should().Be("NONCLUSTERED");
@@ -578,7 +638,9 @@ public async Task CompareAsync()
578638
differences.Tables[1].Target.Indexes[0].Columns[0].Name.Should().Be("TargetName");
579639
differences.Tables[1].Target.Indexes[0].Columns[0].Position.Should().Be(1);
580640
differences.Tables[1].Target.Indexes[0].Filter.Should().Be("([TargetName]='')");
581-
differences.Tables[1].Target.Indexes[0].IncludedColumns.Should().HaveCount(0);
641+
differences.Tables[1].Target.Indexes[0].IncludedColumns.Should().HaveCount(1);
642+
differences.Tables[1].Target.Indexes[0].IncludedColumns[0].Name.Should().Be("TargetForeignKeyId");
643+
differences.Tables[1].Target.Indexes[0].IncludedColumns[0].Position.Should().Be(1);
582644
differences.Tables[1].Target.Indexes[0].IsUnique.Should().BeFalse();
583645
differences.Tables[1].Target.Indexes[0].Name.Should().Be("IndexTarget");
584646
differences.Tables[1].Target.Indexes[1].Columns.Should().HaveCount(1);
@@ -627,7 +689,9 @@ public async Task CompareAsync()
627689
differences.Tables[2].Source.Indexes[0].Columns[0].Name.Should().Be("SourceName");
628690
differences.Tables[2].Source.Indexes[0].Columns[0].Position.Should().Be(1);
629691
differences.Tables[2].Source.Indexes[0].Filter.Should().Be("([SourceName]='')");
630-
differences.Tables[2].Source.Indexes[0].IncludedColumns.Should().HaveCount(0);
692+
differences.Tables[2].Source.Indexes[0].IncludedColumns.Should().HaveCount(1);
693+
differences.Tables[2].Source.Indexes[0].IncludedColumns[0].Name.Should().Be("SourceForeignKeyId");
694+
differences.Tables[2].Source.Indexes[0].IncludedColumns[0].Position.Should().Be(1);
631695
differences.Tables[2].Source.Indexes[0].IsUnique.Should().BeFalse();
632696
differences.Tables[2].Source.Indexes[0].Name.Should().Be("IndexSource");
633697
differences.Tables[2].Source.Indexes[1].Columns.Should().HaveCount(1);

0 commit comments

Comments
 (0)