github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/catalog/catalogkv/catalogkv.go (about)

     1  // Copyright 2020 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  // Package catalogkv provides functions for interacting with the system catalog
    12  // tables using the kv client.
    13  package catalogkv
    14  
    15  import (
    16  	"context"
    17  	"fmt"
    18  
    19  	"github.com/cockroachdb/cockroach/pkg/keys"
    20  	"github.com/cockroachdb/cockroach/pkg/kv"
    21  	"github.com/cockroachdb/cockroach/pkg/settings/cluster"
    22  	"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode"
    23  	"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror"
    24  	"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
    25  	"github.com/cockroachdb/cockroach/pkg/sql/sqlbase"
    26  	"github.com/cockroachdb/cockroach/pkg/util/log"
    27  	"github.com/cockroachdb/errors"
    28  )
    29  
    30  // GenerateUniqueDescID returns the next available Descriptor ID and increments
    31  // the counter. The incrementing is non-transactional, and the counter could be
    32  // incremented multiple times because of retries.
    33  func GenerateUniqueDescID(ctx context.Context, db *kv.DB, codec keys.SQLCodec) (sqlbase.ID, error) {
    34  	// Increment unique descriptor counter.
    35  	newVal, err := kv.IncrementValRetryable(ctx, db, codec.DescIDSequenceKey(), 1)
    36  	if err != nil {
    37  		return sqlbase.InvalidID, err
    38  	}
    39  	return sqlbase.ID(newVal - 1), nil
    40  }
    41  
    42  // GetDescriptorID looks up the ID for plainKey.
    43  // InvalidID is returned if the name cannot be resolved.
    44  func GetDescriptorID(
    45  	ctx context.Context, txn *kv.Txn, codec keys.SQLCodec, plainKey sqlbase.DescriptorKey,
    46  ) (sqlbase.ID, error) {
    47  	key := plainKey.Key(codec)
    48  	log.Eventf(ctx, "looking up descriptor ID for name key %q", key)
    49  	gr, err := txn.Get(ctx, key)
    50  	if err != nil {
    51  		return sqlbase.InvalidID, err
    52  	}
    53  	if !gr.Exists() {
    54  		return sqlbase.InvalidID, nil
    55  	}
    56  	return sqlbase.ID(gr.ValueInt()), nil
    57  }
    58  
    59  // ResolveSchemaID resolves a schema's ID based on db and name.
    60  func ResolveSchemaID(
    61  	ctx context.Context, txn *kv.Txn, codec keys.SQLCodec, dbID sqlbase.ID, scName string,
    62  ) (bool, sqlbase.ID, error) {
    63  	// Try to use the system name resolution bypass. Avoids a hotspot by explicitly
    64  	// checking for public schema.
    65  	if scName == tree.PublicSchema {
    66  		return true, keys.PublicSchemaID, nil
    67  	}
    68  
    69  	sKey := sqlbase.NewSchemaKey(dbID, scName)
    70  	schemaID, err := GetDescriptorID(ctx, txn, codec, sKey)
    71  	if err != nil || schemaID == sqlbase.InvalidID {
    72  		return false, sqlbase.InvalidID, err
    73  	}
    74  
    75  	return true, schemaID, nil
    76  }
    77  
    78  // LookupDescriptorByID looks up the descriptor for `id` and returns it.
    79  // It can be a table or database descriptor.
    80  // Returns the descriptor (if found), a bool representing whether the
    81  // descriptor was found and an error if any.
    82  //
    83  // TODO(ajwerner): Understand the difference between this and GetDescriptorByID.
    84  func LookupDescriptorByID(
    85  	ctx context.Context, txn *kv.Txn, codec keys.SQLCodec, id sqlbase.ID,
    86  ) (sqlbase.DescriptorProto, bool, error) {
    87  	var desc sqlbase.DescriptorProto
    88  	for _, lookupFn := range []func() (sqlbase.DescriptorProto, error){
    89  		func() (sqlbase.DescriptorProto, error) {
    90  			return sqlbase.GetTableDescFromID(ctx, txn, codec, id)
    91  		},
    92  		func() (sqlbase.DescriptorProto, error) {
    93  			return sqlbase.GetDatabaseDescFromID(ctx, txn, codec, id)
    94  		},
    95  	} {
    96  		var err error
    97  		desc, err = lookupFn()
    98  		if err != nil {
    99  			if errors.Is(err, sqlbase.ErrDescriptorNotFound) {
   100  				continue
   101  			}
   102  			return nil, false, err
   103  		}
   104  		return desc, true, nil
   105  	}
   106  	return nil, false, nil
   107  }
   108  
   109  // GetDescriptorByID looks up the descriptor for `id`, validates it.
   110  //
   111  // In most cases you'll want to use wrappers: `GetDatabaseDescByID` or
   112  // `getTableDescByID`.
   113  func GetDescriptorByID(
   114  	ctx context.Context, txn *kv.Txn, codec keys.SQLCodec, id sqlbase.ID,
   115  ) (sqlbase.DescriptorProto, error) {
   116  	log.Eventf(ctx, "fetching descriptor with ID %d", id)
   117  	descKey := sqlbase.MakeDescMetadataKey(codec, id)
   118  	desc := &sqlbase.Descriptor{}
   119  	ts, err := txn.GetProtoTs(ctx, descKey, desc)
   120  	if err != nil {
   121  		return nil, err
   122  	}
   123  	table, database, typ := desc.Table(ts), desc.GetDatabase(), desc.GetType()
   124  	switch {
   125  	case table != nil:
   126  		if err := table.MaybeFillInDescriptor(ctx, txn, codec); err != nil {
   127  			return nil, err
   128  		}
   129  		if err := table.Validate(ctx, txn, codec); err != nil {
   130  			return nil, err
   131  		}
   132  		return table, nil
   133  	case database != nil:
   134  		if err := database.Validate(); err != nil {
   135  			return nil, err
   136  		}
   137  		return database, nil
   138  	case typ != nil:
   139  		return typ, nil
   140  	default:
   141  		return nil, errors.AssertionFailedf("unknown proto: %s", desc.String())
   142  	}
   143  }
   144  
   145  // CountUserDescriptors returns the number of descriptors present that were
   146  // created by the user (i.e. not present when the cluster started).
   147  func CountUserDescriptors(ctx context.Context, txn *kv.Txn, codec keys.SQLCodec) (int, error) {
   148  	allDescs, err := GetAllDescriptors(ctx, txn, codec)
   149  	if err != nil {
   150  		return 0, err
   151  	}
   152  
   153  	count := 0
   154  	for _, desc := range allDescs {
   155  		if !sqlbase.IsDefaultCreatedDescriptor(desc.GetID()) {
   156  			count++
   157  		}
   158  	}
   159  
   160  	return count, nil
   161  }
   162  
   163  // GetAllDescriptors looks up and returns all available descriptors.
   164  func GetAllDescriptors(
   165  	ctx context.Context, txn *kv.Txn, codec keys.SQLCodec,
   166  ) ([]sqlbase.DescriptorProto, error) {
   167  	log.Eventf(ctx, "fetching all descriptors")
   168  	descsKey := sqlbase.MakeAllDescsMetadataKey(codec)
   169  	kvs, err := txn.Scan(ctx, descsKey, descsKey.PrefixEnd(), 0)
   170  	if err != nil {
   171  		return nil, err
   172  	}
   173  
   174  	descs := make([]sqlbase.DescriptorProto, 0, len(kvs))
   175  	for _, kv := range kvs {
   176  		desc := &sqlbase.Descriptor{}
   177  		if err := kv.ValueProto(desc); err != nil {
   178  			return nil, err
   179  		}
   180  		switch t := desc.Union.(type) {
   181  		case *sqlbase.Descriptor_Table:
   182  			table := desc.Table(kv.Value.Timestamp)
   183  			if err := table.MaybeFillInDescriptor(ctx, txn, codec); err != nil {
   184  				return nil, err
   185  			}
   186  			descs = append(descs, table)
   187  		case *sqlbase.Descriptor_Database:
   188  			descs = append(descs, desc.GetDatabase())
   189  		case *sqlbase.Descriptor_Type:
   190  			descs = append(descs, desc.GetType())
   191  		default:
   192  			return nil, errors.AssertionFailedf("Descriptor.Union has unexpected type %T", t)
   193  		}
   194  	}
   195  	return descs, nil
   196  }
   197  
   198  // GetAllDatabaseDescriptorIDs looks up and returns all available database
   199  // descriptor IDs.
   200  func GetAllDatabaseDescriptorIDs(
   201  	ctx context.Context, txn *kv.Txn, codec keys.SQLCodec,
   202  ) ([]sqlbase.ID, error) {
   203  	log.Eventf(ctx, "fetching all database descriptor IDs")
   204  	nameKey := sqlbase.NewDatabaseKey("" /* name */).Key(codec)
   205  	kvs, err := txn.Scan(ctx, nameKey, nameKey.PrefixEnd(), 0 /*maxRows */)
   206  	if err != nil {
   207  		return nil, err
   208  	}
   209  	// See the comment in physical_schema_accessors.go,
   210  	// func (a UncachedPhysicalAccessor) GetObjectNames. Same concept
   211  	// applies here.
   212  	// TODO(solon): This complexity can be removed in 20.2.
   213  	nameKey = sqlbase.NewDeprecatedDatabaseKey("" /* name */).Key(codec)
   214  	dkvs, err := txn.Scan(ctx, nameKey, nameKey.PrefixEnd(), 0 /* maxRows */)
   215  	if err != nil {
   216  		return nil, err
   217  	}
   218  	kvs = append(kvs, dkvs...)
   219  
   220  	descIDs := make([]sqlbase.ID, 0, len(kvs))
   221  	alreadySeen := make(map[sqlbase.ID]bool)
   222  	for _, kv := range kvs {
   223  		ID := sqlbase.ID(kv.ValueInt())
   224  		if alreadySeen[ID] {
   225  			continue
   226  		}
   227  		alreadySeen[ID] = true
   228  		descIDs = append(descIDs, ID)
   229  	}
   230  	return descIDs, nil
   231  }
   232  
   233  // WriteDescToBatch adds a Put command writing a descriptor proto to the
   234  // descriptors table. It writes the descriptor desc at the id descID. If kvTrace
   235  // is enabled, it will log an event explaining the put that was performed.
   236  func WriteDescToBatch(
   237  	ctx context.Context,
   238  	kvTrace bool,
   239  	s *cluster.Settings,
   240  	b *kv.Batch,
   241  	codec keys.SQLCodec,
   242  	descID sqlbase.ID,
   243  	desc sqlbase.DescriptorProto,
   244  ) (err error) {
   245  	descKey := sqlbase.MakeDescMetadataKey(codec, descID)
   246  	descDesc := sqlbase.WrapDescriptor(desc)
   247  	if kvTrace {
   248  		log.VEventf(ctx, 2, "Put %s -> %s", descKey, descDesc)
   249  	}
   250  	b.Put(descKey, descDesc)
   251  	return nil
   252  }
   253  
   254  // WriteNewDescToBatch adds a CPut command writing a descriptor proto to the
   255  // descriptors table. It writes the descriptor desc at the id descID, asserting
   256  // that there was no previous descriptor at that id present already. If kvTrace
   257  // is enabled, it will log an event explaining the CPut that was performed.
   258  func WriteNewDescToBatch(
   259  	ctx context.Context,
   260  	kvTrace bool,
   261  	s *cluster.Settings,
   262  	b *kv.Batch,
   263  	codec keys.SQLCodec,
   264  	tableID sqlbase.ID,
   265  	desc sqlbase.DescriptorProto,
   266  ) (err error) {
   267  	descKey := sqlbase.MakeDescMetadataKey(codec, tableID)
   268  	descDesc := sqlbase.WrapDescriptor(desc)
   269  	if kvTrace {
   270  		log.VEventf(ctx, 2, "CPut %s -> %s", descKey, descDesc)
   271  	}
   272  	b.CPut(descKey, descDesc, nil)
   273  	return nil
   274  }
   275  
   276  // GetDatabaseID resolves a database name into a database ID.
   277  // Returns InvalidID on failure.
   278  func GetDatabaseID(
   279  	ctx context.Context, txn *kv.Txn, codec keys.SQLCodec, name string, required bool,
   280  ) (sqlbase.ID, error) {
   281  	if name == sqlbase.SystemDB.Name {
   282  		return sqlbase.SystemDB.ID, nil
   283  	}
   284  	found, dbID, err := sqlbase.LookupDatabaseID(ctx, txn, codec, name)
   285  	if err != nil {
   286  		return sqlbase.InvalidID, err
   287  	}
   288  	if !found && required {
   289  		return dbID, sqlbase.NewUndefinedDatabaseError(name)
   290  	}
   291  	return dbID, nil
   292  }
   293  
   294  // GetDatabaseDescByID looks up the database descriptor given its ID,
   295  // returning nil if the descriptor is not found. If you want the "not
   296  // found" condition to return an error, use mustGetDatabaseDescByID() instead.
   297  func GetDatabaseDescByID(
   298  	ctx context.Context, txn *kv.Txn, codec keys.SQLCodec, id sqlbase.ID,
   299  ) (*sqlbase.DatabaseDescriptor, error) {
   300  	desc, err := GetDescriptorByID(ctx, txn, codec, id)
   301  	if err != nil {
   302  		return nil, err
   303  	}
   304  	db, ok := desc.(*sqlbase.DatabaseDescriptor)
   305  	if !ok {
   306  		return nil, pgerror.Newf(pgcode.WrongObjectType,
   307  			"%q is not a database", desc.String())
   308  	}
   309  	return db, nil
   310  }
   311  
   312  // MustGetDatabaseDescByID looks up the database descriptor given its ID,
   313  // returning an error if the descriptor is not found.
   314  func MustGetDatabaseDescByID(
   315  	ctx context.Context, txn *kv.Txn, codec keys.SQLCodec, id sqlbase.ID,
   316  ) (*sqlbase.DatabaseDescriptor, error) {
   317  	desc, err := GetDatabaseDescByID(ctx, txn, codec, id)
   318  	if err != nil {
   319  		return nil, err
   320  	}
   321  	if desc == nil {
   322  		return nil, sqlbase.NewUndefinedDatabaseError(fmt.Sprintf("[%d]", id))
   323  	}
   324  	return desc, nil
   325  }
   326  
   327  // GetDatabaseDescriptorsFromIDs returns the database descriptors from an input
   328  // set of database IDs. It will return an error if any one of the IDs is not a
   329  // database. It attempts to perform this operation in a single request,
   330  // rather than making a round trip for each ID.
   331  func GetDatabaseDescriptorsFromIDs(
   332  	ctx context.Context, txn *kv.Txn, codec keys.SQLCodec, ids []sqlbase.ID,
   333  ) ([]*sqlbase.DatabaseDescriptor, error) {
   334  	b := txn.NewBatch()
   335  	for _, id := range ids {
   336  		key := sqlbase.MakeDescMetadataKey(codec, id)
   337  		b.Get(key)
   338  	}
   339  	if err := txn.Run(ctx, b); err != nil {
   340  		return nil, err
   341  	}
   342  	results := make([]*sqlbase.DatabaseDescriptor, 0, len(ids))
   343  	for i := range b.Results {
   344  		result := &b.Results[i]
   345  		if result.Err != nil {
   346  			return nil, result.Err
   347  		}
   348  		if len(result.Rows) != 1 {
   349  			return nil, errors.AssertionFailedf(
   350  				"expected one result for key %s but found %d",
   351  				result.Keys[0],
   352  				len(result.Rows),
   353  			)
   354  		}
   355  		desc := &sqlbase.Descriptor{}
   356  		if err := result.Rows[0].ValueProto(desc); err != nil {
   357  			return nil, err
   358  		}
   359  		db := desc.GetDatabase()
   360  		if db == nil {
   361  			return nil, errors.AssertionFailedf(
   362  				"%q is not a database",
   363  				desc.String(),
   364  			)
   365  		}
   366  		results = append(results, db)
   367  	}
   368  	return results, nil
   369  }