// writeDescriptor takes a Table or Database descriptor and writes it // if needed, incrementing the descriptor counter. func (p *planner) writeDescriptor(key proto.Key, descriptor descriptorProto, ifNotExists bool) error { // Check whether key exists. gr, err := p.db.Get(key) if err != nil { return err } if gr.Exists() { if ifNotExists { // Noop. return nil } // Key exists, but we don't want it to: error out. // TODO(marc): prettify the error (strip stuff off the type name) return fmt.Errorf("%T \"%s\" already exists", descriptor, key.String()) } // Increment unique descriptor counter. if ir, err := p.db.Inc(keys.DescIDGenerator, 1); err == nil { descriptor.SetID(uint32(ir.ValueInt() - 1)) } else { return 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. descKey := keys.MakeDescMetadataKey(descriptor.GetID()) return p.db.Txn(func(txn *client.Txn) error { b := &client.Batch{} b.CPut(key, descKey, nil) b.CPut(descKey, descriptor, nil) return txn.Commit(b) }) }
// Revoke removes privileges from users. // Current status: // - Target: DATABASE X only // - Privileges: ALL, or one or more of READ, WRITE. // TODO(marc): open questions: // - should we have root always allowed and not present in the permissions list? // - should we make users case-insensitive? func (p *planner) Revoke(n *parser.Revoke) (planNode, error) { if len(n.Targets.Targets) == 0 { return nil, errEmptyDatabaseName } if len(n.Targets.Targets) != 1 { return nil, util.Errorf("TODO(marc): multiple targets not implemented") } // Lookup the database descriptor. // TODO(marc): iterate over n.Targets.Targets once the grammar supports more than one. dbDesc, err := p.getDatabaseDesc(n.Targets.Targets[0]) if err != nil { return nil, err } if err := dbDesc.Revoke(n); err != nil { return nil, err } // Now update the descriptor. // TODO(marc): do this inside a transaction. This will be needed // when modifying multiple descriptors in the same op. descKey := keys.MakeDescMetadataKey(dbDesc.ID) if err := p.db.Put(descKey, dbDesc); err != nil { return nil, err } return &valuesNode{}, nil }
func TestGrant(t *testing.T) { defer leaktest.AfterTest(t) s, sqlDB, kvDB := setup(t) defer cleanup(s, sqlDB) // The first `MaxReservedDescID` (plus 0) are set aside. expectedCounter := uint32(structured.MaxReservedDescID + 1) if _, err := sqlDB.Exec(`CREATE DATABASE test`); err != nil { t.Fatal(err) } descKey := keys.MakeDescMetadataKey(expectedCounter) desc := structured.DatabaseDescriptor{} if err := kvDB.GetProto(descKey, &desc); err != nil { t.Fatal(err) } if len(desc.Read) != 1 || desc.Read[0] != security.RootUser { t.Fatalf("wrong Read list: %+v", desc.Read) } if len(desc.Write) != 1 || desc.Write[0] != security.RootUser { t.Fatalf("wrong Write list: %+v", desc.Write) } // Grant WRITE permissions. if _, err := sqlDB.Exec(`GRANT WRITE ON DATABASE TEST TO foo`); err != nil { t.Fatal(err) } if err := kvDB.GetProto(descKey, &desc); err != nil { t.Fatal(err) } if len(desc.Read) != 1 || desc.Read[0] != security.RootUser { t.Fatalf("wrong Read list: %+v", desc.Read) } if len(desc.Write) != 2 || desc.Write[0] != "foo" || desc.Write[1] != security.RootUser { t.Fatalf("wrong Write list: %+v", desc.Write) } // Grant ALL Permissions. if _, err := sqlDB.Exec(`GRANT ALL ON DATABASE TEST TO bar`); err != nil { t.Fatal(err) } if err := kvDB.GetProto(descKey, &desc); err != nil { t.Fatal(err) } if len(desc.Read) != 2 || desc.Read[0] != "bar" || desc.Read[1] != security.RootUser { t.Fatalf("wrong Read list: %+v", desc.Read) } if len(desc.Write) != 3 || desc.Write[0] != "bar" || desc.Write[1] != "foo" || desc.Write[2] != security.RootUser { t.Fatalf("wrong Write list: %+v", desc.Write) } // Adding permissions to root is a noop. if _, err := sqlDB.Exec(`GRANT ALL ON DATABASE TEST TO root`); err != nil { t.Fatal(err) } }
// CreateTable creates a table. func (p *planner) CreateTable(n *parser.CreateTable) (planNode, error) { var err error n.Table, err = p.normalizeTableName(n.Table) if err != nil { return nil, err } dbID, err := p.lookupDatabase(n.Table.Database()) if err != nil { return nil, err } desc, err := makeTableDesc(n) if err != nil { return nil, err } if err := desc.AllocateIDs(); err != nil { return nil, err } nameKey := keys.MakeNameMetadataKey(dbID, n.Table.Table()) // This isn't strictly necessary as the conditional put below will fail if // the key already exists, but it seems good to avoid the table ID allocation // in most cases when the table already exists. if gr, err := p.db.Get(nameKey); err != nil { return nil, err } else if gr.Exists() { if n.IfNotExists { return &valuesNode{}, nil } return nil, fmt.Errorf("table \"%s\" already exists", n.Table) } ir, err := p.db.Inc(keys.DescIDGenerator, 1) if err != nil { return nil, err } desc.ID = uint32(ir.ValueInt() - 1) // TODO(pmattis): Be cognizant of error messages when this is ported to the // server. The error currently returned below is likely going to be difficult // to interpret. // TODO(pmattis): Need to handle if-not-exists here as well. err = p.db.Txn(func(txn *client.Txn) error { descKey := keys.MakeDescMetadataKey(desc.ID) b := &client.Batch{} b.CPut(nameKey, descKey, nil) b.Put(descKey, &desc) return txn.Commit(b) }) if err != nil { return nil, err } return &valuesNode{}, nil }
func (c *conn) CreateTable(p *parser.CreateTable, args []driver.Value) (*rows, error) { if err := c.normalizeTableName(p.Table); err != nil { return nil, err } dbID, err := c.lookupDatabase(p.Table.Qualifier) if err != nil { return nil, err } schema, err := makeSchema(p) if err != nil { return nil, err } desc := structured.TableDescFromSchema(schema) if err := structured.ValidateTableDesc(desc); err != nil { return nil, err } nameKey := keys.MakeNameMetadataKey(dbID, p.Table.Name) // This isn't strictly necessary as the conditional put below will fail if // the key already exists, but it seems good to avoid the table ID allocation // in most cases when the table already exists. if gr, err := c.db.Get(nameKey); err != nil { return nil, err } else if gr.Exists() { if p.IfNotExists { return &rows{}, nil } return nil, fmt.Errorf("table \"%s\" already exists", p.Table) } ir, err := c.db.Inc(keys.DescIDGenerator, 1) if err != nil { return nil, err } desc.ID = uint32(ir.ValueInt() - 1) // TODO(pmattis): Be cognizant of error messages when this is ported to the // server. The error currently returned below is likely going to be difficult // to interpret. err = c.db.Txn(func(txn *client.Txn) error { descKey := keys.MakeDescMetadataKey(desc.ID) b := &client.Batch{} b.CPut(nameKey, descKey, nil) b.Put(descKey, &desc) return txn.Commit(b) }) if err != nil { // TODO(pmattis): Need to handle if-not-exists here as well. return nil, err } return &rows{}, nil }
// CreateTable creates a table if it doesn't already exist. func (s *Server) CreateTable(session *Session, p *parser.CreateTable, args []sqlwire.Datum, resp *sqlwire.Response) error { if err := s.normalizeTableName(session.Database, p.Table); err != nil { return err } dbID, err := s.lookupDatabase(p.Table.Qualifier) if err != nil { return err } desc, err := makeTableDesc(p) if err != nil { return err } if err := desc.AllocateIDs(); err != nil { return err } nameKey := keys.MakeNameMetadataKey(dbID, p.Table.Name) // This isn't strictly necessary as the conditional put below will fail if // the key already exists, but it seems good to avoid the table ID allocation // in most cases when the table already exists. if gr, err := s.db.Get(nameKey); err != nil { return err } else if gr.Exists() { if p.IfNotExists { return nil } return fmt.Errorf("table \"%s\" already exists", p.Table) } ir, err := s.db.Inc(keys.DescIDGenerator, 1) if err != nil { return err } desc.ID = uint32(ir.ValueInt() - 1) // TODO(pmattis): Be cognizant of error messages when this is ported to the // server. The error currently returned below is likely going to be difficult // to interpret. // TODO(pmattis): Need to handle if-not-exists here as well. return s.db.Txn(func(txn *client.Txn) error { descKey := keys.MakeDescMetadataKey(desc.ID) b := &client.Batch{} b.CPut(nameKey, descKey, nil) b.Put(descKey, &desc) return txn.Commit(b) }) }
// CreateTable creates a table from the specified schema. Table creation will // fail if the table name is already in use. The table name is required to have // the form "<namespace>.<table>". func (db *DB) CreateTable(schema structured.TableSchema) error { schema.Name = strings.ToLower(schema.Name) desc := structured.TableDescFromSchema(schema) if err := structured.ValidateTableDesc(desc); err != nil { return err } nsID, name, err := db.lookupTable(desc.Name) if err != nil { return err } if name == "" { return fmt.Errorf("empty table name: %s", desc.Name) } nameKey := keys.MakeNameMetadataKey(nsID, name) // This isn't strictly necessary as the conditional put below will fail if // the key already exists, but it seems good to avoid the table ID allocation // in most cases when the table already exists. if gr, err := db.Get(nameKey); err != nil { return err } else if gr.Exists() { return fmt.Errorf("table \"%s\" already exists", desc.Name) } ir, err := db.Inc(keys.DescIDGenerator, 1) if err != nil { return err } desc.ID = uint32(ir.ValueInt() - 1) // TODO(pmattis): Be cognizant of error messages when this is ported to the // server. The error currently returned below is likely going to be difficult // to interpret. return db.Txn(func(txn *Txn) error { descKey := keys.MakeDescMetadataKey(desc.ID) b := &Batch{} b.CPut(nameKey, descKey, nil) b.Put(descKey, &desc) return txn.Commit(b) }) }
func TestDatabaseDescriptor(t *testing.T) { defer leaktest.AfterTest(t) s, sqlDB, kvDB := setup(t) defer cleanup(s, sqlDB) // The first `MaxReservedDescID` (plus 0) are set aside. expectedCounter := int64(structured.MaxReservedDescID + 1) // Test values before creating the database. // descriptor ID counter. if ir, err := kvDB.Get(keys.DescIDGenerator); err != nil { t.Fatal(err) } else if ir.ValueInt() != expectedCounter { t.Fatalf("expected descriptor ID == %d, got %d", expectedCounter, ir.ValueInt()) } // Database name. nameKey := keys.MakeNameMetadataKey(structured.RootNamespaceID, "test") if gr, err := kvDB.Get(nameKey); err != nil { t.Fatal(err) } else if gr.Exists() { t.Fatal("expected non-existing key") } if _, err := sqlDB.Exec(`CREATE DATABASE test`); err != nil { t.Fatal(err) } expectedCounter++ // Check keys again. // descriptor ID counter. if ir, err := kvDB.Get(keys.DescIDGenerator); err != nil { t.Fatal(err) } else if ir.ValueInt() != expectedCounter { t.Fatalf("expected descriptor ID == %d, got %d", expectedCounter, ir.ValueInt()) } // Database name. if gr, err := kvDB.Get(nameKey); err != nil { t.Fatal(err) } else if !gr.Exists() { t.Fatal("key is missing") } // database descriptor. descKey := keys.MakeDescMetadataKey(uint32(expectedCounter - 1)) if gr, err := kvDB.Get(descKey); 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(keys.DescIDGenerator); err != nil { t.Fatal(err) } else if ir.ValueInt() != expectedCounter { t.Fatalf("expected descriptor ID == %d, got %d", expectedCounter, ir.ValueInt()) } // Database name. if gr, err := kvDB.Get(nameKey); err != nil { t.Fatal(err) } else if !gr.Exists() { t.Fatal("key is missing") } // database descriptor. if gr, err := kvDB.Get(descKey); err != nil { t.Fatal(err) } else if !gr.Exists() { t.Fatal("key is missing") } }
func TestRevoke(t *testing.T) { defer leaktest.AfterTest(t) s, sqlDB, kvDB := setup(t) defer cleanup(s, sqlDB) // The first `MaxReservedDescID` (plus 0) are set aside. expectedCounter := uint32(structured.MaxReservedDescID + 1) if _, err := sqlDB.Exec(`CREATE DATABASE test`); err != nil { t.Fatal(err) } descKey := keys.MakeDescMetadataKey(expectedCounter) desc := structured.DatabaseDescriptor{} if err := kvDB.GetProto(descKey, &desc); err != nil { t.Fatal(err) } if len(desc.Read) != 1 || desc.Read[0] != security.RootUser { t.Fatalf("wrong Read list: %+v", desc.Read) } if len(desc.Write) != 1 || desc.Write[0] != security.RootUser { t.Fatalf("wrong Write list: %+v", desc.Write) } // Add some permissions. if _, err := sqlDB.Exec(`GRANT ALL ON DATABASE TEST TO rw`); err != nil { t.Fatal(err) } if _, err := sqlDB.Exec(`GRANT READ ON DATABASE TEST TO reader`); err != nil { t.Fatal(err) } if _, err := sqlDB.Exec(`GRANT WRITE ON DATABASE TEST TO writer`); err != nil { t.Fatal(err) } if err := kvDB.GetProto(descKey, &desc); err != nil { t.Fatal(err) } if len(desc.Read) != 3 || len(desc.Write) != 3 { t.Fatalf("wrong read/write length: %d, %d", len(desc.Read), len(desc.Write)) } // Test some revokes. if _, err := sqlDB.Exec(`REVOKE WRITE ON DATABASE TEST FROM writer,reader`); err != nil { t.Fatal(err) } if err := kvDB.GetProto(descKey, &desc); err != nil { t.Fatal(err) } if len(desc.Read) != 3 { t.Fatalf("wrong Read list: %+v", desc.Read) } if len(desc.Write) != 2 || desc.Write[0] != security.RootUser || desc.Write[1] != "rw" { t.Fatalf("wrong Write list: %+v", desc.Write) } // Remove ALL Permissions. if _, err := sqlDB.Exec(`REVOKE ALL ON DATABASE TEST FROM rw`); err != nil { t.Fatal(err) } if err := kvDB.GetProto(descKey, &desc); err != nil { t.Fatal(err) } if len(desc.Read) != 2 || desc.Read[0] != "reader" || desc.Read[1] != security.RootUser { t.Fatalf("wrong Read list: %+v", desc.Read) } if len(desc.Write) != 1 || desc.Write[0] != security.RootUser { t.Fatalf("wrong Write list: %+v", desc.Write) } // Removing permissions for "root" fails. if _, err := sqlDB.Exec(`REVOKE READ ON DATABASE TEST FROM root`); err == nil { t.Fatal("unexpected success") } }