github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/libraries/doltcore/sqle/dtables/conflicts_tables_prolly.go (about) 1 // Copyright 2022 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 dtables 16 17 import ( 18 "context" 19 "encoding/base64" 20 "fmt" 21 22 "github.com/dolthub/go-mysql-server/sql" 23 "github.com/zeebo/xxh3" 24 25 "github.com/dolthub/dolt/go/libraries/doltcore/doltdb" 26 "github.com/dolthub/dolt/go/libraries/doltcore/doltdb/durable" 27 "github.com/dolthub/dolt/go/libraries/doltcore/merge" 28 "github.com/dolthub/dolt/go/libraries/doltcore/schema" 29 "github.com/dolthub/dolt/go/libraries/doltcore/sqle/index" 30 "github.com/dolthub/dolt/go/libraries/doltcore/sqle/sqlutil" 31 "github.com/dolthub/dolt/go/store/hash" 32 "github.com/dolthub/dolt/go/store/pool" 33 "github.com/dolthub/dolt/go/store/prolly" 34 "github.com/dolthub/dolt/go/store/prolly/tree" 35 "github.com/dolthub/dolt/go/store/types" 36 "github.com/dolthub/dolt/go/store/val" 37 ) 38 39 func newProllyConflictsTable(ctx *sql.Context, tbl *doltdb.Table, sourceUpdatableTbl sql.UpdatableTable, tblName string, root doltdb.RootValue, rs RootSetter) (sql.Table, error) { 40 arts, err := tbl.GetArtifacts(ctx) 41 if err != nil { 42 return nil, err 43 } 44 m := durable.ProllyMapFromArtifactIndex(arts) 45 46 baseSch, ourSch, theirSch, err := tbl.GetConflictSchemas(ctx, tblName) 47 if err != nil { 48 return nil, err 49 } 50 confSch, versionMappings, err := calculateConflictSchema(baseSch, ourSch, theirSch) 51 if err != nil { 52 return nil, err 53 } 54 sqlSch, err := sqlutil.FromDoltSchema("", doltdb.DoltConfTablePrefix+tblName, confSch) 55 if err != nil { 56 return nil, err 57 } 58 59 return ProllyConflictsTable{ 60 tblName: tblName, 61 sqlSch: sqlSch, 62 baseSch: baseSch, 63 ourSch: ourSch, 64 theirSch: theirSch, 65 root: root, 66 tbl: tbl, 67 rs: rs, 68 artM: m, 69 sqlTable: sourceUpdatableTbl, 70 versionMappings: versionMappings, 71 }, nil 72 } 73 74 // ProllyConflictsTable is a sql.Table implementation that uses the merge 75 // artifacts table to persist and read conflicts. 76 type ProllyConflictsTable struct { 77 tblName string 78 sqlSch sql.PrimaryKeySchema 79 baseSch, ourSch, theirSch schema.Schema 80 root doltdb.RootValue 81 tbl *doltdb.Table 82 rs RootSetter 83 artM prolly.ArtifactMap 84 sqlTable sql.UpdatableTable 85 versionMappings *versionMappings 86 } 87 88 var _ sql.UpdatableTable = ProllyConflictsTable{} 89 var _ sql.DeletableTable = ProllyConflictsTable{} 90 91 func (ct ProllyConflictsTable) Name() string { 92 return doltdb.DoltConfTablePrefix + ct.tblName 93 } 94 95 func (ct ProllyConflictsTable) String() string { 96 return doltdb.DoltConfTablePrefix + ct.tblName 97 } 98 99 func (ct ProllyConflictsTable) Schema() sql.Schema { 100 return ct.sqlSch.Schema 101 } 102 103 func (ct ProllyConflictsTable) Collation() sql.CollationID { 104 return sql.Collation_Default 105 } 106 107 func (ct ProllyConflictsTable) Partitions(ctx *sql.Context) (sql.PartitionIter, error) { 108 return index.SinglePartitionIterFromNomsMap(nil), nil 109 } 110 111 func (ct ProllyConflictsTable) PartitionRows(ctx *sql.Context, part sql.Partition) (sql.RowIter, error) { 112 return newProllyConflictRowIter(ctx, ct) 113 } 114 115 func (ct ProllyConflictsTable) Updater(ctx *sql.Context) sql.RowUpdater { 116 ourUpdater := ct.sqlTable.Updater(ctx) 117 return newProllyConflictOurTableUpdater(ourUpdater, ct.versionMappings, ct.baseSch, ct.ourSch, ct.theirSch) 118 } 119 120 func (ct ProllyConflictsTable) Deleter(ctx *sql.Context) sql.RowDeleter { 121 return newProllyConflictDeleter(ct) 122 } 123 124 type prollyConflictRowIter struct { 125 itr prolly.ConflictArtifactIter 126 tblName string 127 vrw types.ValueReadWriter 128 ns tree.NodeStore 129 ourRows prolly.Map 130 keyless bool 131 ourSch schema.Schema 132 133 kd val.TupleDesc 134 baseVD, oursVD, theirsVD val.TupleDesc 135 // offsets for each version 136 b, o, t int 137 n int 138 139 baseHash, theirHash hash.Hash 140 baseRows prolly.Map 141 theirRows prolly.Map 142 } 143 144 var _ sql.RowIter = (*prollyConflictRowIter)(nil) 145 146 // base_cols, our_cols, our_diff_type, their_cols, their_diff_type 147 func newProllyConflictRowIter(ctx *sql.Context, ct ProllyConflictsTable) (*prollyConflictRowIter, error) { 148 idx, err := ct.tbl.GetRowData(ctx) 149 if err != nil { 150 return nil, err 151 } 152 ourRows := durable.ProllyMapFromIndex(idx) 153 154 itr, err := ct.artM.IterAllConflicts(ctx) 155 if err != nil { 156 return nil, err 157 } 158 159 keyless := schema.IsKeyless(ct.ourSch) 160 161 kd := ct.baseSch.GetKeyDescriptor() 162 baseVD := ct.baseSch.GetValueDescriptor() 163 oursVD := ct.ourSch.GetValueDescriptor() 164 theirsVD := ct.theirSch.GetValueDescriptor() 165 166 b := 1 167 var o, t, n int 168 if !keyless { 169 o = b + kd.Count() + baseVD.Count() 170 t = o + kd.Count() + oursVD.Count() + 1 171 n = t + kd.Count() + theirsVD.Count() + 2 172 } else { 173 o = b + baseVD.Count() - 1 174 t = o + oursVD.Count() 175 n = t + theirsVD.Count() + 4 176 } 177 178 return &prollyConflictRowIter{ 179 itr: itr, 180 tblName: ct.tblName, 181 vrw: ct.tbl.ValueReadWriter(), 182 ns: ct.tbl.NodeStore(), 183 ourRows: ourRows, 184 keyless: keyless, 185 ourSch: ct.ourSch, 186 kd: kd, 187 baseVD: baseVD, 188 oursVD: oursVD, 189 theirsVD: theirsVD, 190 b: b, 191 o: o, 192 t: t, 193 n: n, 194 }, nil 195 } 196 197 func (itr *prollyConflictRowIter) Next(ctx *sql.Context) (sql.Row, error) { 198 c, err := itr.nextConflictVals(ctx) 199 if err != nil { 200 return nil, err 201 } 202 203 r := make(sql.Row, itr.n) 204 r[0] = c.h.String() 205 206 if !itr.keyless { 207 for i := 0; i < itr.kd.Count(); i++ { 208 f, err := tree.GetField(ctx, itr.kd, i, c.k, itr.baseRows.NodeStore()) 209 if err != nil { 210 return nil, err 211 } 212 if c.bV != nil { 213 r[itr.b+i] = f 214 } 215 if c.oV != nil { 216 r[itr.o+i] = f 217 } 218 if c.tV != nil { 219 r[itr.t+i] = f 220 } 221 } 222 223 err = itr.putConflictRowVals(ctx, c, r) 224 if err != nil { 225 return nil, err 226 } 227 } else { 228 229 err = itr.putKeylessConflictRowVals(ctx, c, r) 230 if err != nil { 231 return nil, err 232 } 233 } 234 235 return r, nil 236 } 237 238 func (itr *prollyConflictRowIter) putConflictRowVals(ctx *sql.Context, c conf, r sql.Row) error { 239 if c.bV != nil { 240 for i := 0; i < itr.baseVD.Count(); i++ { 241 f, err := tree.GetField(ctx, itr.baseVD, i, c.bV, itr.baseRows.NodeStore()) 242 if err != nil { 243 return err 244 } 245 r[itr.b+itr.kd.Count()+i] = f 246 } 247 } 248 249 if c.oV != nil { 250 for i := 0; i < itr.oursVD.Count(); i++ { 251 f, err := tree.GetField(ctx, itr.oursVD, i, c.oV, itr.baseRows.NodeStore()) 252 if err != nil { 253 return err 254 } 255 r[itr.o+itr.kd.Count()+i] = f 256 } 257 } 258 r[itr.o+itr.kd.Count()+itr.oursVD.Count()] = getDiffType(c.bV, c.oV) 259 260 if c.tV != nil { 261 for i := 0; i < itr.theirsVD.Count(); i++ { 262 f, err := tree.GetField(ctx, itr.theirsVD, i, c.tV, itr.baseRows.NodeStore()) 263 if err != nil { 264 return err 265 } 266 r[itr.t+itr.kd.Count()+i] = f 267 } 268 } 269 r[itr.t+itr.kd.Count()+itr.theirsVD.Count()] = getDiffType(c.bV, c.tV) 270 r[itr.t+itr.kd.Count()+itr.theirsVD.Count()+1] = c.id 271 272 return nil 273 } 274 275 func getDiffType(base val.Tuple, other val.Tuple) string { 276 if base == nil { 277 return merge.ConflictDiffTypeAdded 278 } else if other == nil { 279 return merge.ConflictDiffTypeRemoved 280 } 281 282 // There has to be some edit, otherwise it wouldn't be a conflict... 283 return merge.ConflictDiffTypeModified 284 } 285 286 func (itr *prollyConflictRowIter) putKeylessConflictRowVals(ctx *sql.Context, c conf, r sql.Row) (err error) { 287 ns := itr.baseRows.NodeStore() 288 289 if c.bV != nil { 290 // Cardinality 291 r[itr.n-3], err = tree.GetField(ctx, itr.baseVD, 0, c.bV, ns) 292 if err != nil { 293 return err 294 } 295 296 for i := 0; i < itr.baseVD.Count()-1; i++ { 297 f, err := tree.GetField(ctx, itr.baseVD, i+1, c.bV, ns) 298 if err != nil { 299 return err 300 } 301 r[itr.b+i] = f 302 } 303 } else { 304 r[itr.n-3] = uint64(0) 305 } 306 307 if c.oV != nil { 308 r[itr.n-2], err = tree.GetField(ctx, itr.oursVD, 0, c.oV, ns) 309 if err != nil { 310 return err 311 } 312 313 for i := 0; i < itr.oursVD.Count()-1; i++ { 314 f, err := tree.GetField(ctx, itr.oursVD, i+1, c.oV, ns) 315 if err != nil { 316 return err 317 } 318 r[itr.o+i] = f 319 } 320 } else { 321 r[itr.n-2] = uint64(0) 322 } 323 324 r[itr.o+itr.oursVD.Count()-1] = getDiffType(c.bV, c.oV) 325 326 if c.tV != nil { 327 r[itr.n-1], err = tree.GetField(ctx, itr.theirsVD, 0, c.tV, ns) 328 if err != nil { 329 return err 330 } 331 332 for i := 0; i < itr.theirsVD.Count()-1; i++ { 333 f, err := tree.GetField(ctx, itr.theirsVD, i+1, c.tV, ns) 334 if err != nil { 335 return err 336 } 337 r[itr.t+i] = f 338 } 339 } else { 340 r[itr.n-1] = uint64(0) 341 } 342 343 o := itr.t + itr.theirsVD.Count() - 1 344 r[o] = getDiffType(c.bV, c.tV) 345 r[itr.n-4] = c.id 346 347 return nil 348 } 349 350 type conf struct { 351 k, bV, oV, tV val.Tuple 352 h hash.Hash 353 id string 354 } 355 356 func (itr *prollyConflictRowIter) nextConflictVals(ctx *sql.Context) (c conf, err error) { 357 ca, err := itr.itr.Next(ctx) 358 if err != nil { 359 return conf{}, err 360 } 361 c.k = ca.Key 362 c.h = ca.TheirRootIsh 363 364 // To ensure that the conflict id is unique, we hash both TheirRootIsh and the key of the table. 365 b := xxh3.Hash128(append(ca.Key, c.h[:]...)).Bytes() 366 c.id = base64.RawStdEncoding.EncodeToString(b[:]) 367 368 err = itr.loadTableMaps(ctx, ca.Metadata.BaseRootIsh, ca.TheirRootIsh) 369 if err != nil { 370 return conf{}, err 371 } 372 373 err = itr.baseRows.Get(ctx, ca.Key, func(_, v val.Tuple) error { 374 c.bV = v 375 return nil 376 }) 377 if err != nil { 378 return conf{}, err 379 } 380 err = itr.ourRows.Get(ctx, ca.Key, func(_, v val.Tuple) error { 381 c.oV = v 382 return nil 383 }) 384 if err != nil { 385 return conf{}, err 386 } 387 err = itr.theirRows.Get(ctx, ca.Key, func(_, v val.Tuple) error { 388 c.tV = v 389 return nil 390 }) 391 if err != nil { 392 return conf{}, err 393 } 394 395 return c, nil 396 } 397 398 // loadTableMaps loads the maps specified in the metadata if they are different from 399 // the currently loaded maps. |baseHash| and |theirHash| are table hashes. 400 func (itr *prollyConflictRowIter) loadTableMaps(ctx context.Context, baseHash, theirHash hash.Hash) error { 401 if itr.baseHash.Compare(baseHash) != 0 { 402 rv, err := doltdb.LoadRootValueFromRootIshAddr(ctx, itr.vrw, itr.ns, baseHash) 403 if err != nil { 404 return err 405 } 406 baseTbl, ok, err := rv.GetTable(ctx, doltdb.TableName{Name: itr.tblName}) 407 if err != nil { 408 return err 409 } 410 411 var idx durable.Index 412 if !ok { 413 idx, err = durable.NewEmptyIndex(ctx, itr.vrw, itr.ns, itr.ourSch) 414 } else { 415 idx, err = baseTbl.GetRowData(ctx) 416 } 417 418 if err != nil { 419 return err 420 } 421 422 itr.baseRows = durable.ProllyMapFromIndex(idx) 423 itr.baseHash = baseHash 424 } 425 426 if itr.theirHash.Compare(theirHash) != 0 { 427 rv, err := doltdb.LoadRootValueFromRootIshAddr(ctx, itr.vrw, itr.ns, theirHash) 428 if err != nil { 429 return err 430 } 431 theirTbl, ok, err := rv.GetTable(ctx, doltdb.TableName{Name: itr.tblName}) 432 if err != nil { 433 return err 434 } 435 if !ok { 436 return fmt.Errorf("failed to find table %s in right root value", itr.tblName) 437 } 438 439 idx, err := theirTbl.GetRowData(ctx) 440 if err != nil { 441 return err 442 } 443 itr.theirRows = durable.ProllyMapFromIndex(idx) 444 itr.theirHash = theirHash 445 } 446 447 return nil 448 } 449 450 func (itr *prollyConflictRowIter) Close(ctx *sql.Context) error { 451 return nil 452 } 453 454 // prollyConflictOurTableUpdater allows users to update the "our table" by 455 // modifying rows in the conflict table. Any updates to the conflict table our 456 // columns are applied on the source table. 457 type prollyConflictOurTableUpdater struct { 458 baseSch, ourSch, theirSch schema.Schema 459 srcUpdater sql.RowUpdater 460 versionMappings *versionMappings 461 pkOrdinals []int 462 schemaOK bool 463 } 464 465 func newProllyConflictOurTableUpdater(ourUpdater sql.RowUpdater, versionMappings *versionMappings, baseSch, ourSch, theirSch schema.Schema) *prollyConflictOurTableUpdater { 466 return &prollyConflictOurTableUpdater{ 467 srcUpdater: ourUpdater, 468 versionMappings: versionMappings, 469 pkOrdinals: ourSch.GetPkOrdinals(), 470 } 471 } 472 473 // Update implements sql.RowUpdater. It translates updates on the conflict table to the source table. 474 func (cu *prollyConflictOurTableUpdater) Update(ctx *sql.Context, oldRow sql.Row, newRow sql.Row) error { 475 476 // Apply updates to columns prefixed with our_ 477 // Updates to other columns are no-ops. 478 ourOldRow := make(sql.Row, len(cu.versionMappings.ourMapping)) 479 ourNewRow := make(sql.Row, len(cu.versionMappings.ourMapping)) 480 for i, j := range cu.versionMappings.ourMapping { 481 ourOldRow[i] = oldRow[j] 482 } 483 for i, j := range cu.versionMappings.ourMapping { 484 ourNewRow[i] = newRow[j] 485 } 486 487 return cu.srcUpdater.Update(ctx, ourOldRow, ourNewRow) 488 } 489 490 // StatementBegin implements sql.RowUpdater. 491 func (cu *prollyConflictOurTableUpdater) StatementBegin(ctx *sql.Context) { 492 cu.srcUpdater.StatementBegin(ctx) 493 } 494 495 // DiscardChanges implements sql.RowUpdater. 496 func (cu *prollyConflictOurTableUpdater) DiscardChanges(ctx *sql.Context, errorEncountered error) error { 497 return cu.srcUpdater.DiscardChanges(ctx, errorEncountered) 498 } 499 500 // StatementComplete implements sql.RowUpdater. 501 func (cu *prollyConflictOurTableUpdater) StatementComplete(ctx *sql.Context) error { 502 return cu.srcUpdater.StatementComplete(ctx) 503 } 504 505 // Close implements sql.RowUpdater. 506 func (cu *prollyConflictOurTableUpdater) Close(c *sql.Context) error { 507 return cu.srcUpdater.Close(c) 508 } 509 510 type prollyConflictDeleter struct { 511 kd, vd val.TupleDesc 512 kB, vB *val.TupleBuilder 513 pool pool.BuffPool 514 ed *prolly.ArtifactsEditor 515 ct ProllyConflictsTable 516 rs RootSetter 517 ourDiffTypeIdx int 518 baseColSize int 519 ourColSize int 520 } 521 522 func newProllyConflictDeleter(ct ProllyConflictsTable) *prollyConflictDeleter { 523 kd, _ := ct.artM.Descriptors() 524 ed := ct.artM.Editor() 525 kB := val.NewTupleBuilder(kd) 526 527 vd := ct.ourSch.GetValueDescriptor() 528 vB := val.NewTupleBuilder(vd) 529 p := ct.artM.Pool() 530 531 baseColSize := ct.baseSch.GetAllCols().Size() 532 ourColSize := ct.ourSch.GetAllCols().Size() 533 // root_ish, base_cols..., our_cols, our_diff_type 534 ourDiffTypeIdx := 1 + baseColSize + ourColSize 535 536 return &prollyConflictDeleter{ 537 kd: kd, 538 vd: vd, 539 kB: kB, 540 vB: vB, 541 pool: p, 542 ed: ed, 543 ct: ct, 544 ourDiffTypeIdx: ourDiffTypeIdx, 545 baseColSize: baseColSize, 546 ourColSize: ourColSize, 547 } 548 } 549 550 func (cd *prollyConflictDeleter) Delete(ctx *sql.Context, r sql.Row) (err error) { 551 // first part of the artifact key is the keys of the source table 552 if !schema.IsKeyless(cd.ct.ourSch) { 553 err = cd.putPrimaryKeys(ctx, r) 554 } else { 555 err = cd.putKeylessHash(ctx, r) 556 } 557 if err != nil { 558 return err 559 } 560 561 // then the hash follows. It is the first column of the row and the second to last in the key 562 h := hash.Parse(r[0].(string)) 563 cd.kB.PutCommitAddr(cd.kd.Count()-2, h) 564 565 // Finally the artifact type which is always a conflict 566 cd.kB.PutUint8(cd.kd.Count()-1, uint8(prolly.ArtifactTypeConflict)) 567 568 key := cd.kB.Build(cd.pool) 569 err = cd.ed.Delete(ctx, key) 570 if err != nil { 571 return err 572 } 573 574 return nil 575 } 576 577 func (cd *prollyConflictDeleter) putPrimaryKeys(ctx *sql.Context, r sql.Row) error { 578 // get keys from either base, ours, or theirs 579 o := func() int { 580 if o := 1; r[o] != nil { 581 return o 582 } else if o = 1 + cd.kd.Count() - 2 + cd.vd.Count(); r[o] != nil { 583 return o 584 } else if o = 1 + (cd.kd.Count()-2+cd.vd.Count())*2 + 1; r[o] != nil { 585 return o 586 } else { 587 panic("neither base, ours, or theirs had a key") 588 } 589 }() 590 591 for i := 0; i < cd.kd.Count()-2; i++ { 592 err := tree.PutField(ctx, cd.ed.NodeStore(), cd.kB, i, r[o+i]) 593 594 if err != nil { 595 return err 596 } 597 } 598 599 return nil 600 } 601 602 func (cd *prollyConflictDeleter) putKeylessHash(ctx *sql.Context, r sql.Row) error { 603 var rowVals sql.Row 604 if r[cd.ourDiffTypeIdx] == merge.ConflictDiffTypeAdded { 605 // use our cols 606 rowVals = r[1+cd.baseColSize : 1+cd.baseColSize+cd.ourColSize] 607 } else { 608 // use base cols 609 rowVals = r[1 : 1+cd.baseColSize] 610 } 611 612 // init cardinality to 0 613 cd.vB.PutUint64(0, 0) 614 for i, v := range rowVals { 615 err := tree.PutField(ctx, cd.ed.NodeStore(), cd.vB, i+1, v) 616 if err != nil { 617 return err 618 } 619 } 620 621 v := cd.vB.Build(cd.pool) 622 k := val.HashTupleFromValue(cd.pool, v) 623 cd.kB.PutHash128(0, k.GetField(0)) 624 return nil 625 } 626 627 // StatementBegin implements the interface sql.TableEditor. Currently a no-op. 628 func (cd *prollyConflictDeleter) StatementBegin(ctx *sql.Context) {} 629 630 // DiscardChanges implements the interface sql.TableEditor. Currently a no-op. 631 func (cd *prollyConflictDeleter) DiscardChanges(ctx *sql.Context, errorEncountered error) error { 632 return nil 633 } 634 635 // StatementComplete implements the interface sql.TableEditor. Currently a no-op. 636 func (cd *prollyConflictDeleter) StatementComplete(ctx *sql.Context) error { 637 return nil 638 } 639 640 // Close finalizes the delete operation, persisting the result. 641 func (cd *prollyConflictDeleter) Close(ctx *sql.Context) error { 642 arts, err := cd.ed.Flush(ctx) 643 if err != nil { 644 return err 645 } 646 647 // TODO: We can delete from more than one table in a single statement. Root 648 // updates should be restricted to write session and not individual table 649 // editors. 650 651 updatedTbl, err := cd.ct.tbl.SetArtifacts(ctx, durable.ArtifactIndexFromProllyMap(arts)) 652 if err != nil { 653 return err 654 } 655 656 updatedRoot, err := cd.ct.root.PutTable(ctx, doltdb.TableName{Name: cd.ct.tblName}, updatedTbl) 657 if err != nil { 658 return err 659 } 660 661 return cd.ct.rs.SetRoot(ctx, updatedRoot) 662 } 663 664 type versionMappings struct { 665 ourMapping, theirMapping, baseMapping val.OrdinalMapping 666 } 667 668 // returns the schema of the rows returned by the conflicts table and a mappings between each version and the source table. 669 func calculateConflictSchema(base, ours, theirs schema.Schema) (schema.Schema, *versionMappings, error) { 670 keyless := schema.IsKeyless(ours) 671 n := 4 + ours.GetAllCols().Size() + theirs.GetAllCols().Size() + base.GetAllCols().Size() 672 if keyless { 673 n += 3 674 } 675 676 cols := make([]schema.Column, n) 677 678 // the commit hash or working set hash of the right side during merge 679 cols[0] = schema.NewColumn("from_root_ish", 0, types.StringKind, false) 680 681 i := 1 682 putWithPrefix := func(prefix string, sch schema.Schema, stripConstraints bool) (val.OrdinalMapping, error) { 683 allCols := sch.GetAllCols() 684 mapping := make(val.OrdinalMapping, allCols.Size()) 685 err := sch.GetPKCols().Iter(func(tag uint64, col schema.Column) (stop bool, err error) { 686 var cons []schema.ColConstraint 687 if !stripConstraints { 688 cons = col.Constraints 689 } 690 c, err := schema.NewColumnWithTypeInfo(prefix+col.Name, uint64(i), col.TypeInfo, false, col.Default, false, col.Comment, cons...) 691 if err != nil { 692 return true, err 693 } 694 cols[i] = c 695 mapping[allCols.TagToIdx[tag]] = i 696 i++ 697 return false, nil 698 }) 699 if err != nil { 700 return nil, err 701 } 702 err = sch.GetNonPKCols().Iter(func(tag uint64, col schema.Column) (stop bool, err error) { 703 var cons []schema.ColConstraint 704 if !stripConstraints { 705 cons = col.Constraints 706 } 707 c, err := schema.NewColumnWithTypeInfo(prefix+col.Name, uint64(i), col.TypeInfo, false, col.Default, false, col.Comment, cons...) 708 if err != nil { 709 return true, err 710 } 711 cols[i] = c 712 mapping[allCols.TagToIdx[tag]] = i 713 i++ 714 return false, nil 715 }) 716 return mapping, err 717 } 718 719 baseColMapping, err := putWithPrefix("base_", base, true) 720 if err != nil { 721 return nil, nil, err 722 } 723 ourColMapping, err := putWithPrefix("our_", ours, false) 724 if err != nil { 725 return nil, nil, err 726 } 727 cols[i] = schema.NewColumn("our_diff_type", uint64(i), types.StringKind, false) 728 i++ 729 theirColMapping, err := putWithPrefix("their_", theirs, true) 730 if err != nil { 731 return nil, nil, err 732 } 733 cols[i] = schema.NewColumn("their_diff_type", uint64(i), types.StringKind, false) 734 i++ 735 736 cols[i] = schema.NewColumn("dolt_conflict_id", uint64(i), types.StringKind, false) 737 i++ 738 739 if keyless { 740 cols[i] = schema.NewColumn("base_cardinality", uint64(i), types.UintKind, false) 741 i++ 742 cols[i] = schema.NewColumn("our_cardinality", uint64(i), types.UintKind, false) 743 i++ 744 cols[i] = schema.NewColumn("their_cardinality", uint64(i), types.UintKind, false) 745 i++ 746 } 747 748 sch, err := schema.NewSchema(schema.NewColCollection(cols...), nil, schema.Collation_Default, nil, nil) 749 if err != nil { 750 return nil, nil, err 751 } 752 753 return sch, 754 &versionMappings{ 755 ourMapping: ourColMapping, 756 theirMapping: theirColMapping, 757 baseMapping: baseColMapping}, 758 nil 759 }