first commit
This commit is contained in:
commit
c6a1103562
BIN
BkupDB.exe
Normal file
BIN
BkupDB.exe
Normal file
Binary file not shown.
318
BkupDB.go
Normal file
318
BkupDB.go
Normal file
@ -0,0 +1,318 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
type Cfg struct {
|
||||
Settings Settings `yaml:"Settings"`
|
||||
DBConfig DBConfig `yaml:"DBConfig"`
|
||||
FormatColumns FormatColumns `yaml:"FormatColumns"`
|
||||
}
|
||||
|
||||
type Settings struct {
|
||||
Condition string `yaml:"Condition"`
|
||||
PrimaryKey string `yaml:"PrimaryKey"`
|
||||
DeleteSource bool `yaml:"DeleteSource"`
|
||||
}
|
||||
|
||||
type FormatColumns struct {
|
||||
Enablement bool `yaml:"Enablement"`
|
||||
Reference string `yaml:"Reference"`
|
||||
Year string `yaml:"Year"`
|
||||
Month string `yaml:"Month"`
|
||||
Day string `yaml:"Day"`
|
||||
Week string `yaml:"Week"`
|
||||
}
|
||||
|
||||
type DBConfig struct {
|
||||
Username string `yaml:"Username"`
|
||||
Password string `yaml:"Password"`
|
||||
Server string `yaml:"Server"`
|
||||
Port string `yaml:"Port"`
|
||||
Database string `yaml:"Database"`
|
||||
SourceTable string `yaml:"SourceTable"`
|
||||
DestinationTable string `yaml:"DestinationTable"`
|
||||
SourceColumns []string `yaml:"SourceColumns"`
|
||||
DestinationColumns []string `yaml:"DestinationColumns"`
|
||||
}
|
||||
|
||||
var cfg = Cfg{}
|
||||
var dsn string
|
||||
|
||||
func main() {
|
||||
log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds)
|
||||
log.SetOutput(os.Stdout)
|
||||
|
||||
self := strings.TrimSuffix(os.Args[0], ".exe")
|
||||
file := self + ".yml"
|
||||
txt, err := os.ReadFile(file)
|
||||
if err != nil {
|
||||
log.Printf("[ERR] %s\r\n", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
err = yaml.Unmarshal(txt, &cfg)
|
||||
if err != nil {
|
||||
log.Printf("[ERR] %s\r\n", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// srcCols := cfg.DBConfig.Columns
|
||||
// dstCols := cfg.DBConfig.Columns
|
||||
// if len(srcCols) != len(dstCols) {
|
||||
// log.Println("[ERR] Mismatched Length Of Source Columns And Destination Columns.")
|
||||
// os.Exit(1)
|
||||
// }
|
||||
|
||||
condition := cfg.Settings.Condition
|
||||
log.Printf("[MSG] Condition: %s\r\n", condition)
|
||||
|
||||
if condition == "" {
|
||||
log.Println("[ERR] Missing Query Condition.")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
dsn = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s",
|
||||
cfg.DBConfig.Username,
|
||||
cfg.DBConfig.Password,
|
||||
cfg.DBConfig.Server,
|
||||
cfg.DBConfig.Port,
|
||||
cfg.DBConfig.Database,
|
||||
)
|
||||
|
||||
qry, err := retrieveData(condition)
|
||||
if err != nil {
|
||||
log.Printf("[ERR] %v\r\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
log.Printf("[MSG] Selected Rows: %d\r\n", len(qry))
|
||||
if len(qry) == 0 {
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
err = backupData(qry)
|
||||
if err != nil {
|
||||
log.Printf("[ERR] %v\r\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func retrieveData(condition string) ([]map[string]interface{}, error) {
|
||||
rst := make([]map[string]interface{}, 0)
|
||||
dbo, err := sql.Open("mysql", dsn)
|
||||
if err != nil {
|
||||
return rst, err
|
||||
}
|
||||
defer dbo.Close()
|
||||
err = dbo.Ping()
|
||||
if err != nil {
|
||||
return rst, err
|
||||
}
|
||||
|
||||
cols := ""
|
||||
for _, c := range cfg.DBConfig.SourceColumns {
|
||||
cols = cols + c + ","
|
||||
}
|
||||
cols = strings.TrimSuffix(cols, ",")
|
||||
|
||||
qry := fmt.Sprintf("SELECT %s FROM %s.%s",
|
||||
cols,
|
||||
cfg.DBConfig.Database,
|
||||
cfg.DBConfig.SourceTable,
|
||||
)
|
||||
flt := fmt.Sprintf("WHERE %s;", condition)
|
||||
if condition != "" {
|
||||
qry = qry + " " + flt
|
||||
}
|
||||
|
||||
lnth := len(cfg.DBConfig.SourceColumns)
|
||||
vals := make([]interface{}, lnth)
|
||||
valsPtr := make([]interface{}, lnth)
|
||||
for i := 0; i < lnth; i++ {
|
||||
valsPtr[i] = &vals[i]
|
||||
}
|
||||
|
||||
rows, err := dbo.Query(qry)
|
||||
if err != nil {
|
||||
return rst, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
err := rows.Scan(valsPtr...)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
row := make(map[string]interface{}, 0)
|
||||
for i, val := range vals {
|
||||
key := cfg.DBConfig.SourceColumns[i]
|
||||
var v interface{}
|
||||
b, ok := val.([]byte)
|
||||
if ok {
|
||||
v = string(b)
|
||||
} else {
|
||||
v = val
|
||||
}
|
||||
row[key] = v
|
||||
}
|
||||
rst = append(rst, row)
|
||||
}
|
||||
return rst, nil
|
||||
}
|
||||
|
||||
func backupData(data []map[string]interface{}) error {
|
||||
dbo, err := sql.Open("mysql", dsn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer dbo.Close()
|
||||
err = dbo.Ping()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cols := ""
|
||||
for _, c := range cfg.DBConfig.DestinationColumns {
|
||||
cols = cols + c + ","
|
||||
}
|
||||
|
||||
// Append Formated Column Keys
|
||||
if cfg.FormatColumns.Enablement {
|
||||
cols = cols + strings.Join(
|
||||
[]string{
|
||||
cfg.FormatColumns.Year,
|
||||
cfg.FormatColumns.Month,
|
||||
cfg.FormatColumns.Day,
|
||||
cfg.FormatColumns.Week,
|
||||
},
|
||||
",",
|
||||
)
|
||||
}
|
||||
cols = strings.TrimSuffix(cols, ",")
|
||||
|
||||
var timeStr string = ""
|
||||
var timeVal time.Time
|
||||
for i, d := range data {
|
||||
log.Printf("[MSG] #%d: %#v\r\n", i+1, d)
|
||||
vals := ""
|
||||
for _, c := range cfg.DBConfig.DestinationColumns {
|
||||
for k, v := range d {
|
||||
if k == c {
|
||||
vals = vals + fmt.Sprintf("%#v,", v)
|
||||
}
|
||||
if k == cfg.FormatColumns.Reference {
|
||||
timeStr = v.(string)
|
||||
timeVal, err = time.Parse("2006-01-02 15:04:05", timeStr)
|
||||
if err != nil {
|
||||
log.Printf("[ERR] #%d: %#v\r\n", i+1, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Append Formated Column Values
|
||||
if cfg.FormatColumns.Enablement {
|
||||
vals = vals + strings.Join(
|
||||
[]string{
|
||||
fmt.Sprintf("%#v", timeVal.Format("2006")),
|
||||
fmt.Sprintf("%#v", timeVal.Format("01")),
|
||||
fmt.Sprintf("%#v", timeVal.Format("02")),
|
||||
fmt.Sprintf("%#v", calculateWeek(timeVal)),
|
||||
},
|
||||
",",
|
||||
)
|
||||
}
|
||||
vals = strings.TrimSuffix(vals, ",")
|
||||
|
||||
tx, err := dbo.Begin()
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
log.Printf("[ERR] txBegin: %v\r\n\r\n", err)
|
||||
continue
|
||||
}
|
||||
|
||||
stmt, err := tx.Prepare(fmt.Sprintf("INSERT INTO %s.%s (%s) VALUES (%s);",
|
||||
cfg.DBConfig.Database,
|
||||
cfg.DBConfig.DestinationTable,
|
||||
cols,
|
||||
vals,
|
||||
))
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
log.Printf("[ERR] txPrepare_Insert: %v\r\n\r\n", err)
|
||||
continue
|
||||
}
|
||||
defer stmt.Close()
|
||||
|
||||
_, err = stmt.Exec()
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
log.Printf("[ERR] txExecute_Insert: %v\r\n\r\n", err)
|
||||
continue
|
||||
}
|
||||
log.Printf("[MSG] Backed Up: %s=%s\r\n", cfg.Settings.PrimaryKey, d[cfg.Settings.PrimaryKey])
|
||||
|
||||
if cfg.Settings.DeleteSource {
|
||||
stmt, err = tx.Prepare(fmt.Sprintf("DELETE FROM %s.%s WHERE %s=%s;",
|
||||
cfg.DBConfig.Database,
|
||||
cfg.DBConfig.SourceTable,
|
||||
cfg.Settings.PrimaryKey,
|
||||
fmt.Sprintf("%#v", d[cfg.Settings.PrimaryKey]),
|
||||
))
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
log.Printf("[ERR] txPrepare_Delete: %v\r\n\r\n", err)
|
||||
continue
|
||||
}
|
||||
defer stmt.Close()
|
||||
|
||||
_, err = stmt.Exec()
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
log.Printf("[ERR] txExecute_Delete: %v\r\n\r\n", err)
|
||||
continue
|
||||
}
|
||||
log.Printf("[MSG] Deleted Souce: %s=%s\r\n", cfg.Settings.PrimaryKey, d[cfg.Settings.PrimaryKey])
|
||||
}
|
||||
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
log.Printf("[ERR] txCommit: %v\r\n\r\n", err)
|
||||
continue
|
||||
}
|
||||
log.Printf("[MSG] ********** Transaction Commited.\r\n\r\n")
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func calculateWeek(t time.Time) string {
|
||||
yearDay := t.YearDay()
|
||||
lastYearEndDay := t.AddDate(0, 0, -yearDay)
|
||||
lastYearEndDayWeek := int(lastYearEndDay.Weekday())
|
||||
firstWeekDays := 7
|
||||
if lastYearEndDayWeek != 0 {
|
||||
firstWeekDays = 7 - lastYearEndDayWeek
|
||||
}
|
||||
week := 0
|
||||
if yearDay <= firstWeekDays {
|
||||
week = 1
|
||||
} else {
|
||||
plusDay := 0
|
||||
if (yearDay-firstWeekDays)%7 > 0 {
|
||||
plusDay = 1
|
||||
}
|
||||
week = (yearDay-firstWeekDays)/7 + 1 + plusDay
|
||||
}
|
||||
return fmt.Sprintf("%02d", week)
|
||||
}
|
21
BkupDB.yml
Normal file
21
BkupDB.yml
Normal file
@ -0,0 +1,21 @@
|
||||
Settings:
|
||||
Condition: 'TIMESTAMPDIFF(HOUR,last_change,NOW()) > 72'
|
||||
PrimaryKey: 'seqid'
|
||||
DeleteSource: true
|
||||
DBConfig:
|
||||
Username: apisvc
|
||||
Password: wcqte
|
||||
Server: 127.0.0.1
|
||||
Port: 3306
|
||||
Database: ewsv3_f715
|
||||
SourceTable: uutinfo
|
||||
DestinationTable: uutinfobkup
|
||||
SourceColumns: [seqid,usn,mac,ipaddr,relay,item,status,message,first_ack,last_ack,last_change,partno,mo,sku,line,stage]
|
||||
DestinationColumns: [usn,mac,ipaddr,relay,item,status,message,first_ack,last_ack,last_change,partno,mo,sku,line,stage]
|
||||
FormatColumns:
|
||||
Enablement: true
|
||||
Reference: 'last_change'
|
||||
Year: 'syear'
|
||||
Month: 'smonth'
|
||||
Day: 'sday'
|
||||
Week: 'sweek'
|
8
go.mod
Normal file
8
go.mod
Normal file
@ -0,0 +1,8 @@
|
||||
module BkupDB
|
||||
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/go-sql-driver/mysql v1.7.1
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
)
|
6
go.sum
Normal file
6
go.sum
Normal file
@ -0,0 +1,6 @@
|
||||
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
|
||||
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
Loading…
x
Reference in New Issue
Block a user