// createDescriptor implements the DescriptorAccessor interface. func (p *planner) createDescriptor(plainKey sqlbase.DescriptorKey, descriptor sqlbase.DescriptorProto, ifNotExists bool) (bool, error) { idKey := plainKey.Key() // Check whether idKey exists. gr, err := p.txn.Get(idKey) if err != nil { return false, err } if gr.Exists() { if ifNotExists { // Noop. return false, nil } // Key exists, but we don't want it to: error out. return false, fmt.Errorf("%s %q already exists", descriptor.TypeName(), plainKey.Name()) } // Increment unique descriptor counter. if ir, err := p.txn.Inc(keys.DescIDGenerator, 1); err == nil { descriptor.SetID(sqlbase.ID(ir.ValueInt() - 1)) } else { return false, err } // 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("CPut %s -> %d", idKey, descID) log.Infof("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 true, p.txn.Run(&b) }
// getDescriptor implements the DescriptorAccessor interface. func (p *planner) getDescriptor(plainKey sqlbase.DescriptorKey, descriptor sqlbase.DescriptorProto, ) (bool, error) { gr, err := p.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 := p.txn.GetProto(descKey, desc); err != nil { return false, err } switch t := descriptor.(type) { case *sqlbase.TableDescriptor: table := desc.GetTable() 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 table == nil { return false, util.Errorf("%q is not a table", plainKey.Name()) } *t = *table case *sqlbase.DatabaseDescriptor: database := desc.GetDatabase() if database == nil { return false, util.Errorf("%q is not a database", plainKey.Name()) } *t = *database } if err := descriptor.Validate(); err != nil { return false, err } return true, nil }
// checkPrivilege implements the DescriptorAccessor interface. func (p *planner) checkPrivilege(descriptor sqlbase.DescriptorProto, privilege privilege.Kind) error { if descriptor.GetPrivileges().CheckPrivilege(p.session.User, privilege) { return nil } return fmt.Errorf("user %s does not have %s privilege on %s %s", p.session.User, privilege, descriptor.TypeName(), descriptor.GetName()) }
// anyPrivilege implements the DescriptorAccessor interface. func (p *planner) anyPrivilege(descriptor sqlbase.DescriptorProto) error { if descriptor.GetPrivileges().AnyPrivilege(p.session.User) || isVirtualDescriptor(descriptor) { return nil } return fmt.Errorf("user %s has no privileges on %s %s", p.session.User, descriptor.TypeName(), descriptor.GetName()) }
func (p *planner) createDescriptorWithID( idKey roachpb.Key, id sqlbase.ID, descriptor sqlbase.DescriptorProto, ) (bool, 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 true, p.txn.Run(b) }
// getDescriptor implements the DescriptorAccessor interface. func (p *planner) getDescriptor(plainKey sqlbase.DescriptorKey, descriptor sqlbase.DescriptorProto, ) (bool, error) { gr, err := p.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 := p.txn.GetProto(descKey, desc); err != nil { return false, err } switch t := descriptor.(type) { case *sqlbase.TableDescriptor: table := desc.GetTable() if table == nil { return false, util.Errorf("%q is not a table", plainKey.Name()) } *t = *table case *sqlbase.DatabaseDescriptor: database := desc.GetDatabase() if database == nil { return false, util.Errorf("%q is not a database", plainKey.Name()) } *t = *database } if err := descriptor.Validate(); err != nil { return false, err } return true, nil }
// isVirtualDescriptor checks if the provided DescriptorProto is an instance of // a Virtual Descriptor. func isVirtualDescriptor(desc sqlbase.DescriptorProto) bool { return desc.GetID() == keys.VirtualDescriptorID }