2026-08-15 07:29:45 +08:00
|
|
|
|
// Applies init.sql using the packaged sync defaults (build/sync.defaults.json).
|
2026-08-14 07:52:01 +08:00
|
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"database/sql"
|
2026-08-15 07:29:45 +08:00
|
|
|
|
"encoding/json"
|
2026-08-14 07:52:01 +08:00
|
|
|
|
"fmt"
|
|
|
|
|
|
"os"
|
2026-08-15 07:29:45 +08:00
|
|
|
|
"path/filepath"
|
2026-08-14 07:52:01 +08:00
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
|
|
|
|
_ "github.com/go-sql-driver/mysql"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
2026-08-15 07:29:45 +08:00
|
|
|
|
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)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-14 07:52:01 +08:00
|
|
|
|
func main() {
|
2026-08-15 07:29:45 +08:00
|
|
|
|
cfg := loadDefaults()
|
2026-08-14 07:52:01 +08:00
|
|
|
|
if len(os.Args) > 1 && os.Args[1] == "inspect" {
|
2026-08-15 07:29:45 +08:00
|
|
|
|
inspect(cfg)
|
2026-08-14 07:52:01 +08:00
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
raw, err := os.ReadFile("init.sql")
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
panic(err)
|
|
|
|
|
|
}
|
2026-08-15 07:29:45 +08:00
|
|
|
|
db, err := sql.Open("mysql", dsn(cfg, false))
|
2026-08-14 07:52:01 +08:00
|
|
|
|
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
|
2026-08-15 07:29:45 +08:00
|
|
|
|
if err := db.QueryRow("SELECT COUNT(*) FROM " + cfg.Database + ".sync_settings").Scan(&n); err != nil {
|
2026-08-14 07:52:01 +08:00
|
|
|
|
fmt.Println("verify failed:", err)
|
|
|
|
|
|
os.Exit(1)
|
|
|
|
|
|
}
|
2026-08-15 07:29:45 +08:00
|
|
|
|
fmt.Println("ok, sync_settings rows:", n, "host:", cfg.Host)
|
2026-08-14 07:52:01 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func min(a, b int) int {
|
|
|
|
|
|
if a < b {
|
|
|
|
|
|
return a
|
|
|
|
|
|
}
|
|
|
|
|
|
return b
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-15 07:29:45 +08:00
|
|
|
|
func inspect(cfg syncDefaults) {
|
|
|
|
|
|
db, err := sql.Open("mysql", dsn(cfg, true))
|
2026-08-14 07:52:01 +08:00
|
|
|
|
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)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|