mirror of
https://github.com/dolthub/dolt.git
synced 2026-05-04 11:30:14 -05:00
go/{doltcore/merge, store}: refactored MergeRoots to return conflicts, serialization method for unmergable tables
This commit is contained in:
@@ -217,13 +217,13 @@ func getCherryPickedRootValue(ctx context.Context, dEnv *env.DoltEnv, workingRoo
|
||||
|
||||
// use parent of cherry-pick as ancestor to merge
|
||||
mo := merge.MergeOpts{IsCherryPick: true}
|
||||
mergedRoot, mergeStats, err := merge.MergeRoots(ctx, workingRoot, cherryRoot, parentRoot, cherryCm, parentCm, opts, mo)
|
||||
result, err := merge.MergeRoots(ctx, workingRoot, cherryRoot, parentRoot, cherryCm, parentCm, opts, mo)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
var tablesWithConflict []string
|
||||
for tbl, stats := range mergeStats {
|
||||
for tbl, stats := range result.Stats {
|
||||
if stats.Conflicts > 0 {
|
||||
tablesWithConflict = append(tablesWithConflict, tbl)
|
||||
}
|
||||
@@ -234,5 +234,5 @@ func getCherryPickedRootValue(ctx context.Context, dEnv *env.DoltEnv, workingRoo
|
||||
return nil, "", errors.New(fmt.Sprintf("conflicts in table {'%s'}", tblNames))
|
||||
}
|
||||
|
||||
return mergedRoot, commitMsg, nil
|
||||
return result.Root, commitMsg, nil
|
||||
}
|
||||
|
||||
@@ -153,13 +153,13 @@ func applyStashAtIdx(ctx context.Context, dEnv *env.DoltEnv, curWorkingRoot *dol
|
||||
}
|
||||
|
||||
opts := editor.Options{Deaf: dEnv.BulkDbEaFactory(), Tempdir: tmpDir}
|
||||
mergedRoot, mergeStats, err := merge.MergeRoots(ctx, curWorkingRoot, stashRoot, parentRoot, stashRoot, parentCommit, opts, merge.MergeOpts{IsCherryPick: false})
|
||||
result, err := merge.MergeRoots(ctx, curWorkingRoot, stashRoot, parentRoot, stashRoot, parentCommit, opts, merge.MergeOpts{IsCherryPick: false})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
var tablesWithConflict []string
|
||||
for tbl, stats := range mergeStats {
|
||||
for tbl, stats := range result.Stats {
|
||||
if stats.Conflicts > 0 {
|
||||
tablesWithConflict = append(tablesWithConflict, tbl)
|
||||
}
|
||||
@@ -173,7 +173,7 @@ func applyStashAtIdx(ctx context.Context, dEnv *env.DoltEnv, curWorkingRoot *dol
|
||||
return false, nil
|
||||
}
|
||||
|
||||
err = dEnv.UpdateWorkingRoot(ctx, mergedRoot)
|
||||
err = dEnv.UpdateWorkingRoot(ctx, result.Root)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
@@ -353,7 +353,7 @@ func (rcv *MergeState) FromCommitSpecStr() []byte {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rcv *MergeState) SchemaConflictTables(j int) []byte {
|
||||
func (rcv *MergeState) UnmergableTables(j int) []byte {
|
||||
o := flatbuffers.UOffsetT(rcv._tab.Offset(10))
|
||||
if o != 0 {
|
||||
a := rcv._tab.Vector(o)
|
||||
@@ -362,7 +362,7 @@ func (rcv *MergeState) SchemaConflictTables(j int) []byte {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rcv *MergeState) SchemaConflictTablesLength() int {
|
||||
func (rcv *MergeState) UnmergableTablesLength() int {
|
||||
o := flatbuffers.UOffsetT(rcv._tab.Offset(10))
|
||||
if o != 0 {
|
||||
return rcv._tab.VectorLen(o)
|
||||
@@ -390,10 +390,10 @@ func MergeStateStartFromCommitAddrVector(builder *flatbuffers.Builder, numElems
|
||||
func MergeStateAddFromCommitSpecStr(builder *flatbuffers.Builder, fromCommitSpecStr flatbuffers.UOffsetT) {
|
||||
builder.PrependUOffsetTSlot(2, flatbuffers.UOffsetT(fromCommitSpecStr), 0)
|
||||
}
|
||||
func MergeStateAddSchemaConflictTables(builder *flatbuffers.Builder, schemaConflictTables flatbuffers.UOffsetT) {
|
||||
builder.PrependUOffsetTSlot(3, flatbuffers.UOffsetT(schemaConflictTables), 0)
|
||||
func MergeStateAddUnmergableTables(builder *flatbuffers.Builder, unmergableTables flatbuffers.UOffsetT) {
|
||||
builder.PrependUOffsetTSlot(3, flatbuffers.UOffsetT(unmergableTables), 0)
|
||||
}
|
||||
func MergeStateStartSchemaConflictTablesVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
|
||||
func MergeStateStartUnmergableTablesVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
|
||||
return builder.StartVector(4, numElems, 4)
|
||||
}
|
||||
func MergeStateEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
|
||||
|
||||
@@ -35,10 +35,11 @@ type MergeState struct {
|
||||
commitSpecStr string
|
||||
preMergeWorking *RootValue
|
||||
|
||||
sourceCommit hash.Hash
|
||||
schemaConflictTables []string
|
||||
sourceCommit hash.Hash
|
||||
unmergableTables []string
|
||||
}
|
||||
|
||||
// todo(andy): this might make more sense in pkg merge
|
||||
type SchemaConflict struct {
|
||||
ToSch, FromSch schema.Schema
|
||||
ToFks, FromFks []ForeignKey
|
||||
@@ -78,7 +79,7 @@ func (m MergeState) PreMergeWorkingRoot() *RootValue {
|
||||
type SchemaConflictFn func(table string, conflict SchemaConflict) error
|
||||
|
||||
func (m MergeState) HasSchemaConflicts() bool {
|
||||
return len(m.schemaConflictTables) > 0
|
||||
return len(m.unmergableTables) > 0
|
||||
}
|
||||
|
||||
func (m MergeState) IterSchemaConflicts(ctx context.Context, ddb *DoltDB, cb SchemaConflictFn) error {
|
||||
@@ -111,7 +112,7 @@ func (m MergeState) IterSchemaConflicts(ctx context.Context, ddb *DoltDB, cb Sch
|
||||
return err
|
||||
}
|
||||
|
||||
for _, name := range m.schemaConflictTables {
|
||||
for _, name := range m.unmergableTables {
|
||||
var toTbl, fromTbl *Table
|
||||
if toTbl, _, err = to.GetTable(ctx, name); err != nil {
|
||||
return err
|
||||
@@ -286,10 +287,16 @@ func NewWorkingSet(ctx context.Context, name string, vrw types.ValueReadWriter,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
unmergableTables, err := dsws.MergeState.UnmergableTables(ctx, vrw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mergeState = &MergeState{
|
||||
commit: commit,
|
||||
commitSpecStr: commitSpec,
|
||||
preMergeWorking: preMergeWorkingRoot,
|
||||
commit: commit,
|
||||
commitSpecStr: commitSpec,
|
||||
preMergeWorking: preMergeWorkingRoot,
|
||||
unmergableTables: unmergableTables,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -182,18 +182,22 @@ func ExecuteMerge(ctx context.Context, dEnv *env.DoltEnv, spec *MergeSpec) (map[
|
||||
return nil, err
|
||||
}
|
||||
opts := editor.Options{Deaf: dEnv.BulkDbEaFactory(), Tempdir: tmpDir}
|
||||
mergedRoot, tblToStats, err := MergeCommits(ctx, spec.HeadC, spec.MergeC, opts)
|
||||
result, err := MergeCommits(ctx, spec.HeadC, spec.MergeC, opts)
|
||||
if err != nil {
|
||||
switch err {
|
||||
case doltdb.ErrUpToDate:
|
||||
return tblToStats, fmt.Errorf("already up to date; %w", err)
|
||||
return result.Stats, fmt.Errorf("already up to date; %w", err)
|
||||
case ErrFastForward:
|
||||
panic("fast forward merge")
|
||||
}
|
||||
return tblToStats, err
|
||||
return result.Stats, err
|
||||
}
|
||||
|
||||
return tblToStats, mergedRootToWorking(ctx, spec.Squash, dEnv, mergedRoot, spec.WorkingDiffs, spec.MergeC, spec.MergeCSpecStr, tblToStats)
|
||||
err = mergedRootToWorking(ctx, spec.Squash, dEnv, result.Root, spec.WorkingDiffs, spec.MergeC, spec.MergeCSpecStr, result.Stats)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result.Stats, nil
|
||||
}
|
||||
|
||||
// TODO: change this to be functional and not write to repo state
|
||||
|
||||
@@ -29,7 +29,6 @@ import (
|
||||
|
||||
var ErrFastForward = errors.New("fast forward")
|
||||
var ErrTableDeletedAndModified = errors.New("conflict: table with same name deleted and modified ")
|
||||
var ErrSchemaConflict = errors.New("schema conflict found, merge aborted. Please alter schema to prevent schema conflicts before merging")
|
||||
|
||||
// ErrCantOverwriteConflicts is returned when there are unresolved conflicts
|
||||
// and the merge produces new conflicts. Because we currently don't have a model
|
||||
@@ -45,30 +44,35 @@ var ErrMultipleViolationsForRow = errors.New("multiple violations for row not su
|
||||
|
||||
var ErrSameTblAddedTwice = goerrors.NewKind("table with same name '%s' added in 2 commits can't be merged")
|
||||
|
||||
func MergeCommits(ctx context.Context, commit, mergeCommit *doltdb.Commit, opts editor.Options) (*doltdb.RootValue, map[string]*MergeStats, error) {
|
||||
func MergeCommits(ctx context.Context, commit, mergeCommit *doltdb.Commit, opts editor.Options) (*Result, error) {
|
||||
ancCommit, err := doltdb.GetCommitAncestor(ctx, commit, mergeCommit)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ourRoot, err := commit.GetRootValue(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
theirRoot, err := mergeCommit.GetRootValue(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ancRoot, err := ancCommit.GetRootValue(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return MergeRoots(ctx, ourRoot, theirRoot, ancRoot, mergeCommit, ancCommit, opts, MergeOpts{IsCherryPick: false})
|
||||
}
|
||||
|
||||
type Result struct {
|
||||
Root *doltdb.RootValue
|
||||
SchemaConflicts []string
|
||||
Stats map[string]*MergeStats
|
||||
}
|
||||
|
||||
// MergeRoots three-way merges |ourRoot|, |theirRoot|, and |ancRoot| and returns
|
||||
// the merged root. If any conflicts or constraint violations are produced they
|
||||
// are stored in the merged root. If |ourRoot| already contains conflicts they
|
||||
@@ -88,18 +92,18 @@ func MergeRoots(
|
||||
theirs, ancestor doltdb.Rootish,
|
||||
opts editor.Options,
|
||||
mergeOpts MergeOpts,
|
||||
) (*doltdb.RootValue, map[string]*MergeStats, error) {
|
||||
) (*Result, error) {
|
||||
var conflictStash *conflictStash
|
||||
var violationStash *violationStash
|
||||
var err error
|
||||
if !types.IsFormat_DOLT(ourRoot.VRW().Format()) {
|
||||
ourRoot, conflictStash, err = stashConflicts(ctx, ourRoot)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
ancRoot, violationStash, err = stashViolations(ctx, ancRoot)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,7 +116,7 @@ func MergeRoots(
|
||||
tblNames, err := doltdb.UnionTableNames(ctx, ourRoot, theirRoot)
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tblToStats := make(map[string]*MergeStats)
|
||||
@@ -127,13 +131,16 @@ func MergeRoots(
|
||||
// TODO: merge based on a more durable table identity that persists across renames
|
||||
merger, err := NewMerger(ourRoot, theirRoot, ancRoot, theirs, ancestor, ourRoot.VRW(), ourRoot.NodeStore())
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var schConflictTables []string
|
||||
for _, tblName := range tblNames {
|
||||
mergedTable, stats, err := merger.MergeTable(ctx, tblName, opts, mergeOpts)
|
||||
|
||||
schConflictTables, err = filterSchemaConflicts(schConflictTables, err)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if mergedTable != nil {
|
||||
@@ -141,14 +148,14 @@ func MergeRoots(
|
||||
|
||||
mergedRoot, err = mergedRoot.PutTable(ctx, tblName, mergedTable)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
newRootHasTable, err := mergedRoot.HasTable(ctx, tblName)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if newRootHasTable {
|
||||
@@ -157,7 +164,7 @@ func MergeRoots(
|
||||
|
||||
mergedRoot, err = mergedRoot.RemoveTables(ctx, false, false, tblName)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
} else {
|
||||
@@ -171,57 +178,73 @@ func MergeRoots(
|
||||
|
||||
mergedFKColl, conflicts, err := ForeignKeysMerge(ctx, mergedRoot, ourRoot, theirRoot, ancRoot)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
if len(conflicts) > 0 {
|
||||
return nil, nil, fmt.Errorf("foreign key conflicts")
|
||||
return nil, fmt.Errorf("foreign key conflicts")
|
||||
}
|
||||
|
||||
mergedRoot, err = mergedRoot.PutForeignKeyCollection(ctx, mergedFKColl)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
h, err := merger.rightSrc.HashOf()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mergedRoot, _, err = AddForeignKeyViolations(ctx, mergedRoot, ancRoot, nil, h)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if types.IsFormat_DOLT(ourRoot.VRW().Format()) {
|
||||
err = getConstraintViolationStats(ctx, mergedRoot, tblToStats)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return mergedRoot, tblToStats, nil
|
||||
return &Result{
|
||||
Root: mergedRoot,
|
||||
SchemaConflicts: schConflictTables,
|
||||
Stats: tblToStats,
|
||||
}, nil
|
||||
}
|
||||
|
||||
mergedRoot, err = mergeCVsWithStash(ctx, mergedRoot, violationStash)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = getConstraintViolationStats(ctx, mergedRoot, tblToStats)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mergedHasConflicts := checkForConflicts(tblToStats)
|
||||
if !conflictStash.Empty() && mergedHasConflicts {
|
||||
return nil, nil, ErrCantOverwriteConflicts
|
||||
return nil, ErrCantOverwriteConflicts
|
||||
} else if !conflictStash.Empty() {
|
||||
mergedRoot, err = applyConflictStash(ctx, conflictStash.Stash, mergedRoot)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return mergedRoot, tblToStats, nil
|
||||
return &Result{
|
||||
Root: mergedRoot,
|
||||
SchemaConflicts: schConflictTables,
|
||||
Stats: tblToStats,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func filterSchemaConflicts(conflicts []string, err error) ([]string, error) {
|
||||
if sc, ok := err.(SchemaConflict); ok {
|
||||
conflicts = append(conflicts, sc.TableName)
|
||||
err = nil
|
||||
}
|
||||
return conflicts, err
|
||||
}
|
||||
|
||||
// mergeCVsWithStash merges the table constraint violations in |stash| with |root|.
|
||||
|
||||
@@ -126,10 +126,9 @@ func (rm *RootMerger) MergeTable(ctx context.Context, tblName string, opts edito
|
||||
mergeSch, schConflicts, err := SchemaMerge(ctx, tm.vrw.Format(), tm.leftSch, tm.rightSch, tm.ancSch, tblName)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if schConflicts.Count() != 0 {
|
||||
// error on schema conflicts for now
|
||||
return nil, nil, fmt.Errorf("%w.\n%s", ErrSchemaConflict, schConflicts.AsError().Error())
|
||||
} else if schConflicts.Count() > 0 {
|
||||
// handle schema conflicts above
|
||||
return nil, nil, schConflicts
|
||||
}
|
||||
|
||||
if types.IsFormat_DOLT(tm.vrw.Format()) {
|
||||
|
||||
@@ -45,15 +45,18 @@ type SchemaConflict struct {
|
||||
ChkConflicts []ChkConflict
|
||||
}
|
||||
|
||||
var EmptySchConflicts = SchemaConflict{}
|
||||
var _ error = SchemaConflict{}
|
||||
|
||||
func (sc SchemaConflict) Count() int {
|
||||
return len(sc.ColConflicts) + len(sc.IdxConflicts) + len(sc.ChkConflicts)
|
||||
}
|
||||
|
||||
func (sc SchemaConflict) AsError() error {
|
||||
func (sc SchemaConflict) Error() string {
|
||||
|
||||
var b strings.Builder
|
||||
b.WriteString(fmt.Sprintf("schema conflicts for table %s:\n", sc.TableName))
|
||||
b.WriteString("merge aborted: schema conflict found for table ")
|
||||
b.WriteString(sc.TableName)
|
||||
b.WriteString("\n please resolve schema conflicts before merging")
|
||||
for _, c := range sc.ColConflicts {
|
||||
b.WriteString(fmt.Sprintf("\t%s\n", c.String()))
|
||||
}
|
||||
@@ -63,7 +66,7 @@ func (sc SchemaConflict) AsError() error {
|
||||
for _, c := range sc.ChkConflicts {
|
||||
b.WriteString(fmt.Sprintf("\t%s\n", c.String()))
|
||||
}
|
||||
return fmt.Errorf(b.String())
|
||||
return b.String()
|
||||
}
|
||||
|
||||
type ColConflict struct {
|
||||
@@ -136,7 +139,7 @@ func SchemaMerge(ctx context.Context, format *types.NomsBinFormat, ourSch, their
|
||||
var mergedCC *schema.ColCollection
|
||||
mergedCC, sc.ColConflicts, err = mergeColumns(ourSch.GetAllCols(), theirSch.GetAllCols(), ancSch.GetAllCols())
|
||||
if err != nil {
|
||||
return nil, EmptySchConflicts, err
|
||||
return nil, SchemaConflict{}, err
|
||||
}
|
||||
if len(sc.ColConflicts) > 0 {
|
||||
return nil, sc, nil
|
||||
@@ -168,7 +171,7 @@ func SchemaMerge(ctx context.Context, format *types.NomsBinFormat, ourSch, their
|
||||
var mergedChks []schema.Check
|
||||
mergedChks, sc.ChkConflicts, err = mergeChecks(ctx, ourSch.Checks(), theirSch.Checks(), ancSch.Checks())
|
||||
if err != nil {
|
||||
return nil, EmptySchConflicts, err
|
||||
return nil, SchemaConflict{}, err
|
||||
}
|
||||
if len(sc.ChkConflicts) > 0 {
|
||||
return nil, sc, nil
|
||||
|
||||
@@ -68,16 +68,19 @@ func Revert(ctx context.Context, ddb *doltdb.DoltDB, root *doltdb.RootValue, hea
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
root, _, err = MergeRoots(ctx, root, theirRoot, baseRoot, parentCM, baseCommit, opts, MergeOpts{IsCherryPick: false})
|
||||
var result *Result
|
||||
result, err = MergeRoots(ctx, root, theirRoot, baseRoot, parentCM, baseCommit, opts, MergeOpts{IsCherryPick: false})
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
if ok, err := root.HasConflicts(ctx); err != nil {
|
||||
root = result.Root
|
||||
|
||||
if ok, err := result.Root.HasConflicts(ctx); err != nil {
|
||||
return nil, "", err
|
||||
} else if ok {
|
||||
return nil, "", fmt.Errorf("revert currently does not handle conflicts")
|
||||
}
|
||||
if ok, err := root.HasConstraintViolations(ctx); err != nil {
|
||||
if ok, err := result.Root.HasConstraintViolations(ctx); err != nil {
|
||||
return nil, "", err
|
||||
} else if ok {
|
||||
return nil, "", fmt.Errorf("revert currently does not handle constraint violations")
|
||||
|
||||
@@ -687,10 +687,10 @@ func testMergeForeignKeys(t *testing.T, test mergeForeignKeyTest) {
|
||||
|
||||
opts := editor.TestEditorOptions(dEnv.DoltDB.ValueReadWriter())
|
||||
mo := merge.MergeOpts{IsCherryPick: false}
|
||||
mergedRoot, _, err := merge.MergeRoots(ctx, mainRoot, otherRoot, ancRoot, mainWS, otherWS, opts, mo)
|
||||
result, err := merge.MergeRoots(ctx, mainRoot, otherRoot, ancRoot, mainWS, otherWS, opts, mo)
|
||||
assert.NoError(t, err)
|
||||
|
||||
fkc, err := mergedRoot.GetForeignKeyCollection(ctx)
|
||||
fkc, err := result.Root.GetForeignKeyCollection(ctx)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, test.fkColl.Count(), fkc.Count())
|
||||
|
||||
|
||||
@@ -551,12 +551,12 @@ func testSchemaMerge(t *testing.T, tests []schemaMergeTest) {
|
||||
var eo editor.Options
|
||||
eo = eo.WithDeaf(editor.NewInMemDeaf(a.VRW()))
|
||||
// attempt merge before skipping to assert no panics
|
||||
root, _, err := merge.MergeRoots(ctx, l, r, a, rootish{r}, rootish{a}, eo, mo)
|
||||
result, err := merge.MergeRoots(ctx, l, r, a, rootish{r}, rootish{a}, eo, mo)
|
||||
maybeSkip(t, a.VRW().Format(), test)
|
||||
require.NoError(t, err)
|
||||
exp, err := m.MapTableHashes(ctx)
|
||||
assert.NoError(t, err)
|
||||
act, err := root.MapTableHashes(ctx)
|
||||
act, err := result.Root.MapTableHashes(ctx)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, len(exp), len(act))
|
||||
|
||||
@@ -171,13 +171,13 @@ func cherryPick(ctx *sql.Context, dSess *dsess.DoltSession, roots doltdb.Roots,
|
||||
|
||||
// use parent of cherry-pick as ancestor root to merge
|
||||
mo := merge.MergeOpts{IsCherryPick: true}
|
||||
mergedRoot, mergeStats, err := merge.MergeRoots(ctx, roots.Working, cherryRoot, parentRoot, cherryCommit, parentCommit, dbState.EditOpts(), mo)
|
||||
result, err := merge.MergeRoots(ctx, roots.Working, cherryRoot, parentRoot, cherryCommit, parentCommit, dbState.EditOpts(), mo)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
var tablesWithConflict []string
|
||||
for tbl, stats := range mergeStats {
|
||||
for tbl, stats := range result.Stats {
|
||||
if stats.Conflicts > 0 {
|
||||
tablesWithConflict = append(tablesWithConflict, tbl)
|
||||
}
|
||||
@@ -188,7 +188,7 @@ func cherryPick(ctx *sql.Context, dSess *dsess.DoltSession, roots doltdb.Roots,
|
||||
return nil, "", fmt.Errorf("conflicts in table {'%s'}", tblNames)
|
||||
}
|
||||
|
||||
workingRootHash, err = mergedRoot.HashOf()
|
||||
workingRootHash, err = result.Root.HashOf()
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
@@ -202,5 +202,5 @@ func cherryPick(ctx *sql.Context, dSess *dsess.DoltSession, roots doltdb.Roots,
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
return mergedRoot, cherryCommitMeta.Description, nil
|
||||
return result.Root, cherryCommitMeta.Description, nil
|
||||
}
|
||||
|
||||
@@ -243,8 +243,7 @@ func abortMerge(ctx *sql.Context, workingSet *doltdb.WorkingSet, roots doltdb.Ro
|
||||
}
|
||||
|
||||
func executeMerge(ctx *sql.Context, squash bool, head, cm *doltdb.Commit, cmSpec string, ws *doltdb.WorkingSet, opts editor.Options) (*doltdb.WorkingSet, error) {
|
||||
mergeRoot, mergeStats, err := merge.MergeCommits(ctx, head, cm, opts)
|
||||
|
||||
result, err := merge.MergeCommits(ctx, head, cm, opts)
|
||||
if err != nil {
|
||||
switch err {
|
||||
case doltdb.ErrUpToDate:
|
||||
@@ -255,8 +254,7 @@ func executeMerge(ctx *sql.Context, squash bool, head, cm *doltdb.Commit, cmSpec
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return mergeRootToWorking(squash, ws, mergeRoot, cm, cmSpec, mergeStats)
|
||||
return mergeRootToWorking(squash, ws, result.Root, cm, cmSpec, result.Stats)
|
||||
}
|
||||
|
||||
func executeFFMerge(ctx *sql.Context, dbName string, squash bool, ws *doltdb.WorkingSet, dbData env.DbData, cm2 *doltdb.Commit) (*doltdb.WorkingSet, error) {
|
||||
|
||||
@@ -184,7 +184,7 @@ func doltCommit(ctx *sql.Context,
|
||||
// updates). The merged root value becomes our new Staged root value which
|
||||
// is the value which we are trying to commit.
|
||||
start := time.Now()
|
||||
pending.Roots.Staged, _, err = merge.MergeRoots(
|
||||
result, err := merge.MergeRoots(
|
||||
ctx,
|
||||
pending.Roots.Staged,
|
||||
curRootVal,
|
||||
@@ -196,6 +196,7 @@ func doltCommit(ctx *sql.Context,
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
pending.Roots.Staged = result.Root
|
||||
|
||||
// We also need to update the working set to reflect the new staged root value
|
||||
workingSet = workingSet.WithStagedRoot(pending.Roots.Staged)
|
||||
@@ -321,7 +322,7 @@ func (tx *DoltTransaction) mergeRoots(
|
||||
) (*doltdb.WorkingSet, error) {
|
||||
|
||||
if !rootsEqual(existingWorkingSet.WorkingRoot(), workingSet.WorkingRoot()) {
|
||||
mergedRoot, _, err := merge.MergeRoots(
|
||||
result, err := merge.MergeRoots(
|
||||
ctx,
|
||||
existingWorkingSet.WorkingRoot(),
|
||||
workingSet.WorkingRoot(),
|
||||
@@ -333,11 +334,11 @@ func (tx *DoltTransaction) mergeRoots(
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
workingSet = workingSet.WithWorkingRoot(mergedRoot)
|
||||
workingSet = workingSet.WithWorkingRoot(result.Root)
|
||||
}
|
||||
|
||||
if !rootsEqual(existingWorkingSet.StagedRoot(), workingSet.StagedRoot()) {
|
||||
mergedRoot, _, err := merge.MergeRoots(
|
||||
result, err := merge.MergeRoots(
|
||||
ctx,
|
||||
existingWorkingSet.StagedRoot(),
|
||||
workingSet.StagedRoot(),
|
||||
@@ -349,7 +350,7 @@ func (tx *DoltTransaction) mergeRoots(
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
workingSet = workingSet.WithStagedRoot(mergedRoot)
|
||||
workingSet = workingSet.WithStagedRoot(result.Root)
|
||||
}
|
||||
|
||||
return workingSet, nil
|
||||
|
||||
@@ -37,7 +37,7 @@ table MergeState {
|
||||
// for backwards compatibility.
|
||||
from_commit_spec_str:string;
|
||||
|
||||
schema_conflict_tables:[string];
|
||||
unmergable_tables:[string];
|
||||
}
|
||||
|
||||
// KEEP THIS IN SYNC WITH fileidentifiers.go
|
||||
|
||||
@@ -324,7 +324,7 @@ func LoadCommitAddr(ctx context.Context, vr types.ValueReader, addr hash.Hash) (
|
||||
return nil, err
|
||||
}
|
||||
if v == nil {
|
||||
return nil, errors.New("target commit (" + addr.String() + ") not found")
|
||||
return nil, errors.New("target commit not found")
|
||||
}
|
||||
return commitFromValue(vr.Format(), v)
|
||||
}
|
||||
|
||||
@@ -164,6 +164,7 @@ type MergeState struct {
|
||||
preMergeWorkingAddr *hash.Hash
|
||||
fromCommitAddr *hash.Hash
|
||||
fromCommitSpec string
|
||||
unmergableTables []string
|
||||
|
||||
nomsMergeStateRef *types.Ref
|
||||
nomsMergeState *types.Struct
|
||||
@@ -255,6 +256,13 @@ func (ms *MergeState) FromCommitSpec(ctx context.Context, vr types.ValueReader)
|
||||
return string(commitSpecStr.(types.String)), nil
|
||||
}
|
||||
|
||||
func (ms *MergeState) UnmergableTables(ctx context.Context, vr types.ValueReader) ([]string, error) {
|
||||
if vr.Format().UsesFlatbuffers() {
|
||||
return ms.unmergableTables, nil
|
||||
}
|
||||
return nil, errors.New("schema conflicts only supported for fmt __DOLT__")
|
||||
}
|
||||
|
||||
type dsHead interface {
|
||||
TypeName() string
|
||||
Addr() hash.Hash
|
||||
@@ -369,6 +377,10 @@ func (h serialWorkingSetHead) HeadWorkingSet() (*WorkingSetHead, error) {
|
||||
}
|
||||
*ret.MergeState.preMergeWorkingAddr = hash.New(mergeState.PreWorkingRootAddrBytes())
|
||||
*ret.MergeState.fromCommitAddr = hash.New(mergeState.FromCommitAddrBytes())
|
||||
ret.MergeState.unmergableTables = make([]string, mergeState.UnmergableTablesLength())
|
||||
for i := range ret.MergeState.unmergableTables {
|
||||
ret.MergeState.unmergableTables[i] = string(mergeState.UnmergableTables(i))
|
||||
}
|
||||
}
|
||||
return &ret, nil
|
||||
}
|
||||
|
||||
@@ -162,10 +162,12 @@ func workingset_flatbuffer(working hash.Hash, staged *hash.Hash, mergeState *Mer
|
||||
prerootaddroff := builder.CreateByteVector((*mergeState.preMergeWorkingAddr)[:])
|
||||
fromaddroff := builder.CreateByteVector((*mergeState.fromCommitAddr)[:])
|
||||
fromspecoff := builder.CreateString(mergeState.fromCommitSpec)
|
||||
unmergableoff := SerializeStringVector(builder, mergeState.unmergableTables)
|
||||
serial.MergeStateStart(builder)
|
||||
serial.MergeStateAddPreWorkingRootAddr(builder, prerootaddroff)
|
||||
serial.MergeStateAddFromCommitAddr(builder, fromaddroff)
|
||||
serial.MergeStateAddFromCommitSpecStr(builder, fromspecoff)
|
||||
serial.MergeStateAddUnmergableTables(builder, unmergableoff)
|
||||
mergeStateOff = serial.MergeStateEnd(builder)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user