Skip to content

Commit 8db9716

Browse files
committed
Failed connection attempts include all errors
A single Connect("connstring") may actually make multiple connection requests due to TLS or HA configuration. Previously, when all attempts failed only the last error was returned. This could be confusing. Now details of all failed attempts are included. For example, the following connection string: host=localhost,127.0.0.1,foo.invalid port=1,2,3 Will now return an error like the following: failed to connect to `user=postgres database=pgx_test`: lookup foo.invalid: no such host [::1]:1 (localhost): dial error: dial tcp [::1]:1: connect: connection refused 127.0.0.1:1 (localhost): dial error: dial tcp 127.0.0.1:1: connect: connection refused 127.0.0.1:2 (127.0.0.1): dial error: dial tcp 127.0.0.1:2: connect: connection refused #1929
1 parent 48cdd7b commit 8db9716

File tree

4 files changed

+179
-115
lines changed

4 files changed

+179
-115
lines changed

pgconn/config.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,14 @@ type FallbackConfig struct {
118118
TLSConfig *tls.Config // nil disables TLS
119119
}
120120

121+
// connectOneConfig is the configuration for a single attempt to connect to a single host.
122+
type connectOneConfig struct {
123+
network string
124+
address string
125+
originalHostname string // original hostname before resolving
126+
tlsConfig *tls.Config // nil disables TLS
127+
}
128+
121129
// isAbsolutePath checks if the provided value is an absolute path either
122130
// beginning with a forward slash (as on Linux-based systems) or with a capital
123131
// letter A-Z followed by a colon and a backslash, e.g., "C:\", (as on Windows).

pgconn/errors.go

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,23 +62,37 @@ func (pe *PgError) SQLState() string {
6262
// ConnectError is the error returned when a connection attempt fails.
6363
type ConnectError struct {
6464
Config *Config // The configuration that was used in the connection attempt.
65-
msg string
6665
err error
6766
}
6867

6968
func (e *ConnectError) Error() string {
70-
sb := &strings.Builder{}
71-
fmt.Fprintf(sb, "failed to connect to `host=%s user=%s database=%s`: %s", e.Config.Host, e.Config.User, e.Config.Database, e.msg)
72-
if e.err != nil {
73-
fmt.Fprintf(sb, " (%s)", e.err.Error())
69+
prefix := fmt.Sprintf("failed to connect to `user=%s database=%s`:", e.Config.User, e.Config.Database)
70+
details := e.err.Error()
71+
if strings.Contains(details, "\n") {
72+
return prefix + "\n\t" + strings.ReplaceAll(details, "\n", "\n\t")
73+
} else {
74+
return prefix + " " + details
7475
}
75-
return sb.String()
7676
}
7777

7878
func (e *ConnectError) Unwrap() error {
7979
return e.err
8080
}
8181

82+
type perDialConnectError struct {
83+
address string
84+
originalHostname string
85+
err error
86+
}
87+
88+
func (e *perDialConnectError) Error() string {
89+
return fmt.Sprintf("%s (%s): %s", e.address, e.originalHostname, e.err.Error())
90+
}
91+
92+
func (e *perDialConnectError) Unwrap() error {
93+
return e.err
94+
}
95+
8296
type connLockError struct {
8397
status string
8498
}

0 commit comments

Comments
 (0)