github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/libraries/doltcore/doltdb/root_val.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 doltdb 16 17 import ( 18 "bytes" 19 "context" 20 "errors" 21 "fmt" 22 "strings" 23 24 "github.com/dolthub/dolt/go/libraries/doltcore/schema" 25 "github.com/dolthub/dolt/go/libraries/doltcore/schema/encoding" 26 "github.com/dolthub/dolt/go/libraries/utils/set" 27 "github.com/dolthub/dolt/go/store/hash" 28 "github.com/dolthub/dolt/go/store/types" 29 ) 30 31 const ( 32 ddbRootStructName = "dolt_db_root" 33 34 tablesKey = "tables" 35 superSchemasKey = "super_schemas" 36 foreignKeyKey = "foreign_key" 37 featureVersKey = "feature_ver" 38 ) 39 40 type FeatureVersion int64 41 42 // DoltFeatureVersion is described in feature_version.md. 43 // only variable for testing. 44 var DoltFeatureVersion FeatureVersion = 1 // last bumped for CHECK constraint storage 45 46 // RootValue defines the structure used inside all Dolthub noms dbs 47 type RootValue struct { 48 vrw types.ValueReadWriter 49 valueSt types.Struct 50 fkc *ForeignKeyCollection // cache the first load 51 } 52 53 func newRootValue(vrw types.ValueReadWriter, st types.Struct) (*RootValue, error) { 54 v, ok, err := st.MaybeGet(featureVersKey) 55 if err != nil { 56 return nil, err 57 } 58 if ok { 59 ver := FeatureVersion(v.(types.Int)) 60 if DoltFeatureVersion < ver { 61 return nil, ErrClientOutOfDate{ 62 ClientVer: DoltFeatureVersion, 63 RepoVer: ver, 64 } 65 } 66 } 67 68 return &RootValue{vrw, st, nil}, nil 69 } 70 71 func EmptyRootValue(ctx context.Context, vrw types.ValueReadWriter) (*RootValue, error) { 72 empty, err := types.NewMap(ctx, vrw) 73 if err != nil { 74 return nil, err 75 } 76 77 sd := types.StructData{ 78 tablesKey: empty, 79 superSchemasKey: empty, 80 foreignKeyKey: empty, 81 featureVersKey: types.Int(DoltFeatureVersion), 82 } 83 84 st, err := types.NewStruct(vrw.Format(), ddbRootStructName, sd) 85 if err != nil { 86 return nil, err 87 } 88 89 return newRootValue(vrw, st) 90 } 91 92 func (root *RootValue) VRW() types.ValueReadWriter { 93 return root.vrw 94 } 95 96 // GetFeatureVersion returns the feature version of this root, if one is written 97 func (root *RootValue) GetFeatureVersion(ctx context.Context) (ver FeatureVersion, ok bool, err error) { 98 v, ok, err := root.valueSt.MaybeGet(featureVersKey) 99 if err != nil || !ok { 100 return ver, ok, err 101 } 102 ver = FeatureVersion(v.(types.Int)) 103 return ver, ok, err 104 } 105 106 func (root *RootValue) HasTable(ctx context.Context, tName string) (bool, error) { 107 val, found, err := root.valueSt.MaybeGet(tablesKey) 108 109 if err != nil { 110 return false, err 111 } 112 113 if !found { 114 return false, nil 115 } 116 117 tableMap := val.(types.Map) 118 return tableMap.Has(ctx, types.String(tName)) 119 } 120 121 // TableNameInUse checks if a name can be used to create a new table. The most recent 122 // names of all current tables and all previously existing tables cannot be used. 123 func (root *RootValue) TableNameInUse(ctx context.Context, tName string) (bool, error) { 124 _, ok, err := root.GetSuperSchema(ctx, tName) 125 if err != nil { 126 return false, err 127 } 128 return ok, nil 129 } 130 131 // GetSuperSchema returns the SuperSchema for the table name specified if that table exists. 132 func (root *RootValue) GetSuperSchema(ctx context.Context, tName string) (*schema.SuperSchema, bool, error) { 133 // SuperSchema is only persisted on Commit() 134 ss, found, err := root.getSuperSchemaAtLastCommit(ctx, tName) 135 136 if err != nil { 137 return nil, false, err 138 } 139 if !found { 140 ss, _ = schema.NewSuperSchema() 141 } 142 143 t, tblFound, err := root.GetTable(ctx, tName) 144 if err != nil { 145 return nil, false, err 146 } 147 148 if !found && !tblFound { 149 // table doesn't exist in current commit or in history 150 return nil, false, nil 151 } 152 153 if tblFound { 154 sch, err := t.GetSchema(ctx) 155 if err != nil { 156 return nil, false, err 157 } 158 159 err = ss.AddSchemas(sch) 160 if err != nil { 161 return nil, false, err 162 } 163 } 164 165 return ss, true, err 166 } 167 168 func (root *RootValue) GenerateTagsForNewColColl(ctx context.Context, tableName string, cc *schema.ColCollection) (*schema.ColCollection, error) { 169 newColNames := make([]string, 0, cc.Size()) 170 newColKinds := make([]types.NomsKind, 0, cc.Size()) 171 _ = cc.Iter(func(tag uint64, col schema.Column) (stop bool, err error) { 172 newColNames = append(newColNames, col.Name) 173 newColKinds = append(newColKinds, col.Kind) 174 return false, nil 175 }) 176 177 newTags, err := root.GenerateTagsForNewColumns(ctx, tableName, newColNames, newColKinds, nil) 178 if err != nil { 179 return nil, err 180 } 181 182 idx := 0 183 return schema.MapColCollection(cc, func(col schema.Column) schema.Column { 184 col.Tag = newTags[idx] 185 idx++ 186 return col 187 }), nil 188 } 189 190 // GenerateTagsForNewColumns deterministically generates a slice of new tags that are unique within the history of this root. The names and NomsKinds of 191 // the new columns are used to see the tag generator. 192 func (root *RootValue) GenerateTagsForNewColumns(ctx context.Context, tableName string, newColNames []string, newColKinds []types.NomsKind, headRoot *RootValue) ([]uint64, error) { 193 if len(newColNames) != len(newColKinds) { 194 return nil, fmt.Errorf("error generating tags, newColNames and newColKinds must be of equal length") 195 } 196 197 if headRoot != nil { 198 tbl, found, err := headRoot.GetTable(ctx, tableName) 199 if err != nil { 200 return nil, err 201 } 202 203 if found { 204 sch, err := tbl.GetSchema(ctx) 205 if err != nil { 206 return nil, err 207 } 208 209 colOverlap := schema.GetSharedCols(sch, newColNames, newColKinds) 210 if len(colOverlap) == len(newColNames) { 211 var reusedTags []uint64 212 for _, k := range newColNames { 213 reusedTags = append(reusedTags, colOverlap[k]) 214 } 215 return reusedTags, nil 216 } 217 } 218 } 219 220 rootSuperSchema, err := GetRootValueSuperSchema(ctx, root) 221 222 if err != nil { 223 return nil, err 224 } 225 226 var existingColKinds []types.NomsKind 227 tbl, found, err := root.GetTable(ctx, tableName) 228 if err != nil { 229 return nil, err 230 } 231 if found { 232 sch, err := tbl.GetSchema(ctx) 233 if err != nil { 234 return nil, err 235 } 236 _ = sch.GetAllCols().Iter(func(tag uint64, col schema.Column) (stop bool, err error) { 237 existingColKinds = append(existingColKinds, col.Kind) 238 return false, nil 239 }) 240 } 241 242 newTags := make([]uint64, len(newColNames)) 243 existingTags := set.NewUint64Set(rootSuperSchema.AllTags()) 244 for i := range newTags { 245 newTags[i] = schema.AutoGenerateTag(existingTags, tableName, existingColKinds, newColNames[i], newColKinds[i]) 246 existingColKinds = append(existingColKinds, newColKinds[i]) 247 existingTags.Add(newTags[i]) 248 } 249 250 return newTags, nil 251 } 252 253 // GerSuperSchemaMap returns the Noms map that tracks SuperSchemas, used to create new RootValues on checkout branch. 254 func (root *RootValue) GetSuperSchemaMap(ctx context.Context) (types.Map, error) { 255 return root.getOrCreateSuperSchemaMap(ctx) 256 } 257 258 // SuperSchemas are only persisted on commit. 259 func (root *RootValue) getSuperSchemaAtLastCommit(ctx context.Context, tName string) (*schema.SuperSchema, bool, error) { 260 ssm, err := root.getOrCreateSuperSchemaMap(ctx) 261 if err != nil { 262 return nil, false, err 263 } 264 265 v, found, err := ssm.MaybeGet(ctx, types.String(tName)) 266 if err != nil { 267 return nil, false, err 268 } 269 if !found { 270 // Super Schema doesn't exist for new or nonexistent table 271 return nil, false, nil 272 } 273 274 ssValRef := v.(types.Ref) 275 ssVal, err := ssValRef.TargetValue(ctx, root.vrw) 276 if err != nil { 277 return nil, false, err 278 } 279 280 ss, err := encoding.UnmarshalSuperSchemaNomsValue(ctx, root.vrw.Format(), ssVal) 281 if err != nil { 282 return nil, false, err 283 } 284 285 return ss, true, nil 286 } 287 288 func (root *RootValue) getOrCreateSuperSchemaMap(ctx context.Context) (types.Map, error) { 289 v, found, err := root.valueSt.MaybeGet(superSchemasKey) 290 291 if err != nil { 292 return types.EmptyMap, err 293 } 294 295 var ssm types.Map 296 if found { 297 ssm = v.(types.Map) 298 } else { 299 ssm, err = types.NewMap(ctx, root.vrw) 300 } 301 return ssm, err 302 } 303 304 func (root *RootValue) getTableSt(ctx context.Context, tName string) (*types.Struct, bool, error) { 305 tableMap, err := root.getTableMap() 306 307 if err != nil { 308 return nil, false, err 309 } 310 311 tVal, found, err := tableMap.MaybeGet(ctx, types.String(tName)) 312 if err != nil { 313 return nil, false, err 314 } 315 316 if tVal == nil || !found { 317 return nil, false, nil 318 } 319 320 tValRef := tVal.(types.Ref) 321 val, err := tValRef.TargetValue(ctx, root.vrw) 322 if err != nil { 323 return nil, false, err 324 } 325 326 tableStruct := val.(types.Struct) 327 return &tableStruct, true, nil 328 } 329 330 func (root *RootValue) GetAllSchemas(ctx context.Context) (map[string]schema.Schema, error) { 331 m := make(map[string]schema.Schema) 332 err := root.IterTables(ctx, func(name string, table *Table, sch schema.Schema) (stop bool, err error) { 333 m[name] = sch 334 return false, nil 335 }) 336 337 if err != nil { 338 return nil, err 339 } 340 341 return m, nil 342 } 343 344 func (root *RootValue) GetTableHash(ctx context.Context, tName string) (hash.Hash, bool, error) { 345 tableMap, err := root.getTableMap() 346 if err != nil { 347 return hash.Hash{}, false, err 348 } 349 350 tVal, found, err := tableMap.MaybeGet(ctx, types.String(tName)) 351 if err != nil { 352 return hash.Hash{}, false, err 353 } 354 355 if tVal == nil || !found { 356 return hash.Hash{}, false, nil 357 } 358 359 tValRef := tVal.(types.Ref) 360 return tValRef.TargetHash(), true, nil 361 } 362 363 func (root *RootValue) SetTableHash(ctx context.Context, tName string, h hash.Hash) (*RootValue, error) { 364 val, err := root.vrw.ReadValue(ctx, h) 365 366 if err != nil { 367 return nil, err 368 } 369 370 ref, err := types.NewRef(val, root.vrw.Format()) 371 372 if err != nil { 373 return nil, err 374 } 375 376 return putTable(ctx, root, tName, ref) 377 } 378 379 // GetTable will retrieve a table by name 380 func (root *RootValue) GetTable(ctx context.Context, tName string) (*Table, bool, error) { 381 if st, ok, err := root.getTableSt(ctx, tName); err != nil { 382 return nil, false, err 383 } else if ok { 384 return &Table{root.vrw, *st}, true, nil 385 } 386 387 return nil, false, nil 388 } 389 390 func (root *RootValue) GetTableInsensitive(ctx context.Context, tName string) (*Table, string, bool, error) { 391 tableMap, err := root.getTableMap() 392 393 if err != nil { 394 return nil, "", false, err 395 } 396 397 var foundKey string 398 hasExact, err := tableMap.Has(ctx, types.String(tName)) 399 400 if err != nil { 401 return nil, "", false, err 402 } 403 404 if hasExact { 405 foundKey = tName 406 } else { 407 lwrName := strings.ToLower(tName) 408 err = tableMap.Iter(ctx, func(key, value types.Value) (stop bool, err error) { 409 keyStr := string(key.(types.String)) 410 if lwrName == strings.ToLower(keyStr) { 411 foundKey = keyStr 412 return true, nil 413 } 414 415 return false, nil 416 }) 417 418 if err != nil { 419 return nil, "", false, nil 420 } 421 } 422 423 tbl, ok, err := root.GetTable(ctx, foundKey) 424 425 if err != nil { 426 return nil, "", false, err 427 } 428 429 return tbl, foundKey, ok, nil 430 } 431 432 // GetTableByColTag looks for the table containing the given column tag. It returns false if no table exists in the history. 433 // If the table containing the given tag previously existed and was deleted, it will return its name and a nil pointer. 434 func (root *RootValue) GetTableByColTag(ctx context.Context, tag uint64) (tbl *Table, name string, found bool, err error) { 435 err = root.IterTables(ctx, func(tn string, t *Table, s schema.Schema) (bool, error) { 436 _, found = s.GetAllCols().GetByTag(tag) 437 if found { 438 name, tbl = tn, t 439 } 440 441 return found, nil 442 }) 443 444 if err != nil { 445 return nil, "", false, err 446 } 447 448 err = root.iterSuperSchemas(ctx, func(tn string, ss *schema.SuperSchema) (bool, error) { 449 _, found = ss.GetByTag(tag) 450 if found { 451 name = tn 452 } 453 454 return found, nil 455 }) 456 if err != nil { 457 return nil, "", false, err 458 } 459 460 return tbl, name, found, nil 461 } 462 463 // GetTableNames retrieves the lists of all tables for a RootValue 464 func (root *RootValue) GetTableNames(ctx context.Context) ([]string, error) { 465 tableMap, err := root.getTableMap() 466 467 if err != nil { 468 return nil, err 469 } 470 471 numTables := int(tableMap.Len()) 472 names := make([]string, 0, numTables) 473 474 err = tableMap.Iter(ctx, func(key, _ types.Value) (stop bool, err error) { 475 names = append(names, string(key.(types.String))) 476 return false, nil 477 }) 478 479 if err != nil { 480 return nil, err 481 } 482 483 return names, nil 484 } 485 486 func (root *RootValue) getTableMap() (types.Map, error) { 487 val, found, err := root.valueSt.MaybeGet(tablesKey) 488 489 if err != nil { 490 return types.EmptyMap, err 491 } 492 493 if !found || val == nil { 494 return types.EmptyMap, err 495 } 496 497 tableMap := val.(types.Map) 498 return tableMap, err 499 } 500 501 func (root *RootValue) TablesInConflict(ctx context.Context) ([]string, error) { 502 tableMap, err := root.getTableMap() 503 504 if err != nil { 505 return nil, err 506 } 507 508 numTables := int(tableMap.Len()) 509 names := make([]string, 0, numTables) 510 511 err = tableMap.Iter(ctx, func(key, tblRefVal types.Value) (stop bool, err error) { 512 tblVal, err := tblRefVal.(types.Ref).TargetValue(ctx, root.vrw) 513 514 if err != nil { 515 return false, err 516 } 517 518 tblSt := tblVal.(types.Struct) 519 tbl := &Table{root.vrw, tblSt} 520 if has, err := tbl.HasConflicts(); err != nil { 521 return false, err 522 } else if has { 523 names = append(names, string(key.(types.String))) 524 } 525 526 return false, nil 527 }) 528 529 if err != nil { 530 return nil, err 531 } 532 533 return names, nil 534 } 535 536 func (root *RootValue) HasConflicts(ctx context.Context) (bool, error) { 537 cnfTbls, err := root.TablesInConflict(ctx) 538 539 if err != nil { 540 return false, err 541 } 542 543 return len(cnfTbls) > 0, nil 544 } 545 546 // IterTables calls the callback function cb on each table in this RootValue. 547 func (root *RootValue) IterTables(ctx context.Context, cb func(name string, table *Table, sch schema.Schema) (stop bool, err error)) error { 548 tm, err := root.getTableMap() 549 550 if err != nil { 551 return err 552 } 553 554 itr, err := tm.Iterator(ctx) 555 556 if err != nil { 557 return err 558 } 559 560 for { 561 nm, tableRef, err := itr.Next(ctx) 562 563 if err != nil || nm == nil || tableRef == nil { 564 return err 565 } 566 567 tableStruct, err := tableRef.(types.Ref).TargetValue(ctx, root.vrw) 568 569 if err != nil { 570 return err 571 } 572 573 name := string(nm.(types.String)) 574 table := &Table{root.vrw, tableStruct.(types.Struct)} 575 576 sch, err := table.GetSchema(ctx) 577 if err != nil { 578 return err 579 } 580 581 stop, err := cb(name, table, sch) 582 583 if err != nil || stop { 584 return err 585 } 586 } 587 } 588 589 func (root *RootValue) iterSuperSchemas(ctx context.Context, cb func(name string, ss *schema.SuperSchema) (stop bool, err error)) error { 590 m, err := root.getOrCreateSuperSchemaMap(ctx) 591 if err != nil { 592 return err 593 } 594 595 return m.Iter(ctx, func(key, value types.Value) (stop bool, err error) { 596 name := string(key.(types.String)) 597 598 // use GetSuperSchema() to pickup uncommitted SuperSchemas 599 ss, _, err := root.GetSuperSchema(ctx, name) 600 if err != nil { 601 return false, err 602 } 603 604 return cb(name, ss) 605 }) 606 } 607 608 // PutSuperSchema writes a new map entry for the table name and super schema supplied, it will overwrite an existing entry. 609 func (root *RootValue) PutSuperSchema(ctx context.Context, tName string, ss *schema.SuperSchema) (*RootValue, error) { 610 newRoot := root 611 ssm, err := newRoot.getOrCreateSuperSchemaMap(ctx) 612 613 if err != nil { 614 return nil, err 615 } 616 617 ssVal, err := encoding.MarshalSuperSchemaAsNomsValue(ctx, newRoot.VRW(), ss) 618 619 if err != nil { 620 return nil, err 621 } 622 623 ssRef, err := WriteValAndGetRef(ctx, newRoot.VRW(), ssVal) 624 625 if err != nil { 626 return nil, err 627 } 628 629 m, err := ssm.Edit().Set(types.String(tName), ssRef).Map(ctx) 630 631 if err != nil { 632 return nil, err 633 } 634 635 newRootSt := newRoot.valueSt 636 newRootSt, err = newRootSt.Set(superSchemasKey, m) 637 638 if err != nil { 639 return nil, err 640 } 641 642 return newRootValue(root.vrw, newRootSt) 643 } 644 645 // PutTable inserts a table by name into the map of tables. If a table already exists with that name it will be replaced 646 func (root *RootValue) PutTable(ctx context.Context, tName string, table *Table) (*RootValue, error) { 647 err := validateTagUniqueness(ctx, root, tName, table) 648 649 if err != nil { 650 return nil, err 651 } 652 653 tableRef, err := WriteValAndGetRef(ctx, root.VRW(), table.tableStruct) 654 655 if err != nil { 656 return nil, err 657 } 658 659 return putTable(ctx, root, tName, tableRef) 660 } 661 662 func putTable(ctx context.Context, root *RootValue, tName string, tableRef types.Ref) (*RootValue, error) { 663 if !IsValidTableName(tName) { 664 panic("Don't attempt to put a table with a name that fails the IsValidTableName check") 665 } 666 667 tableMap, err := root.getTableMap() 668 669 if err != nil { 670 return nil, err 671 } 672 673 tMapEditor := tableMap.Edit() 674 tMapEditor = tMapEditor.Set(types.String(tName), tableRef) 675 676 m, err := tMapEditor.Map(ctx) 677 678 if err != nil { 679 return nil, err 680 } 681 682 rootValSt := root.valueSt 683 rootValSt, err = rootValSt.Set(tablesKey, m) 684 685 if err != nil { 686 return nil, err 687 } 688 689 return newRootValue(root.vrw, rootValSt) 690 } 691 692 // CreateEmptyTable creates an empty table in this root with the name and schema given, returning the new root value. 693 func (root *RootValue) CreateEmptyTable(ctx context.Context, tName string, sch schema.Schema) (*RootValue, error) { 694 schVal, err := encoding.MarshalSchemaAsNomsValue(ctx, root.VRW(), sch) 695 if err != nil { 696 return nil, err 697 } 698 699 empty, err := types.NewMap(ctx, root.VRW()) 700 if err != nil { 701 return nil, err 702 } 703 704 emptyRef, err := WriteValAndGetRef(ctx, root.VRW(), empty) 705 if err != nil { 706 return nil, err 707 } 708 709 ed := empty.Edit() 710 err = sch.Indexes().Iter(func(index schema.Index) (stop bool, err error) { 711 // create an empty indexRowData map for every index 712 ed.Set(types.String(index.Name()), emptyRef) 713 return 714 }) 715 if err != nil { 716 return nil, err 717 } 718 719 indexes, err := ed.Map(ctx) 720 if err != nil { 721 return nil, err 722 } 723 724 tbl, err := NewTable(ctx, root.VRW(), schVal, empty, indexes, nil) 725 if err != nil { 726 return nil, err 727 } 728 729 newRoot, err := root.PutTable(ctx, tName, tbl) 730 if err != nil { 731 return nil, err 732 } 733 734 return newRoot, nil 735 } 736 737 // HashOf gets the hash of the root value 738 func (root *RootValue) HashOf() (hash.Hash, error) { 739 return root.valueSt.Hash(root.vrw.Format()) 740 } 741 742 // UpdateSuperSchemasFromOther updates SuperSchemas of tblNames using SuperSchemas from other. 743 func (root *RootValue) UpdateSuperSchemasFromOther(ctx context.Context, tblNames []string, other *RootValue) (*RootValue, error) { 744 newRoot := root 745 ssm, err := newRoot.getOrCreateSuperSchemaMap(ctx) 746 747 if err != nil { 748 return nil, err 749 } 750 751 sse := ssm.Edit() 752 753 for _, tn := range tblNames { 754 755 ss, found, err := root.GetSuperSchema(ctx, tn) 756 757 if err != nil { 758 return nil, err 759 } 760 761 oss, foundOther, err := other.GetSuperSchema(ctx, tn) 762 763 if err != nil { 764 return nil, err 765 } 766 767 var newSS *schema.SuperSchema 768 if found && foundOther { 769 newSS, err = schema.SuperSchemaUnion(ss, oss) 770 } else if found { 771 newSS = ss 772 } else if foundOther { 773 newSS = oss 774 } else { 775 h, _ := root.HashOf() 776 oh, _ := other.HashOf() 777 return nil, errors.New(fmt.Sprintf("table %s does not exist in root %s or root %s", tn, h.String(), oh.String())) 778 } 779 780 if err != nil { 781 return nil, err 782 } 783 784 ssVal, err := encoding.MarshalSuperSchemaAsNomsValue(ctx, newRoot.VRW(), newSS) 785 786 if err != nil { 787 return nil, err 788 } 789 790 ssRef, err := WriteValAndGetRef(ctx, newRoot.VRW(), ssVal) 791 792 if err != nil { 793 return nil, err 794 } 795 796 sse = sse.Set(types.String(tn), ssRef) 797 } 798 799 m, err := sse.Map(ctx) 800 801 if err != nil { 802 return nil, err 803 } 804 805 newRootSt := newRoot.valueSt 806 newRootSt, err = newRootSt.Set(superSchemasKey, m) 807 808 if err != nil { 809 return nil, err 810 } 811 812 return newRootValue(root.vrw, newRootSt) 813 } 814 815 // RenameTable renames a table by changing its string key in the RootValue's table map. In order to preserve 816 // column tag information, use this method instead of a table drop + add. 817 func (root *RootValue) RenameTable(ctx context.Context, oldName, newName string) (*RootValue, error) { 818 tableMap, err := root.getTableMap() 819 if err != nil { 820 return nil, err 821 } 822 823 tv, found, err := tableMap.MaybeGet(ctx, types.String(oldName)) 824 if err != nil { 825 return nil, err 826 } 827 if !found { 828 return nil, ErrTableNotFound 829 } 830 831 _, found, err = tableMap.MaybeGet(ctx, types.String(newName)) 832 if err != nil { 833 return nil, err 834 } 835 if found { 836 return nil, ErrTableExists 837 } 838 839 tme := tableMap.Edit().Remove(types.String(oldName)) 840 tme = tme.Set(types.String(newName), tv) 841 tableMap, err = tme.Map(ctx) 842 if err != nil { 843 return nil, err 844 } 845 rootValSt := root.valueSt 846 rootValSt, err = rootValSt.Set(tablesKey, tableMap) 847 if err != nil { 848 return nil, err 849 } 850 851 foreignKeyCollection, err := root.GetForeignKeyCollection(ctx) 852 if err != nil { 853 return nil, err 854 } 855 foreignKeyCollection.RenameTable(oldName, newName) 856 fkMap, err := foreignKeyCollection.Map(ctx, root.vrw) 857 if err != nil { 858 return nil, err 859 } 860 rootValSt, err = rootValSt.Set(foreignKeyKey, fkMap) 861 if err != nil { 862 return nil, err 863 } 864 865 ssMap, err := root.getOrCreateSuperSchemaMap(ctx) 866 if err != nil { 867 return nil, err 868 } 869 870 ssv, found, err := ssMap.MaybeGet(ctx, types.String(oldName)) 871 if err != nil { 872 return nil, err 873 } 874 if found { 875 ssme := ssMap.Edit().Remove(types.String(oldName)) 876 ssme = ssme.Set(types.String(newName), ssv) 877 ssMap, err = ssme.Map(ctx) 878 if err != nil { 879 return nil, err 880 } 881 882 rootValSt, err = rootValSt.Set(superSchemasKey, ssMap) 883 if err != nil { 884 return nil, err 885 } 886 return newRootValue(root.vrw, rootValSt) 887 } 888 889 return newRootValue(root.vrw, rootValSt) 890 } 891 892 func (root *RootValue) RemoveTables(ctx context.Context, tables ...string) (*RootValue, error) { 893 tableMap, err := root.getTableMap() 894 895 if err != nil { 896 return nil, err 897 } 898 899 me := tableMap.Edit() 900 for _, tbl := range tables { 901 key := types.String(tbl) 902 903 if has, err := tableMap.Has(ctx, key); err != nil { 904 return nil, err 905 } else if has { 906 me = me.Remove(key) 907 } else { 908 return nil, ErrTableNotFound 909 } 910 } 911 912 m, err := me.Map(ctx) 913 914 if err != nil { 915 return nil, err 916 } 917 918 rootValSt, err := root.valueSt.Set(tablesKey, m) 919 920 if err != nil { 921 return nil, err 922 } 923 924 newRoot, err := newRootValue(root.vrw, rootValSt) 925 if err != nil { 926 return nil, err 927 } 928 929 fkc, err := newRoot.GetForeignKeyCollection(ctx) 930 931 if err != nil { 932 return nil, err 933 } 934 935 err = fkc.RemoveTables(ctx, tables...) 936 937 if err != nil { 938 return nil, err 939 } 940 941 return newRoot.PutForeignKeyCollection(ctx, fkc) 942 } 943 944 // GetForeignKeyCollection returns the ForeignKeyCollection for this root. As collections are meant to be modified 945 // in-place, each returned collection may freely be altered without affecting future returned collections from this root. 946 func (root *RootValue) GetForeignKeyCollection(ctx context.Context) (*ForeignKeyCollection, error) { 947 if root.fkc == nil { 948 fkMap, err := root.GetForeignKeyCollectionMap(ctx) 949 if err != nil { 950 return nil, err 951 } 952 root.fkc, err = LoadForeignKeyCollection(ctx, fkMap) 953 if err != nil { 954 return nil, err 955 } 956 } 957 return root.fkc.copy(), nil 958 } 959 960 // GetForeignKeyCollectionMap returns the persisted noms Map of the foreign key collection on this root. If the intent 961 // is to retrieve a ForeignKeyCollection in particular, it is advised to call GetForeignKeyCollection as it caches the 962 // result for performance. 963 func (root *RootValue) GetForeignKeyCollectionMap(ctx context.Context) (types.Map, error) { 964 v, found, err := root.valueSt.MaybeGet(foreignKeyKey) 965 if err != nil { 966 return types.EmptyMap, err 967 } 968 969 var fkMap types.Map 970 if found { 971 fkMap = v.(types.Map) 972 } else { 973 fkMap, err = types.NewMap(ctx, root.vrw) 974 if err != nil { 975 return types.EmptyMap, err 976 } 977 } 978 return fkMap, nil 979 } 980 981 // PutForeignKeyCollection returns a new root with the given foreign key collection. 982 func (root *RootValue) PutForeignKeyCollection(ctx context.Context, fkc *ForeignKeyCollection) (*RootValue, error) { 983 fkMap, err := fkc.Map(ctx, root.vrw) 984 if err != nil { 985 return nil, err 986 } 987 rootValSt, err := root.valueSt.Set(foreignKeyKey, fkMap) 988 if err != nil { 989 return nil, err 990 } 991 return &RootValue{root.vrw, rootValSt, fkc.copy()}, nil 992 } 993 994 // ValidateForeignKeysOnSchemas ensures that all foreign keys' tables are present, removing any foreign keys where the declared 995 // table is missing, and returning an error if a key is in an invalid state or a referenced table is missing. Does not 996 // check any tables' row data. 997 func (root *RootValue) ValidateForeignKeysOnSchemas(ctx context.Context) (*RootValue, error) { 998 fkCollection, err := root.GetForeignKeyCollection(ctx) 999 if err != nil { 1000 return nil, err 1001 } 1002 allTablesSlice, err := root.GetTableNames(ctx) 1003 if err != nil { 1004 return nil, err 1005 } 1006 allTablesSet := make(map[string]schema.Schema) 1007 for _, tableName := range allTablesSlice { 1008 tbl, ok, err := root.GetTable(ctx, tableName) 1009 if err != nil { 1010 return nil, err 1011 } 1012 if !ok { 1013 return nil, fmt.Errorf("found table `%s` in staging but could not load for foreign key check", tableName) 1014 } 1015 tblSch, err := tbl.GetSchema(ctx) 1016 if err != nil { 1017 return nil, err 1018 } 1019 allTablesSet[tableName] = tblSch 1020 } 1021 1022 // some of these checks are sanity checks and should never happen 1023 allForeignKeys := fkCollection.AllKeys() 1024 for _, foreignKey := range allForeignKeys { 1025 tblSch, existsInRoot := allTablesSet[foreignKey.TableName] 1026 if existsInRoot { 1027 if err := foreignKey.ValidateTableSchema(tblSch); err != nil { 1028 return nil, err 1029 } 1030 parentSch, existsInRoot := allTablesSet[foreignKey.ReferencedTableName] 1031 if !existsInRoot { 1032 return nil, fmt.Errorf("foreign key `%s` requires the referenced table `%s`", foreignKey.Name, foreignKey.ReferencedTableName) 1033 } 1034 if err := foreignKey.ValidateReferencedTableSchema(parentSch); err != nil { 1035 return nil, err 1036 } 1037 } else { 1038 err := fkCollection.RemoveKeyByName(foreignKey.Name) 1039 if err != nil { 1040 return nil, err 1041 } 1042 } 1043 } 1044 1045 return root.PutForeignKeyCollection(ctx, fkCollection) 1046 } 1047 1048 // RootNeedsUniqueTagsMigration determines if this root needs to be migrated to uniquify its tags. 1049 func RootNeedsUniqueTagsMigration(root *RootValue) (bool, error) { 1050 // SuperSchemas were added in the same update that required unique tags. If a root does not have a 1051 // SuperSchema map then it was created before the unique tags constraint was enforced. 1052 _, found, err := root.valueSt.MaybeGet(superSchemasKey) 1053 if err != nil { 1054 return false, err 1055 } 1056 needToMigrate := !found 1057 return needToMigrate, nil 1058 } 1059 1060 // GetRootValueSuperSchema creates a SuperSchema with every column in history of root. 1061 func GetRootValueSuperSchema(ctx context.Context, root *RootValue) (*schema.SuperSchema, error) { 1062 ssMap, err := root.getOrCreateSuperSchemaMap(ctx) 1063 1064 if err != nil { 1065 return nil, err 1066 } 1067 1068 var sss []*schema.SuperSchema 1069 err = ssMap.Iter(ctx, func(key, value types.Value) (stop bool, err error) { 1070 ssValRef := value.(types.Ref) 1071 ssVal, err := ssValRef.TargetValue(ctx, root.vrw) 1072 1073 if err != nil { 1074 return true, err 1075 } 1076 1077 ss, err := encoding.UnmarshalSuperSchemaNomsValue(ctx, root.vrw.Format(), ssVal) 1078 1079 if err != nil { 1080 return true, err 1081 } 1082 1083 sss = append(sss, ss) // go get -f parseltongue 1084 return false, nil 1085 }) 1086 1087 if err != nil { 1088 return nil, err 1089 } 1090 1091 rootSuperSchema, err := schema.SuperSchemaUnion(sss...) 1092 if err != nil { 1093 return nil, err 1094 } 1095 1096 // super schemas are only persisted on commit, so add in working schemas 1097 tblMap, err := root.getTableMap() 1098 if err != nil { 1099 return nil, err 1100 } 1101 1102 err = tblMap.Iter(ctx, func(key, _ types.Value) (stop bool, err error) { 1103 tbl, _, err := root.GetTable(ctx, string(key.(types.String))) 1104 if err != nil { 1105 return true, err 1106 } 1107 sch, err := tbl.GetSchema(ctx) 1108 if err != nil { 1109 return true, err 1110 } 1111 err = rootSuperSchema.AddSchemas(sch) 1112 if err != nil { 1113 return true, err 1114 } 1115 return false, nil 1116 }) 1117 if err != nil { 1118 return nil, err 1119 } 1120 1121 return rootSuperSchema, nil 1122 } 1123 1124 // UnionTableNames returns an array of all table names in all roots passed as params. 1125 func UnionTableNames(ctx context.Context, roots ...*RootValue) ([]string, error) { 1126 allTblNames := make([]string, 0, 16) 1127 for _, root := range roots { 1128 tblNames, err := root.GetTableNames(ctx) 1129 1130 if err != nil { 1131 return nil, err 1132 } 1133 1134 allTblNames = append(allTblNames, tblNames...) 1135 } 1136 1137 return set.Unique(allTblNames), nil 1138 } 1139 1140 // validateTagUniqueness checks for tag collisions between the given table and the set of tables in then given root. 1141 func validateTagUniqueness(ctx context.Context, root *RootValue, tableName string, table *Table) error { 1142 prev, ok, err := root.GetTable(ctx, tableName) 1143 if err != nil { 1144 return err 1145 } 1146 if ok { 1147 prevRef, err := prev.GetSchemaRef() 1148 if err != nil { 1149 return err 1150 } 1151 1152 newRef, err := table.GetSchemaRef() 1153 if err != nil { 1154 return err 1155 } 1156 1157 // short-circuit if schema unchanged 1158 if prevRef.Equals(newRef) { 1159 return nil 1160 } 1161 } 1162 1163 sch, err := table.GetSchema(ctx) 1164 if err != nil { 1165 return err 1166 } 1167 1168 var ee []string 1169 err = root.iterSuperSchemas(ctx, func(tn string, ss *schema.SuperSchema) (stop bool, err error) { 1170 if tn == tableName { 1171 return false, nil 1172 } 1173 1174 err = sch.GetAllCols().Iter(func(tag uint64, col schema.Column) (stop bool, err error) { 1175 _, ok := ss.GetByTag(tag) 1176 if ok { 1177 ee = append(ee, schema.ErrTagPrevUsed(tag, col.Name, tn).Error()) 1178 } 1179 return false, nil 1180 }) 1181 return false, err 1182 }) 1183 if err != nil { 1184 return err 1185 } 1186 1187 if len(ee) > 0 { 1188 return fmt.Errorf(strings.Join(ee, "\n")) 1189 } 1190 1191 return nil 1192 } 1193 1194 // DebugString returns a human readable string with the contents of this root. If |transitive| is true, row data from 1195 // all tables is also included. This method is very expensive for large root values, so |transitive| should only be used 1196 // when debugging tests. 1197 func (root *RootValue) DebugString(ctx context.Context, transitive bool) string { 1198 var buf bytes.Buffer 1199 err := types.WriteEncodedValue(ctx, &buf, root.valueSt) 1200 if err != nil { 1201 panic(err) 1202 } 1203 1204 if transitive { 1205 buf.WriteString("\nTables:") 1206 root.IterTables(ctx, func(name string, table *Table, sch schema.Schema) (stop bool, err error) { 1207 buf.WriteString("\nName:") 1208 buf.WriteString(name) 1209 buf.WriteString("\n") 1210 1211 buf.WriteString("Data:\n") 1212 data, err := table.GetRowData(ctx) 1213 if err != nil { 1214 panic(err) 1215 } 1216 1217 err = types.WriteEncodedValue(ctx, &buf, data) 1218 if err != nil { 1219 panic(err) 1220 } 1221 return false, nil 1222 }) 1223 } 1224 1225 return buf.String() 1226 }