forked from go-sql-driver/mysql
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinfile.go
125 lines (113 loc) · 2.87 KB
/
infile.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
//
// Copyright 2013 Julien Schmidt. All rights reserved.
// http://www.julienschmidt.com
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.
package mysql
import (
"database/sql/driver"
"fmt"
"io"
"os"
"strings"
)
var (
fileRegister map[string]bool
readerRegister map[string]func() io.Reader
)
func init() {
fileRegister = make(map[string]bool)
readerRegister = make(map[string]func() io.Reader)
}
// RegisterLocalFile adds the given file to the file whitelist,
// so that it can be used by "LOAD DATA LOCAL INFILE <filepath>".
// Alternatively you can allow the use of all local files with
// the DSN parameter 'allowAllFiles=true'
func RegisterLocalFile(filepath string) {
fileRegister[strings.Trim(filepath, `"`)] = true
}
// RegisterReaderHandler registers a handler function which is used
// to receive a io.Reader.
// The Reader can be used by "LOAD DATA LOCAL INFILE Reader::<name>".
// If the handler returns a io.ReadCloser Close() is called when the
// request is finished.
func RegisterReaderHandler(name string, handler func() io.Reader) {
readerRegister[name] = handler
}
func (mc *mysqlConn) handleInFileRequest(name string) (err error) {
var rdr io.Reader
data := make([]byte, 4+mc.maxWriteSize)
if strings.HasPrefix(name, "Reader::") { // io.Reader
name = name[8:]
handler, inMap := readerRegister[name]
if handler != nil {
rdr = handler()
}
if rdr == nil {
if !inMap {
err = fmt.Errorf("Reader '%s' is not registered", name)
} else {
err = fmt.Errorf("Reader '%s' is <nil>", name)
}
}
} else { // File
name = strings.Trim(name, `"`)
if fileRegister[name] || mc.cfg.params[`allowAllFiles`] == `true` {
rdr, err = os.Open(name)
} else {
err = fmt.Errorf("Local File '%s' is not registered. Use the DSN parameter 'allowAllFiles=true' to allow all files", name)
}
}
if rdc, ok := rdr.(io.ReadCloser); ok {
defer func() {
if err == nil {
err = rdc.Close()
} else {
rdc.Close()
}
}()
}
// send content packets
var ioErr error
if err == nil {
var n int
for err == nil && ioErr == nil {
n, err = rdr.Read(data[4:])
if n > 0 {
data[0] = byte(n)
data[1] = byte(n >> 8)
data[2] = byte(n >> 16)
data[3] = mc.sequence
ioErr = mc.writePacket(data[:4+n])
}
}
if err == io.EOF {
err = nil
}
if ioErr != nil {
errLog.Print(ioErr.Error())
return driver.ErrBadConn
}
}
// send empty packet (termination)
ioErr = mc.writePacket([]byte{
0x00,
0x00,
0x00,
mc.sequence,
})
if ioErr != nil {
errLog.Print(ioErr.Error())
return driver.ErrBadConn
}
// read OK packet
if err == nil {
return mc.readResultOK()
} else {
mc.readPacket()
}
return err
}