Repository: ariga/atlas
Pull request #3429 (2025-03-17 11:45:31)

sql/sqlcheck/datadepend: dont report MF101 diag on index recreation


Patch:
diff --git a/sql/sqlcheck/datadepend/datadepend.go b/sql/sqlcheck/datadepend/datadepend.go
index e54996aa..ddf16422 100644
--- a/sql/sqlcheck/datadepend/datadepend.go
+++ b/sql/sqlcheck/datadepend/datadepend.go
@@ -81,6 +81,20 @@ var (
 // Diagnostics runs the common analysis on the file and returns its diagnostics.
 func (a *Analyzer) Diagnostics(_ context.Context, p *sqlcheck.Pass) (diags []sqlcheck.Diagnostic) {
 	for _, sc := range p.File.Changes {
+		var dropI []*schema.DropIndex
+		for _, sc := range p.File.Changes {
+			for _, c := range sc.Changes {
+				m, ok := c.(*schema.ModifyTable)
+				if !ok {
+					continue
+				}
+				for _, mc := range m.Changes {
+					if d, ok := mc.(*schema.DropIndex); ok {
+						dropI = append(dropI, d)
+					}
+				}
+			}
+		}
 		for _, c := range sc.Changes {
 			m, ok := c.(*schema.ModifyTable)
 			if !ok {
@@ -89,6 +103,32 @@ func (a *Analyzer) Diagnostics(_ context.Context, p *sqlcheck.Pass) (diags []sql
 			for _, c := range m.Changes {
 				switch c := c.(type) {
 				case *schema.AddIndex:
+					// Check if the current index is not unique or if it matches any of the dropped unique indexes by comparing their parts.
+					if !c.I.Unique || slices.ContainsFunc(dropI, func(drop *schema.DropIndex) bool {
+						if !drop.I.Unique || len(drop.I.Parts) > len(c.I.Parts) {
+							return false
+						}
+						for _, p1 := range c.I.Parts {
+							switch {
+							case p1.C != nil:
+								if p.File.ColumnSpan(m.T, p1.C)&sqlcheck.SpanAdded == 0 && !slices.ContainsFunc(drop.I.Parts, func(p2 *schema.IndexPart) bool {
+									return p2.C != nil && p2.C.Name == p1.C.Name
+								}) {
+									return false
+								}
+							case p1.X != nil:
+								if rx1, ok := p1.X.(*schema.RawExpr); ok && !slices.ContainsFunc(drop.I.Parts, func(p2 *schema.IndexPart) bool {
+									rx2, ok := p2.X.(*schema.RawExpr)
+									return ok && rx1.X == rx2.X
+								}) {
+									return false
+								}
+							}
+						}
+						return true
+					}) {
+						continue
+					}
 					names := func() []string {
 						var names []string
 						for i := range c.I.Parts {


Test patch:
diff --git a/sql/sqlcheck/datadepend/datadepend_test.go b/sql/sqlcheck/datadepend/datadepend_test.go
index 01e46055..0a502add 100644
--- a/sql/sqlcheck/datadepend/datadepend_test.go
+++ b/sql/sqlcheck/datadepend/datadepend_test.go
@@ -82,6 +82,54 @@ func TestAnalyzer_AddUniqueIndex(t *testing.T) {
 	require.Len(t, report.Diagnostics, 2)
 	require.Equal(t, `Adding a unique index "idx_b" on table "users" might fail in case column "b" contains duplicate entries`, report.Diagnostics[0].Text)
 	require.Equal(t, `Adding a unique index "idx_c_d" on table "users" might fail in case columns "c", "d" contain duplicate entries`, report.Diagnostics[1].Text)
+
+	// Dropping index and then creating it again with added columns should not report any diagnostics.
+	*report = sqlcheck.Report{}
+	pass.File = &sqlcheck.File{
+		Changes: []*sqlcheck.Change{
+			{
+				Stmt: &migrate.Stmt{
+					Text: "ALTER TABLE users",
+				},
+				Changes: schema.Changes{
+					&schema.ModifyTable{
+						T: schema.NewTable("users").
+							SetSchema(schema.New("test")).
+							AddColumns(
+								schema.NewColumn("a"),
+								schema.NewColumn("b"),
+								schema.NewColumn("c"),
+							),
+						Changes: []schema.Change{
+							&schema.DropIndex{
+								I: schema.NewUniqueIndex("idx_a_b").
+									AddColumns(
+										schema.NewColumn("a"),
+										schema.NewColumn("b"),
+									).
+									AddExprs(&schema.RawExpr{X: "a + b"}),
+							},
+							&schema.AddColumn{C: schema.NewColumn("c")},
+							&schema.AddIndex{
+								I: schema.NewUniqueIndex("idx_a_b_c").
+									AddColumns(
+										schema.NewColumn("a"),
+										schema.NewColumn("b"),
+										schema.NewColumn("c"),
+									).
+									AddExprs(&schema.RawExpr{X: "a + b"}),
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+	az, err = datadepend.New(nil, datadepend.Handler{})
+	require.NoError(t, err)
+	err = az.Analyze(context.Background(), pass)
+	require.NoError(t, err)
+	require.Len(t, report.Diagnostics, 0)
 }
 
 func TestAnalyzer_ModifyUniqueIndex(t *testing.T) {