github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/libraries/doltcore/doltdb/table.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 "context" 19 "errors" 20 "fmt" 21 "regexp" 22 23 "github.com/dolthub/dolt/go/libraries/doltcore/schema" 24 "github.com/dolthub/dolt/go/libraries/doltcore/schema/encoding" 25 "github.com/dolthub/dolt/go/store/hash" 26 "github.com/dolthub/dolt/go/store/types" 27 ) 28 29 const ( 30 tableStructName = "table" 31 32 schemaRefKey = "schema_ref" 33 tableRowsKey = "rows" 34 conflictsKey = "conflicts" 35 conflictSchemasKey = "conflict_schemas" 36 indexesKey = "indexes" 37 autoIncrementKey = "auto_increment" 38 39 // TableNameRegexStr is the regular expression that valid tables must match. 40 TableNameRegexStr = `^[a-zA-Z]{1}$|^[a-zA-Z_]+[-_0-9a-zA-Z]*[0-9a-zA-Z]+$` 41 // ForeignKeyNameRegexStr is the regular expression that valid foreign keys must match. 42 // From the unquoted identifiers: https://dev.mysql.com/doc/refman/8.0/en/identifiers.html 43 // We also allow the '-' character from quoted identifiers. 44 ForeignKeyNameRegexStr = `^[-$_0-9a-zA-Z]+$` 45 // IndexNameRegexStr is the regular expression that valid indexes must match. 46 // From the unquoted identifiers: https://dev.mysql.com/doc/refman/8.0/en/identifiers.html 47 // We also allow the '-' character from quoted identifiers. 48 IndexNameRegexStr = `^[-$_0-9a-zA-Z]+$` 49 ) 50 51 var ( 52 tableNameRegex = regexp.MustCompile(TableNameRegexStr) 53 foreignKeyNameRegex = regexp.MustCompile(ForeignKeyNameRegexStr) 54 indexNameRegex = regexp.MustCompile(IndexNameRegexStr) 55 56 ErrNoConflictsResolved = errors.New("no conflicts resolved") 57 ErrNoAutoIncrementValue = fmt.Errorf("auto increment set for non-numeric column type") 58 ) 59 60 // IsValidTableName returns true if the name matches the regular expression TableNameRegexStr. 61 // Table names must be composed of 1 or more letters and non-initial numerals, as well as the characters _ and - 62 func IsValidTableName(name string) bool { 63 return tableNameRegex.MatchString(name) 64 } 65 66 // IsValidForeignKeyName returns true if the name matches the regular expression ForeignKeyNameRegexStr. 67 func IsValidForeignKeyName(name string) bool { 68 return foreignKeyNameRegex.MatchString(name) 69 } 70 71 // IsValidIndexName returns true if the name matches the regular expression IndexNameRegexStr. 72 func IsValidIndexName(name string) bool { 73 return indexNameRegex.MatchString(name) 74 } 75 76 // Table is a struct which holds row data, as well as a reference to it's schema. 77 type Table struct { 78 vrw types.ValueReadWriter 79 tableStruct types.Struct 80 } 81 82 // NewTable creates a noms Struct which stores row data, index data, and schema. 83 func NewTable(ctx context.Context, vrw types.ValueReadWriter, schemaVal types.Value, rowData types.Map, indexData types.Map, autoIncVal types.Value) (*Table, error) { 84 schemaRef, err := WriteValAndGetRef(ctx, vrw, schemaVal) 85 if err != nil { 86 return nil, err 87 } 88 89 rowDataRef, err := WriteValAndGetRef(ctx, vrw, rowData) 90 if err != nil { 91 return nil, err 92 } 93 94 indexesRef, err := WriteValAndGetRef(ctx, vrw, indexData) 95 if err != nil { 96 return nil, err 97 } 98 99 sd := types.StructData{ 100 schemaRefKey: schemaRef, 101 tableRowsKey: rowDataRef, 102 indexesKey: indexesRef, 103 } 104 105 if autoIncVal != nil { 106 sd[autoIncrementKey] = autoIncVal 107 } 108 109 tableStruct, err := types.NewStruct(vrw.Format(), tableStructName, sd) 110 if err != nil { 111 return nil, err 112 } 113 114 return &Table{vrw, tableStruct}, nil 115 } 116 117 func (t *Table) Format() *types.NomsBinFormat { 118 return t.vrw.Format() 119 } 120 121 // ValueReadWriter returns the ValueReadWriter for this table. 122 func (t *Table) ValueReadWriter() types.ValueReadWriter { 123 return t.vrw 124 } 125 126 func (t *Table) SetConflicts(ctx context.Context, schemas Conflict, conflictData types.Map) (*Table, error) { 127 conflictsRef, err := WriteValAndGetRef(ctx, t.vrw, conflictData) 128 129 if err != nil { 130 return nil, err 131 } 132 133 tpl, err := schemas.ToNomsList(t.vrw) 134 135 if err != nil { 136 return nil, err 137 } 138 139 updatedSt, err := t.tableStruct.Set(conflictSchemasKey, tpl) 140 141 if err != nil { 142 return nil, err 143 } 144 145 updatedSt, err = updatedSt.Set(conflictsKey, conflictsRef) 146 147 if err != nil { 148 return nil, err 149 } 150 151 return &Table{t.vrw, updatedSt}, nil 152 } 153 154 func (t *Table) GetConflicts(ctx context.Context) (Conflict, types.Map, error) { 155 schemasVal, ok, err := t.tableStruct.MaybeGet(conflictSchemasKey) 156 157 if err != nil { 158 return Conflict{}, types.EmptyMap, err 159 } 160 161 if !ok { 162 return Conflict{}, types.EmptyMap, ErrNoConflicts 163 } 164 165 schemas, err := ConflictFromTuple(schemasVal.(types.Tuple)) 166 167 if err != nil { 168 return Conflict{}, types.EmptyMap, err 169 } 170 171 conflictsVal, _, err := t.tableStruct.MaybeGet(conflictsKey) 172 173 if err != nil { 174 return Conflict{}, types.EmptyMap, err 175 } 176 177 confMap := types.EmptyMap 178 if conflictsVal != nil { 179 confMapRef := conflictsVal.(types.Ref) 180 v, err := confMapRef.TargetValue(ctx, t.vrw) 181 182 if err != nil { 183 return Conflict{}, types.EmptyMap, err 184 } 185 186 confMap = v.(types.Map) 187 } 188 189 return schemas, confMap, nil 190 } 191 192 func (t *Table) HasConflicts() (bool, error) { 193 if t == nil { 194 return false, nil 195 } 196 197 _, ok, err := t.tableStruct.MaybeGet(conflictSchemasKey) 198 199 return ok, err 200 } 201 202 func (t *Table) NumRowsInConflict(ctx context.Context) (uint64, error) { 203 if t == nil { 204 return 0, nil 205 } 206 207 conflictsVal, ok, err := t.tableStruct.MaybeGet(conflictsKey) 208 209 if err != nil { 210 return 0, err 211 } 212 213 if !ok { 214 return 0, nil 215 } 216 217 confMap := types.EmptyMap 218 if conflictsVal != nil { 219 confMapRef := conflictsVal.(types.Ref) 220 v, err := confMapRef.TargetValue(ctx, t.vrw) 221 222 if err != nil { 223 return 0, err 224 } 225 confMap = v.(types.Map) 226 } 227 228 return confMap.Len(), nil 229 } 230 231 func (t *Table) ClearConflicts() (*Table, error) { 232 tSt, err := t.tableStruct.Delete(conflictSchemasKey) 233 234 if err != nil { 235 return nil, err 236 } 237 238 tSt, err = tSt.Delete(conflictsKey) 239 240 if err != nil { 241 return nil, err 242 } 243 244 return &Table{t.vrw, tSt}, nil 245 } 246 247 func (t *Table) GetConflictSchemas(ctx context.Context) (base, sch, mergeSch schema.Schema, err error) { 248 schemasVal, ok, err := t.tableStruct.MaybeGet(conflictSchemasKey) 249 250 if err != nil { 251 return nil, nil, nil, err 252 } 253 254 if ok { 255 schemas, err := ConflictFromTuple(schemasVal.(types.Tuple)) 256 257 if err != nil { 258 return nil, nil, nil, err 259 } 260 261 baseRef := schemas.Base.(types.Ref) 262 valRef := schemas.Value.(types.Ref) 263 mergeRef := schemas.MergeValue.(types.Ref) 264 265 var baseSch, sch, mergeSch schema.Schema 266 if baseSch, err = RefToSchema(ctx, t.vrw, baseRef); err == nil { 267 if sch, err = RefToSchema(ctx, t.vrw, valRef); err == nil { 268 mergeSch, err = RefToSchema(ctx, t.vrw, mergeRef) 269 } 270 } 271 272 return baseSch, sch, mergeSch, err 273 } 274 return nil, nil, nil, ErrNoConflicts 275 } 276 277 func RefToSchema(ctx context.Context, vrw types.ValueReadWriter, ref types.Ref) (schema.Schema, error) { 278 schemaVal, err := ref.TargetValue(ctx, vrw) 279 280 if err != nil { 281 return nil, err 282 } 283 284 schema, err := encoding.UnmarshalSchemaNomsValue(ctx, vrw.Format(), schemaVal) 285 286 if err != nil { 287 return nil, err 288 } 289 290 return schema, nil 291 } 292 293 // GetSchema will retrieve the schema being referenced from the table in noms and unmarshal it. 294 func (t *Table) GetSchema(ctx context.Context) (schema.Schema, error) { 295 schemaRefVal, _, err := t.tableStruct.MaybeGet(schemaRefKey) 296 297 if err != nil { 298 return nil, err 299 } 300 301 schemaRef := schemaRefVal.(types.Ref) 302 return RefToSchema(ctx, t.vrw, schemaRef) 303 } 304 305 func (t *Table) GetSchemaRef() (types.Ref, error) { 306 v, _, err := t.tableStruct.MaybeGet(schemaRefKey) 307 308 if err != nil { 309 return types.Ref{}, err 310 } 311 312 if v == nil { 313 return types.Ref{}, errors.New("missing schema") 314 } 315 316 return v.(types.Ref), nil 317 } 318 319 // UpdateSchema updates the table with the schema given and returns the updated table. The original table is unchanged. 320 func (t *Table) UpdateSchema(ctx context.Context, sch schema.Schema) (*Table, error) { 321 newSchemaVal, err := encoding.MarshalSchemaAsNomsValue(ctx, t.vrw, sch) 322 if err != nil { 323 return nil, err 324 } 325 326 schRef, err := WriteValAndGetRef(ctx, t.vrw, newSchemaVal) 327 if err != nil { 328 return nil, err 329 } 330 331 newTableStruct, err := t.tableStruct.Set(schemaRefKey, schRef) 332 if err != nil { 333 return nil, err 334 } 335 336 return &Table{t.vrw, newTableStruct}, nil 337 } 338 339 // HasTheSameSchema tests the schema within 2 tables for equality 340 func (t *Table) HasTheSameSchema(t2 *Table) (bool, error) { 341 schemaVal, _, err := t.tableStruct.MaybeGet(schemaRefKey) 342 343 if err != nil { 344 return false, err 345 } 346 347 schemaRef := schemaVal.(types.Ref) 348 349 schema2Val, _, err := t2.tableStruct.MaybeGet(schemaRefKey) 350 351 if err != nil { 352 return false, err 353 } 354 355 schema2Ref := schema2Val.(types.Ref) 356 357 return schemaRef.TargetHash() == schema2Ref.TargetHash(), nil 358 } 359 360 // HashOf returns the hash of the underlying table struct 361 func (t *Table) HashOf() (hash.Hash, error) { 362 return t.tableStruct.Hash(t.vrw.Format()) 363 } 364 365 // UpdateRows replaces the current row data and returns and updated Table. Calls to UpdateRows will not be written to the 366 // database. The root must be updated with the updated table, and the root must be committed or written. 367 func (t *Table) UpdateRows(ctx context.Context, updatedRows types.Map) (*Table, error) { 368 rowDataRef, err := WriteValAndGetRef(ctx, t.vrw, updatedRows) 369 370 if err != nil { 371 return nil, err 372 } 373 374 updatedSt, err := t.tableStruct.Set(tableRowsKey, rowDataRef) 375 376 if err != nil { 377 return nil, err 378 } 379 380 return &Table{t.vrw, updatedSt}, nil 381 } 382 383 // GetRowData retrieves the underlying map which is a map from a primary key to a list of field values. 384 func (t *Table) GetRowData(ctx context.Context) (types.Map, error) { 385 val, _, err := t.tableStruct.MaybeGet(tableRowsKey) 386 387 if err != nil { 388 return types.EmptyMap, err 389 } 390 391 rowMapRef := val.(types.Ref) 392 393 val, err = rowMapRef.TargetValue(ctx, t.vrw) 394 395 if err != nil { 396 return types.EmptyMap, err 397 } 398 399 rowMap := val.(types.Map) 400 return rowMap, nil 401 } 402 403 func (t *Table) ResolveConflicts(ctx context.Context, pkTuples []types.Value) (invalid, notFound []types.Value, tbl *Table, err error) { 404 removed := 0 405 _, confData, err := t.GetConflicts(ctx) 406 407 if err != nil { 408 return nil, nil, nil, err 409 } 410 411 confEdit := confData.Edit() 412 for _, pkTupleVal := range pkTuples { 413 if has, err := confData.Has(ctx, pkTupleVal); err != nil { 414 return nil, nil, nil, err 415 } else if has { 416 removed++ 417 confEdit.Remove(pkTupleVal) 418 } else { 419 notFound = append(notFound, pkTupleVal) 420 } 421 } 422 423 if removed == 0 { 424 return invalid, notFound, tbl, ErrNoConflictsResolved 425 } 426 427 conflicts, err := confEdit.Map(ctx) 428 429 if err != nil { 430 return nil, nil, nil, err 431 } 432 433 conflictsRef, err := WriteValAndGetRef(ctx, t.vrw, conflicts) 434 435 if err != nil { 436 return nil, nil, nil, err 437 } 438 439 updatedSt, err := t.tableStruct.Set(conflictsKey, conflictsRef) 440 441 if err != nil { 442 return nil, nil, nil, err 443 } 444 445 return invalid, notFound, &Table{t.vrw, updatedSt}, nil 446 } 447 448 // GetIndexData returns the internal index map which goes from index name to a ref of the row data map. 449 func (t *Table) GetIndexData(ctx context.Context) (types.Map, error) { 450 indexesVal, ok, err := t.tableStruct.MaybeGet(indexesKey) 451 if err != nil { 452 return types.EmptyMap, err 453 } 454 if !ok { 455 newEmptyMap, err := types.NewMap(ctx, t.vrw) 456 if err != nil { 457 return types.EmptyMap, err 458 } 459 return newEmptyMap, nil 460 } 461 462 indexesMap, err := indexesVal.(types.Ref).TargetValue(ctx, t.vrw) 463 if err != nil { 464 return types.EmptyMap, err 465 } 466 467 return indexesMap.(types.Map), nil 468 } 469 470 // SetIndexData replaces the current internal index map, and returns an updated Table. 471 func (t *Table) SetIndexData(ctx context.Context, indexesMap types.Map) (*Table, error) { 472 indexesRef, err := WriteValAndGetRef(ctx, t.vrw, indexesMap) 473 if err != nil { 474 return nil, err 475 } 476 477 newTableStruct, err := t.tableStruct.Set(indexesKey, indexesRef) 478 if err != nil { 479 return nil, err 480 } 481 482 return &Table{t.vrw, newTableStruct}, nil 483 } 484 485 // GetIndexRowData retrieves the underlying map of an index, in which the primary key consists of all indexed columns. 486 func (t *Table) GetIndexRowData(ctx context.Context, indexName string) (types.Map, error) { 487 indexesMap, err := t.GetIndexData(ctx) 488 if err != nil { 489 return types.EmptyMap, err 490 } 491 492 indexMapRef, ok, err := indexesMap.MaybeGet(ctx, types.String(indexName)) 493 if err != nil { 494 return types.EmptyMap, err 495 } 496 if !ok { 497 return types.EmptyMap, fmt.Errorf("index `%s` is missing its data", indexName) 498 } 499 500 indexMap, err := indexMapRef.(types.Ref).TargetValue(ctx, t.vrw) 501 if err != nil { 502 return types.EmptyMap, err 503 } 504 505 return indexMap.(types.Map), nil 506 } 507 508 // SetIndexRowData replaces the current row data for the given index and returns an updated Table. 509 func (t *Table) SetIndexRowData(ctx context.Context, indexName string, indexRowData types.Map) (*Table, error) { 510 indexesMap, err := t.GetIndexData(ctx) 511 if err != nil { 512 return nil, err 513 } 514 515 indexRowDataRef, err := WriteValAndGetRef(ctx, t.vrw, indexRowData) 516 if err != nil { 517 return nil, err 518 } 519 indexesMap, err = indexesMap.Edit().Set(types.String(indexName), indexRowDataRef).Map(ctx) 520 if err != nil { 521 return nil, err 522 } 523 524 return t.SetIndexData(ctx, indexesMap) 525 } 526 527 // DeleteIndexRowData removes the underlying map of an index, along with its key entry. This should only be used 528 // when removing an index altogether. If the intent is to clear an index's data, then use SetIndexRowData with 529 // an empty map. 530 func (t *Table) DeleteIndexRowData(ctx context.Context, indexName string) (*Table, error) { 531 indexesMap, err := t.GetIndexData(ctx) 532 if err != nil { 533 return nil, err 534 } 535 536 key := types.String(indexName) 537 if has, err := indexesMap.Has(ctx, key); err != nil { 538 return nil, err 539 } else if has { 540 indexesMap, err = indexesMap.Edit().Remove(key).Map(ctx) 541 if err != nil { 542 return nil, err 543 } 544 } else { 545 return t, nil 546 } 547 548 return t.SetIndexData(ctx, indexesMap) 549 } 550 551 // RenameIndexRowData changes the name for the index data. Does not verify that the new name is unoccupied. If the old 552 // name does not exist, then this returns the called table without error. 553 func (t *Table) RenameIndexRowData(ctx context.Context, oldIndexName, newIndexName string) (*Table, error) { 554 indexesMap, err := t.GetIndexData(ctx) 555 if err != nil { 556 return nil, err 557 } 558 559 oldKey := types.String(oldIndexName) 560 newKey := types.String(newIndexName) 561 if indexRowData, ok, err := indexesMap.MaybeGet(ctx, oldKey); err != nil { 562 return nil, err 563 } else if ok { 564 indexesMap, err = indexesMap.Edit().Set(newKey, indexRowData).Remove(oldKey).Map(ctx) 565 if err != nil { 566 return nil, err 567 } 568 } else { 569 return t, nil 570 } 571 572 return t.SetIndexData(ctx, indexesMap) 573 } 574 575 // VerifyIndexRowData verifies that the index with the given name's data matches what the index expects. 576 func (t *Table) VerifyIndexRowData(ctx context.Context, indexName string) error { 577 sch, err := t.GetSchema(ctx) 578 if err != nil { 579 return err 580 } 581 582 index := sch.Indexes().GetByName(indexName) 583 if index == nil { 584 return fmt.Errorf("index `%s` does not exist", indexName) 585 } 586 587 indexesMap, err := t.GetIndexData(ctx) 588 if err != nil { 589 return err 590 } 591 592 indexMapRef, ok, err := indexesMap.MaybeGet(ctx, types.String(indexName)) 593 if err != nil { 594 return err 595 } 596 if !ok { 597 return fmt.Errorf("index `%s` is missing its data", indexName) 598 } 599 600 indexMapValue, err := indexMapRef.(types.Ref).TargetValue(ctx, t.vrw) 601 if err != nil { 602 return err 603 } 604 605 iter, err := indexMapValue.(types.Map).Iterator(ctx) 606 if err != nil { 607 return err 608 } 609 610 return index.VerifyMap(ctx, iter, indexMapValue.(types.Map).Format()) 611 } 612 613 func (t *Table) GetAutoIncrementValue(ctx context.Context) (types.Value, error) { 614 val, ok, err := t.tableStruct.MaybeGet(autoIncrementKey) 615 if err != nil { 616 return nil, err 617 } 618 if ok { 619 return val, nil 620 } 621 622 sch, err := t.GetSchema(ctx) 623 if err != nil { 624 return nil, err 625 } 626 627 kind := types.UnknownKind 628 _ = sch.GetAllCols().Iter(func(tag uint64, col schema.Column) (stop bool, err error) { 629 if col.AutoIncrement { 630 kind = col.Kind 631 stop = true 632 } 633 return 634 }) 635 switch kind { 636 case types.IntKind: 637 return types.Int(1), nil 638 case types.UintKind: 639 return types.Uint(1), nil 640 case types.FloatKind: 641 return types.Float(1), nil 642 default: 643 return nil, ErrNoAutoIncrementValue 644 } 645 } 646 647 func (t *Table) SetAutoIncrementValue(val types.Value) (*Table, error) { 648 switch val.(type) { 649 case types.Int, types.Uint, types.Float: 650 st, err := t.tableStruct.Set(autoIncrementKey, val) 651 if err != nil { 652 return nil, err 653 } 654 return &Table{t.vrw, st}, nil 655 656 default: 657 return nil, fmt.Errorf("cannot set auto increment to non-numeric value") 658 } 659 }