diff --git a/driver.go b/driver.go index 80e54ef8..68d4eead 100644 --- a/driver.go +++ b/driver.go @@ -40,41 +40,3 @@ func (d *databricksDriver) OpenConnector(dsn string) (driver.Connector, error) { var _ driver.Driver = (*databricksDriver)(nil) var _ driver.DriverContext = (*databricksDriver)(nil) - -// type databricksDB struct { -// *sql.DB -// } - -// func OpenDB(c driver.Connector) *databricksDB { -// db := sql.OpenDB(c) -// return &databricksDB{db} -// } - -// func (db *databricksDB) QueryContextAsync(ctx context.Context, query string, args ...any) (rows *sql.Rows, queryId string, err error) { -// return nil, "", nil -// } - -// func (db *databricksDB) ExecContextAsync(ctx context.Context, query string, args ...any) (result sql.Result, queryId string) { -// //go do something -// return nil, "" -// } - -// func (db *databricksDB) CancelQuery(ctx context.Context, queryId string) error { -// //go do something -// return nil -// } - -// func (db *databricksDB) GetQueryStatus(ctx context.Context, queryId string) error { -// //go do something -// return nil -// } - -// func (db *databricksDB) FetchRows(ctx context.Context, queryId string) (rows *sql.Rows, err error) { -// //go do something -// return nil, nil -// } - -// func (db *databricksDB) FetchResult(ctx context.Context, queryId string) (rows sql.Result, err error) { -// //go do something -// return nil, nil -// } diff --git a/internal/config/config.go b/internal/config/config.go index 3bdf0188..c0d50935 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -11,6 +11,7 @@ import ( "github.com/databricks/databricks-sql-go/internal/cli_service" "github.com/databricks/databricks-sql-go/logger" "github.com/pkg/errors" + "github.com/rs/zerolog/log" ) // Driver Configurations @@ -38,6 +39,10 @@ func (c *Config) ToEndpointURL() string { var userInfo string if c.AccessToken != "" { userInfo = fmt.Sprintf("%s:%s@", "token", url.QueryEscape(c.AccessToken)) + } else { + if c.Username != "" { + userInfo = fmt.Sprintf("%s:%s@", c.Username, url.QueryEscape(c.Password)) + } } endpointUrl := fmt.Sprintf("%s://%s%s:%d%s", c.Protocol, userInfo, c.Host, c.Port, c.HTTPPath) return endpointUrl @@ -76,7 +81,9 @@ type UserConfig struct { HTTPPath string // from databricks UI Catalog string Schema string - AccessToken string // from databricks UI + AccessToken string // from databricks UI + Username string + Password string MaxRows int // max rows per page QueryTimeout time.Duration // Timeout passed to server for query processing UserAgentEntry string @@ -110,6 +117,8 @@ func (ucfg UserConfig) DeepCopy() UserConfig { Catalog: ucfg.Catalog, Schema: ucfg.Schema, AccessToken: ucfg.AccessToken, + Username: ucfg.Username, + Password: ucfg.Password, MaxRows: ucfg.MaxRows, QueryTimeout: ucfg.QueryTimeout, UserAgentEntry: ucfg.UserAgentEntry, @@ -125,6 +134,9 @@ func (ucfg UserConfig) WithDefaults() UserConfig { if ucfg.Protocol == "" { ucfg.Protocol = "https" } + if ucfg.Port == 0 { + ucfg.Port = 443 + } ucfg.SessionParams = make(map[string]string) return ucfg } @@ -168,17 +180,15 @@ func ParseDSN(dsn string) (UserConfig, error) { } ucfg.Port = port name := parsedURL.User.Username() + pass, ok := parsedURL.User.Password() + if !ok { + log.Warn().Msg("password not set") + } if name == "token" { - pass, ok := parsedURL.User.Password() - if ok { - ucfg.AccessToken = pass - } else { - return UserConfig{}, errors.New("invalid DSN: token not set") - } + ucfg.AccessToken = pass } else { - if name != "" { - return UserConfig{}, errors.New("invalid DSN: basic auth not enabled") - } + ucfg.Username = name + ucfg.Password = pass } ucfg.HTTPPath = parsedURL.Path params := parsedURL.Query() diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 7ef42c81..05db3a96 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -223,6 +223,22 @@ func TestParseConfig(t *testing.T) { wantURL: "https://token:supersecret2@example.cloud.databricks.com:443", wantErr: false, }, + { + name: "with basic auth", + args: args{dsn: "jim:supersecret2@example.cloud.databricks.com:443/sql/1.0/endpoints/12346a5b5b0e123a"}, + wantCfg: UserConfig{ + Protocol: "https", + Host: "example.cloud.databricks.com", + Port: 443, + Username: "jim", + Password: "supersecret2", + MaxRows: 10000, + HTTPPath: "/sql/1.0/endpoints/12346a5b5b0e123a", + SessionParams: make(map[string]string), + }, + wantURL: "https://jim:supersecret2@example.cloud.databricks.com:443/sql/1.0/endpoints/12346a5b5b0e123a", + wantErr: false, + }, { name: "with wrong port", args: args{dsn: "token:supersecret2@example.cloud.databricks.com:foo/sql/1.0/endpoints/12346a5b5b0e123a?catalog=default&schema=system&timeout=100&maxRows=1000"}, @@ -230,20 +246,20 @@ func TestParseConfig(t *testing.T) { wantErr: true, }, { - name: "missing port", - args: args{dsn: "token:supersecret2@example.cloud.databricks.com?catalog=default&schema=system&timeout=100&maxRows=1000"}, + name: "with invalid maxRows", + args: args{dsn: "token:supersecret2@example.cloud.databricks.com:443/sql/1.0/endpoints/12346a5b5b0e123a?catalog=default&schema=system&timeout=100&maxRows=foo"}, wantCfg: UserConfig{}, wantErr: true, }, { - name: "with wrong username", - args: args{dsn: "jim:supersecret2@example.cloud.databricks.com:443/sql/1.0/endpoints/12346a5b5b0e123a?catalog=default&schema=system&timeout=100&maxRows=1000"}, + name: "with invalid timeout", + args: args{dsn: "token:supersecret2@example.cloud.databricks.com:443/sql/1.0/endpoints/12346a5b5b0e123a?catalog=default&schema=system&timeout=foo&maxRows=12"}, wantCfg: UserConfig{}, wantErr: true, }, { - name: "with token but no secret", - args: args{dsn: "token@example.cloud.databricks.com:443/sql/1.0/endpoints/12346a5b5b0e123a?catalog=default&schema=system&timeout=100&maxRows=1000"}, + name: "missing port", + args: args{dsn: "token:supersecret2@example.cloud.databricks.com?catalog=default&schema=system&timeout=100&maxRows=1000"}, wantCfg: UserConfig{}, wantErr: true, },