mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2024-11-18 07:54:28 +00:00
Preliminary MySQL support. Barely tested.
Requirements: MySQL/MariaDB need to be configured with this settings: innodb_file_format = Barracuda innodb_file_per_table = On innodb_large_prefix = On to support key prefix length up to 3042 bytes. MySQL/MariaDB DSN will need this parameter: parseTime=true as per [1] The migration system itself mostly inspired by Rails (ActiveRecord), but it still rough at the edges. Could use some inputs. Next Todo: more testing! [1] https://github.com/go-sql-driver/mysql#parsetime
This commit is contained in:
parent
5903eb8f04
commit
7cf4f2eb89
8 changed files with 96 additions and 35 deletions
|
@ -51,7 +51,9 @@ func Init(name, datasource string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
migration := migrate.New(db)
|
migration := migrate.New(db)
|
||||||
migration.All().Migrate()
|
if err := migration.All().Migrate(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@ func (r *rev1st) Up(mg *MigrationDriver) error {
|
||||||
|
|
||||||
if _, err := mg.CreateTable("repos", []string{
|
if _, err := mg.CreateTable("repos", []string{
|
||||||
t.Integer("id", PRIMARYKEY, AUTOINCREMENT),
|
t.Integer("id", PRIMARYKEY, AUTOINCREMENT),
|
||||||
t.Varchar("slug", 1024, UNIQUE),
|
t.String("slug", UNIQUE),
|
||||||
t.String("host"),
|
t.String("host"),
|
||||||
t.String("owner"),
|
t.String("owner"),
|
||||||
t.String("name"),
|
t.String("name"),
|
||||||
|
@ -113,7 +113,7 @@ func (r *rev1st) Up(mg *MigrationDriver) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := mg.CreateTable("settings", []string{
|
_, err := mg.CreateTable("settings", []string{
|
||||||
t.Integer("id", PRIMARYKEY),
|
t.Integer("id", PRIMARYKEY, AUTOINCREMENT),
|
||||||
t.String("github_key"),
|
t.String("github_key"),
|
||||||
t.String("github_secret"),
|
t.String("github_secret"),
|
||||||
t.String("bitbucket_key"),
|
t.String("bitbucket_key"),
|
||||||
|
|
|
@ -13,11 +13,11 @@ func (r *rev2nd) Up(mg *MigrationDriver) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := mg.AddIndex("members", []string{"team_id"}, ""); err != nil {
|
if _, err := mg.AddIndex("members", []string{"team_id"}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := mg.AddIndex("members", []string{"user_id"}, ""); err != nil {
|
if _, err := mg.AddIndex("members", []string{"user_id"}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,27 +25,27 @@ func (r *rev2nd) Up(mg *MigrationDriver) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := mg.AddIndex("commits", []string{"repo_id"}, ""); err != nil {
|
if _, err := mg.AddIndex("commits", []string{"repo_id"}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := mg.AddIndex("commits", []string{"repo_id", "branch"}, ""); err != nil {
|
if _, err := mg.AddIndex("commits", []string{"repo_id", "branch"}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := mg.AddIndex("repos", []string{"team_id"}, ""); err != nil {
|
if _, err := mg.AddIndex("repos", []string{"team_id"}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := mg.AddIndex("repos", []string{"user_id"}, ""); err != nil {
|
if _, err := mg.AddIndex("repos", []string{"user_id"}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := mg.AddIndex("builds", []string{"commit_id"}, ""); err != nil {
|
if _, err := mg.AddIndex("builds", []string{"commit_id"}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := mg.AddIndex("builds", []string{"commit_id", "slug"}, "")
|
_, err := mg.AddIndex("builds", []string{"commit_id", "slug"})
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ type Operation interface {
|
||||||
|
|
||||||
RenameColumns(tableName string, columnChanges map[string]string) (sql.Result, error)
|
RenameColumns(tableName string, columnChanges map[string]string) (sql.Result, error)
|
||||||
|
|
||||||
AddIndex(tableName string, columns []string, flag string) (sql.Result, error)
|
AddIndex(tableName string, columns []string, flags ...string) (sql.Result, error)
|
||||||
|
|
||||||
DropIndex(tableName string, columns []string) (sql.Result, error)
|
DropIndex(tableName string, columns []string) (sql.Result, error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ import (
|
||||||
|
|
||||||
const migrationTableStmt = `
|
const migrationTableStmt = `
|
||||||
CREATE TABLE IF NOT EXISTS migration (
|
CREATE TABLE IF NOT EXISTS migration (
|
||||||
revision NUMBER PRIMARY KEY
|
revision BIGINT PRIMARY KEY
|
||||||
)
|
)
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,8 @@ package migrate
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
"fmt"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type mysqlDriver struct {
|
type mysqlDriver struct {
|
||||||
|
@ -13,41 +14,96 @@ func MySQL(tx *sql.Tx) *MigrationDriver {
|
||||||
return &MigrationDriver{
|
return &MigrationDriver{
|
||||||
Tx: tx,
|
Tx: tx,
|
||||||
Operation: &mysqlDriver{Tx: tx},
|
Operation: &mysqlDriver{Tx: tx},
|
||||||
|
T: &columnType{
|
||||||
|
AttrMap: map[int]string{AUTOINCREMENT: "AUTO_INCREMENT"},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mysqlDriver) CreateTable(tableName string, args []string) (sql.Result, error) {
|
func (m *mysqlDriver) CreateTable(tableName string, args []string) (sql.Result, error) {
|
||||||
return nil, errors.New("not implemented yet")
|
return m.Tx.Exec(fmt.Sprintf("CREATE TABLE %s (%s) ROW_FORMAT=DYNAMIC", tableName, strings.Join(args, ", ")))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mysqlDriver) RenameTable(tableName, newName string) (sql.Result, error) {
|
func (m *mysqlDriver) RenameTable(tableName, newName string) (sql.Result, error) {
|
||||||
return nil, errors.New("not implemented yet")
|
return m.Tx.Exec(fmt.Sprintf("ALTER TABLE %s RENAME TO %s", tableName, newName))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mysqlDriver) DropTable(tableName string) (sql.Result, error) {
|
func (m *mysqlDriver) DropTable(tableName string) (sql.Result, error) {
|
||||||
return nil, errors.New("not implemented yet")
|
return m.Tx.Exec(fmt.Sprintf("DROP TABLE IF EXISTS %s", tableName))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mysqlDriver) AddColumn(tableName, columnSpec string) (sql.Result, error) {
|
func (m *mysqlDriver) AddColumn(tableName, columnSpec string) (sql.Result, error) {
|
||||||
return nil, errors.New("not implemented yet")
|
return m.Tx.Exec(fmt.Sprintf("ALTER TABLE %s ADD COLUMN (%s)", tableName, columnSpec))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mysqlDriver) ChangeColumn(tableName, columnName, newSpecs string) (sql.Result, error) {
|
func (m *mysqlDriver) ChangeColumn(tableName, columnName, newSpecs string) (sql.Result, error) {
|
||||||
return nil, errors.New("not implemented yet")
|
return m.Tx.Exec(fmt.Sprintf("ALTER TABLE %s MODIFY %s %s", tableName, columnName, newSpecs))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mysqlDriver) DropColumns(tableName string, columnsToDrop []string) (sql.Result, error) {
|
func (m *mysqlDriver) DropColumns(tableName string, columnsToDrop []string) (sql.Result, error) {
|
||||||
return nil, errors.New("not implemented yet")
|
for k, v := range columnsToDrop {
|
||||||
|
columnsToDrop[k] = fmt.Sprintf("DROP %s", v)
|
||||||
|
}
|
||||||
|
return m.Tx.Exec(fmt.Sprintf("ALTER TABLE %s %s", tableName, strings.Join(columnsToDrop, ", ")))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mysqlDriver) RenameColumns(tableName string, columnChanges map[string]string) (sql.Result, error) {
|
func (m *mysqlDriver) RenameColumns(tableName string, columnChanges map[string]string) (sql.Result, error) {
|
||||||
return nil, errors.New("not implemented yet")
|
var columns []string
|
||||||
|
|
||||||
|
tableSQL, err := m.getTableDefinition(tableName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
columns, err = fetchColumns(tableSQL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var colspec []string
|
||||||
|
for k, v := range columnChanges {
|
||||||
|
for _, col := range columns {
|
||||||
|
col = strings.Trim(col, " \n")
|
||||||
|
cols := strings.SplitN(col, " ", 2)
|
||||||
|
if quote(k) == cols[0] {
|
||||||
|
colspec = append(colspec, fmt.Sprintf("CHANGE %s %s %s", k, v, cols[1]))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return m.Tx.Exec(fmt.Sprintf("ALTER TABLE %s %s", tableName, strings.Join(colspec, ", ")))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mysqlDriver) AddIndex(tableName string, columns []string, flag string) (sql.Result, error) {
|
func (m *mysqlDriver) AddIndex(tableName string, columns []string, flags ...string) (sql.Result, error) {
|
||||||
return nil, errors.New("not implemented yet")
|
flag := ""
|
||||||
|
if len(flags) > 0 {
|
||||||
|
switch strings.ToUpper(flags[0]) {
|
||||||
|
case "UNIQUE":
|
||||||
|
fallthrough
|
||||||
|
case "FULLTEXT":
|
||||||
|
fallthrough
|
||||||
|
case "SPATIAL":
|
||||||
|
flag = flags[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m.Tx.Exec(fmt.Sprintf("CREATE %s INDEX %s ON %s (%s)", flag,
|
||||||
|
indexName(tableName, columns), tableName, strings.Join(columns, ", ")))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mysqlDriver) DropIndex(tableName string, columns []string) (sql.Result, error) {
|
func (m *mysqlDriver) DropIndex(tableName string, columns []string) (sql.Result, error) {
|
||||||
return nil, errors.New("not implemented yet")
|
return m.Tx.Exec(fmt.Sprintf("DROP INDEX %s on %s", indexName(tableName, columns), tableName))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mysqlDriver) getTableDefinition(tableName string) (string, error) {
|
||||||
|
var name, def string
|
||||||
|
st := fmt.Sprintf("SHOW CREATE TABLE %s", tableName)
|
||||||
|
if err := m.Tx.QueryRow(st).Scan(&name, &def); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return def, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func quote(name string) string {
|
||||||
|
return fmt.Sprintf("`%s`", name)
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,7 @@ func (p *postgresqlDriver) RenameColumns(tableName string, columnChanges map[str
|
||||||
return nil, errors.New("not implemented yet")
|
return nil, errors.New("not implemented yet")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *postgresqlDriver) AddIndex(tableName string, columns []string, flag string) (sql.Result, error) {
|
func (p *postgresqlDriver) AddIndex(tableName string, columns []string, flags ...string) (sql.Result, error) {
|
||||||
return nil, errors.New("not implemented yet")
|
return nil, errors.New("not implemented yet")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,19 +19,19 @@ func SQLite(tx *sql.Tx) *MigrationDriver {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *sqliteDriver) CreateTable(tableName string, args []string) (sql.Result, error) {
|
func (s *sqliteDriver) CreateTable(tableName string, args []string) (sql.Result, error) {
|
||||||
return s.Tx.Exec(fmt.Sprintf("CREATE TABLE %s (%s);", tableName, strings.Join(args, ", ")))
|
return s.Tx.Exec(fmt.Sprintf("CREATE TABLE %s (%s)", tableName, strings.Join(args, ", ")))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *sqliteDriver) RenameTable(tableName, newName string) (sql.Result, error) {
|
func (s *sqliteDriver) RenameTable(tableName, newName string) (sql.Result, error) {
|
||||||
return s.Tx.Exec(fmt.Sprintf("ALTER TABLE %s RENAME TO %s;", tableName, newName))
|
return s.Tx.Exec(fmt.Sprintf("ALTER TABLE %s RENAME TO %s", tableName, newName))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *sqliteDriver) DropTable(tableName string) (sql.Result, error) {
|
func (s *sqliteDriver) DropTable(tableName string) (sql.Result, error) {
|
||||||
return s.Tx.Exec(fmt.Sprintf("DROP TABLE IF EXISTS %s;", tableName))
|
return s.Tx.Exec(fmt.Sprintf("DROP TABLE IF EXISTS %s", tableName))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *sqliteDriver) AddColumn(tableName, columnSpec string) (sql.Result, error) {
|
func (s *sqliteDriver) AddColumn(tableName, columnSpec string) (sql.Result, error) {
|
||||||
return s.Tx.Exec(fmt.Sprintf("ALTER TABLE %s ADD COLUMN %s;", tableName, columnSpec))
|
return s.Tx.Exec(fmt.Sprintf("ALTER TABLE %s ADD COLUMN %s", tableName, columnSpec))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *sqliteDriver) ChangeColumn(tableName, columnName, newType string) (sql.Result, error) {
|
func (s *sqliteDriver) ChangeColumn(tableName, columnName, newType string) (sql.Result, error) {
|
||||||
|
@ -173,7 +173,7 @@ func (s *sqliteDriver) DropColumns(tableName string, columnsToDrop []string) (sq
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move data from old table
|
// Move data from old table
|
||||||
if result, err = s.Tx.Exec(fmt.Sprintf("INSERT INTO %s SELECT %s FROM %s;", tableName,
|
if result, err = s.Tx.Exec(fmt.Sprintf("INSERT INTO %s SELECT %s FROM %s", tableName,
|
||||||
strings.Join(selectName(preparedColumns), ", "), proxy)); err != nil {
|
strings.Join(selectName(preparedColumns), ", "), proxy)); err != nil {
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
@ -291,9 +291,12 @@ func (s *sqliteDriver) RenameColumns(tableName string, columnChanges map[string]
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *sqliteDriver) AddIndex(tableName string, columns []string, flag string) (sql.Result, error) {
|
func (s *sqliteDriver) AddIndex(tableName string, columns []string, flags ...string) (sql.Result, error) {
|
||||||
if strings.ToUpper(flag) != "UNIQUE" {
|
flag := ""
|
||||||
flag = ""
|
if len(flags) > 0 {
|
||||||
|
if strings.ToUpper(flags[0]) == "UNIQUE" {
|
||||||
|
flag = flags[0]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return s.Tx.Exec(fmt.Sprintf("CREATE %s INDEX %s ON %s (%s)", flag, indexName(tableName, columns),
|
return s.Tx.Exec(fmt.Sprintf("CREATE %s INDEX %s ON %s (%s)", flag, indexName(tableName, columns),
|
||||||
tableName, strings.Join(columns, ", ")))
|
tableName, strings.Join(columns, ", ")))
|
||||||
|
@ -305,7 +308,7 @@ func (s *sqliteDriver) DropIndex(tableName string, columns []string) (sql.Result
|
||||||
|
|
||||||
func (s *sqliteDriver) getTableDefinition(tableName string) (string, error) {
|
func (s *sqliteDriver) getTableDefinition(tableName string) (string, error) {
|
||||||
var sql string
|
var sql string
|
||||||
query := `SELECT sql FROM sqlite_master WHERE type='table' and name=?;`
|
query := `SELECT sql FROM sqlite_master WHERE type='table' and name=?`
|
||||||
err := s.Tx.QueryRow(query, tableName).Scan(&sql)
|
err := s.Tx.QueryRow(query, tableName).Scan(&sql)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -316,7 +319,7 @@ func (s *sqliteDriver) getTableDefinition(tableName string) (string, error) {
|
||||||
func (s *sqliteDriver) getIndexDefinition(tableName string) ([]string, error) {
|
func (s *sqliteDriver) getIndexDefinition(tableName string) ([]string, error) {
|
||||||
var sqls []string
|
var sqls []string
|
||||||
|
|
||||||
query := `SELECT sql FROM sqlite_master WHERE type='index' and tbl_name=?;`
|
query := `SELECT sql FROM sqlite_master WHERE type='index' and tbl_name=?`
|
||||||
rows, err := s.Tx.Query(query, tableName)
|
rows, err := s.Tx.Query(query, tableName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return sqls, err
|
return sqls, err
|
||||||
|
|
Loading…
Reference in a new issue