Support passing JDBC username and password to backing database via DSN
Project: http://git-wip-us.apache.org/repos/asf/calcite-avatica-go/repo Commit: http://git-wip-us.apache.org/repos/asf/calcite-avatica-go/commit/b1a6e6b4 Tree: http://git-wip-us.apache.org/repos/asf/calcite-avatica-go/tree/b1a6e6b4 Diff: http://git-wip-us.apache.org/repos/asf/calcite-avatica-go/diff/b1a6e6b4 Branch: refs/heads/master Commit: b1a6e6b41b435affecb621827d65c97a51e32246 Parents: 28cd280 Author: Francis Chuang <[email protected]> Authored: Mon May 22 09:07:49 2017 +1000 Committer: Julian Hyde <[email protected]> Committed: Thu Aug 10 18:47:11 2017 -0700 ---------------------------------------------------------------------- README.md | 10 +++++++++- driver.go | 19 +++++++++++++++---- dsn.go | 15 +++++++++++++++ dsn_test.go | 18 +++++++++++++++++- 4 files changed, 56 insertions(+), 6 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/calcite-avatica-go/blob/b1a6e6b4/README.md ---------------------------------------------------------------------- diff --git a/README.md b/README.md index 8d701c5..e211292 100644 --- a/README.md +++ b/README.md @@ -35,11 +35,19 @@ rows := db.Query("SELECT COUNT(*) FROM test") The DSN has the following format (optional parts are marked by square brackets): ``` -http://address:port[/schema][?parameter1=value&...parameterN=value] +http://[username:password@]address:port[/schema][?parameter1=value&...parameterN=value] ``` In other words, the scheme (http), address and port is mandatory, but the schema and parameters are optional. +#### username +This is the JDBC username that is passed directly to the backing database. It is *NOT* used for authenticating +against Avatica. + +#### password +This is the JDBC password that is passed directly to the backing database. It is *NOT* used for authenticating +against Avatica. + #### schema The `schema` path sets the default schema to use for this connection. For example, if you set it to `myschema`, then executing the query `SELECT * FROM my_table` will have the equivalence of `SELECT * FROM myschema.my_table`. http://git-wip-us.apache.org/repos/asf/calcite-avatica-go/blob/b1a6e6b4/driver.go ---------------------------------------------------------------------- diff --git a/driver.go b/driver.go index 509ed79..537aa16 100644 --- a/driver.go +++ b/driver.go @@ -18,6 +18,7 @@ import ( "database/sql" "database/sql/driver" "fmt" + "github.com/Boostport/avatica/message" "github.com/satori/go.uuid" "golang.org/x/net/context" @@ -40,13 +41,23 @@ func (a *Driver) Open(dsn string) (driver.Conn, error) { httpClient := NewHTTPClient(config.endpoint) connectionId := uuid.NewV4().String() + info := map[string]string{ + "AutoCommit": "true", + "Consistency": "8", + } + + if config.user != "" { + info["user"] = config.user + } + + if config.password != "" { + info["password"] = config.password + } + // Open a connection to the server req := &message.OpenConnectionRequest{ ConnectionId: connectionId, - Info: map[string]string{ - "AutoCommit": "true", - "Consistency": "8", - }, + Info: info, } if config.schema != "" { http://git-wip-us.apache.org/repos/asf/calcite-avatica-go/blob/b1a6e6b4/dsn.go ---------------------------------------------------------------------- diff --git a/dsn.go b/dsn.go index d1cbad0..1311026 100644 --- a/dsn.go +++ b/dsn.go @@ -16,6 +16,8 @@ type Config struct { location *time.Location schema string transactionIsolation uint32 + user string + password string } // ParseDSN parses a DSN string to a Config @@ -34,6 +36,18 @@ func ParseDSN(dsn string) (*Config, error) { return nil, fmt.Errorf("Unable to parse DSN: %s", err) } + userInfo := parsed.User + + if userInfo != nil { + if userInfo.Username() != "" { + conf.user = userInfo.Username() + } + + if pass, ok := userInfo.Password(); ok { + conf.password = pass + } + } + queries := parsed.Query() if v := queries.Get("maxRowsTotal"); v != "" { @@ -88,6 +102,7 @@ func ParseDSN(dsn string) (*Config, error) { conf.transactionIsolation = uint32(isolation) } + parsed.User = nil parsed.RawQuery = "" parsed.Fragment = "" http://git-wip-us.apache.org/repos/asf/calcite-avatica-go/blob/b1a6e6b4/dsn_test.go ---------------------------------------------------------------------- diff --git a/dsn_test.go b/dsn_test.go index 6fce9da..8d10f7d 100644 --- a/dsn_test.go +++ b/dsn_test.go @@ -8,12 +8,20 @@ import ( func TestParseDSN(t *testing.T) { - config, err := ParseDSN("http://localhost:8765/myschema?maxRowsTotal=1&frameMaxSize=1&location=Australia/Melbourne&transactionIsolation=8") + config, err := ParseDSN("http://username:password@localhost:8765/myschema?maxRowsTotal=1&frameMaxSize=1&location=Australia/Melbourne&transactionIsolation=8") if err != nil { t.Fatalf("Unexpected error: %s", err) } + if config.user != "username"{ + t.Errorf("Expected username to be %s, got %s", "username", config.user) + } + + if config.password != "password"{ + t.Errorf("Expected password to be %s, got %s", "password", config.password) + } + if config.endpoint != "http://localhost:8765/myschema" { t.Errorf("Expected endpoint to be %s, got %s", "http://localhost:8765/myschema", config.endpoint) } @@ -56,6 +64,14 @@ func TestDSNDefaults(t *testing.T) { t.Fatalf("Unexpected error: %s", err) } + if config.user != ""{ + t.Errorf("Default username should be empty, got %s", config.user) + } + + if config.password != ""{ + t.Errorf("Default password should be empty, got %s", config.password) + } + if config.location.String() == "" { t.Error("There was no timezone set.") }
