ParseDSN doesn't support usernames containing colons
Issue description
ParseDSN unspoport ":" in username
Example code
func main() {
config := &mysql.Config{
User: "user:db",
Passwd: "test",
Net: "tcp",
Addr: "127.0.0.1",
DBName: "test",
}
s := config.FormatDSN()
fmt.Printf("dsn: %s\n", s)
config2, err := mysql.ParseDSN(s)
if err != nil {
log.Fatal(err)
}
fmt.Printf("user: %s, pass: %s\n", config2.User, config2.Passwd)
}
may I suggest use url.UserInfo to format and parse user:passwd field?
also, use url compliant dsn scheme would be great, and save a lot dsn related parsing / formating code. for example tcp://user:pass@host:port/db?param1=value1&...
😟 I just checked the docs and then tried with the commandline client:
mysql> select user from mysql.user where user = '!: \\';
+------+
| user |
+------+
| !: \ |
+------+
1 row in set (0.00 sec)
mysql> CREATE USER '!: %\\';
Query OK, 0 rows affected (0.00 sec)
mysql> select user from mysql.user where user = '!: %\\';
+-------+
| user |
+-------+
| !: %\ |
+-------+
1 row in set (0.00 sec)
Apparently that's valid.
We have lots and lots of old code using the existing DSN and we must not break it. To support that kind of username, we have to signal that a new kind of DSN is used. I thought about a leading colon for base64 encoded username and password, but empty usernames are ok, too.
mysql> CREATE USER '';
Query OK, 0 rows affected (0.00 sec)
mysql> select user from mysql.user where user = '';
+------+
| user |
+------+
| |
+------+
1 row in set (0.00 sec)
The options as I see them:
- signal that a new DSN is used by a leading "
:" The new DSN might use base64 encoding or somesuch, that part is open.- ugly
- breaks existing code for users with empty name but using a password
- add an alternative Open identifier ("mysql2") using another DSN
- wontfix
@julienschmidt @methane what do you think?
@csyangchen if we would start from scratch, we would certainly choose to use just a standard conforming URL as DSN. However, we currently have about 4000 repository clones daily. I assume the outcry would be huge if we introduce a breaking change here. I assume that we would break thousands of programs. A breaking change is definitely not an option.
So @arnehormann, I would go with option number 2 or 3 (in now more than 5 years this driver exists, nobody ever complained about it until now). In case of number 2, I would however go with something semantically more meaningful than "mysql2" and then use the url package to parse the DSN string.
let's go with wontfix, then. Adding a different Open identifier is its own can of worms...
So not a problem in 5 years and now 2 problems in less than 6 months. Any consideration to the other options? I hate to maintain a fork.
Starting with Go 1.10 there will be an alternative way to open connections using a Connector (we will use our Config struct to implement the Connector interface): https://tip.golang.org/pkg/database/sql/#OpenDB
This would avoid all of these encoding problems.
See also #671
We should at least document the current situation and propose workarounds.
Waiting until Go 1.10 seems like a good compromise.
Documentation would be great. I spent a lot of time pulling out hair. I already implement my own driver that does some preliminary lookups against our service discovery system, so mysql DSNs are never interacted with directly.
In fact if Connector interface were to be implemented i could use it directly today even on older versions of go since I already create my own Driver and just wrap it?
I guess the concerns could be that the interface signature could change before the 1.10 freeze, but that is pretty low.