• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

go-sql-driver / mysql / 3601392501

pending completion
3601392501

push

github

GitHub
update changelog for Version 1.7 (#1376)

2932 of 3584 relevant lines covered (81.81%)

1490385.18 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.37
/infile.go
1
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
2
//
3
// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved.
4
//
5
// This Source Code Form is subject to the terms of the Mozilla Public
6
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
7
// You can obtain one at http://mozilla.org/MPL/2.0/.
8

9
package mysql
10

11
import (
12
        "fmt"
13
        "io"
14
        "os"
15
        "strings"
16
        "sync"
17
)
18

19
var (
20
        fileRegister       map[string]bool
21
        fileRegisterLock   sync.RWMutex
22
        readerRegister     map[string]func() io.Reader
23
        readerRegisterLock sync.RWMutex
24
)
25

26
// RegisterLocalFile adds the given file to the file allowlist,
27
// so that it can be used by "LOAD DATA LOCAL INFILE <filepath>".
28
// Alternatively you can allow the use of all local files with
29
// the DSN parameter 'allowAllFiles=true'
30
//
31
//        filePath := "/home/gopher/data.csv"
32
//        mysql.RegisterLocalFile(filePath)
33
//        err := db.Exec("LOAD DATA LOCAL INFILE '" + filePath + "' INTO TABLE foo")
34
//        if err != nil {
35
//        ...
36
func RegisterLocalFile(filePath string) {
81✔
37
        fileRegisterLock.Lock()
81✔
38
        // lazy map init
81✔
39
        if fileRegister == nil {
108✔
40
                fileRegister = make(map[string]bool)
27✔
41
        }
27✔
42

43
        fileRegister[strings.Trim(filePath, `"`)] = true
81✔
44
        fileRegisterLock.Unlock()
81✔
45
}
46

47
// DeregisterLocalFile removes the given filepath from the allowlist.
48
func DeregisterLocalFile(filePath string) {
×
49
        fileRegisterLock.Lock()
×
50
        delete(fileRegister, strings.Trim(filePath, `"`))
×
51
        fileRegisterLock.Unlock()
×
52
}
×
53

54
// RegisterReaderHandler registers a handler function which is used
55
// to receive a io.Reader.
56
// The Reader can be used by "LOAD DATA LOCAL INFILE Reader::<name>".
57
// If the handler returns a io.ReadCloser Close() is called when the
58
// request is finished.
59
//
60
//        mysql.RegisterReaderHandler("data", func() io.Reader {
61
//                var csvReader io.Reader // Some Reader that returns CSV data
62
//                ... // Open Reader here
63
//                return csvReader
64
//        })
65
//        err := db.Exec("LOAD DATA LOCAL INFILE 'Reader::data' INTO TABLE foo")
66
//        if err != nil {
67
//        ...
68
func RegisterReaderHandler(name string, handler func() io.Reader) {
81✔
69
        readerRegisterLock.Lock()
81✔
70
        // lazy map init
81✔
71
        if readerRegister == nil {
108✔
72
                readerRegister = make(map[string]func() io.Reader)
27✔
73
        }
27✔
74

75
        readerRegister[name] = handler
81✔
76
        readerRegisterLock.Unlock()
81✔
77
}
78

79
// DeregisterReaderHandler removes the ReaderHandler function with
80
// the given name from the registry.
81
func DeregisterReaderHandler(name string) {
×
82
        readerRegisterLock.Lock()
×
83
        delete(readerRegister, name)
×
84
        readerRegisterLock.Unlock()
×
85
}
×
86

87
func deferredClose(err *error, closer io.Closer) {
243✔
88
        closeErr := closer.Close()
243✔
89
        if *err == nil {
486✔
90
                *err = closeErr
243✔
91
        }
243✔
92
}
93

94
const defaultPacketSize = 16 * 1024 // 16KB is small enough for disk readahead and large enough for TCP
95

96
func (mc *mysqlConn) handleInFileRequest(name string) (err error) {
405✔
97
        var rdr io.Reader
405✔
98
        var data []byte
405✔
99
        packetSize := defaultPacketSize
405✔
100
        if mc.maxWriteSize < packetSize {
405✔
101
                packetSize = mc.maxWriteSize
×
102
        }
×
103

104
        if idx := strings.Index(name, "Reader::"); idx == 0 || (idx > 0 && name[idx-1] == '/') { // io.Reader
567✔
105
                // The server might return an an absolute path. See issue #355.
162✔
106
                name = name[idx+8:]
162✔
107

162✔
108
                readerRegisterLock.RLock()
162✔
109
                handler, inMap := readerRegister[name]
162✔
110
                readerRegisterLock.RUnlock()
162✔
111

162✔
112
                if inMap {
243✔
113
                        rdr = handler()
81✔
114
                        if rdr != nil {
162✔
115
                                if cl, ok := rdr.(io.Closer); ok {
162✔
116
                                        defer deferredClose(&err, cl)
81✔
117
                                }
81✔
118
                        } else {
×
119
                                err = fmt.Errorf("Reader '%s' is <nil>", name)
×
120
                        }
×
121
                } else {
81✔
122
                        err = fmt.Errorf("Reader '%s' is not registered", name)
81✔
123
                }
81✔
124
        } else { // File
243✔
125
                name = strings.Trim(name, `"`)
243✔
126
                fileRegisterLock.RLock()
243✔
127
                fr := fileRegister[name]
243✔
128
                fileRegisterLock.RUnlock()
243✔
129
                if mc.cfg.AllowAllFiles || fr {
405✔
130
                        var file *os.File
162✔
131
                        var fi os.FileInfo
162✔
132

162✔
133
                        if file, err = os.Open(name); err == nil {
324✔
134
                                defer deferredClose(&err, file)
162✔
135

162✔
136
                                // get file size
162✔
137
                                if fi, err = file.Stat(); err == nil {
324✔
138
                                        rdr = file
162✔
139
                                        if fileSize := int(fi.Size()); fileSize < packetSize {
324✔
140
                                                packetSize = fileSize
162✔
141
                                        }
162✔
142
                                }
143
                        }
144
                } else {
81✔
145
                        err = fmt.Errorf("local file '%s' is not registered", name)
81✔
146
                }
81✔
147
        }
148

149
        // send content packets
150
        // if packetSize == 0, the Reader contains no data
151
        if err == nil && packetSize > 0 {
567✔
152
                data := make([]byte, 4+packetSize)
162✔
153
                var n int
162✔
154
                for err == nil {
486✔
155
                        n, err = rdr.Read(data[4:])
324✔
156
                        if n > 0 {
486✔
157
                                if ioErr := mc.writePacket(data[:4+n]); ioErr != nil {
162✔
158
                                        return ioErr
×
159
                                }
×
160
                        }
161
                }
162
                if err == io.EOF {
324✔
163
                        err = nil
162✔
164
                }
162✔
165
        }
166

167
        // send empty packet (termination)
168
        if data == nil {
810✔
169
                data = make([]byte, 4)
405✔
170
        }
405✔
171
        if ioErr := mc.writePacket(data[:4]); ioErr != nil {
405✔
172
                return ioErr
×
173
        }
×
174

175
        // read OK packet
176
        if err == nil {
648✔
177
                return mc.readResultOK()
243✔
178
        }
243✔
179

180
        mc.readPacket()
162✔
181
        return err
162✔
182
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc