func restoreTableDesc( ctx context.Context, txn *client.Txn, database sqlbase.DatabaseDescriptor, table sqlbase.TableDescriptor, ) error { // Run getDescriptorID again to make sure the database hasn't been dropped // while we were importing. var err error if table.ParentID, err = getDescriptorID(txn, tableKey{name: database.Name}); err != nil { return err } tableIDKey := tableKey{parentID: table.ParentID, name: table.Name}.Key() tableDescKey := sqlbase.MakeDescMetadataKey(table.ID) // Check for an existing table. var existingDesc sqlbase.Descriptor existingIDKV, err := txn.Get(tableIDKey) if err != nil { return err } if existingIDKV.Value != nil { existingID, err := existingIDKV.Value.GetInt() if err != nil { return err } existingDescKV, err := txn.Get(sqlbase.MakeDescMetadataKey(sqlbase.ID(existingID))) if err != nil { return err } if err := existingDescKV.Value.GetProto(&existingDesc); err != nil { return err } } // Write the new descriptors. First the ID -> TableDescriptor for the new // table, then flip (or initialize) the name -> ID entry so any new queries // will use the new one. If there was an existing table, it can now be // cleaned up. b := txn.NewBatch() b.CPut(tableDescKey, sqlbase.WrapDescriptor(&table), nil) if existingTable := existingDesc.GetTable(); existingTable == nil { b.CPut(tableIDKey, table.ID, nil) } else { existingIDKV.Value.ClearChecksum() b.CPut(tableIDKey, table.ID, existingIDKV.Value) // TODO(dan): This doesn't work for interleaved tables. Fix it when we // fix the empty range interleaved table TODO below. existingDataPrefix := roachpb.Key(keys.MakeTablePrefix(uint32(existingTable.ID))) b.DelRange(existingDataPrefix, existingDataPrefix.PrefixEnd(), false) zoneKey, _, descKey := GetKeysForTableDescriptor(existingTable) // Delete the desc and zone entries. Leave the name because the new // table is using it. b.Del(descKey) b.Del(zoneKey) } return txn.Run(b) }
// writeMutation writes the mutation to the table descriptor. If the // State or the Direction is undefined, these values are populated via // picking random values before the mutation is written. func (mt mutationTest) writeMutation(m sqlbase.DescriptorMutation) { if m.Direction == sqlbase.DescriptorMutation_NONE { // randomly pick ADD/DROP mutation if this is the first mutation, or // pick the direction already chosen for the first mutation. if len(mt.tableDesc.Mutations) > 0 { m.Direction = mt.tableDesc.Mutations[0].Direction } else { m.Direction = sqlbase.DescriptorMutation_DROP if rand.Intn(2) == 0 { m.Direction = sqlbase.DescriptorMutation_ADD } } } if m.State == sqlbase.DescriptorMutation_UNKNOWN { // randomly pick DELETE_ONLY/WRITE_ONLY state. r := rand.Intn(2) if r == 0 { m.State = sqlbase.DescriptorMutation_DELETE_ONLY } else { m.State = sqlbase.DescriptorMutation_WRITE_ONLY } } mt.tableDesc.Mutations = append(mt.tableDesc.Mutations, m) if err := mt.tableDesc.ValidateTable(); err != nil { mt.Fatal(err) } if err := mt.kvDB.Put( context.TODO(), sqlbase.MakeDescMetadataKey(mt.tableDesc.ID), sqlbase.WrapDescriptor(mt.tableDesc), ); err != nil { mt.Fatal(err) } }
func (sc *SchemaChanger) maybeWriteResumeSpan( txn *client.Txn, version sqlbase.DescriptorVersion, resume roachpb.Span, mutationIdx int, lastCheckpoint *time.Time, ) error { checkpointInterval := checkpointInterval if sc.testingKnobs.WriteCheckpointInterval > 0 { checkpointInterval = sc.testingKnobs.WriteCheckpointInterval } if timeutil.Since(*lastCheckpoint) < checkpointInterval { return nil } tableDesc, err := sqlbase.GetTableDescFromID(txn, sc.tableID) if err != nil { return err } if tableDesc.Version != version { return errVersionMismatch } tableDesc.Mutations[mutationIdx].ResumeSpan = resume txn.SetSystemConfigTrigger() if err := txn.Put(sqlbase.MakeDescMetadataKey(tableDesc.GetID()), sqlbase.WrapDescriptor(tableDesc)); err != nil { return err } *lastCheckpoint = timeutil.Now() return nil }
// Convert all the mutations into live descriptors for the table // and write the updated table descriptor to the DB. func (mt mutationTest) makeMutationsActive() { // Remove mutation to check real values in DB using SQL if mt.tableDesc.Mutations == nil || len(mt.tableDesc.Mutations) == 0 { mt.Fatal("No mutations to make active") } for _, m := range mt.tableDesc.Mutations { if col := m.GetColumn(); col != nil { mt.tableDesc.Columns = append(mt.tableDesc.Columns, *col) } else if index := m.GetIndex(); index != nil { mt.tableDesc.Indexes = append(mt.tableDesc.Indexes, *index) } else { mt.Fatalf("no descriptor in mutation: %v", m) } } mt.tableDesc.Mutations = nil if err := mt.tableDesc.ValidateTable(); err != nil { mt.Fatal(err) } if err := mt.kvDB.Put( context.TODO(), sqlbase.MakeDescMetadataKey(mt.tableDesc.ID), sqlbase.WrapDescriptor(mt.tableDesc), ); err != nil { mt.Fatal(err) } }
// GetZoneConfig returns the zone config for the object with 'id'. func GetZoneConfig(cfg config.SystemConfig, id uint32) (config.ZoneConfig, bool, error) { // Look in the zones table. if zoneVal := cfg.GetValue(sqlbase.MakeZoneKey(sqlbase.ID(id))); zoneVal != nil { // We're done. zone, err := config.MigrateZoneConfig(zoneVal) return zone, true, err } // No zone config for this ID. We need to figure out if it's a database // or table. Lookup its descriptor. if descVal := cfg.GetValue(sqlbase.MakeDescMetadataKey(sqlbase.ID(id))); descVal != nil { // Determine whether this is a database or table. var desc sqlbase.Descriptor if err := descVal.GetProto(&desc); err != nil { return config.ZoneConfig{}, false, err } if tableDesc := desc.GetTable(); tableDesc != nil { // This is a table descriptor. Lookup its parent database zone config. return GetZoneConfig(cfg, uint32(tableDesc.ParentID)) } } // Retrieve the default zone config, but only as long as that wasn't the ID // we were trying to retrieve (avoid infinite recursion). if id != keys.RootNamespaceID { return GetZoneConfig(cfg, keys.RootNamespaceID) } // No descriptor or not a table. return config.ZoneConfig{}, false, nil }
// waitForOneVersion returns once there are no unexpired leases on the // previous version of the table descriptor. It returns the current version. // After returning there can only be versions of the descriptor >= to the // returned version. Lease acquisition (see acquire()) maintains the // invariant that no new leases for desc.Version-1 will be granted once // desc.Version exists. func (s LeaseStore) waitForOneVersion( tableID sqlbase.ID, retryOpts retry.Options, ) (sqlbase.DescriptorVersion, error) { desc := &sqlbase.Descriptor{} descKey := sqlbase.MakeDescMetadataKey(tableID) var tableDesc *sqlbase.TableDescriptor for r := retry.Start(retryOpts); r.Next(); { // Get the current version of the table descriptor non-transactionally. // // TODO(pmattis): Do an inconsistent read here? if err := s.db.GetProto(context.TODO(), descKey, desc); err != nil { return 0, err } tableDesc = desc.GetTable() if tableDesc == nil { return 0, errors.Errorf("ID %d is not a table", tableID) } // Check to see if there are any leases that still exist on the previous // version of the descriptor. now := s.clock.Now() count, err := s.countLeases(tableDesc.ID, tableDesc.Version-1, now.GoTime()) if err != nil { return 0, err } if count == 0 { break } log.Infof(context.TODO(), "publish (count leases): descID=%d name=%s version=%d count=%d", tableDesc.ID, tableDesc.Name, tableDesc.Version-1, count) } return tableDesc.Version, nil }
// getCachedDatabaseDesc implements the DatabaseAccessor interface. func (p *planner) getCachedDatabaseDesc(name string) (*sqlbase.DatabaseDescriptor, error) { if name == sqlbase.SystemDB.Name { return &sqlbase.SystemDB, nil } nameKey := databaseKey{name} nameVal := p.systemConfig.GetValue(nameKey.Key()) if nameVal == nil { return nil, fmt.Errorf("database %q does not exist in system cache", name) } id, err := nameVal.GetInt() if err != nil { return nil, err } descKey := sqlbase.MakeDescMetadataKey(sqlbase.ID(id)) descVal := p.systemConfig.GetValue(descKey) if descVal == nil { return nil, fmt.Errorf("database %q has name entry, but no descriptor in system cache", name) } desc := &sqlbase.Descriptor{} if err := descVal.GetProto(desc); err != nil { return nil, err } database := desc.GetDatabase() if database == nil { return nil, errors.Errorf("%q is not a database", name) } return database, database.Validate() }
// writeTableDesc implements the SchemaAccessor interface. func (p *planner) writeTableDesc(tableDesc *sqlbase.TableDescriptor) error { if isVirtualDescriptor(tableDesc) { panic(fmt.Sprintf("Virtual Descriptors cannot be stored, found: %v", tableDesc)) } return p.txn.Put(sqlbase.MakeDescMetadataKey(tableDesc.GetID()), sqlbase.WrapDescriptor(tableDesc)) }
func (p *planner) createDescriptorWithID( idKey roachpb.Key, id sqlbase.ID, descriptor sqlbase.DescriptorProto, ) error { descriptor.SetID(id) // TODO(pmattis): The error currently returned below is likely going to be // difficult to interpret. // // TODO(pmattis): Need to handle if-not-exists here as well. // // TODO(pmattis): This is writing the namespace and descriptor table entries, // but not going through the normal INSERT logic and not performing a precise // mimicry. In particular, we're only writing a single key per table, while // perfect mimicry would involve writing a sentinel key for each row as well. descKey := sqlbase.MakeDescMetadataKey(descriptor.GetID()) b := &client.Batch{} descID := descriptor.GetID() descDesc := sqlbase.WrapDescriptor(descriptor) if log.V(2) { log.Infof(p.ctx(), "CPut %s -> %d", idKey, descID) log.Infof(p.ctx(), "CPut %s -> %s", descKey, descDesc) } b.CPut(idKey, descID, nil) b.CPut(descKey, descDesc, nil) p.setTestingVerifyMetadata(func(systemConfig config.SystemConfig) error { if err := expectDescriptorID(systemConfig, idKey, descID); err != nil { return err } return expectDescriptor(systemConfig, descKey, descDesc) }) return p.txn.Run(b) }
// AcquireLease acquires a schema change lease on the table if // an unexpired lease doesn't exist. It returns the lease. func (sc *SchemaChanger) AcquireLease() (sqlbase.TableDescriptor_SchemaChangeLease, error) { var lease sqlbase.TableDescriptor_SchemaChangeLease err := sc.db.Txn(context.TODO(), func(txn *client.Txn) error { txn.SetSystemConfigTrigger() tableDesc, err := sqlbase.GetTableDescFromID(txn, sc.tableID) if err != nil { return err } // A second to deal with the time uncertainty across nodes. // It is perfectly valid for two or more goroutines to hold a valid // lease and execute a schema change in parallel, because schema // changes are executed using transactions that run sequentially. // This just reduces the probability of a write collision. expirationTimeUncertainty := time.Second if tableDesc.Lease != nil { if time.Unix(0, tableDesc.Lease.ExpirationTime).Add(expirationTimeUncertainty).After(timeutil.Now()) { return errExistingSchemaChangeLease } log.Infof(txn.Context, "Overriding existing expired lease %v", tableDesc.Lease) } lease = sc.createSchemaChangeLease() tableDesc.Lease = &lease return txn.Put(sqlbase.MakeDescMetadataKey(tableDesc.ID), sqlbase.WrapDescriptor(tableDesc)) }) return lease, err }
// TestRenameTable tests the table descriptor changes during // a rename operation. func TestRenameTable(t *testing.T) { defer leaktest.AfterTest(t)() s, db, kvDB := serverutils.StartServer(t, base.TestServerArgs{}) defer s.Stopper().Stop() counter := int64(keys.MaxReservedDescID) counter++ oldDBID := sqlbase.ID(counter) if _, err := db.Exec(`CREATE DATABASE test`); err != nil { t.Fatal(err) } // Create table in 'test'. counter++ oldName := "foo" if _, err := db.Exec(`CREATE TABLE test.foo (k INT PRIMARY KEY, v int)`); err != nil { t.Fatal(err) } // Check the table descriptor. desc := &sqlbase.Descriptor{} tableDescKey := sqlbase.MakeDescMetadataKey(sqlbase.ID(counter)) if err := kvDB.GetProto(context.TODO(), tableDescKey, desc); err != nil { t.Fatal(err) } tableDesc := desc.GetTable() if tableDesc.Name != oldName { t.Fatalf("Wrong table name, expected %s, got: %+v", oldName, tableDesc) } if tableDesc.ParentID != oldDBID { t.Fatalf("Wrong parent ID on table, expected %d, got: %+v", oldDBID, tableDesc) } // Create database test2. counter++ newDBID := sqlbase.ID(counter) if _, err := db.Exec(`CREATE DATABASE test2`); err != nil { t.Fatal(err) } // Move table to test2 and change its name as well. newName := "bar" if _, err := db.Exec(`ALTER TABLE test.foo RENAME TO test2.bar`); err != nil { t.Fatal(err) } // Check the table descriptor again. if err := kvDB.GetProto(context.TODO(), tableDescKey, desc); err != nil { t.Fatal(err) } tableDesc = desc.GetTable() if tableDesc.Name != newName { t.Fatalf("Wrong table name, expected %s, got: %+v", newName, tableDesc) } if tableDesc.ParentID != newDBID { t.Fatalf("Wrong parent ID on table, expected %d, got: %+v", newDBID, tableDesc) } }
// GetKeysForTableDescriptor retrieves the KV keys corresponding // to the zone, name and descriptor of a table. func GetKeysForTableDescriptor( tableDesc *sqlbase.TableDescriptor, ) (zoneKey roachpb.Key, nameKey roachpb.Key, descKey roachpb.Key) { zoneKey = sqlbase.MakeZoneKey(tableDesc.ID) nameKey = sqlbase.MakeNameMetadataKey(tableDesc.ParentID, tableDesc.GetName()) descKey = sqlbase.MakeDescMetadataKey(tableDesc.ID) return }
// getKeysForDatabaseDescriptor retrieves the KV keys corresponding to // the zone, name and descriptor of a database. func getKeysForDatabaseDescriptor( dbDesc *sqlbase.DatabaseDescriptor, ) (zoneKey roachpb.Key, nameKey roachpb.Key, descKey roachpb.Key) { zoneKey = sqlbase.MakeZoneKey(dbDesc.ID) nameKey = sqlbase.MakeNameMetadataKey(keys.RootNamespaceID, dbDesc.GetName()) descKey = sqlbase.MakeDescMetadataKey(dbDesc.ID) return }
// GetTableDesc returns the table descriptor for the table with 'id'. // Returns nil if the descriptor is not present, or is present but is not a // table. func GetTableDesc(cfg config.SystemConfig, id sqlbase.ID) (*sqlbase.TableDescriptor, error) { if descVal := cfg.GetValue(sqlbase.MakeDescMetadataKey(id)); descVal != nil { desc := &sqlbase.Descriptor{} if err := descVal.GetProto(desc); err != nil { return nil, err } return desc.GetTable(), nil } return nil, nil }
// ReleaseLease releases the table lease if it is the one registered with // the table descriptor. func (sc *SchemaChanger) ReleaseLease(lease sqlbase.TableDescriptor_SchemaChangeLease) error { err := sc.db.Txn(context.TODO(), func(txn *client.Txn) error { tableDesc, err := sc.findTableWithLease(txn, lease) if err != nil { return err } tableDesc.Lease = nil txn.SetSystemConfigTrigger() return txn.Put(sqlbase.MakeDescMetadataKey(tableDesc.ID), sqlbase.WrapDescriptor(tableDesc)) }) return err }
func isDeleted(tableID sqlbase.ID, cfg config.SystemConfig) bool { descKey := sqlbase.MakeDescMetadataKey(tableID) val := cfg.GetValue(descKey) if val == nil { return false } var descriptor sqlbase.Descriptor if err := val.GetProto(&descriptor); err != nil { panic("unable to unmarshal table descriptor") } table := descriptor.GetTable() return table.Dropped() }
func (p *planner) changePrivileges( targets parser.TargetList, grantees parser.NameList, changePrivilege func(*sqlbase.PrivilegeDescriptor, string), ) (planNode, error) { descriptors, err := p.getDescriptorsFromTargetList(targets) if err != nil { return nil, err } for _, descriptor := range descriptors { if err := p.checkPrivilege(descriptor, privilege.GRANT); err != nil { return nil, err } privileges := descriptor.GetPrivileges() for _, grantee := range grantees { changePrivilege(privileges, string(grantee)) } switch d := descriptor.(type) { case *sqlbase.DatabaseDescriptor: if err := d.Validate(); err != nil { return nil, err } case *sqlbase.TableDescriptor: if err := d.Validate(p.txn); err != nil { return nil, err } if err := d.SetUpVersion(); err != nil { return nil, err } p.notifySchemaChange(d.ID, sqlbase.InvalidMutationID) } } // Now update the descriptors transactionally. b := p.txn.NewBatch() for _, descriptor := range descriptors { descKey := sqlbase.MakeDescMetadataKey(descriptor.GetID()) b.Put(descKey, sqlbase.WrapDescriptor(descriptor)) } if err := p.txn.Run(b); err != nil { return nil, err } return &emptyNode{}, nil }
func getDescriptor( txn *client.Txn, plainKey sqlbase.DescriptorKey, descriptor sqlbase.DescriptorProto, ) (bool, error) { gr, err := txn.Get(plainKey.Key()) if err != nil { return false, err } if !gr.Exists() { return false, nil } descKey := sqlbase.MakeDescMetadataKey(sqlbase.ID(gr.ValueInt())) desc := &sqlbase.Descriptor{} if err := txn.GetProto(descKey, desc); err != nil { return false, err } switch t := descriptor.(type) { case *sqlbase.TableDescriptor: table := desc.GetTable() if table == nil { return false, errors.Errorf("%q is not a table", plainKey.Name()) } table.MaybeUpgradeFormatVersion() // TODO(dan): Write the upgraded TableDescriptor back to kv. This will break // the ability to use a previous version of cockroach with the on-disk data, // but it's worth it to avoid having to do the upgrade every time the // descriptor is fetched. Our current test for this enforces compatibility // backward and forward, so that'll have to be extended before this is done. if err := table.Validate(txn); err != nil { return false, err } *t = *table case *sqlbase.DatabaseDescriptor: database := desc.GetDatabase() if database == nil { return false, errors.Errorf("%q is not a database", plainKey.Name()) } if err := database.Validate(); err != nil { return false, err } *t = *database } return true, nil }
// isRenamed tests if a descriptor is updated by gossip to the specified name // and version. func isRenamed( tableID sqlbase.ID, expectedName string, expectedVersion sqlbase.DescriptorVersion, cfg config.SystemConfig, ) bool { descKey := sqlbase.MakeDescMetadataKey(tableID) val := cfg.GetValue(descKey) if val == nil { return false } var descriptor sqlbase.Descriptor if err := val.GetProto(&descriptor); err != nil { panic("unable to unmarshal table descriptor") } table := descriptor.GetTable() return table.Name == expectedName && table.Version == expectedVersion }
// renameDatabase implements the DatabaseAccessor interface. func (p *planner) renameDatabase(oldDesc *sqlbase.DatabaseDescriptor, newName string) error { onAlreadyExists := func() error { return fmt.Errorf("the new database name %q already exists", newName) } if p.session.virtualSchemas.isVirtualDatabase(newName) { return onAlreadyExists() } oldName := oldDesc.Name oldDesc.SetName(newName) if err := oldDesc.Validate(); err != nil { return err } oldKey := databaseKey{oldName}.Key() newKey := databaseKey{newName}.Key() descID := oldDesc.GetID() descKey := sqlbase.MakeDescMetadataKey(descID) descDesc := sqlbase.WrapDescriptor(oldDesc) b := &client.Batch{} b.CPut(newKey, descID, nil) b.Put(descKey, descDesc) b.Del(oldKey) if err := p.txn.Run(b); err != nil { if _, ok := err.(*roachpb.ConditionFailedError); ok { return onAlreadyExists() } return err } p.setTestingVerifyMetadata(func(systemConfig config.SystemConfig) error { if err := expectDescriptorID(systemConfig, newKey, descID); err != nil { return err } if err := expectDescriptor(systemConfig, descKey, descDesc); err != nil { return err } return expectDeleted(systemConfig, oldKey) }) return nil }
// TestAddingFKs checks the behavior of a table in the non-public `ADD` state. // Being non-public, it should not be visible to clients, and is therefore // assumed to be empty (e.g. by foreign key checks), since no one could have // written to it yet. func TestAddingFKs(t *testing.T) { defer leaktest.AfterTest(t)() params, _ := createTestServerParams() s, sqlDB, kvDB := serverutils.StartServer(t, params) defer s.Stopper().Stop() if _, err := sqlDB.Exec(` CREATE DATABASE t; CREATE TABLE t.products (id INT PRIMARY KEY); INSERT INTO t.products VALUES (1), (2); CREATE TABLE t.orders (id INT PRIMARY KEY, product INT REFERENCES t.products, INDEX (product)); `); err != nil { t.Fatal(err) } // Step the referencing table back to the ADD state. ordersDesc := sqlbase.GetTableDescriptor(kvDB, "t", "orders") ordersDesc.State = sqlbase.TableDescriptor_ADD ordersDesc.Version++ if err := kvDB.Put( context.TODO(), sqlbase.MakeDescMetadataKey(ordersDesc.ID), sqlbase.WrapDescriptor(ordersDesc), ); err != nil { t.Fatal(err) } // Generally a referenced table needs to lookup referencing tables to check // FKs during delete operations, but referencing tables in the ADD state are // given special treatment. if _, err := sqlDB.Exec(`DELETE FROM t.products`); err != nil { t.Fatal(err) } // Client should not see the orders table. if _, err := sqlDB.Exec( `SELECT * FROM t.orders`, ); !testutils.IsError(err, "table is being added") { t.Fatal(err) } }
// ExtendLease for the current leaser. This needs to be called often while // doing a schema change to prevent more than one node attempting to apply a // schema change (which is still safe, but unwise). func (sc *SchemaChanger) ExtendLease( existingLease sqlbase.TableDescriptor_SchemaChangeLease, ) (sqlbase.TableDescriptor_SchemaChangeLease, error) { // Check if there is still time on this lease. minDesiredExpiration := timeutil.Now().Add(MinSchemaChangeLeaseDuration) if time.Unix(0, existingLease.ExpirationTime).After(minDesiredExpiration) { return existingLease, nil } // Update lease. var lease sqlbase.TableDescriptor_SchemaChangeLease err := sc.db.Txn(context.TODO(), func(txn *client.Txn) error { tableDesc, err := sc.findTableWithLease(txn, existingLease) if err != nil { return err } lease = sc.createSchemaChangeLease() tableDesc.Lease = &lease txn.SetSystemConfigTrigger() return txn.Put(sqlbase.MakeDescMetadataKey(tableDesc.ID), sqlbase.WrapDescriptor(tableDesc)) }) return lease, err }
func TestSchemaChangeProcess(t *testing.T) { defer leaktest.AfterTest(t)() // The descriptor changes made must have an immediate effect // so disable leases on tables. defer csql.TestDisableTableLeases()() params, _ := createTestServerParams() // Disable external processing of mutations. params.Knobs.SQLSchemaChanger = &csql.SchemaChangerTestingKnobs{ AsyncExecNotification: asyncSchemaChangerDisabled, } s, sqlDB, kvDB := serverutils.StartServer(t, params) defer s.Stopper().Stop() var id = sqlbase.ID(keys.MaxReservedDescID + 2) var node = roachpb.NodeID(2) stopper := stop.NewStopper() leaseMgr := csql.NewLeaseManager( &base.NodeIDContainer{}, *kvDB, hlc.NewClock(hlc.UnixNano, time.Nanosecond), csql.LeaseManagerTestingKnobs{}, stopper, &csql.MemoryMetrics{}, ) defer stopper.Stop() changer := csql.NewSchemaChangerForTesting(id, 0, node, *kvDB, leaseMgr) if _, err := sqlDB.Exec(` CREATE DATABASE t; CREATE TABLE t.test (k CHAR PRIMARY KEY, v CHAR, INDEX foo(v)); INSERT INTO t.test VALUES ('a', 'b'), ('c', 'd'); `); err != nil { t.Fatal(err) } // Read table descriptor for version. tableDesc := sqlbase.GetTableDescriptor(kvDB, "t", "test") expectedVersion := tableDesc.Version desc, err := changer.MaybeIncrementVersion() if err != nil { t.Fatal(err) } tableDesc = desc.GetTable() newVersion := tableDesc.Version if newVersion != expectedVersion { t.Fatalf("bad version; e = %d, v = %d", expectedVersion, newVersion) } isDone, err := changer.IsDone() if err != nil { t.Fatal(err) } if !isDone { t.Fatalf("table expected to not have an outstanding schema change: %v", tableDesc) } // Check that MaybeIncrementVersion increments the version // correctly. expectedVersion++ tableDesc.UpVersion = true if err := kvDB.Put( context.TODO(), sqlbase.MakeDescMetadataKey(tableDesc.ID), sqlbase.WrapDescriptor(tableDesc), ); err != nil { t.Fatal(err) } isDone, err = changer.IsDone() if err != nil { t.Fatal(err) } if isDone { t.Fatalf("table expected to have an outstanding schema change: %v", desc.GetTable()) } desc, err = changer.MaybeIncrementVersion() if err != nil { t.Fatal(err) } tableDesc = desc.GetTable() savedTableDesc := sqlbase.GetTableDescriptor(kvDB, "t", "test") newVersion = tableDesc.Version if newVersion != expectedVersion { t.Fatalf("bad version in returned desc; e = %d, v = %d", expectedVersion, newVersion) } newVersion = savedTableDesc.Version if newVersion != expectedVersion { t.Fatalf("bad version in saved desc; e = %d, v = %d", expectedVersion, newVersion) } isDone, err = changer.IsDone() if err != nil { t.Fatal(err) } if !isDone { t.Fatalf("table expected to not have an outstanding schema change: %v", tableDesc) } // Check that RunStateMachineBeforeBackfill doesn't do anything // if there are no mutations queued. if err := changer.RunStateMachineBeforeBackfill(); err != nil { t.Fatal(err) } tableDesc = sqlbase.GetTableDescriptor(kvDB, "t", "test") newVersion = tableDesc.Version if newVersion != expectedVersion { t.Fatalf("bad version; e = %d, v = %d", expectedVersion, newVersion) } // Check that RunStateMachineBeforeBackfill functions properly. expectedVersion = tableDesc.Version // Make a copy of the index for use in a mutation. index := protoutil.Clone(&tableDesc.Indexes[0]).(*sqlbase.IndexDescriptor) index.Name = "bar" index.ID = tableDesc.NextIndexID tableDesc.NextIndexID++ changer = csql.NewSchemaChangerForTesting(id, tableDesc.NextMutationID, node, *kvDB, leaseMgr) tableDesc.Mutations = append(tableDesc.Mutations, sqlbase.DescriptorMutation{ Descriptor_: &sqlbase.DescriptorMutation_Index{Index: index}, Direction: sqlbase.DescriptorMutation_ADD, State: sqlbase.DescriptorMutation_DELETE_ONLY, MutationID: tableDesc.NextMutationID, }) tableDesc.NextMutationID++ // Run state machine in both directions. for _, direction := range []sqlbase.DescriptorMutation_Direction{sqlbase.DescriptorMutation_ADD, sqlbase.DescriptorMutation_DROP} { tableDesc.Mutations[0].Direction = direction expectedVersion++ if err := kvDB.Put( context.TODO(), sqlbase.MakeDescMetadataKey(tableDesc.ID), sqlbase.WrapDescriptor(tableDesc), ); err != nil { t.Fatal(err) } // The expected end state. expectedState := sqlbase.DescriptorMutation_WRITE_ONLY if direction == sqlbase.DescriptorMutation_DROP { expectedState = sqlbase.DescriptorMutation_DELETE_ONLY } // Run two times to ensure idempotency of operations. for i := 0; i < 2; i++ { if err := changer.RunStateMachineBeforeBackfill(); err != nil { t.Fatal(err) } tableDesc = sqlbase.GetTableDescriptor(kvDB, "t", "test") newVersion = tableDesc.Version if newVersion != expectedVersion { t.Fatalf("bad version; e = %d, v = %d", expectedVersion, newVersion) } state := tableDesc.Mutations[0].State if state != expectedState { t.Fatalf("bad state; e = %d, v = %d", expectedState, state) } } } // RunStateMachineBeforeBackfill() doesn't complete the schema change. isDone, err = changer.IsDone() if err != nil { t.Fatal(err) } if isDone { t.Fatalf("table expected to have an outstanding schema change: %v", tableDesc) } }
func TestSystemConfigGossip(t *testing.T) { defer leaktest.AfterTest(t)() t.Skip("#12351") s, _, kvDB := serverutils.StartServer(t, base.TestServerArgs{}) defer s.Stopper().Stop() ts := s.(*TestServer) ctx := context.TODO() key := sqlbase.MakeDescMetadataKey(keys.MaxReservedDescID) valAt := func(i int) *sqlbase.DatabaseDescriptor { return &sqlbase.DatabaseDescriptor{Name: "foo", ID: sqlbase.ID(i)} } // Register a callback for gossip updates. resultChan := ts.Gossip().RegisterSystemConfigChannel() // The span gets gossiped when it first shows up. select { case <-resultChan: case <-time.After(500 * time.Millisecond): t.Fatal("did not receive gossip message") } // Try a plain KV write first. if err := kvDB.Put(ctx, key, valAt(0)); err != nil { t.Fatal(err) } // Now do it as part of a transaction, but without the trigger set. if err := kvDB.Txn(ctx, func(txn *client.Txn) error { return txn.Put(key, valAt(1)) }); err != nil { t.Fatal(err) } // Gossip channel should be dormant. // TODO(tschottdorf): This test is likely flaky. Why can't some other // process trigger gossip? It seems that a new range lease being // acquired will gossip a new system config since the hash changed and fail // the test (seen in practice during some buggy WIP). var systemConfig config.SystemConfig select { case <-resultChan: systemConfig, _ = ts.gossip.GetSystemConfig() t.Fatalf("unexpected message received on gossip channel: %v", systemConfig) case <-time.After(50 * time.Millisecond): } // This time mark the transaction as having a Gossip trigger. if err := kvDB.Txn(ctx, func(txn *client.Txn) error { txn.SetSystemConfigTrigger() return txn.Put(key, valAt(2)) }); err != nil { t.Fatal(err) } // New system config received. select { case <-resultChan: systemConfig, _ = ts.gossip.GetSystemConfig() case <-time.After(500 * time.Millisecond): t.Fatal("did not receive gossip message") } // Now check the new config. var val *roachpb.Value for _, kv := range systemConfig.Values { if bytes.Equal(key, kv.Key) { val = &kv.Value break } } if val == nil { t.Fatal("key not found in gossiped info") } // Make sure the returned value is valAt(2). got := new(sqlbase.DatabaseDescriptor) if err := val.GetProto(got); err != nil { t.Fatal(err) } if expected := valAt(2); !reflect.DeepEqual(got, expected) { t.Fatalf("mismatch: expected %+v, got %+v", *expected, *got) } }
func TestDatabaseDescriptor(t *testing.T) { defer leaktest.AfterTest(t)() params, _ := createTestServerParams() s, sqlDB, kvDB := serverutils.StartServer(t, params) defer s.Stopper().Stop() ctx := context.TODO() expectedCounter := int64(keys.MaxReservedDescID + 1) // Test values before creating the database. // descriptor ID counter. if ir, err := kvDB.Get(ctx, keys.DescIDGenerator); err != nil { t.Fatal(err) } else if actual := ir.ValueInt(); actual != expectedCounter { t.Fatalf("expected descriptor ID == %d, got %d", expectedCounter, actual) } // Database name. nameKey := sqlbase.MakeNameMetadataKey(keys.RootNamespaceID, "test") if gr, err := kvDB.Get(ctx, nameKey); err != nil { t.Fatal(err) } else if gr.Exists() { t.Fatal("expected non-existing key") } // Write a descriptor key that will interfere with database creation. dbDescKey := sqlbase.MakeDescMetadataKey(sqlbase.ID(expectedCounter)) dbDesc := &sqlbase.Descriptor{ Union: &sqlbase.Descriptor_Database{ Database: &sqlbase.DatabaseDescriptor{ Name: "sentinel", ID: sqlbase.ID(expectedCounter), Privileges: &sqlbase.PrivilegeDescriptor{}, }, }, } if err := kvDB.CPut(ctx, dbDescKey, dbDesc, nil); err != nil { t.Fatal(err) } // Database creation should fail, and nothing should have been written. if _, err := sqlDB.Exec(`CREATE DATABASE test`); !testutils.IsError(err, "unexpected value") { t.Fatalf("unexpected error %v", err) } if ir, err := kvDB.Get(ctx, keys.DescIDGenerator); err != nil { t.Fatal(err) } else if actual := ir.ValueInt(); actual != expectedCounter { t.Fatalf("expected descriptor ID == %d, got %d", expectedCounter, actual) } start := roachpb.Key(keys.MakeTablePrefix(uint32(keys.NamespaceTableID))) if kvs, err := kvDB.Scan(ctx, start, start.PrefixEnd(), 0); err != nil { t.Fatal(err) } else { if a, e := len(kvs), server.GetBootstrapSchema().SystemDescriptorCount(); a != e { t.Fatalf("expected %d keys to have been written, found %d keys", e, a) } } // Remove the junk; allow database creation to proceed. if err := kvDB.Del(ctx, dbDescKey); err != nil { t.Fatal(err) } if _, err := sqlDB.Exec(`CREATE DATABASE test`); err != nil { t.Fatal(err) } expectedCounter++ // Check keys again. // descriptor ID counter. if ir, err := kvDB.Get(ctx, keys.DescIDGenerator); err != nil { t.Fatal(err) } else if actual := ir.ValueInt(); actual != expectedCounter { t.Fatalf("expected descriptor ID == %d, got %d", expectedCounter, actual) } // Database name. if gr, err := kvDB.Get(ctx, nameKey); err != nil { t.Fatal(err) } else if !gr.Exists() { t.Fatal("key is missing") } // database descriptor. if gr, err := kvDB.Get(ctx, dbDescKey); err != nil { t.Fatal(err) } else if !gr.Exists() { t.Fatal("key is missing") } // Now try to create it again. We should fail, but not increment the counter. if _, err := sqlDB.Exec(`CREATE DATABASE test`); err == nil { t.Fatal("failure expected") } // Check keys again. // descriptor ID counter. if ir, err := kvDB.Get(ctx, keys.DescIDGenerator); err != nil { t.Fatal(err) } else if actual := ir.ValueInt(); actual != expectedCounter { t.Fatalf("expected descriptor ID == %d, got %d", expectedCounter, actual) } // Database name. if gr, err := kvDB.Get(ctx, nameKey); err != nil { t.Fatal(err) } else if !gr.Exists() { t.Fatal("key is missing") } // database descriptor. if gr, err := kvDB.Get(ctx, dbDescKey); err != nil { t.Fatal(err) } else if !gr.Exists() { t.Fatal("key is missing") } }
// RenameColumn renames the column. // Privileges: CREATE on table. // notes: postgres requires CREATE on the table. // mysql requires ALTER, CREATE, INSERT on the table. func (p *planner) RenameColumn(n *parser.RenameColumn) (planNode, error) { // Check if table exists. tn, err := n.Table.NormalizeWithDatabaseName(p.session.Database) if err != nil { return nil, err } tableDesc, err := p.getTableDesc(tn) if err != nil { return nil, err } if tableDesc == nil { if n.IfExists { // Noop. return &emptyNode{}, nil } // Key does not exist, but we want it to: error out. return nil, fmt.Errorf("table %q does not exist", tn.Table()) } if err := p.checkPrivilege(tableDesc, privilege.CREATE); err != nil { return nil, err } if n.NewName == "" { return nil, errEmptyColumnName } normNewColName := n.NewName.Normalize() normColName := n.Name.Normalize() status, i, err := tableDesc.FindColumnByNormalizedName(normColName) // n.IfExists only applies to table, no need to check here. if err != nil { return nil, err } var column *sqlbase.ColumnDescriptor if status == sqlbase.DescriptorActive { column = &tableDesc.Columns[i] } else { column = tableDesc.Mutations[i].GetColumn() } for _, tableRef := range tableDesc.DependedOnBy { found := false for _, colID := range tableRef.ColumnIDs { if colID == column.ID { found = true } } if found { return nil, p.dependentViewRenameError( "column", n.Name.String(), tableDesc.ParentID, tableRef.ID) } } if normColName == normNewColName { // Noop. return &emptyNode{}, nil } if _, _, err := tableDesc.FindColumnByNormalizedName(normNewColName); err == nil { return nil, fmt.Errorf("column name %q already exists", n.NewName) } preFn := func(expr parser.Expr) (err error, recurse bool, newExpr parser.Expr) { if vBase, ok := expr.(parser.VarName); ok { v, err := vBase.NormalizeVarName() if err != nil { return err, false, nil } if c, ok := v.(*parser.ColumnItem); ok { if c.ColumnName.Normalize() == normColName { c.ColumnName = n.NewName } } return nil, false, v } return nil, true, expr } exprStrings := make([]string, len(tableDesc.Checks)) for i, check := range tableDesc.Checks { exprStrings[i] = check.Expr } exprs, err := parser.ParseExprsTraditional(exprStrings) if err != nil { return nil, err } for i := range tableDesc.Checks { expr, err := parser.SimpleVisit(exprs[i], preFn) if err != nil { return nil, err } if after := expr.String(); after != tableDesc.Checks[i].Expr { tableDesc.Checks[i].Expr = after } } // Rename the column in the indexes. tableDesc.RenameColumnNormalized(column.ID, normNewColName) column.Name = normNewColName if err := tableDesc.SetUpVersion(); err != nil { return nil, err } descKey := sqlbase.MakeDescMetadataKey(tableDesc.GetID()) if err := tableDesc.Validate(p.txn); err != nil { return nil, err } if err := p.txn.Put(descKey, sqlbase.WrapDescriptor(tableDesc)); err != nil { return nil, err } p.notifySchemaChange(tableDesc.ID, sqlbase.InvalidMutationID) return &emptyNode{}, nil }
// RenameIndex renames the index. // Privileges: CREATE on table. // notes: postgres requires CREATE on the table. // mysql requires ALTER, CREATE, INSERT on the table. func (p *planner) RenameIndex(n *parser.RenameIndex) (planNode, error) { tn, err := p.expandIndexName(n.Index) if err != nil { return nil, err } tableDesc, err := p.mustGetTableDesc(tn) if err != nil { return nil, err } normIdxName := n.Index.Index.Normalize() status, i, err := tableDesc.FindIndexByNormalizedName(normIdxName) if err != nil { if n.IfExists { // Noop. return &emptyNode{}, nil } // Index does not exist, but we want it to: error out. return nil, err } if err := p.checkPrivilege(tableDesc, privilege.CREATE); err != nil { return nil, err } for _, tableRef := range tableDesc.DependedOnBy { if tableRef.IndexID != tableDesc.Indexes[i].ID { continue } return nil, p.dependentViewRenameError( "index", n.Index.Index.String(), tableDesc.ParentID, tableRef.ID) } if n.NewName == "" { return nil, errEmptyIndexName } normNewIdxName := n.NewName.Normalize() if normIdxName == normNewIdxName { // Noop. return &emptyNode{}, nil } if _, _, err := tableDesc.FindIndexByNormalizedName(normNewIdxName); err == nil { return nil, fmt.Errorf("index name %q already exists", n.NewName) } if status == sqlbase.DescriptorActive { tableDesc.Indexes[i].Name = normNewIdxName } else { tableDesc.Mutations[i].GetIndex().Name = normNewIdxName } if err := tableDesc.SetUpVersion(); err != nil { return nil, err } descKey := sqlbase.MakeDescMetadataKey(tableDesc.GetID()) if err := tableDesc.Validate(p.txn); err != nil { return nil, err } if err := p.txn.Put(descKey, sqlbase.WrapDescriptor(tableDesc)); err != nil { return nil, err } p.notifySchemaChange(tableDesc.ID, sqlbase.InvalidMutationID) return &emptyNode{}, nil }
func TestDropTable(t *testing.T) { defer leaktest.AfterTest(t)() params, _ := createTestServerParams() s, sqlDB, kvDB := serverutils.StartServer(t, params) defer s.Stopper().Stop() ctx := context.TODO() numRows := 2*sql.TableTruncateChunkSize + 1 createKVTable(t, sqlDB, numRows) tableDesc := sqlbase.GetTableDescriptor(kvDB, "t", "kv") nameKey := sqlbase.MakeNameMetadataKey(keys.MaxReservedDescID+1, "kv") gr, err := kvDB.Get(ctx, nameKey) if err != nil { t.Fatal(err) } if !gr.Exists() { t.Fatalf("Name entry %q does not exist", nameKey) } descKey := sqlbase.MakeDescMetadataKey(sqlbase.ID(gr.ValueInt())) // Add a zone config for the table. cfg := config.DefaultZoneConfig() buf, err := protoutil.Marshal(&cfg) if err != nil { t.Fatal(err) } if _, err := sqlDB.Exec(`INSERT INTO system.zones VALUES ($1, $2)`, tableDesc.ID, buf); err != nil { t.Fatal(err) } zoneKey := sqlbase.MakeZoneKey(tableDesc.ID) if gr, err := kvDB.Get(ctx, zoneKey); err != nil { t.Fatal(err) } else if !gr.Exists() { t.Fatalf("zone config entry not found") } tablePrefix := roachpb.Key(keys.MakeTablePrefix(uint32(tableDesc.ID))) checkKeyCount(t, kvDB, tablePrefix, 3*numRows) if _, err := sqlDB.Exec(`DROP TABLE t.kv`); err != nil { t.Fatal(err) } checkKeyCount(t, kvDB, tablePrefix, 0) // Test that deleted table cannot be used. This prevents regressions where // name -> descriptor ID caches might make this statement erronously work. if _, err := sqlDB.Exec(`SELECT * FROM t.kv`); !testutils.IsError(err, `table "t.kv" does not exist`) { t.Fatalf("different error than expected: %v", err) } if gr, err := kvDB.Get(ctx, descKey); err != nil { t.Fatal(err) } else if gr.Exists() { t.Fatalf("table descriptor still exists after the table is dropped") } if gr, err := kvDB.Get(ctx, nameKey); err != nil { t.Fatal(err) } else if gr.Exists() { t.Fatalf("table namekey still exists after the table is dropped") } if gr, err := kvDB.Get(ctx, zoneKey); err != nil { t.Fatal(err) } else if gr.Exists() { t.Fatalf("zone config entry still exists after the table is dropped") } }
func TestDropDatabase(t *testing.T) { defer leaktest.AfterTest(t)() params, _ := createTestServerParams() s, sqlDB, kvDB := serverutils.StartServer(t, params) defer s.Stopper().Stop() ctx := context.TODO() // Fix the column families so the key counts below don't change if the // family heuristics are updated. if _, err := sqlDB.Exec(` CREATE DATABASE t; CREATE TABLE t.kv (k CHAR PRIMARY KEY, v CHAR, FAMILY (k), FAMILY (v)); INSERT INTO t.kv VALUES ('c', 'e'), ('a', 'c'), ('b', 'd'); `); err != nil { t.Fatal(err) } dbNameKey := sqlbase.MakeNameMetadataKey(keys.RootNamespaceID, "t") r, err := kvDB.Get(ctx, dbNameKey) if err != nil { t.Fatal(err) } if !r.Exists() { t.Fatalf(`database "t" does not exist`) } dbDescKey := sqlbase.MakeDescMetadataKey(sqlbase.ID(r.ValueInt())) desc := &sqlbase.Descriptor{} if err := kvDB.GetProto(ctx, dbDescKey, desc); err != nil { t.Fatal(err) } dbDesc := desc.GetDatabase() tbNameKey := sqlbase.MakeNameMetadataKey(dbDesc.ID, "kv") gr, err := kvDB.Get(ctx, tbNameKey) if err != nil { t.Fatal(err) } if !gr.Exists() { t.Fatalf(`table "kv" does not exist`) } tbDescKey := sqlbase.MakeDescMetadataKey(sqlbase.ID(gr.ValueInt())) if err := kvDB.GetProto(ctx, tbDescKey, desc); err != nil { t.Fatal(err) } tbDesc := desc.GetTable() // Add a zone config for both the table and database. cfg := config.DefaultZoneConfig() buf, err := protoutil.Marshal(&cfg) if err != nil { t.Fatal(err) } if _, err := sqlDB.Exec(`INSERT INTO system.zones VALUES ($1, $2)`, tbDesc.ID, buf); err != nil { t.Fatal(err) } if _, err := sqlDB.Exec(`INSERT INTO system.zones VALUES ($1, $2)`, dbDesc.ID, buf); err != nil { t.Fatal(err) } tbZoneKey := sqlbase.MakeZoneKey(tbDesc.ID) dbZoneKey := sqlbase.MakeZoneKey(dbDesc.ID) if gr, err := kvDB.Get(ctx, tbZoneKey); err != nil { t.Fatal(err) } else if !gr.Exists() { t.Fatalf("table zone config entry not found") } if gr, err := kvDB.Get(ctx, dbZoneKey); err != nil { t.Fatal(err) } else if !gr.Exists() { t.Fatalf("database zone config entry not found") } tablePrefix := keys.MakeTablePrefix(uint32(tbDesc.ID)) tableStartKey := roachpb.Key(tablePrefix) tableEndKey := tableStartKey.PrefixEnd() if kvs, err := kvDB.Scan(ctx, tableStartKey, tableEndKey, 0); err != nil { t.Fatal(err) } else if l := 6; len(kvs) != l { t.Fatalf("expected %d key value pairs, but got %d", l, len(kvs)) } if _, err := sqlDB.Exec(`DROP DATABASE t`); err != nil { t.Fatal(err) } if kvs, err := kvDB.Scan(ctx, tableStartKey, tableEndKey, 0); err != nil { t.Fatal(err) } else if l := 0; len(kvs) != l { t.Fatalf("expected %d key value pairs, but got %d", l, len(kvs)) } if gr, err := kvDB.Get(ctx, tbDescKey); err != nil { t.Fatal(err) } else if gr.Exists() { t.Fatalf("table descriptor still exists after database is dropped: %q", tbDescKey) } if gr, err := kvDB.Get(ctx, tbNameKey); err != nil { t.Fatal(err) } else if gr.Exists() { t.Fatalf("table descriptor key still exists after database is dropped") } if gr, err := kvDB.Get(ctx, dbDescKey); err != nil { t.Fatal(err) } else if gr.Exists() { t.Fatalf("database descriptor still exists after database is dropped") } if gr, err := kvDB.Get(ctx, dbNameKey); err != nil { t.Fatal(err) } else if gr.Exists() { t.Fatalf("database descriptor key still exists after database is dropped") } if gr, err := kvDB.Get(ctx, tbZoneKey); err != nil { t.Fatal(err) } else if gr.Exists() { t.Fatalf("table zone config entry still exists after the database is dropped") } if gr, err := kvDB.Get(ctx, dbZoneKey); err != nil { t.Fatal(err) } else if gr.Exists() { t.Fatalf("database zone config entry still exists after the database is dropped") } }
// RenameTable renames the table or view. // Privileges: DROP on source table/view, CREATE on destination database. // Notes: postgres requires the table owner. // mysql requires ALTER, DROP on the original table, and CREATE, INSERT // on the new table (and does not copy privileges over). func (p *planner) RenameTable(n *parser.RenameTable) (planNode, error) { oldTn, err := n.Name.NormalizeWithDatabaseName(p.session.Database) if err != nil { return nil, err } newTn, err := n.NewName.NormalizeWithDatabaseName(p.session.Database) if err != nil { return nil, err } dbDesc, err := p.mustGetDatabaseDesc(oldTn.Database()) if err != nil { return nil, err } // Check if source table or view exists. // Note that Postgres's behavior here is a little lenient - it'll let you // modify views by running ALTER TABLE, but won't let you modify tables // by running ALTER VIEW. Our behavior is strict for now, but can be // made more lenient down the road if needed. var tableDesc *sqlbase.TableDescriptor if n.IsView { tableDesc, err = p.getViewDesc(oldTn) if err != nil { return nil, err } if tableDesc == nil { if n.IfExists { // Noop. return &emptyNode{}, nil } // Key does not exist, but we want it to: error out. return nil, sqlbase.NewUndefinedViewError(oldTn.String()) } if tableDesc.State != sqlbase.TableDescriptor_PUBLIC { return nil, sqlbase.NewUndefinedViewError(oldTn.String()) } } else { tableDesc, err = p.getTableDesc(oldTn) if err != nil { return nil, err } if tableDesc == nil { if n.IfExists { // Noop. return &emptyNode{}, nil } // Key does not exist, but we want it to: error out. return nil, sqlbase.NewUndefinedTableError(oldTn.String()) } if tableDesc.State != sqlbase.TableDescriptor_PUBLIC { return nil, sqlbase.NewUndefinedTableError(oldTn.String()) } } if err := p.checkPrivilege(tableDesc, privilege.DROP); err != nil { return nil, err } // Check if any views depend on this table/view. Because our views // are currently just stored as strings, they explicitly specify the name // of everything they depend on. Rather than trying to rewrite the view's // query with the new name, we simply disallow such renames for now. if len(tableDesc.DependedOnBy) > 0 { return nil, p.dependentViewRenameError( tableDesc.TypeName(), oldTn.String(), tableDesc.ParentID, tableDesc.DependedOnBy[0].ID) } // Check if target database exists. targetDbDesc, err := p.mustGetDatabaseDesc(newTn.Database()) if err != nil { return nil, err } if err := p.checkPrivilege(targetDbDesc, privilege.CREATE); err != nil { return nil, err } // oldTn and newTn are already normalized, so we can compare directly here. if oldTn.Database() == newTn.Database() && oldTn.Table() == newTn.Table() { // Noop. return &emptyNode{}, nil } tableDesc.SetName(newTn.Table()) tableDesc.ParentID = targetDbDesc.ID descKey := sqlbase.MakeDescMetadataKey(tableDesc.GetID()) newTbKey := tableKey{targetDbDesc.ID, newTn.Table()}.Key() if err := tableDesc.Validate(p.txn); err != nil { return nil, err } descID := tableDesc.GetID() descDesc := sqlbase.WrapDescriptor(tableDesc) if err := tableDesc.SetUpVersion(); err != nil { return nil, err } renameDetails := sqlbase.TableDescriptor_RenameInfo{ OldParentID: dbDesc.ID, OldName: oldTn.Table()} tableDesc.Renames = append(tableDesc.Renames, renameDetails) if err := p.writeTableDesc(tableDesc); err != nil { return nil, err } // We update the descriptor to the new name, but also leave the mapping of the // old name to the id, so that the name is not reused until the schema changer // has made sure it's not in use any more. b := &client.Batch{} b.Put(descKey, descDesc) b.CPut(newTbKey, descID, nil) if err := p.txn.Run(b); err != nil { if _, ok := err.(*roachpb.ConditionFailedError); ok { return nil, sqlbase.NewRelationAlreadyExistsError(newTn.Table()) } return nil, err } p.notifySchemaChange(tableDesc.ID, sqlbase.InvalidMutationID) p.setTestingVerifyMetadata(func(systemConfig config.SystemConfig) error { if err := expectDescriptorID(systemConfig, newTbKey, descID); err != nil { return err } if err := expectDescriptor(systemConfig, descKey, descDesc); err != nil { return err } return nil }) return &emptyNode{}, nil }