9
9
package mysql
10
10
11
11
import (
12
+ "bytes"
12
13
"crypto/tls"
13
14
"errors"
14
15
"fmt"
@@ -33,12 +34,13 @@ type Config struct {
33
34
Addr string // Network address
34
35
DBName string // Database name
35
36
Params map [string ]string // Connection parameters
37
+ Collation string // Connection collation
36
38
Loc * time.Location // Location for time.Time values
37
- TLS * tls.Config // TLS configuration
39
+ TLSConfig string // TLS configuration name
40
+ tls * tls.Config // TLS configuration
38
41
Timeout time.Duration // Dial timeout
39
42
ReadTimeout time.Duration // I/O read timeout
40
43
WriteTimeout time.Duration // I/O write timeout
41
- Collation uint8 // Connection collation
42
44
43
45
AllowAllFiles bool // Allow all files to be used with LOAD DATA LOCAL INFILE
44
46
AllowCleartextPasswords bool // Allows the cleartext client side plugin
@@ -51,6 +53,194 @@ type Config struct {
51
53
Strict bool // Return warnings as errors
52
54
}
53
55
56
+ // FormatDSN formats the given Config into a DSN string which can be passed to
57
+ // the driver.
58
+ func (cfg * Config ) FormatDSN () string {
59
+ var buf bytes.Buffer
60
+
61
+ // [username[:password]@]
62
+ if len (cfg .User ) > 0 {
63
+ buf .WriteString (cfg .User )
64
+ if len (cfg .Passwd ) > 0 {
65
+ buf .WriteByte (':' )
66
+ buf .WriteString (cfg .Passwd )
67
+ }
68
+ buf .WriteByte ('@' )
69
+ }
70
+
71
+ // [protocol[(address)]]
72
+ if len (cfg .Net ) > 0 {
73
+ buf .WriteString (cfg .Net )
74
+ if len (cfg .Addr ) > 0 {
75
+ buf .WriteByte ('(' )
76
+ buf .WriteString (cfg .Addr )
77
+ buf .WriteByte (')' )
78
+ }
79
+ }
80
+
81
+ // /dbname
82
+ buf .WriteByte ('/' )
83
+ buf .WriteString (cfg .DBName )
84
+
85
+ // [?param1=value1&...¶mN=valueN]
86
+ hasParam := false
87
+
88
+ if cfg .AllowAllFiles {
89
+ hasParam = true
90
+ buf .WriteString ("?allowAllFiles=true" )
91
+ }
92
+
93
+ if cfg .AllowCleartextPasswords {
94
+ if hasParam {
95
+ buf .WriteString ("&allowCleartextPasswords=true" )
96
+ } else {
97
+ hasParam = true
98
+ buf .WriteString ("?allowCleartextPasswords=true" )
99
+ }
100
+ }
101
+
102
+ if cfg .AllowOldPasswords {
103
+ if hasParam {
104
+ buf .WriteString ("&allowOldPasswords=true" )
105
+ } else {
106
+ hasParam = true
107
+ buf .WriteString ("?allowOldPasswords=true" )
108
+ }
109
+ }
110
+
111
+ if cfg .ClientFoundRows {
112
+ if hasParam {
113
+ buf .WriteString ("&clientFoundRows=true" )
114
+ } else {
115
+ hasParam = true
116
+ buf .WriteString ("?clientFoundRows=true" )
117
+ }
118
+ }
119
+
120
+ if col := cfg .Collation ; col != defaultCollation && len (col ) > 0 {
121
+ if hasParam {
122
+ buf .WriteString ("&collation=" )
123
+ } else {
124
+ hasParam = true
125
+ buf .WriteString ("?collation=" )
126
+ }
127
+ buf .WriteString (col )
128
+ }
129
+
130
+ if cfg .ColumnsWithAlias {
131
+ if hasParam {
132
+ buf .WriteString ("&columnsWithAlias=true" )
133
+ } else {
134
+ hasParam = true
135
+ buf .WriteString ("?columnsWithAlias=true" )
136
+ }
137
+ }
138
+
139
+ if cfg .InterpolateParams {
140
+ if hasParam {
141
+ buf .WriteString ("&interpolateParams=true" )
142
+ } else {
143
+ hasParam = true
144
+ buf .WriteString ("?interpolateParams=true" )
145
+ }
146
+ }
147
+
148
+ if cfg .Loc != time .UTC && cfg .Loc != nil {
149
+ if hasParam {
150
+ buf .WriteString ("&loc=" )
151
+ } else {
152
+ hasParam = true
153
+ buf .WriteString ("?loc=" )
154
+ }
155
+ buf .WriteString (url .QueryEscape (cfg .Loc .String ()))
156
+ }
157
+
158
+ if cfg .MultiStatements {
159
+ if hasParam {
160
+ buf .WriteString ("&multiStatements=true" )
161
+ } else {
162
+ hasParam = true
163
+ buf .WriteString ("?multiStatements=true" )
164
+ }
165
+ }
166
+
167
+ if cfg .ParseTime {
168
+ if hasParam {
169
+ buf .WriteString ("&parseTime=true" )
170
+ } else {
171
+ hasParam = true
172
+ buf .WriteString ("?parseTime=true" )
173
+ }
174
+ }
175
+
176
+ if cfg .ReadTimeout > 0 {
177
+ if hasParam {
178
+ buf .WriteString ("&readTimeout=" )
179
+ } else {
180
+ hasParam = true
181
+ buf .WriteString ("?readTimeout=" )
182
+ }
183
+ buf .WriteString (cfg .ReadTimeout .String ())
184
+ }
185
+
186
+ if cfg .Strict {
187
+ if hasParam {
188
+ buf .WriteString ("&strict=true" )
189
+ } else {
190
+ hasParam = true
191
+ buf .WriteString ("?strict=true" )
192
+ }
193
+ }
194
+
195
+ if cfg .Timeout > 0 {
196
+ if hasParam {
197
+ buf .WriteString ("&timeout=" )
198
+ } else {
199
+ hasParam = true
200
+ buf .WriteString ("?timeout=" )
201
+ }
202
+ buf .WriteString (cfg .Timeout .String ())
203
+ }
204
+
205
+ if len (cfg .TLSConfig ) > 0 {
206
+ if hasParam {
207
+ buf .WriteString ("&tls=" )
208
+ } else {
209
+ hasParam = true
210
+ buf .WriteString ("?tls=" )
211
+ }
212
+ buf .WriteString (url .QueryEscape (cfg .TLSConfig ))
213
+ }
214
+
215
+ if cfg .WriteTimeout > 0 {
216
+ if hasParam {
217
+ buf .WriteString ("&writeTimeout=" )
218
+ } else {
219
+ hasParam = true
220
+ buf .WriteString ("?writeTimeout=" )
221
+ }
222
+ buf .WriteString (cfg .WriteTimeout .String ())
223
+ }
224
+
225
+ // other params
226
+ if cfg .Params != nil {
227
+ for param , value := range cfg .Params {
228
+ if hasParam {
229
+ buf .WriteByte ('&' )
230
+ } else {
231
+ hasParam = true
232
+ buf .WriteByte ('?' )
233
+ }
234
+
235
+ buf .WriteString (param )
236
+ buf .WriteByte ('=' )
237
+ buf .WriteString (url .QueryEscape (value ))
238
+ }
239
+ }
240
+
241
+ return buf .String ()
242
+ }
243
+
54
244
// ParseDSN parses the DSN string to a Config
55
245
func ParseDSN (dsn string ) (cfg * Config , err error ) {
56
246
// New config with some default values
@@ -196,15 +386,7 @@ func parseDSNParams(cfg *Config, params string) (err error) {
196
386
197
387
// Collation
198
388
case "collation" :
199
- collation , ok := collations [value ]
200
- if ! ok {
201
- // Note possibility for false negatives:
202
- // could be triggered although the collation is valid if the
203
- // collations map does not contain entries the server supports.
204
- err = errors .New ("unknown collation" )
205
- return
206
- }
207
- cfg .Collation = collation
389
+ cfg .Collation = value
208
390
break
209
391
210
392
case "columnsWithAlias" :
@@ -279,24 +461,32 @@ func parseDSNParams(cfg *Config, params string) (err error) {
279
461
boolValue , isBool := readBool (value )
280
462
if isBool {
281
463
if boolValue {
282
- cfg .TLS = & tls.Config {}
464
+ cfg .TLSConfig = "true"
465
+ cfg .tls = & tls.Config {}
466
+ } else {
467
+ cfg .TLSConfig = "false"
283
468
}
284
- } else if value , err := url .QueryUnescape (value ); err != nil {
285
- return fmt .Errorf ("invalid value for TLS config name: %v" , err )
469
+ } else if vl := strings .ToLower (value ); vl == "skip-verify" {
470
+ cfg .TLSConfig = vl
471
+ cfg .tls = & tls.Config {InsecureSkipVerify : true }
286
472
} else {
287
- if strings .ToLower (value ) == "skip-verify" {
288
- cfg .TLS = & tls.Config {InsecureSkipVerify : true }
289
- } else if tlsConfig , ok := tlsConfigRegister [value ]; ok {
473
+ name , err := url .QueryUnescape (value )
474
+ if err != nil {
475
+ return fmt .Errorf ("invalid value for TLS config name: %v" , err )
476
+ }
477
+
478
+ if tlsConfig , ok := tlsConfigRegister [name ]; ok {
290
479
if len (tlsConfig .ServerName ) == 0 && ! tlsConfig .InsecureSkipVerify {
291
480
host , _ , err := net .SplitHostPort (cfg .Addr )
292
481
if err == nil {
293
482
tlsConfig .ServerName = host
294
483
}
295
484
}
296
485
297
- cfg .TLS = tlsConfig
486
+ cfg .TLSConfig = name
487
+ cfg .tls = tlsConfig
298
488
} else {
299
- return errors .New ("invalid value / unknown config name: " + value )
489
+ return errors .New ("invalid value / unknown config name: " + name )
300
490
}
301
491
}
302
492
0 commit comments