// 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 makeSchema(p *parser.CreateTable) (structured.TableSchema, error) { s := structured.TableSchema{} s.Name = p.Table.String() for _, def := range p.Defs { switch d := def.(type) { case *parser.ColumnTableDef: col := structured.Column{ Name: d.Name, Nullable: (d.Nullable != parser.NotNull), } switch t := d.Type.(type) { case *parser.BitType: col.Type.Kind = structured.ColumnType_BIT col.Type.Width = int32(t.N) case *parser.IntType: col.Type.Kind = structured.ColumnType_INT col.Type.Width = int32(t.N) case *parser.FloatType: col.Type.Kind = structured.ColumnType_FLOAT col.Type.Width = int32(t.N) col.Type.Precision = int32(t.Prec) case *parser.DecimalType: col.Type.Kind = structured.ColumnType_DECIMAL col.Type.Width = int32(t.N) col.Type.Precision = int32(t.Prec) case *parser.DateType: col.Type.Kind = structured.ColumnType_DATE case *parser.TimeType: col.Type.Kind = structured.ColumnType_TIME case *parser.DateTimeType: col.Type.Kind = structured.ColumnType_DATETIME case *parser.TimestampType: col.Type.Kind = structured.ColumnType_TIMESTAMP case *parser.CharType: col.Type.Kind = structured.ColumnType_CHAR col.Type.Width = int32(t.N) case *parser.BinaryType: col.Type.Kind = structured.ColumnType_BINARY col.Type.Width = int32(t.N) case *parser.TextType: col.Type.Kind = structured.ColumnType_TEXT case *parser.BlobType: col.Type.Kind = structured.ColumnType_BLOB case *parser.EnumType: col.Type.Kind = structured.ColumnType_ENUM col.Type.Vals = t.Vals case *parser.SetType: col.Type.Kind = structured.ColumnType_SET col.Type.Vals = t.Vals } s.Columns = append(s.Columns, col) // Create any associated index. if d.PrimaryKey || d.Unique { index := structured.TableSchema_IndexByName{ Index: structured.Index{ Unique: true, }, ColumnNames: []string{d.Name}, } if d.PrimaryKey { index.Name = "primary" } s.Indexes = append(s.Indexes, index) } case *parser.IndexTableDef: index := structured.TableSchema_IndexByName{ Index: structured.Index{ Name: d.Name, Unique: d.Unique, }, ColumnNames: d.Columns, } s.Indexes = append(s.Indexes, index) default: return s, fmt.Errorf("unsupported table def: %T", def) } } return s, nil }