-
Notifications
You must be signed in to change notification settings - Fork 29
Expand file tree
/
Copy pathdsn.go
More file actions
126 lines (116 loc) · 3.09 KB
/
dsn.go
File metadata and controls
126 lines (116 loc) · 3.09 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
package gohive
import (
"fmt"
"net/url"
"regexp"
"strconv"
"strings"
)
type Config struct {
User string
Passwd string
Addr string
DBName string
Auth string
Batch int
ColumnsWithoutTableName bool // column names not contains table name
SessionCfg map[string]string
}
var (
// Regexp syntax: https://github.com/google/re2/wiki/Syntax
reDSN = regexp.MustCompile(`(.+@)?([^@|^?]+)\\?(.*)`)
reUserPasswd = regexp.MustCompile(`([^:@]+)(:[^:@]+)?@`)
)
const (
sessionConfPrefix = "session."
authConfName = "auth"
defaultAuth = "NOSASL"
batchSizeName = "batch"
columnsWithoutTableNameName = "columns_without_table_name"
defaultBatchSize = 10000
)
// ParseDSN requires DSN names in the format [user[:password]@]addr/dbname.
func ParseDSN(dsn string) (*Config, error) {
// Please read https://play.golang.org/p/_CSLvl1AxOX before code review.
sub := reDSN.FindStringSubmatch(dsn)
if len(sub) != 4 {
return nil, fmt.Errorf("The DSN %s doesn't match [user[:password]@]addr[/dbname][?auth=AUTH_MECHANISM]", dsn)
}
addr := ""
dbname := ""
loc := strings.IndexRune(sub[2], '/')
if loc > -1 {
addr = sub[2][:loc]
dbname = sub[2][loc+1:]
} else {
addr = sub[2]
}
user := ""
passwd := ""
up := reUserPasswd.FindStringSubmatch(sub[1])
if len(up) == 3 {
user = up[1]
if len(up[2]) > 0 {
passwd = up[2][1:]
}
}
auth := defaultAuth
batch := defaultBatchSize
columnsWithoutTableName := false
var err error
sc := make(map[string]string)
if len(sub[3]) > 0 && sub[3][0] == '?' {
qry, _ := url.ParseQuery(sub[3][1:])
if v, found := qry[authConfName]; found {
auth = v[0]
}
if v, found := qry[batchSizeName]; found {
bch, err := strconv.Atoi(v[0])
if err != nil {
return nil, err
}
batch = bch
}
if v, found := qry[columnsWithoutTableNameName]; found {
columnsWithoutTableName, err = strconv.ParseBool(v[0])
if err != nil {
return nil, err
}
}
for k, v := range qry {
if strings.HasPrefix(k, sessionConfPrefix) {
sc[k[len(sessionConfPrefix):]] = v[0]
}
}
}
return &Config{
User: user,
Passwd: passwd,
Addr: addr,
DBName: dbname,
Auth: auth,
Batch: batch,
ColumnsWithoutTableName: columnsWithoutTableName,
SessionCfg: sc,
}, nil
}
// FormatDSN outputs a string in the format "user:password@address?auth=xxx"
func (cfg *Config) FormatDSN() string {
dsn := fmt.Sprintf("%s:%s@%s", cfg.User, cfg.Passwd, cfg.Addr)
if len(cfg.DBName) > 0 {
dsn = fmt.Sprintf("%s/%s", dsn, cfg.DBName)
}
dsn += fmt.Sprintf("?batch=%d", cfg.Batch)
if len(cfg.Auth) > 0 {
dsn += fmt.Sprintf("&auth=%s", cfg.Auth)
}
if cfg.ColumnsWithoutTableName {
dsn += "&columns_without_table_name=true"
}
if len(cfg.SessionCfg) > 0 {
for k, v := range cfg.SessionCfg {
dsn += fmt.Sprintf("&%s%s=%s", sessionConfPrefix, k, v)
}
}
return dsn
}