func (d *ddl) buildFKInfo(fkName model.CIStr, keys []*ast.IndexColName, refer *ast.ReferenceDef) (*model.FKInfo, error) { fkID, err := d.genGlobalID() if err != nil { return nil, errors.Trace(err) } var fkInfo model.FKInfo fkInfo.ID = fkID fkInfo.Name = fkName fkInfo.RefTable = refer.Table.Name fkInfo.Cols = make([]model.CIStr, len(keys)) for i, key := range keys { fkInfo.Cols[i] = key.Column.Name } fkInfo.RefCols = make([]model.CIStr, len(refer.IndexColNames)) for i, key := range refer.IndexColNames { fkInfo.RefCols[i] = key.Column.Name } fkInfo.OnDelete = int(refer.OnDelete.ReferOpt) fkInfo.OnUpdate = int(refer.OnUpdate.ReferOpt) return &fkInfo, nil }
func (d *ddl) buildTableInfo(tableName model.CIStr, cols []*table.Column, constraints []*ast.Constraint) (tbInfo *model.TableInfo, err error) { tbInfo = &model.TableInfo{ Name: tableName, } tbInfo.ID, err = d.genGlobalID() if err != nil { return nil, errors.Trace(err) } for _, v := range cols { v.ID = allocateColumnID(tbInfo) tbInfo.Columns = append(tbInfo.Columns, v.ToInfo()) } for _, constr := range constraints { if constr.Tp == ast.ConstraintForeignKey { for _, fk := range tbInfo.ForeignKeys { if fk.Name.L == strings.ToLower(constr.Name) { return nil, infoschema.ErrCannotAddForeign } } var fk model.FKInfo fk.Name = model.NewCIStr(constr.Name) fk.RefTable = constr.Refer.Table.Name fk.State = model.StatePublic for _, key := range constr.Keys { fk.Cols = append(fk.Cols, key.Column.Name) } for _, key := range constr.Refer.IndexColNames { fk.RefCols = append(fk.RefCols, key.Column.Name) } fk.OnDelete = int(constr.Refer.OnDelete.ReferOpt) fk.OnUpdate = int(constr.Refer.OnUpdate.ReferOpt) if len(fk.Cols) != len(fk.RefCols) { return nil, infoschema.ErrForeignKeyNotMatch } if len(fk.Cols) == 0 { // TODO: In MySQL, this case will report a parse error. return nil, infoschema.ErrCannotAddForeign } tbInfo.ForeignKeys = append(tbInfo.ForeignKeys, &fk) continue } if constr.Tp == ast.ConstraintPrimaryKey { if len(constr.Keys) == 1 { key := constr.Keys[0] col := table.FindCol(cols, key.Column.Name.O) if col == nil { return nil, errKeyColumnDoesNotExits.Gen("key column %s doesn't exist in table", key.Column.Name) } switch col.Tp { case mysql.TypeLong, mysql.TypeLonglong, mysql.TypeTiny, mysql.TypeShort, mysql.TypeInt24: tbInfo.PKIsHandle = true // Avoid creating index for PK handle column. continue } } } // 1. check if the column is exists // 2. add index indexColumns := make([]*model.IndexColumn, 0, len(constr.Keys)) for _, key := range constr.Keys { col := table.FindCol(cols, key.Column.Name.O) if col == nil { return nil, errKeyColumnDoesNotExits.Gen("key column %s doesn't exist in table", key.Column.Name) } indexColumns = append(indexColumns, &model.IndexColumn{ Name: key.Column.Name, Offset: col.Offset, Length: key.Length, }) } idxInfo := &model.IndexInfo{ Name: model.NewCIStr(constr.Name), Columns: indexColumns, State: model.StatePublic, } switch constr.Tp { case ast.ConstraintPrimaryKey: idxInfo.Unique = true idxInfo.Primary = true idxInfo.Name = model.NewCIStr(table.PrimaryKeyName) case ast.ConstraintUniq, ast.ConstraintUniqKey, ast.ConstraintUniqIndex: idxInfo.Unique = true } if constr.Option != nil { idxInfo.Comment = constr.Option.Comment idxInfo.Tp = constr.Option.Tp } else { // Use btree as default index type. idxInfo.Tp = model.IndexTypeBtree } idxInfo.ID = allocateIndexID(tbInfo) tbInfo.Indices = append(tbInfo.Indices, idxInfo) } return }