Repository: snowflakedb/gosnowflake
Pull request #818 (2023-06-09 15:39:18)

SNOW-832816: Unify and remove duplicates of getDsn() function
### Description
Unified the approach how to get the config from the environment variables and replaced duplicated code with new GetConfigFromEnv function

### Checklist
- [x] Code compiles correctly
- [x] Run ``make fmt`` to fix inconsistent formats
- [x] Run ``make lint`` to get lint errors and fix all of them
- [x] Created tests which fail without the change (if possible)
- [x] All tests passing
- [x] Extended the README / documentation, if necessary



Patch:
diff --git a/cmd/async/async.go b/cmd/async/async.go
index 7557a16..b7b3443 100644
--- a/cmd/async/async.go
+++ b/cmd/async/async.go
@@ -6,12 +6,13 @@ import (
 	"database/sql/driver"
 	"flag"
 	"fmt"
-	sf "github.com/snowflakedb/gosnowflake"
 	"io"
 	"log"
 	"os"
 	"strconv"
 	"strings"
+
+	sf "github.com/snowflakedb/gosnowflake"
 )
 
 func getDSN() (string, *sf.Config, error) {
diff --git a/cmd/externalbrowser/externalbrowser.go b/cmd/externalbrowser/externalbrowser.go
index 6a6e686..f7073c0 100644
--- a/cmd/externalbrowser/externalbrowser.go
+++ b/cmd/externalbrowser/externalbrowser.go
@@ -5,51 +5,10 @@ import (
 	"flag"
 	"fmt"
 	"log"
-	"os"
-	"strconv"
 
 	sf "github.com/snowflakedb/gosnowflake"
 )
 
-// getDSN constructs a DSN based on the test connection parameters
-func getDSN() (string, *sf.Config, error) {
-	env := func(k string, failOnMissing bool) string {
-		if value := os.Getenv(k); value != "" {
-			return value
-		}
-		if failOnMissing {
-			log.Fatalf("%v environment variable is not set.", k)
-		}
-		return ""
-	}
-
-	account := env("SNOWFLAKE_TEST_ACCOUNT", true)
-	user := env("SNOWFLAKE_TEST_USER", true)
-	host := env("SNOWFLAKE_TEST_HOST", false)
-	portStr := env("SNOWFLAKE_TEST_PORT", false)
-	protocol := env("SNOWFLAKE_TEST_PROTOCOL", false)
-
-	port := 443 // snowflake default port
-	var err error
-	if len(portStr) > 0 {
-		port, err = strconv.Atoi(portStr)
-		if err != nil {
-			return "", nil, err
-		}
-	}
-	cfg := &sf.Config{
-		Authenticator: sf.AuthTypeExternalBrowser,
-		Account:       account,
-		User:          user,
-		Host:          host,
-		Port:          port,
-		Protocol:      protocol,
-	}
-
-	dsn, err := sf.DSN(cfg)
-	return dsn, cfg, err
-}
-
 // A simple test program for authenticating with an external browser.
 // In order for this to work, SSO needs to be set up on Snowflake as per:
 // https://docs.snowflake.net/manuals/user-guide/admin-security-fed-auth-configure-snowflake.html
@@ -57,8 +16,18 @@ func main() {
 	if !flag.Parsed() {
 		flag.Parse()
 	}
-	dsn, cfg, err := getDSN()
-
+	cfg, err := sf.GetConfigFromEnv([]*sf.ConfigParam{
+		{Name: "Account", EnvName: "SNOWFLAKE_TEST_ACCOUNT", FailOnMissing: true},
+		{Name: "User", EnvName: "SNOWFLAKE_TEST_USER", FailOnMissing: true},
+		{Name: "Host", EnvName: "SNOWFLAKE_TEST_HOST", FailOnMissing: false},
+		{Name: "Port", EnvName: "SNOWFLAKE_TEST_PORT", FailOnMissing: false},
+		{Name: "Protocol", EnvName: "SNOWFLAKE_TEST_PROTOCOL", FailOnMissing: false},
+	})
+	if err != nil {
+		log.Fatalf("failed to create Config, err: %v", err)
+	}
+	cfg.Authenticator = sf.AuthTypeExternalBrowser
+	dsn, err := sf.DSN(cfg)
 	if err != nil {
 		log.Fatalf("failed to create DSN from Config: %v, err: %v", cfg, err)
 	}
diff --git a/cmd/keepalive/keepalive.go b/cmd/keepalive/keepalive.go
index 3ac55a9..d3ddf47 100644
--- a/cmd/keepalive/keepalive.go
+++ b/cmd/keepalive/keepalive.go
@@ -8,59 +8,11 @@ import (
 	"flag"
 	"fmt"
 	"log"
-	"os"
-	"strconv"
 	"time"
 
 	sf "github.com/snowflakedb/gosnowflake"
 )
 
-// getDSN constructs a DSN based on the test connection parameters
-func getDSN() (string, *sf.Config, error) {
-	env := func(k string, failOnMissing bool) string {
-		if value := os.Getenv(k); value != "" {
-			return value
-		}
-		if failOnMissing {
-			log.Fatalf("%v environment variable is not set.", k)
-		}
-		return ""
-	}
-
-	account := env("SNOWFLAKE_TEST_ACCOUNT", true)
-	user := env("SNOWFLAKE_TEST_USER", true)
-	password := env("SNOWFLAKE_TEST_PASSWORD", true)
-	host := env("SNOWFLAKE_TEST_HOST", false)
-	portStr := env("SNOWFLAKE_TEST_PORT", false)
-	protocol := env("SNOWFLAKE_TEST_PROTOCOL", false)
-
-	params := make(map[string]*string)
-	valueTrue := "true"
-	params["client_session_keep_alive"] = &valueTrue
-
-	port := 443 // snowflake default port
-	var err error
-	if len(portStr) > 0 {
-		port, err = strconv.Atoi(portStr)
-		if err != nil {
-			return "", nil, err
-		}
-	}
-
-	cfg := &sf.Config{
-		Account:  account,
-		User:     user,
-		Password: password,
-		Host:     host,
-		Port:     port,
-		Protocol: protocol,
-		Params:   params,
-	}
-
-	dsn, err := sf.DSN(cfg)
-	return dsn, cfg, err
-}
-
 func runQuery(db *sql.DB, query string) {
 	rows, err := db.Query(query) // no cancel is allowed
 	if err != nil {
@@ -89,7 +41,18 @@ func main() {
 		flag.Parse()
 	}
 
-	dsn, cfg, err := getDSN()
+	cfg, err := sf.GetConfigFromEnv([]*sf.ConfigParam{
+		{Name: "Account", EnvName: "SNOWFLAKE_TEST_ACCOUNT", FailOnMissing: true},
+		{Name: "User", EnvName: "SNOWFLAKE_TEST_USER", FailOnMissing: true},
+		{Name: "Password", EnvName: "SNOWFLAKE_TEST_PASSWORD", FailOnMissing: true},
+		{Name: "Host", EnvName: "SNOWFLAKE_TEST_HOST", FailOnMissing: false},
+		{Name: "Port", EnvName: "SNOWFLAKE_TEST_PORT", FailOnMissing: false},
+		{Name: "Protocol", EnvName: "SNOWFLAKE_TEST_PROTOCOL", FailOnMissing: false},
+	})
+	if err != nil {
+		log.Fatalf("failed to create Config, err: %v", err)
+	}
+	dsn, err := sf.DSN(cfg)
 	if err != nil {
 		log.Fatalf("failed to create DSN from Config: %v, err: %v", cfg, err)
 	}
diff --git a/cmd/keypair/keypair.go b/cmd/keypair/keypair.go
index 639be4a..d634da0 100644
--- a/cmd/keypair/keypair.go
+++ b/cmd/keypair/keypair.go
@@ -4,81 +4,32 @@
 package main
 
 import (
-	"crypto/rsa"
-	"crypto/x509"
 	"database/sql"
-	"encoding/pem"
 	"flag"
 	"fmt"
 	"log"
-	"os"
-	"strconv"
 
 	sf "github.com/snowflakedb/gosnowflake"
 )
 
-// getDSN constructs a DSN based on the test connection parameters
-func getDSN() (string, *sf.Config, error) {
-	env := func(k string, failOnMissing bool) string {
-		if value := os.Getenv(k); value != "" {
-			return value
-		}
-		if failOnMissing {
-			log.Fatalf("%v environment variable is not set.", k)
-		}
-		return ""
-	}
-
-	account := env("SNOWFLAKE_TEST_ACCOUNT", true)
-	user := env("SNOWFLAKE_TEST_USER", true)
-	host := env("SNOWFLAKE_TEST_HOST", false)
-	portStr := env("SNOWFLAKE_TEST_PORT", false)
-	protocol := env("SNOWFLAKE_TEST_PROTOCOL", false)
-	privKeyPath := env("SNOWFLAKE_TEST_PRIVATE_KEY", true)
-
-	// Read and parse the private key
-	data, err := os.ReadFile(privKeyPath)
-	if err != nil {
-		log.Fatal(err)
-	}
-	block, _ := pem.Decode([]byte(data))
-	if block == nil {
-		panic("failed to parse PEM block containing the private key")
-	}
-	privKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
-	if err != nil {
-		log.Fatal(err)
-	}
-	rsaPrivateKey, _ := privKey.(*rsa.PrivateKey)
-
-	port := 443 // snowflake default port
-	if len(portStr) > 0 {
-		port, err = strconv.Atoi(portStr)
-		if err != nil {
-			return "", nil, err
-		}
-	}
-
-	cfg := &sf.Config{
-		Account:       account,
-		User:          user,
-		Host:          host,
-		Port:          port,
-		Protocol:      protocol,
-		Authenticator: sf.AuthTypeJwt,
-		PrivateKey:    rsaPrivateKey,
-	}
-
-	dsn, err := sf.DSN(cfg)
-	return dsn, cfg, err
-}
-
 func main() {
 	if !flag.Parsed() {
 		flag.Parse()
 	}
 
-	dsn, cfg, err := getDSN()
+	cfg, err := sf.GetConfigFromEnv([]*sf.ConfigParam{
+		{Name: "Account", EnvName: "SNOWFLAKE_TEST_ACCOUNT", FailOnMissing: true},
+		{Name: "User", EnvName: "SNOWFLAKE_TEST_USER", FailOnMissing: true},
+		{Name: "Host", EnvName: "SNOWFLAKE_TEST_HOST", FailOnMissing: false},
+		{Name: "Port", EnvName: "SNOWFLAKE_TEST_PORT", FailOnMissing: false},
+		{Name: "Protocol", EnvName: "SNOWFLAKE_TEST_PROTOCOL", FailOnMissing: false},
+		{Name: "PrivateKey", EnvName: "SNOWFLAKE_TEST_PRIVATE_KEY", FailOnMissing: true},
+	})
+	if err != nil {
+		log.Fatalf("failed to create Config, err: %v", err)
+	}
+	cfg.Authenticator = sf.AuthTypeJwt
+	dsn, err := sf.DSN(cfg)
 	if err != nil {
 		log.Fatalf("failed to create DSN from Config: %v, err: %v", cfg, err)
 	}
diff --git a/cmd/mfa/mfa.go b/cmd/mfa/mfa.go
index 0f4ffdc..e85d746 100644
--- a/cmd/mfa/mfa.go
+++ b/cmd/mfa/mfa.go
@@ -5,60 +5,28 @@ import (
 	"flag"
 	"fmt"
 	"log"
-	"os"
-	"strconv"
 
 	sf "github.com/snowflakedb/gosnowflake"
 )
 
-// getDSN constructs a DSN based on the test connection parameters
-func getDSN() (string, *sf.Config, error) {
-	env := func(k string, failOnMissing bool) string {
-		if value := os.Getenv(k); value != "" {
-			return value
-		}
-		if failOnMissing {
-			log.Fatalf("%v environment variable is not set.", k)
-		}
-		return ""
-	}
-
-	account := env("SNOWFLAKE_TEST_ACCOUNT", true)
-	user := env("SNOWFLAKE_TEST_USER", true)
-	password := env("SNOWFLAKE_TEST_PASSWORD", true)
-	host := env("SNOWFLAKE_TEST_HOST", false)
-	portStr := env("SNOWFLAKE_TEST_PORT", false)
-	protocol := env("SNOWFLAKE_TEST_PROTOCOL", false)
-
-	port := 443 // snowflake default port
-	var err error
-	if len(portStr) > 0 {
-		port, err = strconv.Atoi(portStr)
-		if err != nil {
-			return "", nil, err
-		}
-	}
-	cfg := &sf.Config{
-		Account:       account,
-		Authenticator: sf.AuthTypeUsernamePasswordMFA,
-		User:          user,
-		Host:          host,
-		Password:      password,
-		Port:          port,
-		Protocol:      protocol,
-	}
-
-	dsn, err := sf.DSN(cfg)
-	return dsn, cfg, err
-}
-
 func main() {
 	if !flag.Parsed() {
 		flag.Parse()
 	}
 
-	dsn, cfg, err := getDSN()
-
+	cfg, err := sf.GetConfigFromEnv([]*sf.ConfigParam{
+		{Name: "Account", EnvName: "SNOWFLAKE_TEST_ACCOUNT", FailOnMissing: true},
+		{Name: "User", EnvName: "SNOWFLAKE_TEST_USER", FailOnMissing: true},
+		{Name: "Password", EnvName: "SNOWFLAKE_TEST_PASSWORD", FailOnMissing: true},
+		{Name: "Host", EnvName: "SNOWFLAKE_TEST_HOST", FailOnMissing: false},
+		{Name: "Port", EnvName: "SNOWFLAKE_TEST_PORT", FailOnMissing: false},
+		{Name: "Protocol", EnvName: "SNOWFLAKE_TEST_PROTOCOL", FailOnMissing: false},
+	})
+	if err != nil {
+		log.Fatalf("failed to create Config, err: %v", err)
+	}
+	cfg.Authenticator = sf.AuthTypeUsernamePasswordMFA
+	dsn, err := sf.DSN(cfg)
 	if err != nil {
 		log.Fatalf("failed to create DSN from Config: %v, err: %v", cfg, err)
 	}
diff --git a/cmd/multistatement/multistatement.go b/cmd/multistatement/multistatement.go
index 9b3477d..da53bf9 100644
--- a/cmd/multistatement/multistatement.go
+++ b/cmd/multistatement/multistatement.go
@@ -6,65 +6,32 @@ import (
 	"flag"
 	"fmt"
 	"log"
-	"os"
-	"strconv"
 	"time"
 
 	sf "github.com/snowflakedb/gosnowflake"
 )
 
-func getDSN() (string, *sf.Config, error) {
-	env := func(key string, failOnMissing bool) string {
-		if value := os.Getenv(key); value != "" {
-			return value
-		}
-		if failOnMissing {
-			log.Fatalf("%v environment not set", key)
-		}
-		return ""
-	}
-
-	account := env("SNOWFLAKE_TEST_ACCOUNT", true)
-	user := env("SNOWFLAKE_TEST_USER", true)
-	password := env("SNOWFLAKE_TEST_PASSWORD", true)
-	host := env("SNOWFLAKE_TEST_HOST", false)
-	portStr := env("SNOWFLAKE_TEST_PORT", false)
-	protocol := env("SNOWFLAKE_TEST_PROTOCOL", false)
-	database := env("SNOWFLAKE_TEST_DATABASE", true)
-	schema := env("SNOWFLAKE_TEST_SCHEMA", true)
-
-	port := 443
-	var err error
-	if len(portStr) > 0 {
-		port, err = strconv.Atoi(portStr)
-		if err != nil {
-			return "", nil, err
-		}
-	}
-
-	cfg := &sf.Config{
-		Account:  account,
-		User:     user,
-		Password: password,
-		Host:     host,
-		Port:     port,
-		Protocol: protocol,
-		Database: database,
-		Schema:   schema,
-	}
-
-	dsn, err := sf.DSN(cfg)
-	return dsn, cfg, err
-}
-
 func main() {
 	if !flag.Parsed() {
 		flag.Parse()
 	}
 
-	dsn, config, err := getDSN()
+	cfg, err := sf.GetConfigFromEnv([]*sf.ConfigParam{
+		{Name: "Account", EnvName: "SNOWFLAKE_TEST_ACCOUNT", FailOnMissing: true},
+		{Name: "User", EnvName: "SNOWFLAKE_TEST_USER", FailOnMissing: true},
+		{Name: "Password", EnvName: "SNOWFLAKE_TEST_PASSWORD", FailOnMissing: true},
+		{Name: "Host", EnvName: "SNOWFLAKE_TEST_HOST", FailOnMissing: false},
+		{Name: "Port", EnvName: "SNOWFLAKE_TEST_PORT", FailOnMissing: false},
+		{Name: "Protocol", EnvName: "SNOWFLAKE_TEST_PROTOCOL", FailOnMissing: false},
+		{Name: "Database", EnvName: "SNOWFLAKE_TEST_DATABASE", FailOnMissing: true},
+		{Name: "Schema", EnvName: "SNOWFLAKE_TEST_SCHEMA", FailOnMissing: true},
+	})
+	if err != nil {
+		log.Fatalf("failed to create Config, err: %v", err)
+	}
+	dsn, err := sf.DSN(cfg)
 	if err != nil {
-		log.Fatalf("Failed to create DSN from config: %v, error: %v", config, err)
+		log.Fatalf("Failed to create DSN from config: %v, error: %v", cfg, err)
 	}
 
 	db, err := sql.Open("snowflake", dsn)
diff --git a/cmd/noconnpool/noconnpool.go b/cmd/noconnpool/noconnpool.go
index 39726ad..5eb14fc 100644
--- a/cmd/noconnpool/noconnpool.go
+++ b/cmd/noconnpool/noconnpool.go
@@ -9,62 +9,28 @@ import (
 	"flag"
 	"fmt"
 	"log"
-	"os"
-	"strconv"
 	"sync"
 
 	sf "github.com/snowflakedb/gosnowflake"
 )
 
-// getDSN constructs a DSN based on the test connection parameters
-func getDSN() (string, *sf.Config, error) {
-	env := func(k string, failOnMissing bool) string {
-		if value := os.Getenv(k); value != "" {
-			return value
-		}
-		if failOnMissing {
-			log.Fatalf("%v environment variable is not set.", k)
-		}
-		return ""
-	}
-
-	account := env("SNOWFLAKE_TEST_ACCOUNT", true)
-	user := env("SNOWFLAKE_TEST_USER", true)
-	password := env("SNOWFLAKE_TEST_PASSWORD", true)
-	host := env("SNOWFLAKE_TEST_HOST", false)
-	portStr := env("SNOWFLAKE_TEST_PORT", false)
-	protocol := env("SNOWFLAKE_TEST_PROTOCOL", false)
-
-	port := 443 // snowflake default port
-	var err error
-	if len(portStr) > 0 {
-		port, err = strconv.Atoi(portStr)
-		if err != nil {
-			return "", nil, err
-		}
-	}
-	if err != nil {
-		return "", nil, err
-	}
-	cfg := &sf.Config{
-		Account:  account,
-		User:     user,
-		Password: password,
-		Host:     host,
-		Port:     port,
-		Protocol: protocol,
-	}
-
-	dsn, err := sf.DSN(cfg)
-	return dsn, cfg, err
-}
-
 func main() {
 	if !flag.Parsed() {
 		flag.Parse()
 	}
 
-	dsn, cfg, err := getDSN()
+	cfg, err := sf.GetConfigFromEnv([]*sf.ConfigParam{
+		{Name: "Account", EnvName: "SNOWFLAKE_TEST_ACCOUNT", FailOnMissing: true},
+		{Name: "User", EnvName: "SNOWFLAKE_TEST_USER", FailOnMissing: true},
+		{Name: "Password", EnvName: "SNOWFLAKE_TEST_PASSWORD", FailOnMissing: true},
+		{Name: "Host", EnvName: "SNOWFLAKE_TEST_HOST", FailOnMissing: false},
+		{Name: "Port", EnvName: "SNOWFLAKE_TEST_PORT", FailOnMissing: false},
+		{Name: "Protocol", EnvName: "SNOWFLAKE_TEST_PROTOCOL", FailOnMissing: false},
+	})
+	if err != nil {
+		log.Fatalf("failed to create Config, err: %v", err)
+	}
+	dsn, err := sf.DSN(cfg)
 	if err != nil {
 		log.Fatalf("failed to create DSN from Config: %v, err: %v", cfg, err)
 	}
diff --git a/cmd/select1/select1.go b/cmd/select1/select1.go
index f5722f9..6cd328b 100644
--- a/cmd/select1/select1.go
+++ b/cmd/select1/select1.go
@@ -9,59 +9,27 @@ import (
 	"flag"
 	"fmt"
 	"log"
-	"os"
-	"strconv"
 
 	sf "github.com/snowflakedb/gosnowflake"
 )
 
-// getDSN constructs a DSN based on the test connection parameters
-func getDSN() (string, *sf.Config, error) {
-	env := func(k string, failOnMissing bool) string {
-		if value := os.Getenv(k); value != "" {
-			return value
-		}
-		if failOnMissing {
-			log.Fatalf("%v environment variable is not set.", k)
-		}
-		return ""
-	}
-
-	account := env("SNOWFLAKE_TEST_ACCOUNT", true)
-	user := env("SNOWFLAKE_TEST_USER", true)
-	password := env("SNOWFLAKE_TEST_PASSWORD", true)
-	host := env("SNOWFLAKE_TEST_HOST", false)
-	portStr := env("SNOWFLAKE_TEST_PORT", false)
-	protocol := env("SNOWFLAKE_TEST_PROTOCOL", false)
-
-	port := 443 // snowflake default port
-	var err error
-	if len(portStr) > 0 {
-		port, err = strconv.Atoi(portStr)
-		if err != nil {
-			return "", nil, err
-		}
-	}
-
-	cfg := &sf.Config{
-		Account:  account,
-		User:     user,
-		Password: password,
-		Host:     host,
-		Port:     port,
-		Protocol: protocol,
-	}
-
-	dsn, err := sf.DSN(cfg)
-	return dsn, cfg, err
-}
-
 func main() {
 	if !flag.Parsed() {
 		flag.Parse()
 	}
 
-	dsn, cfg, err := getDSN()
+	cfg, err := sf.GetConfigFromEnv([]*sf.ConfigParam{
+		{Name: "Account", EnvName: "SNOWFLAKE_TEST_ACCOUNT", FailOnMissing: true},
+		{Name: "User", EnvName: "SNOWFLAKE_TEST_USER", FailOnMissing: true},
+		{Name: "Password", EnvName: "SNOWFLAKE_TEST_PASSWORD", FailOnMissing: true},
+		{Name: "Host", EnvName: "SNOWFLAKE_TEST_HOST", FailOnMissing: false},
+		{Name: "Port", EnvName: "SNOWFLAKE_TEST_PORT", FailOnMissing: false},
+		{Name: "Protocol", EnvName: "SNOWFLAKE_TEST_PROTOCOL", FailOnMissing: false},
+	})
+	if err != nil {
+		log.Fatalf("failed to create Config, err: %v", err)
+	}
+	dsn, err := sf.DSN(cfg)
 	if err != nil {
 		log.Fatalf("failed to create DSN from Config: %v, err: %v", cfg, err)
 	}
diff --git a/cmd/selectmany/selectmany.go b/cmd/selectmany/selectmany.go
index 91fd740..06f3edb 100644
--- a/cmd/selectmany/selectmany.go
+++ b/cmd/selectmany/selectmany.go
@@ -9,12 +9,8 @@ import (
 	"log"
 	"os"
 	"os/signal"
-	"runtime/pprof"
-	"strconv"
-
-	_ "net/http/pprof"
-
 	"runtime/debug"
+	"runtime/pprof"
 
 	sf "github.com/snowflakedb/gosnowflake"
 )
@@ -24,46 +20,6 @@ var (
 	memprofile = flag.String("memprofile", "", "write memory profile to this file")
 )
 
-// getDSN constructs a DSN based on the test connection parameters
-func getDSN() (string, *sf.Config, error) {
-	env := func(k string, failOnMissing bool) string {
-		if value := os.Getenv(k); value != "" {
-			return value
-		}
-		if failOnMissing {
-			log.Fatalf("%v environment variable is not set.", k)
-		}
-		return ""
-	}
-
-	account := env("SNOWFLAKE_TEST_ACCOUNT", true)
-	user := env("SNOWFLAKE_TEST_USER", true)
-	password := env("SNOWFLAKE_TEST_PASSWORD", true)
-	host := env("SNOWFLAKE_TEST_HOST", false)
-	portStr := env("SNOWFLAKE_TEST_PORT", false)
-	protocol := env("SNOWFLAKE_TEST_PROTOCOL", false)
-
-	port := 443 // snowflake default port
-	var err error
-	if len(portStr) > 0 {
-		port, err = strconv.Atoi(portStr)
-		if err != nil {
-			return "", nil, err
-		}
-	}
-	cfg := &sf.Config{
-		Account:  account,
-		User:     user,
-		Password: password,
-		Host:     host,
-		Port:     port,
-		Protocol: protocol,
-	}
-
-	dsn, err := sf.DSN(cfg)
-	return dsn, cfg, err
-}
-
 // run is an actual main
 func run(dsn string) {
 	// handler interrupt signal
@@ -128,7 +84,18 @@ func main() {
 		flag.Parse()
 	}
 
-	dsn, cfg, err := getDSN()
+	cfg, err := sf.GetConfigFromEnv([]*sf.ConfigParam{
+		{Name: "Account", EnvName: "SNOWFLAKE_TEST_ACCOUNT", FailOnMissing: true},
+		{Name: "User", EnvName: "SNOWFLAKE_TEST_USER", FailOnMissing: true},
+		{Name: "Password", EnvName: "SNOWFLAKE_TEST_PASSWORD", FailOnMissing: true},
+		{Name: "Host", EnvName: "SNOWFLAKE_TEST_HOST", FailOnMissing: false},
+		{Name: "Port", EnvName: "SNOWFLAKE_TEST_PORT", FailOnMissing: false},
+		{Name: "Protocol", EnvName: "SNOWFLAKE_TEST_PROTOCOL", FailOnMissing: false},
+	})
+	if err != nil {
+		log.Fatalf("failed to create Config, err: %v", err)
+	}
+	dsn, err := sf.DSN(cfg)
 	if err != nil {
 		log.Fatalf("failed to create DSN from Config: %v, err: %v", cfg, err)
 	}
diff --git a/dsn.go b/dsn.go
index ae4decd..6a33cb9 100644
--- a/dsn.go
+++ b/dsn.go
@@ -4,11 +4,15 @@ package gosnowflake
 
 import (
 	"crypto/rsa"
+	"crypto/x509"
 	"encoding/base64"
+	"encoding/pem"
+	"errors"
 	"fmt"
 	"net"
 	"net/http"
 	"net/url"
+	"os"
 	"strconv"
 	"strings"
 	"time"
@@ -665,3 +669,101 @@ func parseTimeout(value string) (time.Duration, error) {
 	}
 	return time.Duration(vv * int64(time.Second)), nil
 }
+
+// ConfigParam is used to bind the name of the Config field with the environment variable and set the requirement for it
+type ConfigParam struct {
+	Name          string
+	EnvName       string
+	FailOnMissing bool
+}
+
+// GetConfigFromEnv is used to parse the environment variable values to specific fields of the Config
+func GetConfigFromEnv(properties []*ConfigParam) (*Config, error) {
+	var account, user, password, role, host, portStr, protocol, warehouse, database, schema, region, passcode, application string
+	var privateKey *rsa.PrivateKey
+	var err error
+	if len(properties) == 0 || properties == nil {
+		return nil, errors.New("missing configuration parameters for the connection")
+	}
+	for _, prop := range properties {
+		value, err := GetFromEnv(prop.EnvName, prop.FailOnMissing)
+		if err != nil {
+			return nil, err
+		}
+		switch prop.Name {
+		case "Account":
+			account = value
+		case "User":
+			user = value
+		case "Password":
+			password = value
+		case "Role":
+			role = value
+		case "Host":
+			host = value
+		case "Port":
+			portStr = value
+		case "Protocol":
+			protocol = value
+		case "Warehouse":
+			warehouse = value
+		case "Database":
+			database = value
+		case "Region":
+			region = value
+		case "Passcode":
+			passcode = value
+		case "Schema":
+			schema = value
+		case "Application":
+			application = value
+		case "PrivateKey":
+			privateKey, err = parsePrivateKeyFromFile(value)
+			if err != nil {
+				return nil, err
+			}
+		}
+	}
+
+	port := 443 // snowflake default port
+	if len(portStr) > 0 {
+		port, err = strconv.Atoi(portStr)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	cfg := &Config{
+		Account:     account,
+		User:        user,
+		Password:    password,
+		Role:        role,
+		Host:        host,
+		Port:        port,
+		Protocol:    protocol,
+		Warehouse:   warehouse,
+		Database:    database,
+		Schema:      schema,
+		PrivateKey:  privateKey,
+		Region:      region,
+		Passcode:    passcode,
+		Application: application,
+	}
+	return cfg, nil
+}
+
+func parsePrivateKeyFromFile(path string) (*rsa.PrivateKey, error) {
+	bytes, err := os.ReadFile(path)
+	if err != nil {
+		return nil, err
+	}
+	block, _ := pem.Decode(bytes)
+	if block == nil {
+		return nil, errors.New("failed to parse PEM block containing the private key")
+	}
+	privateKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
+	if err != nil {
+		return nil, err
+	}
+	return privateKey.(*rsa.PrivateKey), nil
+}
diff --git a/util.go b/util.go
index 17db5f8..d112189 100644
--- a/util.go
+++ b/util.go
@@ -5,7 +5,9 @@ package gosnowflake
 import (
 	"context"
 	"database/sql/driver"
+	"fmt"
 	"io"
+	"os"
 	"strings"
 	"sync"
 	"time"
@@ -222,3 +224,14 @@ func escapeForCSV(value string) string {
 	}
 	return value
 }
+
+// GetFromEnv is used to get the value of an environment variable from the system
+func GetFromEnv(name string, failOnMissing bool) (string, error) {
+	if value := os.Getenv(name); value != "" {
+		return value, nil
+	}
+	if failOnMissing {
+		return "", fmt.Errorf("%v environment variable is not set", name)
+	}
+	return "", nil
+}


Test patch:
diff --git a/benchmark/jsonresultset/jsonresultset_test.go b/benchmark/jsonresultset/jsonresultset_test.go
index 039a9fd..6654d59 100644
--- a/benchmark/jsonresultset/jsonresultset_test.go
+++ b/benchmark/jsonresultset/jsonresultset_test.go
@@ -7,6 +7,8 @@ import (
 	"log"
 	_ "net/http/pprof"
 	"os"
+	"strconv"
+	"strings"
 	"testing"
 
 	"database/sql"
@@ -16,9 +18,6 @@ import (
 
 	"runtime/debug"
 
-	"strconv"
-	"strings"
-
 	sf "github.com/snowflakedb/gosnowflake"
 )
 
@@ -30,58 +29,6 @@ func BenchmarkJsonResultSet(*testing.B) {
 	runJSONResultSet()
 }
 
-// getDSN constructs a DSN based on the test connection parameters
-func getDSN() (dsn string, cfg *sf.Config, err error) {
-	env := func(k string, failOnMissing bool) string {
-		if value := os.Getenv(k); value != "" {
-			return value
-		}
-		if failOnMissing {
-			log.Fatalf("%v environment variable is not set.", k)
-		}
-		return ""
-	}
-
-	account := env("SNOWFLAKE_TEST_ACCOUNT", true)
-	user := env("SNOWFLAKE_TEST_USER", true)
-	password := env("SNOWFLAKE_TEST_PASSWORD", true)
-	host := env("SNOWFLAKE_TEST_HOST", false)
-	port := env("SNOWFLAKE_TEST_PORT", false)
-	protocol := env("SNOWFLAKE_TEST_PROTOCOL", false)
-	role := env("SNOWFLAKE_TEST_ROLE", false)
-
-	// Use the customer JSON Decoder
-	s := env("SNOWFLAKE_TEST_CUSTOME_JSON_DECODER_ENABLED", true)
-	sf.CustomJSONDecoderEnabled = strings.EqualFold("true", s)
-
-	// Set the maximum chunk download workers
-	n := env("SNOWFLAKE_TEST_MAX_CHUNK_DOWNLOAD_WORKERS", false)
-	if n != "" {
-		n0, err := strconv.Atoi(n)
-		if err != nil {
-			log.Fatalf("invalid value for SNOWFLAKE_TEST_MAX_CHUNK_DOWNLOAD_WORKERS: %v", n)
-		}
-		sf.MaxChunkDownloadWorkers = n0
-	}
-
-	portStr, err := strconv.Atoi(port)
-	if err != nil {
-		return "", nil, err
-	}
-	cfg = &sf.Config{
-		Account:  account,
-		User:     user,
-		Password: password,
-		Host:     host,
-		Role:     role,
-		Port:     portStr,
-		Protocol: protocol,
-	}
-
-	dsn, err = sf.DSN(cfg)
-	return dsn, cfg, err
-}
-
 func runJSONResultSet() {
 	if !flag.Parsed() {
 		flag.Parse()
@@ -102,8 +49,21 @@ func runJSONResultSet() {
 		case <-ctx.Done():
 		}
 	}()
-
-	dsn, cfg, err := getDSN()
+	setCustomJSONDecoder()
+	setMaxChunkDownloadWorkers()
+	cfg, err := sf.GetConfigFromEnv([]*sf.ConfigParam{
+		{Name: "Account", EnvName: "SNOWFLAKE_TEST_ACCOUNT", FailOnMissing: true},
+		{Name: "User", EnvName: "SNOWFLAKE_TEST_USER", FailOnMissing: true},
+		{Name: "Password", EnvName: "SNOWFLAKE_TEST_PASSWORD", FailOnMissing: true},
+		{Name: "Role", EnvName: "SNOWFLAKE_TEST_ROLE", FailOnMissing: false},
+		{Name: "Host", EnvName: "SNOWFLAKE_TEST_HOST", FailOnMissing: false},
+		{Name: "Port", EnvName: "SNOWFLAKE_TEST_PORT", FailOnMissing: false},
+		{Name: "Protocol", EnvName: "SNOWFLAKE_TEST_PROTOCOL", FailOnMissing: false},
+	})
+	if err != nil {
+		log.Fatalf("failed to create Config, err: %v", err)
+	}
+	dsn, err := sf.DSN(cfg)
 	if err != nil {
 		log.Fatalf("failed to create DSN from Config: %v, err: %v", cfg, err)
 	}
@@ -133,3 +93,25 @@ func runJSONResultSet() {
 		counter++
 	}
 }
+
+func setMaxChunkDownloadWorkers() {
+	maxChunkDownloadWorkersStr, err := sf.GetFromEnv("SNOWFLAKE_TEST_MAX_CHUNK_DOWNLOAD_WORKERS", false)
+	if err != nil {
+		log.Fatal(err)
+	}
+	if maxChunkDownloadWorkersStr != "" {
+		maxChunkDownloadWorkers, err := strconv.Atoi(maxChunkDownloadWorkersStr)
+		if err != nil {
+			log.Fatalf("invalid value for SNOWFLAKE_TEST_MAX_CHUNK_DOWNLOAD_WORKERS: %v", maxChunkDownloadWorkers)
+		}
+		sf.MaxChunkDownloadWorkers = maxChunkDownloadWorkers
+	}
+}
+
+func setCustomJSONDecoder() {
+	customJSONDecoderEnabledStr, err := sf.GetFromEnv("SNOWFLAKE_TEST_CUSTOME_JSON_DECODER_ENABLED", true)
+	if err != nil {
+		log.Fatal(err)
+	}
+	sf.CustomJSONDecoderEnabled = strings.EqualFold("true", customJSONDecoderEnabledStr)
+}
diff --git a/benchmark/largesetresult/largesetresult_test.go b/benchmark/largesetresult/largesetresult_test.go
index 3569b4b..99cd4b9 100644
--- a/benchmark/largesetresult/largesetresult_test.go
+++ b/benchmark/largesetresult/largesetresult_test.go
@@ -16,8 +16,6 @@ import (
 
 	"runtime/debug"
 
-	"strconv"
-
 	sf "github.com/snowflakedb/gosnowflake"
 )
 
@@ -29,42 +27,6 @@ func BenchmarkLargeResultSet(*testing.B) {
 	runLargeResultSet()
 }
 
-// getDSN constructs a DSN based on the test connection parameters
-func getDSN() (dsn string, cfg *sf.Config, err error) {
-	env := func(k string, failOnMissing bool) string {
-		if value := os.Getenv(k); value != "" {
-			return value
-		}
-		if failOnMissing {
-			log.Fatalf("%v environment variable is not set.", k)
-		}
-		return ""
-	}
-
-	account := env("SNOWFLAKE_TEST_ACCOUNT", true)
-	user := env("SNOWFLAKE_TEST_USER", true)
-	password := env("SNOWFLAKE_TEST_PASSWORD", true)
-	host := env("SNOWFLAKE_TEST_HOST", false)
-	port := env("SNOWFLAKE_TEST_PORT", false)
-	protocol := env("SNOWFLAKE_TEST_PROTOCOL", false)
-
-	portStr, err := strconv.Atoi(port)
-	if err != nil {
-		return "", nil, err
-	}
-	cfg = &sf.Config{
-		Account:  account,
-		User:     user,
-		Password: password,
-		Host:     host,
-		Port:     portStr,
-		Protocol: protocol,
-	}
-
-	dsn, err = sf.DSN(cfg)
-	return dsn, cfg, err
-}
-
 func runLargeResultSet() {
 	if !flag.Parsed() {
 		flag.Parse()
@@ -86,7 +48,18 @@ func runLargeResultSet() {
 		}
 	}()
 
-	dsn, cfg, err := getDSN()
+	cfg, err := sf.GetConfigFromEnv([]*sf.ConfigParam{
+		{Name: "Account", EnvName: "SNOWFLAKE_TEST_ACCOUNT", FailOnMissing: true},
+		{Name: "User", EnvName: "SNOWFLAKE_TEST_USER", FailOnMissing: true},
+		{Name: "Password", EnvName: "SNOWFLAKE_TEST_PASSWORD", FailOnMissing: true},
+		{Name: "Host", EnvName: "SNOWFLAKE_TEST_HOST", FailOnMissing: false},
+		{Name: "Port", EnvName: "SNOWFLAKE_TEST_PORT", FailOnMissing: false},
+		{Name: "Protocol", EnvName: "SNOWFLAKE_TEST_PROTOCOL", FailOnMissing: false},
+	})
+	if err != nil {
+		log.Fatalf("failed to create Config, err: %v", err)
+	}
+	dsn, err := sf.DSN(cfg)
 	if err != nil {
 		log.Fatalf("failed to create DSN from Config: %v, err: %v", cfg, err)
 	}
diff --git a/dsn_test.go b/dsn_test.go
index 0374808..0798f76 100644
--- a/dsn_test.go
+++ b/dsn_test.go
@@ -3,9 +3,16 @@
 package gosnowflake
 
 import (
+	cr "crypto/rand"
+	"crypto/rsa"
+	"crypto/x509"
+	"encoding/pem"
 	"fmt"
 	"net/url"
+	"os"
 	"reflect"
+	"strconv"
+	"strings"
 	"testing"
 	"time"
 )
@@ -879,3 +886,125 @@ func TestDSN(t *testing.T) {
 		}
 	}
 }
+
+func TestParsePrivateKeyFromFileMissingFile(t *testing.T) {
+	_, err := parsePrivateKeyFromFile("nonexistent")
+
+	if err == nil {
+		t.Error("should report error for nonexistent file")
+	}
+}
+
+func TestParsePrivateKeyFromFileIncorrectData(t *testing.T) {
+	pemFile := createTmpFile("exampleKey.pem", []byte("gibberish"))
+	_, err := parsePrivateKeyFromFile(pemFile)
+
+	if err == nil {
+		t.Error("should report error for wrong data in file")
+	}
+}
+
+func TestParsePrivateKeyFromFile(t *testing.T) {
+	generatedKey, _ := rsa.GenerateKey(cr.Reader, 1024)
+	pemKey, _ := x509.MarshalPKCS8PrivateKey(generatedKey)
+	pemData := pem.EncodeToMemory(
+		&pem.Block{
+			Type:  "RSA PRIVATE KEY",
+			Bytes: pemKey,
+		},
+	)
+	keyFile := createTmpFile("exampleKey.pem", pemData)
+	defer os.Remove(keyFile)
+
+	parsedKey, err := parsePrivateKeyFromFile(keyFile)
+	if err != nil {
+		t.Errorf("unable to parse pam file from path: %v, err: %v", keyFile, err)
+	} else if !parsedKey.Equal(generatedKey) {
+		t.Errorf("generated key does not equal to parsed key from file\ngeneratedKey=%v\nparsedKey=%v",
+			generatedKey, parsedKey)
+	}
+}
+
+func createTmpFile(fileName string, content []byte) string {
+	tempFile, _ := os.CreateTemp("", fileName)
+	tempFile.Write(content)
+	absolutePath := tempFile.Name()
+	return absolutePath
+}
+
+type configParamToValue struct {
+	configParam string
+	value       string
+}
+
+func TestGetConfigFromEnv(t *testing.T) {
+	envMap := map[string]configParamToValue{
+		"SF_TEST_ACCOUNT":     {"Account", "account"},
+		"SF_TEST_USER":        {"User", "user"},
+		"SF_TEST_PASSWORD":    {"Password", "password"},
+		"SF_TEST_ROLE":        {"Role", "role"},
+		"SF_TEST_HOST":        {"Host", "host"},
+		"SF_TEST_PORT":        {"Port", "8080"},
+		"SF_TEST_PROTOCOL":    {"Protocol", "http"},
+		"SF_TEST_WAREHOUSE":   {"Warehouse", "warehouse"},
+		"SF_TEST_DATABASE":    {"Database", "database"},
+		"SF_TEST_REGION":      {"Region", "region"},
+		"SF_TEST_PASSCODE":    {"Passcode", "passcode"},
+		"SF_TEST_SCHEMA":      {"Schema", "schema"},
+		"SF_TEST_APPLICATION": {"Application", "application"},
+	}
+	var properties = make([]*ConfigParam, len(envMap))
+	i := 0
+	for key, ctv := range envMap {
+		os.Setenv(key, ctv.value)
+		cfgParam := ConfigParam{ctv.configParam, key, true}
+		properties[i] = &cfgParam
+		i++
+	}
+	defer func() {
+		for key := range envMap {
+			os.Unsetenv(key)
+		}
+	}()
+
+	cfg, err := GetConfigFromEnv(properties)
+	if err != nil {
+		t.Errorf("unable to parse env variables to Config, err: %v", err)
+	}
+
+	err = checkConfig(*cfg, envMap)
+	if err != nil {
+		t.Error(err)
+	}
+}
+
+func checkConfig(cfg Config, envMap map[string]configParamToValue) error {
+	appendError := func(errArray []string, envName string, expected string, received string) []string {
+		errArray = append(errArray, fmt.Sprintf("field %v expected value: %v, received value: %v", envName, expected, received))
+		return errArray
+	}
+
+	value := reflect.ValueOf(cfg)
+	typeOfCfg := value.Type()
+	cfgValues := make(map[string]interface{}, value.NumField())
+	for i := 0; i < value.NumField(); i++ {
+		cfgValues[typeOfCfg.Field(i).Name] = value.Field(i).Interface()
+	}
+
+	var errArray []string
+	for key, ctv := range envMap {
+		if ctv.configParam == "Port" {
+			if portStr := strconv.Itoa(cfgValues[ctv.configParam].(int)); portStr != ctv.value {
+				errArray = appendError(errArray, key, ctv.value, cfgValues[ctv.configParam].(string))
+			}
+		} else if cfgValues[ctv.configParam] != ctv.value {
+			errArray = appendError(errArray, key, ctv.value, cfgValues[ctv.configParam].(string))
+		}
+	}
+
+	if errArray != nil {
+		return fmt.Errorf(strings.Join(errArray, "\n"))
+	}
+
+	return nil
+}
diff --git a/util_test.go b/util_test.go
index 844d73b..7e59fcc 100644
--- a/util_test.go
+++ b/util_test.go
@@ -6,6 +6,7 @@ import (
 	"context"
 	"database/sql/driver"
 	"math/rand"
+	"os"
 	"strconv"
 	"sync"
 	"testing"
@@ -310,3 +311,23 @@ func TestEscapeForCSV(t *testing.T) {
 		}
 	}
 }
+
+func TestGetFromEnv(t *testing.T) {
+	os.Setenv("SF_TEST", "test")
+	defer os.Unsetenv("SF_TEST")
+	result, err := GetFromEnv("SF_TEST", true)
+
+	if err != nil {
+		t.Error("failed to read SF_TEST environment variable")
+	}
+	if result != "test" {
+		t.Errorf("incorrect value read for SF_TEST. Expected: test, read %v", result)
+	}
+}
+
+func TestGetFromEnvFailOnMissing(t *testing.T) {
+	_, err := GetFromEnv("SF_TEST_MISSING", true)
+	if err == nil {
+		t.Error("should report error when there is missing env parameter")
+	}
+}