Skip to content

Commit

Permalink
Adding ability for odbc URLs to ignore certain parameter prefixes
Browse files Browse the repository at this point in the history
  • Loading branch information
kenshaw committed Jan 17, 2024
1 parent 20e113b commit 65f8664
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 12 deletions.
13 changes: 13 additions & 0 deletions dburl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ func testBadParse(t *testing.T, s string, exp error) {
}

func TestParse(t *testing.T) {
OdbcIgnoreQueryPrefixes = []string{"usql_"}
tests := []struct {
s string
d string
Expand Down Expand Up @@ -330,6 +331,18 @@ func TestParse(t *testing.T) {
`Provider=MSDASQL.1;Extended Properties="Database=dbname;Driver={Postgres Unicode};PWD=pass;Port=5432;Server=host;UID=user"`,
``,
},
{
`odbc+Postgres+Unicode://user:pass@host:5432/dbname?not_ignored=1`,
`odbc`,
`Database=dbname;Driver={Postgres Unicode};PWD=pass;Port=5432;Server=host;UID=user;not_ignored=1`,
``,
},
{
`odbc+Postgres+Unicode://user:pass@host:5432/dbname?usql_ignore=1&not_ignored=1`,
`odbc`,
`Database=dbname;Driver={Postgres Unicode};PWD=pass;Port=5432;Server=host;UID=user;not_ignored=1`,
``,
},
{
`sqlite:///path/to/file.sqlite3`,
`sqlite3`,
Expand Down
39 changes: 27 additions & 12 deletions dsn.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import (
"strings"
)

// OdbcIgnoreQueryPrefixes are the query prefixes to ignore when generating the
// odbc DSN. Used by GenOdbc
var OdbcIgnoreQueryPrefixes []string

// GenScheme returns a generator that will generate a scheme based on the
// passed scheme DSN.
func GenScheme(scheme string) func(*URL) (string, string, error) {
Expand Down Expand Up @@ -126,7 +130,7 @@ func GenAdodb(u *URL) (string, string, error) {
}
u.hostPortDB = []string{host, port, n}
}
return genOptionsOdbc(q, true), "", nil
return genOptionsOdbc(q, true, nil, nil), "", nil
}

// GenCassandra generates a cassandra DSN from the passed URL.
Expand Down Expand Up @@ -169,7 +173,7 @@ func GenCosmos(u *URL) (string, string, error) {
if dbname != "" {
q.Set("Db", dbname)
}
return genOptionsOdbc(q, true), "", nil
return genOptionsOdbc(q, true, nil, nil), "", nil
}

// GenDatabend generates a databend DSN from the passed URL.
Expand All @@ -192,7 +196,7 @@ func GenDynamo(u *URL) (string, string, error) {
v = append(v, "Secret_Key="+pass)
}
}
return strings.Join(v, ";") + genOptions(u.Query(), ";", "=", ";", ",", true, "Region", "Secret_Key", "AkId"), "", nil
return strings.Join(v, ";") + genOptions(u.Query(), ";", "=", ";", ",", true, []string{"Region", "Secret_Key", "AkId"}, nil), "", nil
}

// GenDatabricks generates a databricks DSN from the passed URL.
Expand All @@ -213,7 +217,7 @@ func GenDatabricks(u *URL) (string, string, error) {
port = "443"
}
s := fmt.Sprintf("token:%s@%s.databricks.com:%s/sql/1.0/endpoints/%s", user, pass, port, host)
return s + genOptions(u.Query(), "?", "=", "&", ",", true), "", nil
return s + genOptions(u.Query(), "?", "=", "&", ",", true, nil, nil), "", nil
}

// GenExasol generates a exasol DSN from the passed URL.
Expand All @@ -234,7 +238,7 @@ func GenExasol(u *URL) (string, string, error) {
pass, _ := u.User.Password()
q.Set("password", pass)
}
return fmt.Sprintf("exa:%s:%s%s", host, port, genOptions(q, ";", "=", ";", ",", true)), "", nil
return fmt.Sprintf("exa:%s:%s%s", host, port, genOptions(q, ";", "=", ";", ",", true, nil, nil)), "", nil
}

// GenFirebird generates a firebird DSN from the passed URL.
Expand Down Expand Up @@ -340,6 +344,7 @@ func GenMymysql(u *URL) (string, string, error) {
dsn += genOptions(
convertOptions(u.Query(), "true", ""),
",", "=", ",", " ", false,
nil, nil,
)
dsn += "*" + dbname
if u.User != nil {
Expand Down Expand Up @@ -426,7 +431,7 @@ func GenOdbc(u *URL) (string, string, error) {
p, _ := u.User.Password()
q.Set("PWD", p)
}
return genOptionsOdbc(q, true), "", nil
return genOptionsOdbc(q, true, nil, OdbcIgnoreQueryPrefixes), "", nil
}

// GenOleodbc generates a oleodbc DSN from the passed URL.
Expand Down Expand Up @@ -466,7 +471,7 @@ func GenPostgres(u *URL) (string, string, error) {
if u.hostPortDB == nil {
u.hostPortDB = []string{host, port, dbname}
}
return genOptions(q, "", "=", " ", ",", true), "", nil
return genOptions(q, "", "=", " ", ",", true, nil, nil), "", nil
}

// GenPresto generates a presto DSN from the passed URL.
Expand Down Expand Up @@ -634,7 +639,7 @@ func GenYDB(u *URL) (string, string, error) {
userpass = u.User.String() + "@"
}
s := scheme + "://" + userpass + host + ":" + port + "/" + strings.TrimPrefix(u.Path, "/")
return s + genOptions(u.Query(), "?", "=", "&", ",", true), "", nil
return s + genOptions(u.Query(), "?", "=", "&", ",", true, nil, nil), "", nil
}

// convertOptions converts an option value based on name, value pairs.
Expand Down Expand Up @@ -665,8 +670,8 @@ func genQueryOptions(q url.Values) string {

// genOptionsOdbc is a util wrapper around genOptions that uses the fixed
// settings for ODBC style connection strings.
func genOptionsOdbc(q url.Values, skipWhenEmpty bool, ignore ...string) string {
return genOptions(q, "", "=", ";", ",", skipWhenEmpty, ignore...)
func genOptionsOdbc(q url.Values, skipWhenEmpty bool, ignore, ignorePrefixes []string) string {
return genOptions(q, "", "=", ";", ",", skipWhenEmpty, ignore, ignorePrefixes)
}

// genOptions takes URL values and generates options, joining together with
Expand All @@ -677,7 +682,7 @@ func genOptionsOdbc(q url.Values, skipWhenEmpty bool, ignore ...string) string {
// following:
//
// genOptions(u.Query(), "", "=", ";", ",", false)
func genOptions(q url.Values, joiner, assign, sep, valSep string, skipWhenEmpty bool, ignore ...string) string {
func genOptions(q url.Values, joiner, assign, sep, valSep string, skipWhenEmpty bool, ignore, ignorePrefixes []string) string {
if len(q) == 0 {
return ""
}
Expand All @@ -696,7 +701,7 @@ func genOptions(q url.Values, joiner, assign, sep, valSep string, skipWhenEmpty
sort.Strings(s)
var opts []string
for _, k := range s {
if !ig[strings.ToLower(k)] {
if s := strings.ToLower(k); !ig[s] && !hasPrefix(s, ignorePrefixes) {
val := strings.Join(q[k], valSep)
if !skipWhenEmpty || val != "" {
if val != "" {
Expand All @@ -711,3 +716,13 @@ func genOptions(q url.Values, joiner, assign, sep, valSep string, skipWhenEmpty
}
return ""
}

// hasPrefix returns true when s begins with any listed prefix.
func hasPrefix(s string, prefixes []string) bool {
for _, prefix := range prefixes {
if strings.HasPrefix(s, prefix) {
return true
}
}
return false
}

0 comments on commit 65f8664

Please sign in to comment.