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 }