签入脚本

This commit is contained in:
小蚂蚁云
2026-10-20 11:37:25 +08:00
commit 7f5e8470af
909 changed files with 4045080 additions and 0 deletions
+114
View File
@@ -0,0 +1,114 @@
package migrate
import (
"context"
"fmt"
"github.com/gogf/gf/v2/database/gdb"
)
// ============================== 数据库连接 ==============================
// openConn 按 DSN 动态建立连接并探活
//
// 通过 gdb.New 注册独立命名节点,不触碰 config.yaml 中的默认连接
func openConn(ctx context.Context, node string, dsn DSN) (gdb.DB, error) {
link, err := buildLink(dsn)
if err != nil {
return nil, err
}
db, err := gdb.New(gdb.ConfigNode{
Name: node,
Type: dsn.Type,
Link: link,
})
if err != nil {
return nil, fmt.Errorf("连接 %s 库失败: %v", node, err)
}
if _, err = db.Query(ctx, "SELECT 1"); err != nil {
return nil, fmt.Errorf("%s 库探活失败: %v", node, err)
}
return db, nil
}
// ensureDatabase 目标库不存在时先创建
//
// MySQL、PostgreSQL、SQL Server 经维护库建库;Oracle 与 SQLite 无需预建
func ensureDatabase(ctx context.Context, dsn DSN) error {
var maintainDB, createSQL, checkSQL string
switch dsn.Type {
case "mysql":
maintainDB, checkSQL = "", "SELECT SCHEMA_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME = ?"
createSQL = "CREATE DATABASE `" + dsn.Database + "` CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci"
case "pgsql":
maintainDB, checkSQL = "postgres", "SELECT 1 FROM pg_database WHERE datname = ?"
createSQL = `CREATE DATABASE "` + dsn.Database + `"`
case "mssql":
maintainDB, checkSQL = "master", "SELECT 1 FROM sys.databases WHERE name = ?"
createSQL = "CREATE DATABASE [" + dsn.Database + "]"
default:
return nil // oracle/sqlite 无需预建
}
checkDSN := dsn
checkDSN.Database = maintainDB
link, err := buildLink(checkDSN)
if err != nil {
return err
}
maintain, err := gdb.New(gdb.ConfigNode{Name: "migrate_maintain", Type: dsn.Type, Link: link})
if err != nil {
return fmt.Errorf("连接 %s 维护库失败: %v", dsn.Type, err)
}
defer maintain.Close(ctx)
row, err := maintain.Query(ctx, checkSQL, dsn.Database)
if err != nil {
return fmt.Errorf("检查目标库是否存在失败: %v", err)
}
if len(row) > 0 {
return nil // 已存在
}
if _, err = maintain.Exec(ctx, createSQL); err != nil {
return fmt.Errorf("创建目标库 %s 失败: %v", dsn.Database, err)
}
return nil
}
// buildLink 将 DSN 转换为 gdb link 串
//
// 各方言按驱动约定格式组装,对齐配置示例
func buildLink(dsn DSN) (string, error) {
switch dsn.Type {
case "mysql":
return fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=true&loc=Local",
dsn.Username, dsn.Password, dsn.Host, dsn.Port, dsn.Database), nil
case "pgsql":
return fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?sslmode=disable",
dsn.Username, dsn.Password, dsn.Host, dsn.Port, dsn.Database), nil
case "mssql":
return fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?encrypt=disable",
dsn.Username, dsn.Password, dsn.Host, dsn.Port, dsn.Database), nil
case "oracle":
return fmt.Sprintf("%s:%s@tcp(%s:%s)/%s",
dsn.Username, dsn.Password, dsn.Host, dsn.Port, dsn.Database), nil
case "sqlite":
if dsn.Database == "" {
return "", fmt.Errorf("sqlite 需以 -src-database/-dst-database 指定数据库文件路径")
}
return fmt.Sprintf("sqlite::@file(%s)", dsn.Database), nil
}
return "", fmt.Errorf("不支持的数据库类型: %s", dsn.Type)
}
// tableExists 判断目标库中同名表是否已存在
func tableExists(ctx context.Context, db gdb.DB, table string) (bool, error) {
tables, err := db.Tables(ctx)
if err != nil {
return false, err
}
for _, t := range tables {
if t == table {
return true, nil
}
}
return false, nil
}