// Applies init.sql using the packaged sync defaults (build/sync.defaults.json). package main import ( "database/sql" "encoding/json" "fmt" "os" "path/filepath" "strings" _ "github.com/go-sql-driver/mysql" ) type syncDefaults struct { Host string `json:"host"` Port int `json:"port"` User string `json:"user"` Password string `json:"password"` Database string `json:"database"` } func loadDefaults() syncDefaults { path := filepath.Join("build", "sync.defaults.json") raw, err := os.ReadFile(path) if err != nil { panic(err) } var c syncDefaults if err := json.Unmarshal(raw, &c); err != nil { panic(err) } if c.Port <= 0 { c.Port = 3306 } return c } func dsn(c syncDefaults, withDB bool) string { db := "" if withDB { db = c.Database } return fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?multiStatements=false&charset=utf8mb4", c.User, c.Password, c.Host, c.Port, db) } func main() { cfg := loadDefaults() if len(os.Args) > 1 && os.Args[1] == "inspect" { inspect(cfg) return } raw, err := os.ReadFile("init.sql") if err != nil { panic(err) } db, err := sql.Open("mysql", dsn(cfg, false)) if err != nil { panic(err) } defer db.Close() // init.sql 的升级段依赖会话变量(SET @sql / PREPARE),必须固定在同一连接上执行。 db.SetMaxOpenConns(1) var kept []string for _, line := range strings.Split(string(raw), "\n") { if t := strings.TrimSpace(line); strings.HasPrefix(t, "--") { continue } kept = append(kept, line) } for _, stmt := range strings.Split(strings.Join(kept, "\n"), ";") { s := strings.TrimSpace(stmt) if s == "" { continue } if _, err := db.Exec(s); err != nil { fmt.Println("ERR:", err, "stmt:", s[:min(80, len(s))]) os.Exit(1) } } var n int if err := db.QueryRow("SELECT COUNT(*) FROM " + cfg.Database + ".sync_settings").Scan(&n); err != nil { fmt.Println("verify failed:", err) os.Exit(1) } fmt.Println("ok, sync_settings rows:", n, "host:", cfg.Host) } func min(a, b int) int { if a < b { return a } return b } func inspect(cfg syncDefaults) { db, err := sql.Open("mysql", dsn(cfg, true)) if err != nil { panic(err) } defer db.Close() rows, err := db.Query("SELECT user_id, name, LENGTH(value), updated_at FROM sync_settings ORDER BY user_id, name") if err != nil { panic(err) } defer rows.Close() for rows.Next() { var uid int64 var name, at string var n int if err := rows.Scan(&uid, &name, &n, &at); err != nil { panic(err) } fmt.Printf("user=%d name=%-12s bytes=%-6d at=%s\n", uid, name, n, at) } }