From 760dd75542eb13b37333e0e134b3463efade7cb4 Mon Sep 17 00:00:00 2001 From: Jack Christensen Date: Sat, 24 Aug 2019 09:28:44 -0500 Subject: [PATCH] Require Config to be created by ParseConfig --- config.go | 15 ++++++++++----- pgconn.go | 19 ++++++------------- pgconn_test.go | 8 ++++++++ 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/config.go b/config.go index be8bdab4..a861ff5f 100644 --- a/config.go +++ b/config.go @@ -26,7 +26,8 @@ import ( type AfterConnectFunc func(ctx context.Context, pgconn *PgConn) error type ValidateConnectFunc func(ctx context.Context, pgconn *PgConn) error -// Config is the settings used to establish a connection to a PostgreSQL server. +// Config is the settings used to establish a connection to a PostgreSQL server. It must be created by ParseConfig and +// then it can be modified. A manually initialized Config will cause ConnectConfig to panic. type Config struct { Host string // host (e.g. localhost) or path to unix domain socket directory (e.g. /private/tmp) Port uint16 @@ -55,6 +56,8 @@ type Config struct { // OnNotification is a callback function called when a notification from the LISTEN/NOTIFY system is received. OnNotification NotificationHandler + + createdByParseConfig bool // Used to enforce created by ParseConfig rule. } // FallbackConfig is additional settings to attempt a connection with when the primary Config fails to establish a @@ -157,10 +160,12 @@ func ParseConfig(connString string) (*Config, error) { } config := &Config{ - Database: settings["database"], - User: settings["user"], - Password: settings["password"], - RuntimeParams: make(map[string]string), + createdByParseConfig: true, + Database: settings["database"], + User: settings["user"], + Password: settings["password"], + RuntimeParams: make(map[string]string), + BuildFrontendFunc: makeDefaultBuildFrontendFunc(), } if connectTimeout, present := settings["connect_timeout"]; present { diff --git a/pgconn.go b/pgconn.go index 5d84871b..b0e4cfd2 100644 --- a/pgconn.go +++ b/pgconn.go @@ -99,25 +99,18 @@ func Connect(ctx context.Context, connString string) (*PgConn, error) { return ConnectConfig(ctx, config) } -// Connect establishes a connection to a PostgreSQL server using config. ctx can be used to cancel a connect attempt. +// Connect establishes a connection to a PostgreSQL server using config. config must have been constructed with +// ParseConfig. ctx can be used to cancel a connect attempt. // // If config.Fallbacks are present they will sequentially be tried in case of error establishing network connection. An // authentication error will terminate the chain of attempts (like libpq: // https://www.postgresql.org/docs/11/libpq-connect.html#LIBPQ-MULTIPLE-HOSTS) and be returned as the error. Otherwise, // if all attempts fail the last error is returned. func ConnectConfig(ctx context.Context, config *Config) (pgConn *PgConn, err error) { - // For convenience set a few defaults if not already set. This makes it simpler to directly construct a config. - if config.Port == 0 { - config.Port = 5432 - } - if config.DialFunc == nil { - config.DialFunc = makeDefaultDialer().DialContext - } - if config.BuildFrontendFunc == nil { - config.BuildFrontendFunc = makeDefaultBuildFrontendFunc() - } - if config.RuntimeParams == nil { - config.RuntimeParams = make(map[string]string) + // Default values are set in ParseConfig. Enforce initial creation by ParseConfig rather than setting defaults from + // zero values. + if !config.createdByParseConfig { + panic("config must be created by ParseConfig") } // Simplify usage by treating primary config and fallbacks the same. diff --git a/pgconn_test.go b/pgconn_test.go index f385bc19..1cd74024 100644 --- a/pgconn_test.go +++ b/pgconn_test.go @@ -263,6 +263,14 @@ func TestConnectWithAfterConnect(t *testing.T) { assert.Equal(t, []byte("foobar"), results[0].Rows[0][0]) } +func TestConnectConfigRequiresConfigFromParseConfig(t *testing.T) { + t.Parallel() + + config := &pgconn.Config{} + + require.PanicsWithValue(t, "config must be created by ParseConfig", func() { pgconn.ConnectConfig(context.Background(), config) }) +} + func TestConnPrepareSyntaxError(t *testing.T) { t.Parallel()