github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/libraries/doltcore/merge/merge.go (about)

     1  // Copyright 2019 Dolthub, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package merge
    16  
    17  import (
    18  	"context"
    19  	"errors"
    20  	"fmt"
    21  	"strings"
    22  
    23  	"golang.org/x/sync/errgroup"
    24  
    25  	"github.com/dolthub/dolt/go/libraries/doltcore/diff"
    26  	"github.com/dolthub/dolt/go/libraries/doltcore/doltdb"
    27  	"github.com/dolthub/dolt/go/libraries/doltcore/env"
    28  	"github.com/dolthub/dolt/go/libraries/doltcore/row"
    29  	"github.com/dolthub/dolt/go/libraries/doltcore/schema"
    30  	"github.com/dolthub/dolt/go/libraries/doltcore/table/editor"
    31  	"github.com/dolthub/dolt/go/libraries/utils/valutil"
    32  	"github.com/dolthub/dolt/go/store/atomicerr"
    33  	"github.com/dolthub/dolt/go/store/hash"
    34  	"github.com/dolthub/dolt/go/store/types"
    35  )
    36  
    37  var ErrFastForward = errors.New("fast forward")
    38  var ErrSameTblAddedTwice = errors.New("table with same name added in 2 commits can't be merged")
    39  
    40  type Merger struct {
    41  	root      *doltdb.RootValue
    42  	mergeRoot *doltdb.RootValue
    43  	ancRoot   *doltdb.RootValue
    44  	vrw       types.ValueReadWriter
    45  }
    46  
    47  // NewMerger creates a new merger utility object.
    48  func NewMerger(ctx context.Context, root, mergeRoot, ancRoot *doltdb.RootValue, vrw types.ValueReadWriter) *Merger {
    49  	return &Merger{root, mergeRoot, ancRoot, vrw}
    50  }
    51  
    52  // MergeTable merges schema and table data for the table tblName.
    53  func (merger *Merger) MergeTable(ctx context.Context, tblName string, sess *editor.TableEditSession) (*doltdb.Table, *MergeStats, error) {
    54  	tbl, ok, err := merger.root.GetTable(ctx, tblName)
    55  	if err != nil {
    56  		return nil, nil, err
    57  	}
    58  
    59  	var h hash.Hash
    60  	var tblSchema schema.Schema
    61  	if ok {
    62  		h, err = tbl.HashOf()
    63  		if err != nil {
    64  			return nil, nil, err
    65  		}
    66  		tblSchema, err = tbl.GetSchema(ctx)
    67  		if err != nil {
    68  			return nil, nil, err
    69  		}
    70  	}
    71  
    72  	mergeTbl, mergeOk, err := merger.mergeRoot.GetTable(ctx, tblName)
    73  	if err != nil {
    74  		return nil, nil, err
    75  	}
    76  
    77  	var mh hash.Hash
    78  	var mergeTblSchema schema.Schema
    79  	if mergeOk {
    80  		mh, err = mergeTbl.HashOf()
    81  		if err != nil {
    82  			return nil, nil, err
    83  		}
    84  		mergeTblSchema, err = mergeTbl.GetSchema(ctx)
    85  		if err != nil {
    86  			return nil, nil, err
    87  		}
    88  	}
    89  
    90  	ancTbl, ancOk, err := merger.ancRoot.GetTable(ctx, tblName)
    91  	if err != nil {
    92  		return nil, nil, err
    93  	}
    94  
    95  	var anch hash.Hash
    96  	var ancTblSchema schema.Schema
    97  	var ancRows types.Map
    98  	if ancOk {
    99  		anch, err = ancTbl.HashOf()
   100  		if err != nil {
   101  			return nil, nil, err
   102  		}
   103  		ancTblSchema, err = ancTbl.GetSchema(ctx)
   104  		if err != nil {
   105  			return nil, nil, err
   106  		}
   107  		ancRows, err = ancTbl.GetRowData(ctx)
   108  		if err != nil {
   109  			return nil, nil, err
   110  		}
   111  	}
   112  
   113  	{ // short-circuit logic
   114  		if ancOk && schema.IsKeyless(ancTblSchema) {
   115  			if ok && mergeOk && ancOk && h == mh && h == anch {
   116  				return tbl, &MergeStats{Operation: TableUnmodified}, nil
   117  			}
   118  		} else {
   119  			if ok && mergeOk && h == mh {
   120  				return tbl, &MergeStats{Operation: TableUnmodified}, nil
   121  			}
   122  		}
   123  
   124  		if !ancOk {
   125  			if mergeOk && ok {
   126  				if schema.SchemasAreEqual(tblSchema, mergeTblSchema) {
   127  					// hackity hack
   128  					ancTblSchema, ancTbl = tblSchema, tbl
   129  					ancRows, _ = types.NewMap(ctx, merger.vrw)
   130  				} else {
   131  					return nil, nil, ErrSameTblAddedTwice
   132  				}
   133  			} else if ok {
   134  				// fast-forward
   135  				return tbl, &MergeStats{Operation: TableUnmodified}, nil
   136  			} else {
   137  				// fast-forward
   138  				return mergeTbl, &MergeStats{Operation: TableAdded}, nil
   139  			}
   140  		}
   141  
   142  		if h == anch {
   143  			// fast-forward
   144  			ms := MergeStats{Operation: TableModified}
   145  			if h != mh {
   146  				ms, err = calcTableMergeStats(ctx, tbl, mergeTbl)
   147  				if err != nil {
   148  					return nil, nil, err
   149  				}
   150  			}
   151  			// force load the table editor since this counts as a change
   152  			_, err := sess.GetTableEditor(ctx, tblName, nil)
   153  			if err != nil {
   154  				return nil, nil, err
   155  			}
   156  			return mergeTbl, &ms, nil
   157  		} else if mh == anch {
   158  			// fast-forward
   159  			return tbl, &MergeStats{Operation: TableUnmodified}, nil
   160  		}
   161  	}
   162  
   163  	postMergeSchema, schConflicts, err := SchemaMerge(tblSchema, mergeTblSchema, ancTblSchema, tblName)
   164  	if err != nil {
   165  		return nil, nil, err
   166  	}
   167  	if schConflicts.Count() != 0 {
   168  		// error on schema conflicts for now
   169  		return nil, nil, schConflicts.AsError()
   170  	}
   171  
   172  	rows, err := tbl.GetRowData(ctx)
   173  	if err != nil {
   174  		return nil, nil, err
   175  	}
   176  
   177  	mergeRows, err := mergeTbl.GetRowData(ctx)
   178  	if err != nil {
   179  		return nil, nil, err
   180  	}
   181  
   182  	updatedTbl, err := tbl.UpdateSchema(ctx, postMergeSchema)
   183  	if err != nil {
   184  		return nil, nil, err
   185  	}
   186  
   187  	// If any indexes were added during the merge, then we need to generate their row data to add to our updated table.
   188  	addedIndexesSet := make(map[string]string)
   189  	for _, index := range postMergeSchema.Indexes().AllIndexes() {
   190  		addedIndexesSet[strings.ToLower(index.Name())] = index.Name()
   191  	}
   192  	for _, index := range tblSchema.Indexes().AllIndexes() {
   193  		delete(addedIndexesSet, strings.ToLower(index.Name()))
   194  	}
   195  	for _, addedIndex := range addedIndexesSet {
   196  		newIndexData, err := editor.RebuildIndex(ctx, updatedTbl, addedIndex)
   197  		if err != nil {
   198  			return nil, nil, err
   199  		}
   200  		updatedTbl, err = updatedTbl.SetIndexRowData(ctx, addedIndex, newIndexData)
   201  		if err != nil {
   202  			return nil, nil, err
   203  		}
   204  	}
   205  
   206  	err = sess.UpdateRoot(ctx, func(ctx context.Context, root *doltdb.RootValue) (*doltdb.RootValue, error) {
   207  		return root.PutTable(ctx, tblName, updatedTbl)
   208  	})
   209  	if err != nil {
   210  		return nil, nil, err
   211  	}
   212  
   213  	updatedTblEditor, err := sess.GetTableEditor(ctx, tblName, nil)
   214  	if err != nil {
   215  		return nil, nil, err
   216  	}
   217  
   218  	resultTbl, conflicts, stats, err := mergeTableData(ctx, merger.vrw, tblName, postMergeSchema, rows, mergeRows, ancRows, updatedTblEditor, sess)
   219  	if err != nil {
   220  		return nil, nil, err
   221  	}
   222  
   223  	if conflicts.Len() > 0 {
   224  
   225  		asr, err := ancTbl.GetSchemaRef()
   226  		if err != nil {
   227  			return nil, nil, err
   228  		}
   229  
   230  		sr, err := tbl.GetSchemaRef()
   231  		if err != nil {
   232  			return nil, nil, err
   233  		}
   234  
   235  		msr, err := mergeTbl.GetSchemaRef()
   236  		if err != nil {
   237  			return nil, nil, err
   238  		}
   239  
   240  		schemas := doltdb.NewConflict(asr, sr, msr)
   241  		resultTbl, err = resultTbl.SetConflicts(ctx, schemas, conflicts)
   242  		if err != nil {
   243  			return nil, nil, err
   244  		}
   245  	}
   246  
   247  	resultTbl, err = mergeAutoIncrementValues(ctx, tbl, mergeTbl, resultTbl)
   248  	if err != nil {
   249  		return nil, nil, err
   250  	}
   251  
   252  	return resultTbl, stats, nil
   253  }
   254  
   255  func calcTableMergeStats(ctx context.Context, tbl *doltdb.Table, mergeTbl *doltdb.Table) (MergeStats, error) {
   256  	rows, err := tbl.GetRowData(ctx)
   257  
   258  	if err != nil {
   259  		return MergeStats{}, err
   260  	}
   261  
   262  	mergeRows, err := mergeTbl.GetRowData(ctx)
   263  
   264  	if err != nil {
   265  		return MergeStats{}, err
   266  	}
   267  
   268  	ae := atomicerr.New()
   269  	ch := make(chan diff.DiffSummaryProgress)
   270  	go func() {
   271  		defer close(ch)
   272  		err := diff.Summary(ctx, ch, rows, mergeRows)
   273  
   274  		ae.SetIfError(err)
   275  	}()
   276  
   277  	ms := MergeStats{Operation: TableModified}
   278  	for p := range ch {
   279  		if ae.IsSet() {
   280  			break
   281  		}
   282  
   283  		ms.Adds += int(p.Adds)
   284  		ms.Deletes += int(p.Removes)
   285  		ms.Modifications += int(p.Changes)
   286  	}
   287  
   288  	if err := ae.Get(); err != nil {
   289  		return MergeStats{}, err
   290  	}
   291  
   292  	return ms, nil
   293  }
   294  
   295  type rowMerger func(ctx context.Context, nbf *types.NomsBinFormat, sch schema.Schema, r, mergeRow, baseRow types.Value) (types.Value, bool, error)
   296  
   297  type applicator func(ctx context.Context, sch schema.Schema, tableEditor editor.TableEditor, rowData types.Map, stats *MergeStats, change types.ValueChanged) error
   298  
   299  func mergeTableData(ctx context.Context, vrw types.ValueReadWriter, tblName string, sch schema.Schema, rows, mergeRows, ancRows types.Map, tblEdit editor.TableEditor, sess *editor.TableEditSession) (*doltdb.Table, types.Map, *MergeStats, error) {
   300  	var rowMerge rowMerger
   301  	var applyChange applicator
   302  	if schema.IsKeyless(sch) {
   303  		rowMerge = keylessRowMerge
   304  		applyChange = applyKeylessChange
   305  	} else {
   306  		rowMerge = pkRowMerge
   307  		applyChange = applyPkChange
   308  	}
   309  
   310  	changeChan, mergeChangeChan := make(chan types.ValueChanged, 32), make(chan types.ValueChanged, 32)
   311  
   312  	eg, ctx := errgroup.WithContext(ctx)
   313  
   314  	eg.Go(func() error {
   315  		defer close(changeChan)
   316  		return rows.Diff(ctx, ancRows, changeChan)
   317  	})
   318  	eg.Go(func() error {
   319  		defer close(mergeChangeChan)
   320  		return mergeRows.Diff(ctx, ancRows, mergeChangeChan)
   321  	})
   322  
   323  	conflictValChan := make(chan types.Value)
   324  	sm := types.NewStreamingMap(ctx, vrw, conflictValChan)
   325  	stats := &MergeStats{Operation: TableModified}
   326  
   327  	eg.Go(func() error {
   328  		defer close(conflictValChan)
   329  
   330  		var change, mergeChange types.ValueChanged
   331  		for {
   332  			// Get the next change from both a and b. If either diff(a, parent) or diff(b, parent) is
   333  			// complete, aChange or bChange will get an empty types.ValueChanged containing a nil Value.
   334  			// Generally, though, this allows us to proceed through both diffs in (key) order, considering
   335  			// the "current" change from both diffs at the same time.
   336  			if change.Key == nil {
   337  				select {
   338  				case change = <-changeChan:
   339  					break
   340  				case <-ctx.Done():
   341  					return ctx.Err()
   342  				}
   343  			}
   344  			if mergeChange.Key == nil {
   345  				select {
   346  				case mergeChange = <-mergeChangeChan:
   347  					break
   348  				case <-ctx.Done():
   349  					return ctx.Err()
   350  				}
   351  			}
   352  
   353  			key, mergeKey := change.Key, mergeChange.Key
   354  
   355  			// Both channels are producing zero values, so we're done.
   356  			if key == nil && mergeKey == nil {
   357  				break
   358  			}
   359  
   360  			var err error
   361  			var processed bool
   362  			if key != nil {
   363  				mkNilOrKeyLess := mergeKey == nil
   364  				if !mkNilOrKeyLess {
   365  					mkNilOrKeyLess, err = key.Less(vrw.Format(), mergeKey)
   366  					if err != nil {
   367  						return err
   368  					}
   369  				}
   370  
   371  				if mkNilOrKeyLess {
   372  					// change will already be in the map
   373  					// we apply changes directly to "ours"
   374  					// instead of to ancestor
   375  					change = types.ValueChanged{}
   376  					processed = true
   377  				}
   378  			}
   379  
   380  			if !processed && mergeKey != nil {
   381  				keyNilOrMKLess := key == nil
   382  				if !keyNilOrMKLess {
   383  					keyNilOrMKLess, err = mergeKey.Less(vrw.Format(), key)
   384  					if err != nil {
   385  						return err
   386  					}
   387  				}
   388  
   389  				if keyNilOrMKLess {
   390  					err = applyChange(ctx, sch, tblEdit, rows, stats, mergeChange)
   391  					if err != nil {
   392  						return err
   393  					}
   394  					mergeChange = types.ValueChanged{}
   395  					processed = true
   396  				}
   397  			}
   398  
   399  			if !processed {
   400  				r, mergeRow, ancRow := change.NewValue, mergeChange.NewValue, change.OldValue
   401  				mergedRow, isConflict, err := rowMerge(ctx, vrw.Format(), sch, r, mergeRow, ancRow)
   402  				if err != nil {
   403  					return err
   404  				}
   405  
   406  				if isConflict {
   407  					stats.Conflicts++
   408  					conflictTuple, err := doltdb.NewConflict(ancRow, r, mergeRow).ToNomsList(vrw)
   409  					if err != nil {
   410  						return err
   411  					}
   412  
   413  					err = addConflict(conflictValChan, sm.Done(), key, conflictTuple)
   414  					if err != nil {
   415  						return err
   416  					}
   417  				} else {
   418  					vc := types.ValueChanged{ChangeType: change.ChangeType, Key: key, OldValue: ancRow, NewValue: mergedRow}
   419  					err = applyChange(ctx, sch, tblEdit, rows, stats, vc)
   420  					if err != nil {
   421  						return err
   422  					}
   423  				}
   424  
   425  				change = types.ValueChanged{}
   426  				mergeChange = types.ValueChanged{}
   427  			}
   428  		}
   429  
   430  		return nil
   431  	})
   432  
   433  	if err := eg.Wait(); err != nil {
   434  		return nil, types.EmptyMap, nil, err
   435  	}
   436  
   437  	conflicts, err := sm.Wait()
   438  	if err != nil {
   439  		return nil, types.EmptyMap, nil, err
   440  	}
   441  	newRoot, err := sess.Flush(ctx)
   442  	if err != nil {
   443  		return nil, types.EmptyMap, nil, err
   444  	}
   445  
   446  	mergedTable, ok, err := newRoot.GetTable(ctx, tblName)
   447  	if err != nil {
   448  		return nil, types.EmptyMap, nil, err
   449  	}
   450  	if !ok {
   451  		return nil, types.EmptyMap, nil, fmt.Errorf("updated mergedTable `%s` has disappeared", tblName)
   452  	}
   453  
   454  	return mergedTable, conflicts, stats, nil
   455  }
   456  
   457  func addConflict(conflictChan chan types.Value, done <-chan struct{}, key types.Value, value types.Tuple) error {
   458  	select {
   459  	case conflictChan <- key:
   460  	case <-done:
   461  		return context.Canceled
   462  	}
   463  	select {
   464  	case conflictChan <- value:
   465  	case <-done:
   466  		return context.Canceled
   467  	}
   468  	return nil
   469  }
   470  
   471  func applyPkChange(ctx context.Context, sch schema.Schema, tableEditor editor.TableEditor, rowData types.Map, stats *MergeStats, change types.ValueChanged) error {
   472  	switch change.ChangeType {
   473  	case types.DiffChangeAdded:
   474  		newRow, err := row.FromNoms(sch, change.Key.(types.Tuple), change.NewValue.(types.Tuple))
   475  		if err != nil {
   476  			return err
   477  		}
   478  		// TODO(andy): because we apply changes to "ours" instead of ancestor
   479  		// we have to check for duplicate primary key errors here.
   480  		val, ok, err := rowData.MaybeGet(ctx, change.Key)
   481  		if err != nil {
   482  			return err
   483  		} else if ok {
   484  			oldRow, err := row.FromNoms(sch, change.Key.(types.Tuple), val.(types.Tuple))
   485  			if err != nil {
   486  				return err
   487  			}
   488  			err = tableEditor.UpdateRow(ctx, oldRow, newRow, nil)
   489  			if err != nil {
   490  				return err
   491  			}
   492  		} else {
   493  			err = tableEditor.InsertRow(ctx, newRow, nil)
   494  			if err != nil {
   495  				return err
   496  			}
   497  		}
   498  		stats.Adds++
   499  	case types.DiffChangeModified:
   500  		oldRow, err := row.FromNoms(sch, change.Key.(types.Tuple), change.OldValue.(types.Tuple))
   501  		if err != nil {
   502  			return err
   503  		}
   504  		newRow, err := row.FromNoms(sch, change.Key.(types.Tuple), change.NewValue.(types.Tuple))
   505  		if err != nil {
   506  			return err
   507  		}
   508  		err = tableEditor.UpdateRow(ctx, oldRow, newRow, nil)
   509  		if err != nil {
   510  			return err
   511  		}
   512  		stats.Modifications++
   513  	case types.DiffChangeRemoved:
   514  		oldRow, err := row.FromNoms(sch, change.Key.(types.Tuple), change.OldValue.(types.Tuple))
   515  		if err != nil {
   516  			return err
   517  		}
   518  		err = tableEditor.DeleteRow(ctx, oldRow)
   519  		if err != nil {
   520  			return err
   521  		}
   522  		stats.Deletes++
   523  	}
   524  
   525  	return nil
   526  }
   527  
   528  func applyKeylessChange(ctx context.Context, sch schema.Schema, tableEditor editor.TableEditor, _ types.Map, stats *MergeStats, change types.ValueChanged) (err error) {
   529  	apply := func(ch types.ValueChanged) error {
   530  		switch ch.ChangeType {
   531  		case types.DiffChangeAdded:
   532  			newRow, err := row.FromNoms(sch, ch.Key.(types.Tuple), ch.NewValue.(types.Tuple))
   533  			if err != nil {
   534  				return err
   535  			}
   536  			err = tableEditor.InsertRow(ctx, newRow, nil)
   537  			if err != nil {
   538  				return err
   539  			}
   540  			stats.Adds++
   541  		case types.DiffChangeModified:
   542  			oldRow, err := row.FromNoms(sch, ch.Key.(types.Tuple), ch.OldValue.(types.Tuple))
   543  			if err != nil {
   544  				return err
   545  			}
   546  			newRow, err := row.FromNoms(sch, ch.Key.(types.Tuple), ch.NewValue.(types.Tuple))
   547  			if err != nil {
   548  				return err
   549  			}
   550  			err = tableEditor.UpdateRow(ctx, oldRow, newRow, nil)
   551  			if err != nil {
   552  				return err
   553  			}
   554  			stats.Modifications++
   555  		case types.DiffChangeRemoved:
   556  			oldRow, err := row.FromNoms(sch, ch.Key.(types.Tuple), ch.OldValue.(types.Tuple))
   557  			if err != nil {
   558  				return err
   559  			}
   560  			err = tableEditor.DeleteRow(ctx, oldRow)
   561  			if err != nil {
   562  				return err
   563  			}
   564  			stats.Deletes++
   565  		}
   566  		return nil
   567  	}
   568  
   569  	var card uint64
   570  	change, card, err = convertValueChanged(change)
   571  	if err != nil {
   572  		return err
   573  	}
   574  
   575  	for card > 0 {
   576  		if err = apply(change); err != nil {
   577  			return err
   578  		}
   579  		card--
   580  	}
   581  	return nil
   582  }
   583  
   584  func convertValueChanged(vc types.ValueChanged) (types.ValueChanged, uint64, error) {
   585  	var oldCard uint64
   586  	if vc.OldValue != nil {
   587  		v, err := vc.OldValue.(types.Tuple).Get(row.KeylessCardinalityValIdx)
   588  		if err != nil {
   589  			return vc, 0, err
   590  		}
   591  		oldCard = uint64(v.(types.Uint))
   592  	}
   593  
   594  	var newCard uint64
   595  	if vc.NewValue != nil {
   596  		v, err := vc.NewValue.(types.Tuple).Get(row.KeylessCardinalityValIdx)
   597  		if err != nil {
   598  			return vc, 0, err
   599  		}
   600  		newCard = uint64(v.(types.Uint))
   601  	}
   602  
   603  	switch vc.ChangeType {
   604  	case types.DiffChangeRemoved:
   605  		return vc, oldCard, nil
   606  
   607  	case types.DiffChangeAdded:
   608  		return vc, newCard, nil
   609  
   610  	case types.DiffChangeModified:
   611  		delta := int64(newCard) - int64(oldCard)
   612  		if delta > 0 {
   613  			vc.ChangeType = types.DiffChangeAdded
   614  			vc.OldValue = nil
   615  			return vc, uint64(delta), nil
   616  		} else if delta < 0 {
   617  			vc.ChangeType = types.DiffChangeRemoved
   618  			vc.NewValue = nil
   619  			return vc, uint64(-delta), nil
   620  		} else {
   621  			panic(fmt.Sprintf("diff with delta = 0 for key: %s", vc.Key.HumanReadableString()))
   622  		}
   623  	default:
   624  		return vc, 0, fmt.Errorf("unexpected DiffChange type %d", vc.ChangeType)
   625  	}
   626  }
   627  
   628  func pkRowMerge(ctx context.Context, nbf *types.NomsBinFormat, sch schema.Schema, r, mergeRow, baseRow types.Value) (types.Value, bool, error) {
   629  	var baseVals row.TaggedValues
   630  	if baseRow == nil {
   631  		if r.Equals(mergeRow) {
   632  			// same row added to both
   633  			return r, false, nil
   634  		}
   635  	} else if r == nil && mergeRow == nil {
   636  		// same row removed from both
   637  		return nil, false, nil
   638  	} else if r == nil || mergeRow == nil {
   639  		// removed from one and modified in another
   640  		return nil, true, nil
   641  	} else {
   642  		var err error
   643  		baseVals, err = row.ParseTaggedValues(baseRow.(types.Tuple))
   644  
   645  		if err != nil {
   646  			return nil, false, err
   647  		}
   648  	}
   649  
   650  	rowVals, err := row.ParseTaggedValues(r.(types.Tuple))
   651  	if err != nil {
   652  		return nil, false, err
   653  	}
   654  
   655  	mergeVals, err := row.ParseTaggedValues(mergeRow.(types.Tuple))
   656  	if err != nil {
   657  		return nil, false, err
   658  	}
   659  
   660  	processTagFunc := func(tag uint64) (resultVal types.Value, isConflict bool) {
   661  		baseVal, _ := baseVals.Get(tag)
   662  		val, _ := rowVals.Get(tag)
   663  		mergeVal, _ := mergeVals.Get(tag)
   664  
   665  		if valutil.NilSafeEqCheck(val, mergeVal) {
   666  			return val, false
   667  		} else {
   668  			modified := !valutil.NilSafeEqCheck(val, baseVal)
   669  			mergeModified := !valutil.NilSafeEqCheck(mergeVal, baseVal)
   670  			switch {
   671  			case modified && mergeModified:
   672  				return nil, true
   673  			case modified:
   674  				return val, false
   675  			default:
   676  				return mergeVal, false
   677  			}
   678  		}
   679  
   680  	}
   681  
   682  	resultVals := make(row.TaggedValues)
   683  
   684  	var isConflict bool
   685  	err = sch.GetNonPKCols().Iter(func(tag uint64, _ schema.Column) (stop bool, err error) {
   686  		var val types.Value
   687  		val, isConflict = processTagFunc(tag)
   688  		resultVals[tag] = val
   689  
   690  		return isConflict, nil
   691  	})
   692  
   693  	if err != nil {
   694  		return nil, false, err
   695  	}
   696  
   697  	if isConflict {
   698  		return nil, true, nil
   699  	}
   700  
   701  	tpl := resultVals.NomsTupleForNonPKCols(nbf, sch.GetNonPKCols())
   702  	v, err := tpl.Value(ctx)
   703  
   704  	if err != nil {
   705  		return nil, false, err
   706  	}
   707  
   708  	return v, false, nil
   709  }
   710  
   711  func keylessRowMerge(ctx context.Context, nbf *types.NomsBinFormat, sch schema.Schema, val, mergeVal, ancVal types.Value) (types.Value, bool, error) {
   712  	// both sides of the merge produced a diff for this key,
   713  	// so we always throw a conflict
   714  	return nil, true, nil
   715  }
   716  
   717  func mergeAutoIncrementValues(ctx context.Context, tbl, otherTbl, resultTbl *doltdb.Table) (*doltdb.Table, error) {
   718  	// only need to check one table, no PK changes yet
   719  	sch, err := tbl.GetSchema(ctx)
   720  	if err != nil {
   721  		return nil, err
   722  	}
   723  	auto := false
   724  	_ = sch.GetAllCols().Iter(func(tag uint64, col schema.Column) (stop bool, err error) {
   725  		if col.AutoIncrement {
   726  			auto, stop = true, true
   727  		}
   728  		return
   729  	})
   730  	if !auto {
   731  		return resultTbl, nil
   732  	}
   733  
   734  	autoVal, err := tbl.GetAutoIncrementValue(ctx)
   735  	if err != nil {
   736  		return nil, err
   737  	}
   738  	mergeAutoVal, err := otherTbl.GetAutoIncrementValue(ctx)
   739  	if err != nil {
   740  		return nil, err
   741  	}
   742  	less, err := autoVal.Less(tbl.Format(), mergeAutoVal)
   743  	if err != nil {
   744  		return nil, err
   745  	}
   746  	if less {
   747  		autoVal = mergeAutoVal
   748  	}
   749  	return resultTbl.SetAutoIncrementValue(autoVal)
   750  }
   751  
   752  func MergeCommits(ctx context.Context, commit, mergeCommit *doltdb.Commit) (*doltdb.RootValue, map[string]*MergeStats, error) {
   753  	ancCommit, err := doltdb.GetCommitAncestor(ctx, commit, mergeCommit)
   754  
   755  	if err != nil {
   756  		return nil, nil, err
   757  	}
   758  
   759  	ourRoot, err := commit.GetRootValue()
   760  
   761  	if err != nil {
   762  		return nil, nil, err
   763  	}
   764  
   765  	theirRoot, err := mergeCommit.GetRootValue()
   766  
   767  	if err != nil {
   768  		return nil, nil, err
   769  	}
   770  
   771  	ancRoot, err := ancCommit.GetRootValue()
   772  
   773  	if err != nil {
   774  		return nil, nil, err
   775  	}
   776  
   777  	return MergeRoots(ctx, ourRoot, theirRoot, ancRoot)
   778  }
   779  
   780  func MergeRoots(ctx context.Context, ourRoot, theirRoot, ancRoot *doltdb.RootValue) (*doltdb.RootValue, map[string]*MergeStats, error) {
   781  	merger := NewMerger(ctx, ourRoot, theirRoot, ancRoot, ourRoot.VRW())
   782  
   783  	tblNames, err := doltdb.UnionTableNames(ctx, ourRoot, theirRoot)
   784  
   785  	if err != nil {
   786  		return nil, nil, err
   787  	}
   788  
   789  	tblToStats := make(map[string]*MergeStats)
   790  
   791  	newRoot := ourRoot
   792  	tableEditSession := editor.CreateTableEditSession(ourRoot, editor.TableEditSessionProps{
   793  		ForeignKeyChecksDisabled: true,
   794  	})
   795  	// need to validate merges can be done on all tables before starting the actual merges.
   796  	for _, tblName := range tblNames {
   797  		mergedTable, stats, err := merger.MergeTable(ctx, tblName, tableEditSession)
   798  
   799  		if err != nil {
   800  			return nil, nil, err
   801  		}
   802  
   803  		if mergedTable != nil {
   804  			tblToStats[tblName] = stats
   805  
   806  			err = tableEditSession.UpdateRoot(ctx, func(ctx context.Context, root *doltdb.RootValue) (*doltdb.RootValue, error) {
   807  				return root.PutTable(ctx, tblName, mergedTable)
   808  			})
   809  			if err != nil {
   810  				return nil, nil, err
   811  			}
   812  			newRoot, err = tableEditSession.Flush(ctx)
   813  			if err != nil {
   814  				return nil, nil, err
   815  			}
   816  		} else if has, err := newRoot.HasTable(ctx, tblName); err != nil {
   817  			return nil, nil, err
   818  		} else if has {
   819  			tblToStats[tblName] = &MergeStats{Operation: TableRemoved}
   820  			err = tableEditSession.UpdateRoot(ctx, func(ctx context.Context, root *doltdb.RootValue) (*doltdb.RootValue, error) {
   821  				return root.RemoveTables(ctx, tblName)
   822  			})
   823  			if err != nil {
   824  				return nil, nil, err
   825  			}
   826  			newRoot, err = tableEditSession.Flush(ctx)
   827  			if err != nil {
   828  				return nil, nil, err
   829  			}
   830  		} else {
   831  			panic("?")
   832  		}
   833  	}
   834  
   835  	err = tableEditSession.UpdateRoot(ctx, func(ctx context.Context, root *doltdb.RootValue) (value *doltdb.RootValue, err error) {
   836  		mergedFKColl, conflicts, err := ForeignKeysMerge(ctx, root, ourRoot, theirRoot, ancRoot)
   837  		if err != nil {
   838  			return nil, err
   839  		}
   840  		if len(conflicts) > 0 {
   841  			return nil, fmt.Errorf("foreign key conflicts")
   842  		}
   843  
   844  		root, err = root.PutForeignKeyCollection(ctx, mergedFKColl)
   845  		if err != nil {
   846  			return nil, err
   847  		}
   848  
   849  		return root.UpdateSuperSchemasFromOther(ctx, tblNames, theirRoot)
   850  	})
   851  	if err != nil {
   852  		return nil, nil, err
   853  	}
   854  
   855  	newRoot, err = tableEditSession.Flush(ctx)
   856  	if err != nil {
   857  		return nil, nil, err
   858  	}
   859  
   860  	return newRoot, tblToStats, nil
   861  }
   862  
   863  func GetTablesInConflict(ctx context.Context, ddb *doltdb.DoltDB, rsr env.RepoStateReader) (workingInConflict, stagedInConflict, headInConflict []string, err error) {
   864  	var headRoot, stagedRoot, workingRoot *doltdb.RootValue
   865  
   866  	headRoot, err = env.HeadRoot(ctx, ddb, rsr)
   867  
   868  	if err != nil {
   869  		return nil, nil, nil, err
   870  	}
   871  
   872  	stagedRoot, err = env.StagedRoot(ctx, ddb, rsr)
   873  
   874  	if err != nil {
   875  		return nil, nil, nil, err
   876  	}
   877  
   878  	workingRoot, err = env.WorkingRoot(ctx, ddb, rsr)
   879  
   880  	if err != nil {
   881  		return nil, nil, nil, err
   882  	}
   883  
   884  	headInConflict, err = headRoot.TablesInConflict(ctx)
   885  
   886  	if err != nil {
   887  		return nil, nil, nil, err
   888  	}
   889  
   890  	stagedInConflict, err = stagedRoot.TablesInConflict(ctx)
   891  
   892  	if err != nil {
   893  		return nil, nil, nil, err
   894  	}
   895  
   896  	workingInConflict, err = workingRoot.TablesInConflict(ctx)
   897  
   898  	if err != nil {
   899  		return nil, nil, nil, err
   900  	}
   901  
   902  	return workingInConflict, stagedInConflict, headInConflict, err
   903  }
   904  
   905  func GetDocsInConflict(ctx context.Context, ddb *doltdb.DoltDB, rsr env.RepoStateReader, drw env.DocsReadWriter) (*diff.DocDiffs, error) {
   906  	docs, err := drw.GetDocsOnDisk()
   907  	if err != nil {
   908  		return nil, err
   909  	}
   910  
   911  	workingRoot, err := env.WorkingRoot(ctx, ddb, rsr)
   912  	if err != nil {
   913  		return nil, err
   914  	}
   915  
   916  	return diff.NewDocDiffs(ctx, workingRoot, nil, docs)
   917  }