Files
wehub-resource-sync 5357c39144
Fuzzer / Run Fuzzer (push) Has been cancelled
Race tests / Go race tests (ubuntu-22.04) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:01:40 +08:00

207 lines
5.4 KiB
Go

// Copyright 2019 Dolthub, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package diff
import (
"reflect"
"github.com/dolthub/dolt/go/libraries/doltcore/doltdb"
"github.com/dolthub/dolt/go/libraries/doltcore/schema"
)
type SchemaChangeType int
const (
// SchDiffNone is the SchemaChangeType for two columns with the same tag that are identical
SchDiffNone SchemaChangeType = iota
// SchDiffAdded is the SchemaChangeType when a column is in the new schema but not the old
SchDiffAdded
// SchDiffRemoved is the SchemaChangeType when a column is in the old schema but not the new
SchDiffRemoved
// SchDiffModified is the SchemaChangeType for two columns with the same tag that are different
SchDiffModified
)
// ColumnDifference is the result of comparing two columns from two schemas.
type ColumnDifference struct {
DiffType SchemaChangeType
Tag uint64
Old *schema.Column
New *schema.Column
}
type columnPair [2]*schema.Column
// DiffSchColumns compares two schemas by looking at columns with the same tag.
func DiffSchColumns(fromSch, toSch schema.Schema) (map[uint64]ColumnDifference, []uint64) {
colPairMap, unionTags := pairColumns(fromSch, toSch)
diffs := make(map[uint64]ColumnDifference)
for _, tag := range unionTags {
colPair := colPairMap[tag]
if colPair[0] == nil {
diffs[tag] = ColumnDifference{SchDiffAdded, tag, nil, colPair[1]}
} else if colPair[1] == nil {
diffs[tag] = ColumnDifference{SchDiffRemoved, tag, colPair[0], nil}
} else if !colPair[0].Equals(*colPair[1]) {
diffs[tag] = ColumnDifference{SchDiffModified, tag, colPair[0], colPair[1]}
} else {
diffs[tag] = ColumnDifference{SchDiffNone, tag, colPair[0], colPair[1]}
}
}
return diffs, unionTags
}
// pairColumns loops over both sets of columns pairing columns with the same tag.
func pairColumns(fromSch, toSch schema.Schema) (map[uint64]columnPair, []uint64) {
// collect the tag union of the two schemas, ordering fromSch before toSch
var unionTags []uint64
colPairMap := make(map[uint64]columnPair)
_ = fromSch.GetAllCols().Iter(func(tag uint64, col schema.Column) (stop bool, err error) {
colPairMap[tag] = columnPair{&col, nil}
unionTags = append(unionTags, tag)
return false, nil
})
_ = toSch.GetAllCols().Iter(func(tag uint64, col schema.Column) (stop bool, err error) {
if pair, ok := colPairMap[tag]; ok {
pair[1] = &col
colPairMap[tag] = pair
} else {
colPairMap[tag] = columnPair{nil, &col}
unionTags = append(unionTags, tag)
}
return false, nil
})
return colPairMap, unionTags
}
type IndexDifference struct {
DiffType SchemaChangeType
From schema.Index
To schema.Index
}
// DiffSchIndexes matches two sets of Indexes based on column definitions.
// It returns matched and unmatched Indexes as a slice of IndexDifferences.
func DiffSchIndexes(fromSch, toSch schema.Schema) (diffs []IndexDifference) {
_ = fromSch.Indexes().Iter(func(fromIdx schema.Index) (stop bool, err error) {
toIdx, ok := toSch.Indexes().GetIndexByTags(fromIdx.IndexedColumnTags()...)
if !ok {
diffs = append(diffs, IndexDifference{
DiffType: SchDiffRemoved,
From: fromIdx,
})
return false, nil
}
d := IndexDifference{
DiffType: SchDiffModified,
From: fromIdx,
To: toIdx,
}
if fromIdx.Equals(toIdx) {
d.DiffType = SchDiffNone
}
diffs = append(diffs, d)
return false, nil
})
_ = toSch.Indexes().Iter(func(toIdx schema.Index) (stop bool, err error) {
// if we've seen this index, skip
for _, d := range diffs {
if d.To != nil && d.To.Equals(toIdx) {
return false, nil
}
}
diffs = append(diffs, IndexDifference{
DiffType: SchDiffAdded,
To: toIdx,
})
return false, nil
})
return diffs
}
type ForeignKeyDifference struct {
DiffType SchemaChangeType
From doltdb.ForeignKey
To doltdb.ForeignKey
}
// DiffForeignKeys matches two sets of ForeignKeys based on column definitions.
// It returns matched and unmatched ForeignKeys as a slice of ForeignKeyDifferences.
func DiffForeignKeys(fromFks, toFKs []doltdb.ForeignKey) (diffs []ForeignKeyDifference) {
for _, from := range fromFks {
matched := false
for _, to := range toFKs {
if reflect.DeepEqual(from.ReferencedTableColumns, to.ReferencedTableColumns) &&
reflect.DeepEqual(from.TableColumns, to.TableColumns) {
matched = true
d := ForeignKeyDifference{
DiffType: SchDiffModified,
From: from,
To: to,
}
if from.DeepEquals(to) {
d.DiffType = SchDiffNone
}
diffs = append(diffs, d)
break
}
}
if !matched {
diffs = append(diffs, ForeignKeyDifference{
DiffType: SchDiffRemoved,
From: from,
})
}
}
for _, to := range toFKs {
seen := false
for _, d := range diffs {
if d.To.DeepEquals(to) {
seen = true
break
}
}
if seen {
continue
}
diffs = append(diffs, ForeignKeyDifference{
DiffType: SchDiffAdded,
To: to,
})
}
return diffs
}