github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/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  	"sort"
    23  	"strings"
    24  
    25  	flatbuffers "github.com/dolthub/flatbuffers/v23/go"
    26  
    27  	"github.com/dolthub/dolt/go/gen/fb/serial"
    28  	"github.com/dolthub/dolt/go/libraries/doltcore/doltdb/durable"
    29  	"github.com/dolthub/dolt/go/libraries/doltcore/schema"
    30  	"github.com/dolthub/dolt/go/store/datas"
    31  	"github.com/dolthub/dolt/go/store/hash"
    32  	"github.com/dolthub/dolt/go/store/prolly"
    33  	"github.com/dolthub/dolt/go/store/prolly/tree"
    34  	"github.com/dolthub/dolt/go/store/types"
    35  )
    36  
    37  const (
    38  	ddbRootStructName = "dolt_db_root"
    39  
    40  	tablesKey        = "tables"
    41  	foreignKeyKey    = "foreign_key"
    42  	featureVersKey   = "feature_ver"
    43  	rootCollationKey = "root_collation_key"
    44  
    45  	// deprecated
    46  	superSchemasKey = "super_schemas"
    47  )
    48  
    49  type FeatureVersion int64
    50  
    51  // DoltFeatureVersion is described in feature_version.md.
    52  // only variable for testing.
    53  var DoltFeatureVersion FeatureVersion = 7 // last bumped when fixing bug related to GeomAddrs not getting pushed
    54  
    55  // RootValue is the value of the Database and is the committed value in every Dolt or Doltgres commit.
    56  type RootValue interface {
    57  	Rootish
    58  
    59  	// CreateDatabaseSchema creates the given schema. This differs from a table's schema.
    60  	CreateDatabaseSchema(ctx context.Context, dbSchema schema.DatabaseSchema) (RootValue, error)
    61  	// DebugString returns a human readable string with the contents of this root. If |transitive| is true, row data from
    62  	// all tables is also included. This method is very expensive for large root values, so |transitive| should only be used
    63  	// when debugging tests.
    64  	DebugString(ctx context.Context, transitive bool) string
    65  	// GetCollation returns the database collation.
    66  	GetCollation(ctx context.Context) (schema.Collation, error)
    67  	// GetDatabaseSchemas returns all schemas. These differ from a table's schema.
    68  	GetDatabaseSchemas(ctx context.Context) ([]schema.DatabaseSchema, error)
    69  	// GetFeatureVersion returns the feature version of this root, if one is written
    70  	GetFeatureVersion(ctx context.Context) (ver FeatureVersion, ok bool, err error)
    71  	// GetForeignKeyCollection returns the ForeignKeyCollection for this root. As collections are meant to be modified
    72  	// in-place, each returned collection may freely be altered without affecting future returned collections from this root.
    73  	GetForeignKeyCollection(ctx context.Context) (*ForeignKeyCollection, error)
    74  	// GetTable will retrieve a table by its case-sensitive name.
    75  	GetTable(ctx context.Context, tName TableName) (*Table, bool, error)
    76  	// GetTableHash returns the hash of the given case-sensitive table name.
    77  	GetTableHash(ctx context.Context, tName string) (hash.Hash, bool, error)
    78  	// GetTableNames retrieves the lists of all tables for a RootValue
    79  	GetTableNames(ctx context.Context, schemaName string) ([]string, error)
    80  	// HandlePostMerge handles merging for any root elements that are not handled by the standard merge workflow. This
    81  	// is called at the end of the standard merge workflow. The calling root is the merged root, so it is valid to
    82  	// return it if no further merge work needs to be done. This is primarily used by Doltgres.
    83  	HandlePostMerge(ctx context.Context, ourRoot, theirRoot, ancRoot RootValue) (RootValue, error)
    84  	// HasTable returns whether the root has a table with the given case-sensitive name.
    85  	HasTable(ctx context.Context, tName string) (bool, error)
    86  	// IterTables calls the callback function cb on each table in this RootValue.
    87  	IterTables(ctx context.Context, cb func(name string, table *Table, sch schema.Schema) (stop bool, err error)) error
    88  	// NodeStore returns this root's NodeStore.
    89  	NodeStore() tree.NodeStore
    90  	// NomsValue returns this root's storage as a noms value.
    91  	NomsValue() types.Value
    92  	// PutForeignKeyCollection returns a new root with the given foreign key collection.
    93  	PutForeignKeyCollection(ctx context.Context, fkc *ForeignKeyCollection) (RootValue, error)
    94  	// PutTable inserts a table by name into the map of tables. If a table already exists with that name it will be replaced
    95  	PutTable(ctx context.Context, tName TableName, table *Table) (RootValue, error)
    96  	// RemoveTables removes the given case-sensitive tables from the root, and returns a new root.
    97  	RemoveTables(ctx context.Context, skipFKHandling bool, allowDroppingFKReferenced bool, tables ...string) (RootValue, error)
    98  	// RenameTable renames a table by changing its string key in the RootValue's table map. In order to preserve
    99  	// column tag information, use this method instead of a table drop + add.
   100  	RenameTable(ctx context.Context, oldName string, newName string) (RootValue, error)
   101  	// ResolveTableName resolves a case-insensitive name to the exact name as stored in Dolt. Returns false if no matching
   102  	// name was found.
   103  	ResolveTableName(ctx context.Context, tName string) (string, bool, error)
   104  	// SetCollation sets the given database collation and returns a new root.
   105  	SetCollation(ctx context.Context, collation schema.Collation) (RootValue, error)
   106  	// SetFeatureVersion sets the feature version and returns a new root.
   107  	SetFeatureVersion(v FeatureVersion) (RootValue, error)
   108  	// SetTableHash sets the table with the given case-sensitive name to the new hash, and returns a new root.
   109  	SetTableHash(ctx context.Context, tName string, h hash.Hash) (RootValue, error)
   110  	// VRW returns this root's ValueReadWriter.
   111  	VRW() types.ValueReadWriter
   112  }
   113  
   114  // rootValue is Dolt's implementation of RootValue.
   115  type rootValue struct {
   116  	vrw  types.ValueReadWriter
   117  	ns   tree.NodeStore
   118  	st   rootValueStorage
   119  	fkc  *ForeignKeyCollection // cache the first load
   120  	hash hash.Hash             // cache first load
   121  }
   122  
   123  var _ RootValue = (*rootValue)(nil)
   124  
   125  type tableEdit struct {
   126  	name TableName
   127  	ref  *types.Ref
   128  
   129  	// Used for rename.
   130  	old_name string
   131  }
   132  
   133  // NewRootValue returns a new RootValue. This is a variable as it's changed in Doltgres.
   134  var NewRootValue = func(ctx context.Context, vrw types.ValueReadWriter, ns tree.NodeStore, v types.Value) (RootValue, error) {
   135  	var storage rootValueStorage
   136  
   137  	if vrw.Format().UsesFlatbuffers() {
   138  		srv, err := serial.TryGetRootAsRootValue([]byte(v.(types.SerialMessage)), serial.MessagePrefixSz)
   139  		if err != nil {
   140  			return nil, err
   141  		}
   142  		storage = fbRvStorage{srv}
   143  	} else {
   144  		st, ok := v.(types.Struct)
   145  		if !ok {
   146  			return nil, errors.New("invalid value passed to newRootValue")
   147  		}
   148  
   149  		storage = nomsRvStorage{st}
   150  	}
   151  	ver, ok, err := storage.GetFeatureVersion()
   152  	if err != nil {
   153  		return nil, err
   154  	}
   155  	if ok {
   156  		if DoltFeatureVersion < ver {
   157  			return nil, ErrClientOutOfDate{
   158  				ClientVer: DoltFeatureVersion,
   159  				RepoVer:   ver,
   160  			}
   161  		}
   162  	}
   163  
   164  	return &rootValue{vrw, ns, storage, nil, hash.Hash{}}, nil
   165  }
   166  
   167  // EmptyRootValue returns an empty RootValue. This is a variable as it's changed in Doltgres.
   168  var EmptyRootValue = func(ctx context.Context, vrw types.ValueReadWriter, ns tree.NodeStore) (RootValue, error) {
   169  	if vrw.Format().UsesFlatbuffers() {
   170  		builder := flatbuffers.NewBuilder(80)
   171  
   172  		emptyam, err := prolly.NewEmptyAddressMap(ns)
   173  		if err != nil {
   174  			return nil, err
   175  		}
   176  		ambytes := []byte(tree.ValueFromNode(emptyam.Node()).(types.SerialMessage))
   177  		tablesoff := builder.CreateByteVector(ambytes)
   178  
   179  		var empty hash.Hash
   180  		fkoff := builder.CreateByteVector(empty[:])
   181  		serial.RootValueStart(builder)
   182  		serial.RootValueAddFeatureVersion(builder, int64(DoltFeatureVersion))
   183  		serial.RootValueAddCollation(builder, serial.Collationutf8mb4_0900_bin)
   184  		serial.RootValueAddTables(builder, tablesoff)
   185  		serial.RootValueAddForeignKeyAddr(builder, fkoff)
   186  		bs := serial.FinishMessage(builder, serial.RootValueEnd(builder), []byte(serial.RootValueFileID))
   187  		return NewRootValue(ctx, vrw, ns, types.SerialMessage(bs))
   188  	}
   189  
   190  	empty, err := types.NewMap(ctx, vrw)
   191  	if err != nil {
   192  		return nil, err
   193  	}
   194  
   195  	sd := types.StructData{
   196  		tablesKey:       empty,
   197  		superSchemasKey: empty,
   198  		foreignKeyKey:   empty,
   199  		featureVersKey:  types.Int(DoltFeatureVersion),
   200  	}
   201  
   202  	st, err := types.NewStruct(vrw.Format(), ddbRootStructName, sd)
   203  	if err != nil {
   204  		return nil, err
   205  	}
   206  
   207  	return NewRootValue(ctx, vrw, ns, st)
   208  }
   209  
   210  // LoadRootValueFromRootIshAddr takes the hash of the commit or the hash of a
   211  // working set and returns the corresponding RootValue.
   212  func LoadRootValueFromRootIshAddr(ctx context.Context, vrw types.ValueReadWriter, ns tree.NodeStore, h hash.Hash) (RootValue, error) {
   213  	val, err := datas.LoadRootNomsValueFromRootIshAddr(ctx, vrw, h)
   214  	if err != nil {
   215  		return nil, err
   216  	}
   217  	return decodeRootNomsValue(ctx, vrw, ns, val)
   218  }
   219  
   220  func decodeRootNomsValue(ctx context.Context, vrw types.ValueReadWriter, ns tree.NodeStore, val types.Value) (RootValue, error) {
   221  	if val == nil {
   222  		return nil, ErrNoRootValAtHash
   223  	}
   224  
   225  	if !isRootValue(vrw.Format(), val) {
   226  		return nil, ErrNoRootValAtHash
   227  	}
   228  
   229  	return NewRootValue(ctx, vrw, ns, val)
   230  }
   231  
   232  // isRootValue returns whether the value is a RootValue. This is a variable as it's changed in Doltgres.
   233  func isRootValue(nbf *types.NomsBinFormat, val types.Value) bool {
   234  	if nbf.UsesFlatbuffers() {
   235  		if sm, ok := val.(types.SerialMessage); ok {
   236  			fileID := serial.GetFileID(sm)
   237  			return fileID == serial.RootValueFileID || fileID == serial.DoltgresRootValueFileID
   238  		}
   239  	} else {
   240  		if st, ok := val.(types.Struct); ok {
   241  			return st.Name() == ddbRootStructName
   242  		}
   243  	}
   244  	return false
   245  }
   246  
   247  func (root *rootValue) ResolveRootValue(ctx context.Context) (RootValue, error) {
   248  	return root, nil
   249  }
   250  
   251  func (root *rootValue) VRW() types.ValueReadWriter {
   252  	return root.vrw
   253  }
   254  
   255  func (root *rootValue) NodeStore() tree.NodeStore {
   256  	return root.ns
   257  }
   258  
   259  // GetFeatureVersion returns the feature version of this root, if one is written
   260  func (root *rootValue) GetFeatureVersion(ctx context.Context) (ver FeatureVersion, ok bool, err error) {
   261  	return root.st.GetFeatureVersion()
   262  }
   263  
   264  func (root *rootValue) SetFeatureVersion(v FeatureVersion) (RootValue, error) {
   265  	newStorage, err := root.st.SetFeatureVersion(v)
   266  	if err != nil {
   267  		return nil, err
   268  	}
   269  	return root.withStorage(newStorage), nil
   270  }
   271  
   272  func (root *rootValue) GetCollation(ctx context.Context) (schema.Collation, error) {
   273  	return root.st.GetCollation(ctx)
   274  }
   275  
   276  func (root *rootValue) SetCollation(ctx context.Context, collation schema.Collation) (RootValue, error) {
   277  	newStorage, err := root.st.SetCollation(ctx, collation)
   278  	if err != nil {
   279  		return nil, err
   280  	}
   281  	return root.withStorage(newStorage), nil
   282  }
   283  
   284  func (root *rootValue) HandlePostMerge(ctx context.Context, ourRoot, theirRoot, ancRoot RootValue) (RootValue, error) {
   285  	return root, nil
   286  }
   287  
   288  func (root *rootValue) HasTable(ctx context.Context, tName string) (bool, error) {
   289  	tableMap, err := root.st.GetTablesMap(ctx, root.vrw, root.ns, DefaultSchemaName)
   290  	if err != nil {
   291  		return false, err
   292  	}
   293  	a, err := tableMap.Get(ctx, tName)
   294  	if err != nil {
   295  		return false, err
   296  	}
   297  	return !a.IsEmpty(), nil
   298  }
   299  
   300  func GenerateTagsForNewColColl(ctx context.Context, root RootValue, tableName string, cc *schema.ColCollection) (*schema.ColCollection, error) {
   301  	newColNames := make([]string, 0, cc.Size())
   302  	newColKinds := make([]types.NomsKind, 0, cc.Size())
   303  	_ = cc.Iter(func(tag uint64, col schema.Column) (stop bool, err error) {
   304  		newColNames = append(newColNames, col.Name)
   305  		newColKinds = append(newColKinds, col.Kind)
   306  		return false, nil
   307  	})
   308  
   309  	newTags, err := GenerateTagsForNewColumns(ctx, root, tableName, newColNames, newColKinds, nil)
   310  	if err != nil {
   311  		return nil, err
   312  	}
   313  
   314  	idx := 0
   315  	return schema.MapColCollection(cc, func(col schema.Column) schema.Column {
   316  		col.Tag = newTags[idx]
   317  		idx++
   318  		return col
   319  	}), nil
   320  }
   321  
   322  // GenerateTagsForNewColumns deterministically generates a slice of new tags that are unique within the history of this root. The names and NomsKinds of
   323  // the new columns are used to see the tag generator.
   324  func GenerateTagsForNewColumns(
   325  	ctx context.Context,
   326  	root RootValue,
   327  	tableName string,
   328  	newColNames []string,
   329  	newColKinds []types.NomsKind,
   330  	headRoot RootValue,
   331  ) ([]uint64, error) {
   332  	if len(newColNames) != len(newColKinds) {
   333  		return nil, fmt.Errorf("error generating tags, newColNames and newColKinds must be of equal length")
   334  	}
   335  
   336  	newTags := make([]*uint64, len(newColNames))
   337  
   338  	// Get existing columns from the current root, or the head root if the table doesn't exist in the current root. The
   339  	// latter case is to support reusing table tags in the case of drop / create in the same session, which is common
   340  	// during import.
   341  	existingCols, err := GetExistingColumns(ctx, root, headRoot, tableName, newColNames, newColKinds)
   342  	if err != nil {
   343  		return nil, err
   344  	}
   345  
   346  	// If we found any existing columns set them in the newTags list.
   347  	for _, col := range existingCols {
   348  		col := col
   349  		for i := range newColNames {
   350  			// Only re-use tags if the noms kind didn't change
   351  			// TODO: revisit this when new storage format is further along
   352  			if strings.ToLower(newColNames[i]) == strings.ToLower(col.Name) &&
   353  				newColKinds[i] == col.TypeInfo.NomsKind() {
   354  				newTags[i] = &col.Tag
   355  				break
   356  			}
   357  		}
   358  	}
   359  
   360  	var existingColKinds []types.NomsKind
   361  	for _, col := range existingCols {
   362  		existingColKinds = append(existingColKinds, col.Kind)
   363  	}
   364  
   365  	existingTags, err := GetAllTagsForRoots(ctx, headRoot, root)
   366  	if err != nil {
   367  		return nil, err
   368  	}
   369  
   370  	outputTags := make([]uint64, len(newTags))
   371  	for i := range newTags {
   372  		if newTags[i] != nil {
   373  			outputTags[i] = *newTags[i]
   374  			continue
   375  		}
   376  
   377  		outputTags[i] = schema.AutoGenerateTag(existingTags, tableName, existingColKinds, newColNames[i], newColKinds[i])
   378  		existingColKinds = append(existingColKinds, newColKinds[i])
   379  		existingTags.Add(outputTags[i], tableName)
   380  	}
   381  
   382  	return outputTags, nil
   383  }
   384  
   385  func GetExistingColumns(
   386  	ctx context.Context,
   387  	root, headRoot RootValue,
   388  	tableName string,
   389  	newColNames []string,
   390  	newColKinds []types.NomsKind,
   391  ) ([]schema.Column, error) {
   392  
   393  	var existingCols []schema.Column
   394  	tbl, found, err := root.GetTable(ctx, TableName{Name: tableName})
   395  	if err != nil {
   396  		return nil, err
   397  	}
   398  
   399  	if found {
   400  		sch, err := tbl.GetSchema(ctx)
   401  		if err != nil {
   402  			return nil, err
   403  		}
   404  		_ = sch.GetAllCols().Iter(func(tag uint64, col schema.Column) (stop bool, err error) {
   405  			existingCols = append(existingCols, col)
   406  			return false, nil
   407  		})
   408  	} else if headRoot != nil {
   409  		tbl, found, err := headRoot.GetTable(ctx, TableName{Name: tableName})
   410  		if err != nil {
   411  			return nil, err
   412  		}
   413  
   414  		if found {
   415  			sch, err := tbl.GetSchema(ctx)
   416  			if err != nil {
   417  				return nil, err
   418  			}
   419  
   420  			existingCols = schema.GetSharedCols(sch, newColNames, newColKinds)
   421  		}
   422  	}
   423  
   424  	return existingCols, nil
   425  }
   426  
   427  func GetAllSchemas(ctx context.Context, root RootValue) (map[string]schema.Schema, error) {
   428  	m := make(map[string]schema.Schema)
   429  	err := root.IterTables(ctx, func(name string, table *Table, sch schema.Schema) (stop bool, err error) {
   430  		m[name] = sch
   431  		return false, nil
   432  	})
   433  
   434  	if err != nil {
   435  		return nil, err
   436  	}
   437  
   438  	return m, nil
   439  }
   440  
   441  func (root *rootValue) GetTableHash(ctx context.Context, tName string) (hash.Hash, bool, error) {
   442  	// TODO: schema
   443  	tableMap, err := root.getTableMap(ctx, DefaultSchemaName)
   444  	if err != nil {
   445  		return hash.Hash{}, false, err
   446  	}
   447  
   448  	tVal, err := tableMap.Get(ctx, tName)
   449  	if err != nil {
   450  		return hash.Hash{}, false, err
   451  	}
   452  
   453  	return tVal, !tVal.IsEmpty(), nil
   454  }
   455  
   456  func (root *rootValue) SetTableHash(ctx context.Context, tName string, h hash.Hash) (RootValue, error) {
   457  	val, err := root.vrw.ReadValue(ctx, h)
   458  
   459  	if err != nil {
   460  		return nil, err
   461  	}
   462  
   463  	ref, err := types.NewRef(val, root.vrw.Format())
   464  
   465  	if err != nil {
   466  		return nil, err
   467  	}
   468  
   469  	// TODO: schema
   470  	return root.putTable(ctx, TableName{Name: tName}, ref)
   471  }
   472  
   473  // ResolveTableName resolves a case-insensitive name to the exact name as stored in Dolt. Returns false if no matching
   474  // name was found.
   475  func (root *rootValue) ResolveTableName(ctx context.Context, tName string) (string, bool, error) {
   476  	// TODO: schema name
   477  	tableMap, err := root.getTableMap(ctx, DefaultSchemaName)
   478  	if err != nil {
   479  		return "", false, err
   480  	}
   481  
   482  	a, err := tableMap.Get(ctx, tName)
   483  	if err != nil {
   484  		return "", false, err
   485  	}
   486  	if !a.IsEmpty() {
   487  		return tName, true, nil
   488  	}
   489  
   490  	found := false
   491  	lwrName := strings.ToLower(tName)
   492  	err = tmIterAll(ctx, tableMap, func(name string, addr hash.Hash) {
   493  		if found == false && lwrName == strings.ToLower(name) {
   494  			tName = name
   495  			found = true
   496  		}
   497  	})
   498  	if err != nil {
   499  		return "", false, nil
   500  	}
   501  	return tName, found, nil
   502  }
   503  
   504  // GetTable will retrieve a table by its case-sensitive name.
   505  func (root *rootValue) GetTable(ctx context.Context, tName TableName) (*Table, bool, error) {
   506  	tableMap, err := root.getTableMap(ctx, tName.Schema)
   507  	if err != nil {
   508  		return nil, false, err
   509  	}
   510  
   511  	addr, err := tableMap.Get(ctx, tName.Name)
   512  	if err != nil {
   513  		return nil, false, err
   514  	}
   515  
   516  	return GetTable(ctx, root, addr)
   517  }
   518  
   519  func GetTable(ctx context.Context, root RootValue, addr hash.Hash) (*Table, bool, error) {
   520  	if addr.IsEmpty() {
   521  		return nil, false, nil
   522  	}
   523  	table, err := durable.TableFromAddr(ctx, root.VRW(), root.NodeStore(), addr)
   524  	if err != nil {
   525  		return nil, false, err
   526  	}
   527  	return &Table{table: table}, true, err
   528  }
   529  
   530  // GetTableInsensitive will retrieve a table by its case-insensitive name.
   531  func GetTableInsensitive(ctx context.Context, root RootValue, tName string) (*Table, string, bool, error) {
   532  	resolvedName, ok, err := root.ResolveTableName(ctx, tName)
   533  	if err != nil {
   534  		return nil, "", false, err
   535  	}
   536  	if !ok {
   537  		return nil, "", false, nil
   538  	}
   539  	tbl, ok, err := root.GetTable(ctx, TableName{Name: resolvedName})
   540  	if err != nil {
   541  		return nil, "", false, err
   542  	}
   543  	return tbl, resolvedName, ok, nil
   544  }
   545  
   546  // GetTableByColTag looks for the table containing the given column tag.
   547  func GetTableByColTag(ctx context.Context, root RootValue, tag uint64) (tbl *Table, name string, found bool, err error) {
   548  	err = root.IterTables(ctx, func(tn string, t *Table, s schema.Schema) (bool, error) {
   549  		_, found = s.GetAllCols().GetByTag(tag)
   550  		if found {
   551  			name, tbl = tn, t
   552  		}
   553  
   554  		return found, nil
   555  	})
   556  
   557  	if err != nil {
   558  		return nil, "", false, err
   559  	}
   560  
   561  	return tbl, name, found, nil
   562  }
   563  
   564  // GetTableNames retrieves the lists of all tables for a RootValue
   565  func (root *rootValue) GetTableNames(ctx context.Context, schemaName string) ([]string, error) {
   566  	tableMap, err := root.getTableMap(ctx, schemaName)
   567  	if err != nil {
   568  		return nil, err
   569  	}
   570  
   571  	var names []string
   572  	err = tmIterAll(ctx, tableMap, func(name string, _ hash.Hash) {
   573  		names = append(names, name)
   574  	})
   575  	if err != nil {
   576  		return nil, err
   577  	}
   578  
   579  	return names, nil
   580  }
   581  
   582  func (root *rootValue) getTableMap(ctx context.Context, schemaName string) (tableMap, error) {
   583  	if schemaName == "" {
   584  		schemaName = DefaultSchemaName
   585  	}
   586  	return root.st.GetTablesMap(ctx, root.vrw, root.ns, schemaName)
   587  }
   588  
   589  func TablesWithDataConflicts(ctx context.Context, root RootValue) ([]string, error) {
   590  	names, err := root.GetTableNames(ctx, DefaultSchemaName)
   591  	if err != nil {
   592  		return nil, err
   593  	}
   594  
   595  	conflicted := make([]string, 0, len(names))
   596  	for _, name := range names {
   597  		tbl, _, err := root.GetTable(ctx, TableName{Name: name})
   598  		if err != nil {
   599  			return nil, err
   600  		}
   601  
   602  		ok, err := tbl.HasConflicts(ctx)
   603  		if err != nil {
   604  			return nil, err
   605  		}
   606  		if ok {
   607  			conflicted = append(conflicted, name)
   608  		}
   609  	}
   610  
   611  	return conflicted, nil
   612  }
   613  
   614  // TablesWithConstraintViolations returns all tables that have constraint violations.
   615  func TablesWithConstraintViolations(ctx context.Context, root RootValue) ([]string, error) {
   616  	// TODO: schema name
   617  	names, err := root.GetTableNames(ctx, DefaultSchemaName)
   618  	if err != nil {
   619  		return nil, err
   620  	}
   621  
   622  	violating := make([]string, 0, len(names))
   623  	for _, name := range names {
   624  		tbl, _, err := root.GetTable(ctx, TableName{Name: name})
   625  		if err != nil {
   626  			return nil, err
   627  		}
   628  
   629  		n, err := tbl.NumConstraintViolations(ctx)
   630  		if err != nil {
   631  			return nil, err
   632  		}
   633  
   634  		if n > 0 {
   635  			violating = append(violating, name)
   636  		}
   637  	}
   638  
   639  	return violating, nil
   640  }
   641  
   642  func HasConflicts(ctx context.Context, root RootValue) (bool, error) {
   643  	cnfTbls, err := TablesWithDataConflicts(ctx, root)
   644  
   645  	if err != nil {
   646  		return false, err
   647  	}
   648  
   649  	return len(cnfTbls) > 0, nil
   650  }
   651  
   652  // HasConstraintViolations returns whether any tables have constraint violations.
   653  func HasConstraintViolations(ctx context.Context, root RootValue) (bool, error) {
   654  	tbls, err := TablesWithConstraintViolations(ctx, root)
   655  	if err != nil {
   656  		return false, err
   657  	}
   658  	return len(tbls) > 0, nil
   659  }
   660  
   661  // IterTables calls the callback function cb on each table in this RootValue.
   662  func (root *rootValue) IterTables(ctx context.Context, cb func(name string, table *Table, sch schema.Schema) (stop bool, err error)) error {
   663  	// TODO: schema name
   664  	tm, err := root.getTableMap(ctx, DefaultSchemaName)
   665  	if err != nil {
   666  		return err
   667  	}
   668  
   669  	return tm.Iter(ctx, func(name string, addr hash.Hash) (bool, error) {
   670  		nt, err := durable.TableFromAddr(ctx, root.VRW(), root.ns, addr)
   671  		if err != nil {
   672  			return true, err
   673  		}
   674  		tbl := &Table{table: nt}
   675  
   676  		sch, err := tbl.GetSchema(ctx)
   677  		if err != nil {
   678  			return true, err
   679  		}
   680  
   681  		return cb(name, tbl, sch)
   682  	})
   683  }
   684  
   685  func (root *rootValue) withStorage(st rootValueStorage) *rootValue {
   686  	return &rootValue{root.vrw, root.ns, st, nil, hash.Hash{}}
   687  }
   688  
   689  func (root *rootValue) NomsValue() types.Value {
   690  	return root.st.nomsValue()
   691  }
   692  
   693  // TableName identifies a table in a database uniquely.
   694  type TableName struct {
   695  	// Name is the name of the table
   696  	Name string
   697  	// Schema is the name of the schema that the table belongs to, empty in the case of the default schema.
   698  	Schema string
   699  }
   700  
   701  // DefaultSchemaName is the name of the default schema. Tables with this schema name will be stored in the
   702  // primary (unnamed) table store in a root.
   703  var DefaultSchemaName = ""
   704  
   705  // PutTable inserts a table by name into the map of tables. If a table already exists with that name it will be replaced
   706  func (root *rootValue) PutTable(ctx context.Context, tName TableName, table *Table) (RootValue, error) {
   707  	err := ValidateTagUniqueness(ctx, root, tName.Name, table)
   708  	if err != nil {
   709  		return nil, err
   710  	}
   711  
   712  	tableRef, err := RefFromNomsTable(ctx, table)
   713  	if err != nil {
   714  		return nil, err
   715  	}
   716  
   717  	return root.putTable(ctx, tName, tableRef)
   718  }
   719  
   720  func RefFromNomsTable(ctx context.Context, table *Table) (types.Ref, error) {
   721  	return durable.RefFromNomsTable(ctx, table.table)
   722  }
   723  
   724  func (root *rootValue) putTable(ctx context.Context, tName TableName, ref types.Ref) (RootValue, error) {
   725  	if !IsValidTableName(tName.Name) {
   726  		panic("Don't attempt to put a table with a name that fails the IsValidTableName check")
   727  	}
   728  
   729  	newStorage, err := root.st.EditTablesMap(ctx, root.VRW(), root.NodeStore(), []tableEdit{{name: tName, ref: &ref}})
   730  	if err != nil {
   731  		return nil, err
   732  	}
   733  
   734  	return root.withStorage(newStorage), nil
   735  }
   736  
   737  // CreateEmptyTable creates an empty table in this root with the name and schema given, returning the new root value.
   738  func CreateEmptyTable(ctx context.Context, root RootValue, tName TableName, sch schema.Schema) (RootValue, error) {
   739  	ns := root.NodeStore()
   740  	vrw := root.VRW()
   741  	empty, err := durable.NewEmptyIndex(ctx, vrw, ns, sch)
   742  	if err != nil {
   743  		return nil, err
   744  	}
   745  
   746  	indexes, err := durable.NewIndexSet(ctx, vrw, ns)
   747  	if err != nil {
   748  		return nil, err
   749  	}
   750  	err = sch.Indexes().Iter(func(index schema.Index) (stop bool, err error) {
   751  		// create an empty map for every index
   752  		indexes, err = indexes.PutIndex(ctx, index.Name(), empty)
   753  		return
   754  	})
   755  	if err != nil {
   756  		return nil, err
   757  	}
   758  
   759  	tbl, err := NewTable(ctx, vrw, ns, sch, empty, indexes, nil)
   760  	if err != nil {
   761  		return nil, err
   762  	}
   763  
   764  	newRoot, err := root.PutTable(ctx, tName, tbl)
   765  	if err != nil {
   766  		return nil, err
   767  	}
   768  
   769  	return newRoot, nil
   770  }
   771  
   772  func (root *rootValue) GetDatabaseSchemas(ctx context.Context) ([]schema.DatabaseSchema, error) {
   773  	existingSchemas, err := root.st.GetSchemas(ctx)
   774  	if err != nil {
   775  		return nil, err
   776  	}
   777  
   778  	return existingSchemas, nil
   779  }
   780  
   781  func (root *rootValue) CreateDatabaseSchema(ctx context.Context, dbSchema schema.DatabaseSchema) (RootValue, error) {
   782  	existingSchemas, err := root.st.GetSchemas(ctx)
   783  	if err != nil {
   784  		return nil, err
   785  	}
   786  
   787  	for _, s := range existingSchemas {
   788  		if strings.EqualFold(s.Name, dbSchema.Name) {
   789  			return nil, fmt.Errorf("A schema with the name %s already exists", dbSchema.Name)
   790  		}
   791  	}
   792  
   793  	existingSchemas = append(existingSchemas, dbSchema)
   794  	sort.Slice(existingSchemas, func(i, j int) bool {
   795  		return existingSchemas[i].Name < existingSchemas[j].Name
   796  	})
   797  
   798  	r, err := root.st.SetSchemas(ctx, existingSchemas)
   799  	if err != nil {
   800  		return nil, err
   801  	}
   802  
   803  	return root.withStorage(r), nil
   804  }
   805  
   806  // HashOf gets the hash of the root value
   807  func (root *rootValue) HashOf() (hash.Hash, error) {
   808  	if root.hash.IsEmpty() {
   809  		var err error
   810  		root.hash, err = root.st.nomsValue().Hash(root.vrw.Format())
   811  		if err != nil {
   812  			return hash.Hash{}, nil
   813  		}
   814  	}
   815  	return root.hash, nil
   816  }
   817  
   818  // RenameTable renames a table by changing its string key in the RootValue's table map. In order to preserve
   819  // column tag information, use this method instead of a table drop + add.
   820  func (root *rootValue) RenameTable(ctx context.Context, oldName, newName string) (RootValue, error) {
   821  	newStorage, err := root.st.EditTablesMap(ctx, root.vrw, root.ns, []tableEdit{{old_name: oldName, name: TableName{Name: newName}}})
   822  	if err != nil {
   823  		return nil, err
   824  	}
   825  	return root.withStorage(newStorage), nil
   826  }
   827  
   828  func (root *rootValue) RemoveTables(ctx context.Context, skipFKHandling bool, allowDroppingFKReferenced bool, tables ...string) (RootValue, error) {
   829  	// TODO: schema name
   830  	tableMap, err := root.getTableMap(ctx, DefaultSchemaName)
   831  	if err != nil {
   832  		return nil, err
   833  	}
   834  
   835  	edits := make([]tableEdit, len(tables))
   836  	for i, name := range tables {
   837  		a, err := tableMap.Get(ctx, name)
   838  		if err != nil {
   839  			return nil, err
   840  		}
   841  		if a.IsEmpty() {
   842  			return nil, fmt.Errorf("%w: '%s'", ErrTableNotFound, name)
   843  		}
   844  		edits[i].name = TableName{
   845  			Name: name,
   846  		}
   847  	}
   848  
   849  	newStorage, err := root.st.EditTablesMap(ctx, root.vrw, root.ns, edits)
   850  	if err != nil {
   851  		return nil, err
   852  	}
   853  
   854  	newRoot := root.withStorage(newStorage)
   855  	if skipFKHandling {
   856  		return newRoot, nil
   857  	}
   858  
   859  	fkc, err := newRoot.GetForeignKeyCollection(ctx)
   860  	if err != nil {
   861  		return nil, err
   862  	}
   863  
   864  	if allowDroppingFKReferenced {
   865  		err = fkc.RemoveAndUnresolveTables(ctx, root, tables...)
   866  	} else {
   867  		err = fkc.RemoveTables(ctx, tables...)
   868  	}
   869  
   870  	if err != nil {
   871  		return nil, err
   872  	}
   873  
   874  	return newRoot.PutForeignKeyCollection(ctx, fkc)
   875  }
   876  
   877  // GetForeignKeyCollection returns the ForeignKeyCollection for this root. As collections are meant to be modified
   878  // in-place, each returned collection may freely be altered without affecting future returned collections from this root.
   879  func (root *rootValue) GetForeignKeyCollection(ctx context.Context) (*ForeignKeyCollection, error) {
   880  	if root.fkc == nil {
   881  		fkMap, ok, err := root.st.GetForeignKeys(ctx, root.vrw)
   882  		if err != nil {
   883  			return nil, err
   884  		}
   885  		if !ok {
   886  			fkc := &ForeignKeyCollection{
   887  				foreignKeys: map[string]ForeignKey{},
   888  			}
   889  			return fkc, nil
   890  		}
   891  
   892  		root.fkc, err = DeserializeForeignKeys(ctx, root.vrw.Format(), fkMap)
   893  		if err != nil {
   894  			return nil, err
   895  		}
   896  	}
   897  	return root.fkc.Copy(), nil
   898  }
   899  
   900  // PutForeignKeyCollection returns a new root with the given foreign key collection.
   901  func (root *rootValue) PutForeignKeyCollection(ctx context.Context, fkc *ForeignKeyCollection) (RootValue, error) {
   902  	value, err := SerializeForeignKeys(ctx, root.vrw, fkc)
   903  	if err != nil {
   904  		return nil, err
   905  	}
   906  	newStorage, err := root.st.SetForeignKeyMap(ctx, root.vrw, value)
   907  	if err != nil {
   908  		return nil, err
   909  	}
   910  	return root.withStorage(newStorage), nil
   911  }
   912  
   913  // ValidateForeignKeysOnSchemas ensures that all foreign keys' tables are present, removing any foreign keys where the declared
   914  // table is missing, and returning an error if a key is in an invalid state or a referenced table is missing. Does not
   915  // check any tables' row data.
   916  func ValidateForeignKeysOnSchemas(ctx context.Context, root RootValue) (RootValue, error) {
   917  	fkCollection, err := root.GetForeignKeyCollection(ctx)
   918  	if err != nil {
   919  		return nil, err
   920  	}
   921  
   922  	// TODO: schema name
   923  	allTablesSlice, err := root.GetTableNames(ctx, DefaultSchemaName)
   924  	if err != nil {
   925  		return nil, err
   926  	}
   927  	allTablesSet := make(map[string]schema.Schema)
   928  	for _, tableName := range allTablesSlice {
   929  		tbl, ok, err := root.GetTable(ctx, TableName{Name: tableName})
   930  		if err != nil {
   931  			return nil, err
   932  		}
   933  		if !ok {
   934  			return nil, fmt.Errorf("found table `%s` in staging but could not load for foreign key check", tableName)
   935  		}
   936  		tblSch, err := tbl.GetSchema(ctx)
   937  		if err != nil {
   938  			return nil, err
   939  		}
   940  		allTablesSet[tableName] = tblSch
   941  	}
   942  
   943  	// some of these checks are sanity checks and should never happen
   944  	allForeignKeys := fkCollection.AllKeys()
   945  	for _, foreignKey := range allForeignKeys {
   946  		tblSch, existsInRoot := allTablesSet[foreignKey.TableName]
   947  		if existsInRoot {
   948  			if err := foreignKey.ValidateTableSchema(tblSch); err != nil {
   949  				return nil, err
   950  			}
   951  			parentSch, existsInRoot := allTablesSet[foreignKey.ReferencedTableName]
   952  			if !existsInRoot {
   953  				return nil, fmt.Errorf("foreign key `%s` requires the referenced table `%s`", foreignKey.Name, foreignKey.ReferencedTableName)
   954  			}
   955  			if err := foreignKey.ValidateReferencedTableSchema(parentSch); err != nil {
   956  				return nil, err
   957  			}
   958  		} else {
   959  			if !fkCollection.RemoveKeyByName(foreignKey.Name) {
   960  				return nil, fmt.Errorf("`%s` does not exist as a foreign key", foreignKey.Name)
   961  			}
   962  		}
   963  	}
   964  
   965  	return root.PutForeignKeyCollection(ctx, fkCollection)
   966  }
   967  
   968  // GetAllTagsForRoots gets all tags for |roots|.
   969  func GetAllTagsForRoots(ctx context.Context, roots ...RootValue) (tags schema.TagMapping, err error) {
   970  	tags = make(schema.TagMapping)
   971  	for _, root := range roots {
   972  		if root == nil {
   973  			continue
   974  		}
   975  		err = root.IterTables(ctx, func(tblName string, _ *Table, sch schema.Schema) (stop bool, err error) {
   976  			for _, t := range sch.GetAllCols().Tags {
   977  				tags.Add(t, tblName)
   978  			}
   979  			return
   980  		})
   981  		if err != nil {
   982  			break
   983  		}
   984  	}
   985  	return
   986  }
   987  
   988  // UnionTableNames returns an array of all table names in all roots passed as params.
   989  // The table names are in order of the RootValues passed in.
   990  func UnionTableNames(ctx context.Context, roots ...RootValue) ([]string, error) {
   991  	seenTblNamesMap := make(map[string]bool)
   992  	tblNames := []string{}
   993  	for _, root := range roots {
   994  		// TODO: schema name
   995  		rootTblNames, err := root.GetTableNames(ctx, DefaultSchemaName)
   996  		if err != nil {
   997  			return nil, err
   998  		}
   999  		for _, tn := range rootTblNames {
  1000  			if _, ok := seenTblNamesMap[tn]; !ok {
  1001  				seenTblNamesMap[tn] = true
  1002  				tblNames = append(tblNames, tn)
  1003  			}
  1004  		}
  1005  	}
  1006  
  1007  	return tblNames, nil
  1008  }
  1009  
  1010  // FilterIgnoredTables takes a slice of table names and divides it into new slices based on whether the table is ignored, not ignored, or matches conflicting ignore patterns.
  1011  func FilterIgnoredTables(ctx context.Context, tables []string, roots Roots) (ignoredTables IgnoredTables, err error) {
  1012  	ignorePatterns, err := GetIgnoredTablePatterns(ctx, roots)
  1013  	if err != nil {
  1014  		return ignoredTables, err
  1015  	}
  1016  	for _, tableName := range tables {
  1017  		ignored, err := ignorePatterns.IsTableNameIgnored(tableName)
  1018  		if conflict := AsDoltIgnoreInConflict(err); conflict != nil {
  1019  			ignoredTables.Conflicts = append(ignoredTables.Conflicts, *conflict)
  1020  		} else if err != nil {
  1021  			return ignoredTables, err
  1022  		} else if ignored == DontIgnore {
  1023  			ignoredTables.DontIgnore = append(ignoredTables.DontIgnore, tableName)
  1024  		} else if ignored == Ignore {
  1025  			ignoredTables.Ignore = append(ignoredTables.Ignore, tableName)
  1026  		} else {
  1027  			panic("IsTableNameIgnored returned ErrorOccurred but no error!")
  1028  		}
  1029  	}
  1030  
  1031  	return ignoredTables, nil
  1032  }
  1033  
  1034  // ValidateTagUniqueness checks for tag collisions between the given table and the set of tables in then given root.
  1035  func ValidateTagUniqueness(ctx context.Context, root RootValue, tableName string, table *Table) error {
  1036  	prev, ok, err := root.GetTable(ctx, TableName{Name: tableName})
  1037  	if err != nil {
  1038  		return err
  1039  	}
  1040  	if ok {
  1041  		prevHash, err := prev.GetSchemaHash(ctx)
  1042  		if err != nil {
  1043  			return err
  1044  		}
  1045  
  1046  		newHash, err := table.GetSchemaHash(ctx)
  1047  		if err != nil {
  1048  			return err
  1049  		}
  1050  
  1051  		// short-circuit if schema unchanged
  1052  		if prevHash == newHash {
  1053  			return nil
  1054  		}
  1055  	}
  1056  
  1057  	sch, err := table.GetSchema(ctx)
  1058  	if err != nil {
  1059  		return err
  1060  	}
  1061  
  1062  	existing, err := GetAllTagsForRoots(ctx, root)
  1063  	if err != nil {
  1064  		return err
  1065  	}
  1066  
  1067  	err = sch.GetAllCols().Iter(func(tag uint64, col schema.Column) (stop bool, err error) {
  1068  		oldTableName, ok := existing.Get(tag)
  1069  		if ok && oldTableName != tableName {
  1070  			return true, schema.ErrTagPrevUsed(tag, col.Name, tableName, oldTableName)
  1071  		}
  1072  		return false, nil
  1073  	})
  1074  	if err != nil {
  1075  		return err
  1076  	}
  1077  	return nil
  1078  }
  1079  
  1080  // DebugString returns a human readable string with the contents of this root. If |transitive| is true, row data from
  1081  // all tables is also included. This method is very expensive for large root values, so |transitive| should only be used
  1082  // when debugging tests.
  1083  func (root *rootValue) DebugString(ctx context.Context, transitive bool) string {
  1084  	var buf bytes.Buffer
  1085  	buf.WriteString(root.st.DebugString(ctx))
  1086  
  1087  	if transitive {
  1088  		buf.WriteString("\nTables:")
  1089  		root.IterTables(ctx, func(name string, table *Table, sch schema.Schema) (stop bool, err error) {
  1090  			buf.WriteString("\nTable ")
  1091  			buf.WriteString(name)
  1092  			buf.WriteString(":\n")
  1093  
  1094  			buf.WriteString(table.DebugString(ctx, root.ns))
  1095  
  1096  			return false, nil
  1097  		})
  1098  	}
  1099  
  1100  	return buf.String()
  1101  }
  1102  
  1103  // MapTableHashes returns a map of each table name and hash.
  1104  func MapTableHashes(ctx context.Context, root RootValue) (map[string]hash.Hash, error) {
  1105  	// TODO: schema name
  1106  	names, err := root.GetTableNames(ctx, DefaultSchemaName)
  1107  	if err != nil {
  1108  		return nil, err
  1109  	}
  1110  	nameToHash := make(map[string]hash.Hash)
  1111  	for _, name := range names {
  1112  		h, ok, err := root.GetTableHash(ctx, name)
  1113  		if err != nil {
  1114  			return nil, err
  1115  		} else if !ok {
  1116  			return nil, fmt.Errorf("root found a table with name '%s' but no hash", name)
  1117  		} else {
  1118  			nameToHash[name] = h
  1119  		}
  1120  	}
  1121  	return nameToHash, nil
  1122  }
  1123  
  1124  type DataCacheKey struct {
  1125  	hash.Hash
  1126  }
  1127  
  1128  func NewDataCacheKey(rv RootValue) (DataCacheKey, error) {
  1129  	hash, err := rv.HashOf()
  1130  	if err != nil {
  1131  		return DataCacheKey{}, err
  1132  	}
  1133  
  1134  	return DataCacheKey{hash}, nil
  1135  }