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