Skip to content

Commit d512f20

Browse files
committed
Merge pull request go-sql-driver#383 from mrsinham/thrdsafeinfile
Race on LOAD DATA called from different routines
2 parents f368b3b + d4c1329 commit d512f20

File tree

3 files changed

+24
-5
lines changed

3 files changed

+24
-5
lines changed

AUTHORS

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ Soroush Pour <me at soroushjp.com>
3737
Stan Putrya <root.vagner at gmail.com>
3838
Xiaobing Jiang <s7v7nislands at gmail.com>
3939
Xiuming Chen <cc at cxm.cc>
40+
Julien Lefevre <julien.lefevr at gmail.com>
4041

4142
# Organizations
4243

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@ import "github.com/go-sql-driver/mysql"
331331

332332
Files must be whitelisted by registering them with `mysql.RegisterLocalFile(filepath)` (recommended) or the Whitelist check must be deactivated by using the DSN parameter `allowAllFiles=true` ([*Might be insecure!*](http://dev.mysql.com/doc/refman/5.7/en/load-data-local.html)).
333333

334-
To use a `io.Reader` a handler function must be registered with `mysql.RegisterReaderHandler(name, handler)` which returns a `io.Reader` or `io.ReadCloser`. The Reader is available with the filepath `Reader::<name>` then.
334+
To use a `io.Reader` a handler function must be registered with `mysql.RegisterReaderHandler(name, handler)` which returns a `io.Reader` or `io.ReadCloser`. The Reader is available with the filepath `Reader::<name>` then. Choose different names for different handlers and `DeregisterReaderHandler` when you don't need it anymore.
335335

336336
See the [godoc of Go-MySQL-Driver](http://godoc.org/github.com/go-sql-driver/mysql "golang mysql driver documentation") for details.
337337

infile.go

+22-4
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,14 @@ import (
1313
"io"
1414
"os"
1515
"strings"
16+
"sync"
1617
)
1718

1819
var (
19-
fileRegister map[string]bool
20-
readerRegister map[string]func() io.Reader
20+
fileRegister map[string]bool
21+
fileRegisterLock sync.RWMutex
22+
readerRegister map[string]func() io.Reader
23+
readerRegisterLock sync.RWMutex
2124
)
2225

2326
// RegisterLocalFile adds the given file to the file whitelist,
@@ -32,17 +35,21 @@ var (
3235
// ...
3336
//
3437
func RegisterLocalFile(filePath string) {
38+
fileRegisterLock.Lock()
3539
// lazy map init
3640
if fileRegister == nil {
3741
fileRegister = make(map[string]bool)
3842
}
3943

4044
fileRegister[strings.Trim(filePath, `"`)] = true
45+
fileRegisterLock.Unlock()
4146
}
4247

4348
// DeregisterLocalFile removes the given filepath from the whitelist.
4449
func DeregisterLocalFile(filePath string) {
50+
fileRegisterLock.Lock()
4551
delete(fileRegister, strings.Trim(filePath, `"`))
52+
fileRegisterLock.Unlock()
4653
}
4754

4855
// RegisterReaderHandler registers a handler function which is used
@@ -61,18 +68,22 @@ func DeregisterLocalFile(filePath string) {
6168
// ...
6269
//
6370
func RegisterReaderHandler(name string, handler func() io.Reader) {
71+
readerRegisterLock.Lock()
6472
// lazy map init
6573
if readerRegister == nil {
6674
readerRegister = make(map[string]func() io.Reader)
6775
}
6876

6977
readerRegister[name] = handler
78+
readerRegisterLock.Unlock()
7079
}
7180

7281
// DeregisterReaderHandler removes the ReaderHandler function with
7382
// the given name from the registry.
7483
func DeregisterReaderHandler(name string) {
84+
readerRegisterLock.Lock()
7585
delete(readerRegister, name)
86+
readerRegisterLock.Unlock()
7687
}
7788

7889
func deferredClose(err *error, closer io.Closer) {
@@ -90,7 +101,11 @@ func (mc *mysqlConn) handleInFileRequest(name string) (err error) {
90101
// The server might return an an absolute path. See issue #355.
91102
name = name[idx+8:]
92103

93-
if handler, inMap := readerRegister[name]; inMap {
104+
readerRegisterLock.RLock()
105+
handler, inMap := readerRegister[name]
106+
readerRegisterLock.RUnlock()
107+
108+
if inMap {
94109
rdr = handler()
95110
if rdr != nil {
96111
data = make([]byte, 4+mc.maxWriteSize)
@@ -106,7 +121,10 @@ func (mc *mysqlConn) handleInFileRequest(name string) (err error) {
106121
}
107122
} else { // File
108123
name = strings.Trim(name, `"`)
109-
if mc.cfg.allowAllFiles || fileRegister[name] {
124+
fileRegisterLock.RLock()
125+
fr := fileRegister[name]
126+
fileRegisterLock.RUnlock()
127+
if mc.cfg.allowAllFiles || fr {
110128
var file *os.File
111129
var fi os.FileInfo
112130

0 commit comments

Comments
 (0)