|
|
|
@ -13,6 +13,7 @@ import ( |
|
|
|
|
"os" |
|
|
|
|
"path" |
|
|
|
|
"path/filepath" |
|
|
|
|
"regexp" |
|
|
|
|
"strings" |
|
|
|
|
"time" |
|
|
|
|
|
|
|
|
@ -284,11 +285,98 @@ func dropTableColumns(sess *xorm.Session, tableName string, columnNames ...strin |
|
|
|
|
if tableName == "" || len(columnNames) == 0 { |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
// TODO: This will not work if there are foreign keys
|
|
|
|
|
|
|
|
|
|
switch { |
|
|
|
|
case setting.UseSQLite3: |
|
|
|
|
log.Warn("Unable to drop columns in SQLite") |
|
|
|
|
case setting.UseMySQL, setting.UseTiDB, setting.UsePostgreSQL: |
|
|
|
|
// First drop the indexes on the columns
|
|
|
|
|
res, errIndex := sess.Query(fmt.Sprintf("PRAGMA index_list(`%s`)", tableName)) |
|
|
|
|
if errIndex != nil { |
|
|
|
|
return errIndex |
|
|
|
|
} |
|
|
|
|
for _, row := range res { |
|
|
|
|
indexName := row["name"] |
|
|
|
|
indexRes, err := sess.Query(fmt.Sprintf("PRAGMA index_info(`%s`)", indexName)) |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
if len(indexRes) != 1 { |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
indexColumn := string(indexRes[0]["name"]) |
|
|
|
|
for _, name := range columnNames { |
|
|
|
|
if name == indexColumn { |
|
|
|
|
_, err := sess.Exec(fmt.Sprintf("DROP INDEX `%s`", indexName)) |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Here we need to get the columns from the original table
|
|
|
|
|
sql := fmt.Sprintf("SELECT sql FROM sqlite_master WHERE tbl_name='%s' and type='table'", tableName) |
|
|
|
|
res, err := sess.Query(sql) |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
tableSQL := string(res[0]["sql"]) |
|
|
|
|
tableSQL = tableSQL[strings.Index(tableSQL, "("):] |
|
|
|
|
for _, name := range columnNames { |
|
|
|
|
tableSQL = regexp.MustCompile(regexp.QuoteMeta("`"+name+"`")+"[^`,)]*[,)]").ReplaceAllString(tableSQL, "") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
columns := regexp.MustCompile("`([^`]*)`").FindAllString(tableSQL, -1) |
|
|
|
|
|
|
|
|
|
tableSQL = fmt.Sprintf("CREATE TABLE `new_%s_new` ", tableName) + tableSQL |
|
|
|
|
if _, err := sess.Exec(tableSQL); err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Now restore the data
|
|
|
|
|
columnsSeparated := strings.Join(columns, ",") |
|
|
|
|
insertSQL := fmt.Sprintf("INSERT INTO `new_%s_new` (%s) SELECT %s FROM %s", tableName, columnsSeparated, columnsSeparated, tableName) |
|
|
|
|
if _, err := sess.Exec(insertSQL); err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Now drop the old table
|
|
|
|
|
if _, err := sess.Exec(fmt.Sprintf("DROP TABLE `%s`", tableName)); err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Rename the table
|
|
|
|
|
if _, err := sess.Exec(fmt.Sprintf("ALTER TABLE `new_%s_new` RENAME TO `%s`", tableName, tableName)); err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
case setting.UsePostgreSQL: |
|
|
|
|
cols := "" |
|
|
|
|
for _, col := range columnNames { |
|
|
|
|
if cols != "" { |
|
|
|
|
cols += ", " |
|
|
|
|
} |
|
|
|
|
cols += "DROP COLUMN `" + col + "` CASCADE" |
|
|
|
|
} |
|
|
|
|
if _, err := sess.Exec(fmt.Sprintf("ALTER TABLE `%s` %s", tableName, cols)); err != nil { |
|
|
|
|
return fmt.Errorf("Drop table `%s` columns %v: %v", tableName, columnNames, err) |
|
|
|
|
} |
|
|
|
|
case setting.UseMySQL, setting.UseTiDB: |
|
|
|
|
// Drop indexes on columns first
|
|
|
|
|
sql := fmt.Sprintf("SHOW INDEX FROM %s WHERE column_name IN ('%s')", tableName, strings.Join(columnNames, "','")) |
|
|
|
|
res, err := sess.Query(sql) |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
for _, index := range res { |
|
|
|
|
indexName := index["column_name"] |
|
|
|
|
_, err := sess.Exec(fmt.Sprintf("DROP INDEX `%s` ON `%s`", indexName, tableName)) |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Now drop the columns
|
|
|
|
|
cols := "" |
|
|
|
|
for _, col := range columnNames { |
|
|
|
|
if cols != "" { |
|
|
|
|