-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdatabase.go
More file actions
228 lines (196 loc) · 6.9 KB
/
database.go
File metadata and controls
228 lines (196 loc) · 6.9 KB
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
package manager
import (
"database/sql"
"fmt"
"net/url"
"strconv"
"strings"
"time"
)
const (
defaultDriver = "mysql"
defaultPort = 3306
cDSNFormat = "%s%s=%s&"
)
//Setting is the signature of setting function
type Setting func(string) string
func boolSetting(source, param string, ok bool) string {
return fmt.Sprintf(cDSNFormat, source, param, strconv.FormatBool(ok))
}
func timeSetting(source, param string, t time.Duration) string {
//make sure 1ms<=t<24h
if t < time.Millisecond || t >= 24*time.Hour {
return ""
}
return fmt.Sprintf(cDSNFormat, source, param, t)
}
func stringSetting(source, param, value string) string {
if "" == value {
return ""
}
return fmt.Sprintf(cDSNFormat, source, param, value)
}
//SetCharset Sets the charset used for client-server interaction
func SetCharset(v string) Setting {
return func(source string) string {
return stringSetting(source, "charset", v)
}
}
//SetLoc Sets the location for time.Time values (when using parseTime=true). "Local" sets the system's location. See time.LoadLocation for details.
func SetLoc(v string) Setting {
return func(source string) string {
return stringSetting(source, "loc", url.QueryEscape(v))
}
}
//SetTimeZone Sets the time_zone used for client-server interaction
func SetTimeZone(v string) Setting {
return func(source string) string {
return stringSetting(source, "time_zone", url.QueryEscape(fmt.Sprintf(`'%s'`, v)))
}
}
//SetCollation Sets the collation used for client-server interaction on connection. In contrast to charset, collation does not issue additional queries. If the specified collation is unavailable on the target server, the connection will fail.
func SetCollation(v string) Setting {
return func(source string) string {
return stringSetting(source, "collation", v)
}
}
//SetAllowCleartextPasswords allowCleartextPasswords=true allows using the cleartext client side plugin if required by an account, such as one defined with the PAM authentication plugin. Sending passwords in clear text may be a security problem in some configurations.
func SetAllowCleartextPasswords(ok bool) Setting {
return func(source string) string {
return boolSetting(source, "allowCleartextPasswords", ok)
}
}
//SetAllowNativePasswords allows the usage of the mysql native password method
func SetAllowNativePasswords(ok bool) Setting {
return func(source string) string {
return boolSetting(source, "allowNativePasswords", ok)
}
}
//SetAutoCommit set it to true if you know what you are doing
func SetAutoCommit(ok bool) Setting {
return func(source string) string {
return boolSetting(source, "autocommit", ok)
}
}
//SetParseTime parseTime=true changes the output type of DATE and DATETIME values to time.Time instead of []byte / string
func SetParseTime(ok bool) Setting {
return func(source string) string {
return boolSetting(source, "parseTime", ok)
}
}
//SetAllowAllFiles allowAllFiles=true disables the file Whitelist for LOAD DATA LOCAL INFILE and allows all files. Might be insecure!
func SetAllowAllFiles(ok bool) Setting {
return func(source string) string {
return boolSetting(source, "allowAllFiles", ok)
}
}
//SetClientFoundRows clientFoundRows=true causes an UPDATE to return the number of matching rows instead of the number of rows changed.
func SetClientFoundRows(ok bool) Setting {
return func(source string) string {
return boolSetting(source, "clientFoundRows", ok)
}
}
//SetMultiStatements multiStatements=true multiStatements.
func SetMultiStatements(ok bool) Setting {
return func(source string) string {
return boolSetting(source, "multiStatements", ok)
}
}
//SetColumnsWithAlias When columnsWithAlias is true, calls to sql.Rows.Columns() will return the table alias and the column name separated by a dot.
func SetColumnsWithAlias(ok bool) Setting {
return func(source string) string {
return boolSetting(source, "columnsWithAlias", ok)
}
}
//SetInterpolateParams If interpolateParams is true, placeholders (?) in calls to db.Query() and db.Exec() are interpolated into a single query string with given parameters. This reduces the number of roundtrips, since the driver has to prepare a statement, execute it with given parameters and close the statement again with interpolateParams=false.
func SetInterpolateParams(ok bool) Setting {
return func(source string) string {
return boolSetting(source, "interpolateParams", ok)
}
}
//SetStrict strict=true enables the strict mode in which MySQL warnings are treated as errors.
func SetStrict(ok bool) Setting {
return func(source string) string {
return boolSetting(source, "strict", ok)
}
}
//SetTimeout Driver side connection timeout. The value must be a decimal number with an unit suffix ( "ms", "s", "m", "h" ), such as "30s", "0.5m" or "1m30s". To set a server side timeout, use the parameter wait_timeout.
func SetTimeout(timeout time.Duration) Setting {
return func(source string) string {
return timeSetting(source, "timeout", timeout)
}
}
//SetReadTimeout I/O read timeout. The value must be a decimal number with an unit suffix ( "ms", "s", "m", "h" ), such as "30s", "0.5m" or "1m30s".
func SetReadTimeout(timeout time.Duration) Setting {
return func(source string) string {
return timeSetting(source, "readTimeout", timeout)
}
}
//SetWriteTimeout I/O write timeout. The value must be a decimal number with an unit suffix ( "ms", "s", "m", "h" ), such as "30s", "0.5m" or "1m30s".
func SetWriteTimeout(timeout time.Duration) Setting {
return func(source string) string {
return timeSetting(source, "writeTimeout", timeout)
}
}
//Option stands for a series of options for creating a DB
type Option struct {
driver string
dbName string
user string
password string
host string
port int
settings []Setting
}
//New returns an Option
func New(dbName, user, password, host string) *Option {
return &Option{
dbName: dbName,
user: user,
password: password,
host: host,
port: defaultPort,
driver: defaultDriver,
}
}
//Port sets the server port,default 3306
func (o *Option) Port(port int) *Option {
o.port = port
return o
}
//Driver sets the driver, default mysql
func (o *Option) Driver(driver string) *Option {
o.driver = driver
return o
}
//Set receives a series of Set*-like functions
func (o *Option) Set(sets ...Setting) *Option {
o.settings = append(o.settings, sets...)
return o
}
//Open is used for creating a *sql.DB
//Use it at the last
func (o *Option) Open(ping bool) (*sql.DB, error) {
db, err := open(o)
if nil != err {
return nil, err
}
if ping {
err = db.Ping()
}
return db, err
}
func concatDSN(settings []Setting) string {
s := ""
for _, f := range settings {
s = f(s)
}
return strings.TrimRight(s, "&")
}
func realDSN(info *Option) string {
format := "%s:%s@tcp(%s:%d)/%s?%s"
return strings.TrimRight(fmt.Sprintf(format, info.user, info.password, info.host, info.port, info.dbName, concatDSN(info.settings)), "?")
}
func open(o *Option) (*sql.DB, error) {
return sql.Open(o.driver, realDSN(o))
}