From ef744bf10ef6dc60e3d31728076e03a587786b75 Mon Sep 17 00:00:00 2001 From: mashiike Date: Wed, 10 Nov 2021 12:29:26 +0900 Subject: [PATCH 01/14] not use dsn in executer --- executer.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/executer.go b/executer.go index 8750955..131c21f 100644 --- a/executer.go +++ b/executer.go @@ -48,7 +48,6 @@ func (c *Config) GetDSN() string { type Executer struct { mu sync.Mutex - dsn string db *sql.DB lastExecuteTime time.Time selectHook func(query string, columns []string, rows [][]string) @@ -67,8 +66,7 @@ func Open(dsn string) (*Executer, error) { db.SetMaxIdleConns(1) db.SetMaxOpenConns(1) return &Executer{ - dsn: dsn, - db: db, + db: db, }, nil } From 8f482758d3641b8fbed093ae17b720a2a9fbdf36 Mon Sep 17 00:00:00 2001 From: mashiike Date: Wed, 10 Nov 2021 12:32:07 +0900 Subject: [PATCH 02/14] scheme check --- executer.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/executer.go b/executer.go index 131c21f..c0f8ce4 100644 --- a/executer.go +++ b/executer.go @@ -6,6 +6,7 @@ import ( "database/sql" "fmt" "io" + "net/url" "strings" "sync" "time" @@ -59,9 +60,13 @@ func New(config *Config) (*Executer, error) { } func Open(dsn string) (*Executer, error) { - db, err := sql.Open("mysql", dsn) + u, err := url.Parse(dsn) if err != nil { - return nil, errors.Wrap(err, "mysql connect failed") + return nil, err + } + db, err := sql.Open(u.Scheme, dsn) + if err != nil { + return nil, errors.Wrap(err, "db connect failed") } db.SetMaxIdleConns(1) db.SetMaxOpenConns(1) From 67a686624e80d0181e9e181513cdaa5bfcc6f2d0 Mon Sep 17 00:00:00 2001 From: mashiike Date: Wed, 10 Nov 2021 12:34:36 +0900 Subject: [PATCH 03/14] create NewWithDB --- executer.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/executer.go b/executer.go index c0f8ce4..ce0f126 100644 --- a/executer.go +++ b/executer.go @@ -68,11 +68,15 @@ func Open(dsn string) (*Executer, error) { if err != nil { return nil, errors.Wrap(err, "db connect failed") } + return NewWithDB(db), nil +} + +func NewWithDB(db *sql.DB) *Executer { db.SetMaxIdleConns(1) db.SetMaxOpenConns(1) return &Executer{ db: db, - }, nil + } } func (e *Executer) Close() error { From ffdefd8bc39ef1b9d4e89a98191a7fe3ca33d325 Mon Sep 17 00:00:00 2001 From: mashiike Date: Wed, 10 Nov 2021 12:38:20 +0900 Subject: [PATCH 04/14] acccept command --- executer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/executer.go b/executer.go index ce0f126..79cde0b 100644 --- a/executer.go +++ b/executer.go @@ -123,7 +123,7 @@ func (e *Executer) executeContext(ctx context.Context, queryReader io.Reader) er } if e.selectHook != nil { upperedQuery := strings.ToUpper(query) - if strings.HasPrefix(upperedQuery, "SELECT") || strings.HasPrefix(upperedQuery, "SHOW") { + if strings.HasPrefix(upperedQuery, "SELECT") || strings.HasPrefix(upperedQuery, "SHOW") || strings.HasPrefix(upperedQuery, `\`) { if err := e.queryContext(ctx, query); err != nil { return errors.Wrap(err, "query rows failed") } From 6d6c51beafac58e7f74d02d1240d3541dc46860a Mon Sep 17 00:00:00 2001 From: mashiike Date: Wed, 10 Nov 2021 12:45:12 +0900 Subject: [PATCH 05/14] isSelectFunc --- executer.go | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/executer.go b/executer.go index 79cde0b..7f995bf 100644 --- a/executer.go +++ b/executer.go @@ -53,6 +53,7 @@ type Executer struct { lastExecuteTime time.Time selectHook func(query string, columns []string, rows [][]string) executeHook func(query string, rowsAffected int64, lastInsertId int64) + isSelectFunc func(query string) bool } func New(config *Config) (*Executer, error) { @@ -123,7 +124,15 @@ func (e *Executer) executeContext(ctx context.Context, queryReader io.Reader) er } if e.selectHook != nil { upperedQuery := strings.ToUpper(query) - if strings.HasPrefix(upperedQuery, "SELECT") || strings.HasPrefix(upperedQuery, "SHOW") || strings.HasPrefix(upperedQuery, `\`) { + var isSelect bool + if e.isSelectFunc == nil { + if strings.HasPrefix(upperedQuery, "SELECT") || strings.HasPrefix(upperedQuery, "SHOW") || strings.HasPrefix(upperedQuery, `\`) { + isSelect = true + } + } else { + isSelect = e.isSelectFunc(upperedQuery) + } + if isSelect { if err := e.queryContext(ctx, query); err != nil { return errors.Wrap(err, "query rows failed") } @@ -194,6 +203,10 @@ func (e *Executer) SetSelectHook(hook func(query string, columns []string, rows e.selectHook = hook } +func (e *Executer) SetIsSelectFunc(f func(query string) bool) { + e.isSelectFunc = f +} + func (e *Executer) SetTableSelectHook(hook func(query, table string)) { e.selectHook = func(query string, columns []string, rows [][]string) { var buf strings.Builder From f3633029414b539501d50752514cdbace68c0ea4 Mon Sep 17 00:00:00 2001 From: mashiike Date: Wed, 10 Nov 2021 12:47:47 +0900 Subject: [PATCH 06/14] SetTimeCheckQuery --- executer.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/executer.go b/executer.go index 7f995bf..cb55789 100644 --- a/executer.go +++ b/executer.go @@ -54,6 +54,7 @@ type Executer struct { selectHook func(query string, columns []string, rows [][]string) executeHook func(query string, rowsAffected int64, lastInsertId int64) isSelectFunc func(query string) bool + timeCheckQuery string } func New(config *Config) (*Executer, error) { @@ -76,7 +77,8 @@ func NewWithDB(db *sql.DB) *Executer { db.SetMaxIdleConns(1) db.SetMaxOpenConns(1) return &Executer{ - db: db, + db: db, + timeCheckQuery: "SELECT NOW()", } } @@ -103,7 +105,7 @@ func (e *Executer) ExecuteContext(ctx context.Context, queryReader io.Reader) er } func (e *Executer) updateLastExecuteTime(ctx context.Context) error { - row := e.db.QueryRowContext(ctx, "SELECT NOW()") + row := e.db.QueryRowContext(ctx, e.timeCheckQuery) if err := row.Err(); err != nil { return errors.Wrap(err, "get db time") } @@ -207,6 +209,10 @@ func (e *Executer) SetIsSelectFunc(f func(query string) bool) { e.isSelectFunc = f } +func (e *Executer) SetTimeCheckQuery(query string) { + e.timeCheckQuery = query +} + func (e *Executer) SetTableSelectHook(hook func(query, table string)) { e.selectHook = func(query string, columns []string, rows [][]string) { var buf strings.Builder From 0aad50367c2fc9e269fe944252a13913c33067a3 Mon Sep 17 00:00:00 2001 From: mashiike Date: Wed, 10 Nov 2021 12:51:26 +0900 Subject: [PATCH 07/14] Revert "scheme check" This reverts commit 8f482758d3641b8fbed093ae17b720a2a9fbdf36. --- executer.go | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/executer.go b/executer.go index cb55789..0a9c1f8 100644 --- a/executer.go +++ b/executer.go @@ -6,7 +6,6 @@ import ( "database/sql" "fmt" "io" - "net/url" "strings" "sync" "time" @@ -62,13 +61,9 @@ func New(config *Config) (*Executer, error) { } func Open(dsn string) (*Executer, error) { - u, err := url.Parse(dsn) + db, err := sql.Open("mysql", dsn) if err != nil { - return nil, err - } - db, err := sql.Open(u.Scheme, dsn) - if err != nil { - return nil, errors.Wrap(err, "db connect failed") + return nil, errors.Wrap(err, "mysql connect failed") } return NewWithDB(db), nil } From 2e8eff54dee0ac7cb609bc090208daa0cc4d3812 Mon Sep 17 00:00:00 2001 From: mashiike Date: Wed, 10 Nov 2021 13:04:59 +0900 Subject: [PATCH 08/14] add comments --- executer.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/executer.go b/executer.go index 0a9c1f8..b8dbafa 100644 --- a/executer.go +++ b/executer.go @@ -15,6 +15,8 @@ import ( "github.com/pkg/errors" ) +// Config is a connection setting to MySQL. +// Exists to generate a Golang connection DSN to MySQL type Config struct { DSN string User string @@ -24,6 +26,7 @@ type Config struct { Database string } +// NewDefaultConfig returns the config for connecting to the local MySQL server func NewDefaultConfig() *Config { return &Config{ User: "root", @@ -32,6 +35,7 @@ func NewDefaultConfig() *Config { } } +//GetDSN returns a DSN dedicated to connecting to MySQL. func (c *Config) GetDSN() string { if c.DSN == "" { return fmt.Sprintf( @@ -46,6 +50,7 @@ func (c *Config) GetDSN() string { return strings.TrimPrefix(c.DSN, "mysql://") } +//Executer queries the DB. There is no parallelism type Executer struct { mu sync.Mutex db *sql.DB @@ -56,10 +61,12 @@ type Executer struct { timeCheckQuery string } +//New return Executer with config func New(config *Config) (*Executer, error) { return Open(config.GetDSN()) } +//Open with dsn func Open(dsn string) (*Executer, error) { db, err := sql.Open("mysql", dsn) if err != nil { @@ -68,6 +75,8 @@ func Open(dsn string) (*Executer, error) { return NewWithDB(db), nil } +// NewWithDB returns Executer with *sql.DB +// Note: Since it is made assuming MySQL, it may be inconvenient for other DBs. func NewWithDB(db *sql.DB) *Executer { db.SetMaxIdleConns(1) db.SetMaxOpenConns(1) @@ -77,6 +86,7 @@ func NewWithDB(db *sql.DB) *Executer { } } +// Close DB func (e *Executer) Close() error { e.mu.Lock() defer e.mu.Unlock() @@ -86,10 +96,12 @@ func (e *Executer) Close() error { return e.db.Close() } +//Execute SQL func (e *Executer) Execute(queryReader io.Reader) error { return e.ExecuteContext(context.Background(), queryReader) } +//ExecuteContext SQL execute with context.Context func (e *Executer) ExecuteContext(ctx context.Context, queryReader io.Reader) error { e.mu.Lock() defer e.mu.Unlock() @@ -188,26 +200,32 @@ func (e *Executer) queryContext(ctx context.Context, query string) error { return nil } +//LastExecuteTime returns last execute time on DB func (e *Executer) LastExecuteTime() time.Time { return e.lastExecuteTime } +//SetExecuteHook set non select query hook func (e *Executer) SetExecuteHook(hook func(query string, rowsAffected, lastInsertId int64)) { e.executeHook = hook } +//SetSelectHook set select query hook func (e *Executer) SetSelectHook(hook func(query string, columns []string, rows [][]string)) { e.selectHook = hook } +//SetIsSelectFunc :Set the function to decide whether to execute in QueryContext func (e *Executer) SetIsSelectFunc(f func(query string) bool) { e.isSelectFunc = f } +//SetTimeCheckQuery set time check query for non mysql db func (e *Executer) SetTimeCheckQuery(query string) { e.timeCheckQuery = query } +//SetTimeCheckQuery set select query hook, but result is table string func (e *Executer) SetTableSelectHook(hook func(query, table string)) { e.selectHook = func(query string, columns []string, rows [][]string) { var buf strings.Builder @@ -219,10 +237,12 @@ func (e *Executer) SetTableSelectHook(hook func(query, table string)) { } } +// QueryScanner separate string by ; and delete newline type QueryScanner struct { *bufio.Scanner } +//NewQueryScanner returns QueryScanner func NewQueryScanner(queryReader io.Reader) *QueryScanner { scanner := bufio.NewScanner(queryReader) onSplit := func(data []byte, atEOF bool) (advance int, token []byte, err error) { @@ -245,6 +265,7 @@ func NewQueryScanner(queryReader io.Reader) *QueryScanner { } } +//Query return func (s *QueryScanner) Query() string { return strings.Trim(strings.NewReplacer( "\r\n", " ", From aa62809f843eb1a57f733e08bd10b111daa7f338 Mon Sep 17 00:00:00 2001 From: mashiike Date: Wed, 10 Nov 2021 13:13:30 +0900 Subject: [PATCH 09/14] update docs --- README.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/README.md b/README.md index eea00ee..a78fa34 100644 --- a/README.md +++ b/README.md @@ -35,3 +35,23 @@ $ mysqlbatch -u root -p ${password} -h localhost < batch.sql ``` +## Usage as a library + + +```go +executer, err := mysqlbatch.Open("root:password@tcp(localhost:3306)/testdb?parseTime=true") +if err != nil { + //... +} +defer executer.Close() +if err := executer.Execute(strings.NewReader("UPDATE users SET name = 'hoge';")); err != nil { + //... +} +``` + +more infomation see [go doc](https://godoc.org/github.com/mashiike/mysqlbatch). + +## License + +see [LICENSE](https://github.com/mashiike/mysqlbatch/blob/master/LICENSE) file. + From 9c85ce7e7566d90d28558464c4e47ea327af7041 Mon Sep 17 00:00:00 2001 From: mashiike Date: Wed, 10 Nov 2021 13:15:07 +0900 Subject: [PATCH 10/14] update go 1.17 --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index f1a4839..3d4fbc2 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/mashiike/mysqlbatch -go 1.16 +go 1.17 require ( github.com/go-sql-driver/mysql v1.6.0 From 143a7c3418da7197c873d1f1808b80453ae783c2 Mon Sep 17 00:00:00 2001 From: mashiike Date: Wed, 10 Nov 2021 13:15:23 +0900 Subject: [PATCH 11/14] go mod tidy --- go.mod | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 3d4fbc2..02502f9 100644 --- a/go.mod +++ b/go.mod @@ -4,8 +4,12 @@ go 1.17 require ( github.com/go-sql-driver/mysql v1.6.0 - github.com/mattn/go-runewidth v0.0.13 // indirect github.com/olekukonko/tablewriter v0.0.5 github.com/pkg/errors v0.9.1 github.com/sergi/go-diff v1.1.0 ) + +require ( + github.com/mattn/go-runewidth v0.0.13 // indirect + github.com/rivo/uniseg v0.2.0 // indirect +) From b3c835ccc56bdc043f194e3bb66904020dae19f3 Mon Sep 17 00:00:00 2001 From: mashiike Date: Wed, 10 Nov 2021 13:22:35 +0900 Subject: [PATCH 12/14] change releaser --- .github/workflows/release.yaml | 33 ++++++++++++++------------------- .goreleaser.yml | 32 ++++++++++++++++++++++++++++++++ Makefile | 11 +---------- cmd/mysqlbatch/main.go | 12 ++++++------ 4 files changed, 53 insertions(+), 35 deletions(-) create mode 100644 .goreleaser.yml diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 3f88597..c55696c 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -4,30 +4,25 @@ on: branches: - "!**/*" tags: - - "v*" + - "v*.*.*" jobs: release: name: Release runs-on: ubuntu-latest steps: - - name: Set up Go - uses: actions/setup-go@v2 - with: - go-version: 1.16 + - name: Set up Go + uses: actions/setup-go@v1 + with: + go-version: 1.17 - - name: Check out code into the Go module directory - uses: actions/checkout@v2 + - name: Check out code into the Go module directory + uses: actions/checkout@v2 - - name: setup tools - run: | - mkdir ~/bin - curl -sL https://github.com/Songmu/goxz/releases/download/v0.4.1/goxz_v0.4.1_linux_amd64.tar.gz | tar zxvf - && install goxz_v0.4.1_linux_amd64/goxz ~/bin/ - curl -sL https://github.com/tcnksm/ghr/releases/download/v0.13.0/ghr_v0.13.0_linux_amd64.tar.gz | tar zxvf - && install ghr_v0.13.0_linux_amd64/ghr ~/bin/ - - name: dist - run: PATH=~/bin:$PATH make dist - - - name: release - run: PATH=~/bin:$PATH make release - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Run GoReleaser + uses: goreleaser/goreleaser-action@v1 + with: + version: latest + args: release --rm-dist + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.goreleaser.yml b/.goreleaser.yml new file mode 100644 index 0000000..529d4c5 --- /dev/null +++ b/.goreleaser.yml @@ -0,0 +1,32 @@ +# This is an example goreleaser.yaml file with some sane defaults. +# Make sure to check the documentation at http://goreleaser.com +before: + hooks: + - go mod download +builds: + - env: + - CGO_ENABLED=0 + main: ./cmd/mysqlbatch + binary: mysqlbatch + ldflags: + - -s -w + goos: + - darwin + - linux + - windows + goarch: + - amd64 + - arm64 +release: + prerelease: true +archives: +checksum: + name_template: "checksums.txt" +snapshot: + name_template: "{{ .Env.NIGHTLY_VERSION }}" +changelog: + sort: asc + filters: + exclude: + - "^docs:" + - "^test:" diff --git a/Makefile b/Makefile index 8dd2160..ae3a9f0 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ export GO111MODULE := on .PHONY: test binary install clean dist cmd/mysqlbatch/mysqlbatch: *.go cmd/mysqlbatch/*.go - cd cmd/mysqlbatch && go build -ldflags "-s -w -X 'main.Version=${GIT_VER}' -X 'main.BuildDate=${DATE}' -X 'main.GoVersion=${GO_VER}'" -gcflags="-trimpath=${PWD}" + cd cmd/mysqlbatch && go build . test: go test -race . @@ -15,12 +15,3 @@ test: clean: rm -f cmd/mysqlbatch/mysqlbatch rm -fr dist/ - -dist: - CGO_ENABLED=0 \ - goxz -pv=$(GIT_VER) \ - -build-ldflags="-s -w -X 'main.Version=${GIT_VER}' -X 'main.BuildDate=${DATE}' -X 'main.GoVersion=${GO_VER}'" \ - -os=darwin,linux -arch=amd64 -d=dist ./cmd/mysqlbatch - -release: - ghr -u mashiike -r mysqlbatch -n "$(GIT_VER)" $(GIT_VER) dist/ diff --git a/cmd/mysqlbatch/main.go b/cmd/mysqlbatch/main.go index 3198415..715045a 100644 --- a/cmd/mysqlbatch/main.go +++ b/cmd/mysqlbatch/main.go @@ -7,15 +7,15 @@ import ( "log" "os" "os/signal" + "runtime" "syscall" "github.com/mashiike/mysqlbatch" ) var ( - Version = "current" - BuildDate = "(no data)" - GoVersion = "(no data)" + version = "current" + date = "unknown" ) func main() { @@ -33,9 +33,9 @@ func main() { flag.Parse() if *versionFlag { - fmt.Printf("version : %s\n", Version) - fmt.Printf("go version: %s\n", GoVersion) - fmt.Printf("build date: %s\n", BuildDate) + fmt.Printf("version : %s\n", version) + fmt.Printf("go version: %s\n", runtime.Version()) + fmt.Printf("build date: %s\n", date) return } From af79b8f49e02f75880b27502f4fcd299342a5b6a Mon Sep 17 00:00:00 2001 From: mashiike Date: Wed, 10 Nov 2021 13:28:03 +0900 Subject: [PATCH 13/14] fix embeded --- .goreleaser.yml | 2 ++ Makefile | 6 +----- cmd/mysqlbatch/main.go | 8 ++++---- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/.goreleaser.yml b/.goreleaser.yml index 529d4c5..b0fd9ea 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -10,6 +10,8 @@ builds: binary: mysqlbatch ldflags: - -s -w + - -X main.Version=v{{.Version}} + - -X main.BuildDate=v{{.Date}} goos: - darwin - linux diff --git a/Makefile b/Makefile index ae3a9f0..2efd6bd 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,6 @@ -GIT_VER := $(shell git describe --tags) -DATE := $(shell date +%Y-%m-%dT%H:%M:%S%z) -GO_VER := $(shell go version) - export GO111MODULE := on -.PHONY: test binary install clean dist +.PHONY: test clean cmd/mysqlbatch/mysqlbatch: *.go cmd/mysqlbatch/*.go cd cmd/mysqlbatch && go build . diff --git a/cmd/mysqlbatch/main.go b/cmd/mysqlbatch/main.go index 715045a..e45fd88 100644 --- a/cmd/mysqlbatch/main.go +++ b/cmd/mysqlbatch/main.go @@ -14,8 +14,8 @@ import ( ) var ( - version = "current" - date = "unknown" + Version = "current" + BuildDate = "(no data)" ) func main() { @@ -33,9 +33,9 @@ func main() { flag.Parse() if *versionFlag { - fmt.Printf("version : %s\n", version) + fmt.Printf("version : %s\n", Version) fmt.Printf("go version: %s\n", runtime.Version()) - fmt.Printf("build date: %s\n", date) + fmt.Printf("build date: %s\n", BuildDate) return } From c4518aaed6ac4f9cf1a16f6db141f0c348de2244 Mon Sep 17 00:00:00 2001 From: mashiike Date: Wed, 10 Nov 2021 13:32:36 +0900 Subject: [PATCH 14/14] test version 1.17 --- .github/workflows/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index f5140a8..5521f10 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -5,7 +5,7 @@ jobs: strategy: matrix: go: - - 1.16 + - 1.17 name: Build runs-on: ubuntu-latest steps: