in webv2/api/schema.go [705:807]
func UpdateForeignKeys(w http.ResponseWriter, r *http.Request) {
tableId := r.FormValue("table")
reqBody, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, fmt.Sprintf("Body Read Error : %v", err), http.StatusInternalServerError)
}
sessionState := session.GetSessionState()
if sessionState.Conv == nil || sessionState.Driver == "" {
http.Error(w, fmt.Sprintf("Schema is not converted or Driver is not configured properly. Please retry converting the database to Spanner."), http.StatusNotFound)
return
}
sessionState.Conv.ConvLock.Lock()
defer sessionState.Conv.ConvLock.Unlock()
newFKs := []ddl.Foreignkey{}
if err = json.Unmarshal(reqBody, &newFKs); err != nil {
http.Error(w, fmt.Sprintf("Request Body parse error : %v", err), http.StatusBadRequest)
return
}
// Check new name for spanner name validity.
newNames := []string{}
newNamesMap := map[string]bool{}
for _, newFk := range newFKs {
if len(newFk.Name) == 0 {
continue
}
for _, oldFk := range sessionState.Conv.SpSchema[tableId].ForeignKeys {
if newFk.Id == oldFk.Id && newFk.Name != oldFk.Name && newFk.Name != "" {
newNames = append(newNames, strings.ToLower(newFk.Name))
}
}
}
for _, newFk := range newFKs {
if len(newFk.Name) == 0 {
continue
}
if _, ok := newNamesMap[strings.ToLower(newFk.Name)]; ok {
http.Error(w, fmt.Sprintf("Found duplicate names in input : %s", strings.ToLower(newFk.Name)), http.StatusBadRequest)
return
}
newNamesMap[strings.ToLower(newFk.Name)] = true
}
if ok, invalidNames := utilities.CheckSpannerNamesValidity(newNames); !ok {
http.Error(w, fmt.Sprintf("Following names are not valid Spanner identifiers: %s", strings.Join(invalidNames, ",")), http.StatusBadRequest)
return
}
// Check that the new names are not already used by existing tables, secondary indexes or foreign key constraints.
if ok, err := utilities.CanRename(newNames, tableId); !ok {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
sp := sessionState.Conv.SpSchema[tableId]
usedNames := sessionState.Conv.UsedNames
// Update session with renamed foreignkeys.
updatedFKs := []ddl.Foreignkey{}
for _, foreignKey := range sp.ForeignKeys {
for i, updatedForeignkey := range newFKs {
if foreignKey.Id == updatedForeignkey.Id && len(updatedForeignkey.ColIds) != 0 && updatedForeignkey.ReferTableId != "" {
delete(usedNames, strings.ToLower(foreignKey.Name))
foreignKey.Name = updatedForeignkey.Name
updatedFKs = append(updatedFKs, foreignKey)
}
if foreignKey.Id == updatedForeignkey.Id && len(updatedForeignkey.ReferColumnIds) == 0 && updatedForeignkey.ReferTableId == "" {
dropFkId := updatedForeignkey.Id
// To remove the interleavable suggestions if they exist on dropping fk
colId := sp.ForeignKeys[i].ColIds[0]
schemaIssue := []internal.SchemaIssue{}
for _, v := range sessionState.Conv.SchemaIssues[tableId].ColumnLevelIssues[colId] {
if v != internal.InterleavedAddColumn && v != internal.InterleavedRenameColumn && v != internal.InterleavedNotInOrder && v != internal.InterleavedChangeColumnSize {
schemaIssue = append(schemaIssue, v)
}
}
if _, ok := sessionState.Conv.SchemaIssues[tableId]; ok {
sessionState.Conv.SchemaIssues[tableId].ColumnLevelIssues[colId] = schemaIssue
}
var err error
sp.ForeignKeys, err = utilities.RemoveFk(sp.ForeignKeys, dropFkId, sessionState.Conv.SrcSchema[tableId], tableId)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
}
}
}
}
sp.ForeignKeys = updatedFKs
sessionState.Conv.SpSchema[tableId] = sp
session.UpdateSessionFile()
convm := session.ConvWithMetadata{
SessionMetadata: sessionState.SessionMetadata,
Conv: *sessionState.Conv,
}
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(convm)
}