connectPreferred attempts to connect to the preferred host from connectOneConfigs. The connections are attempted in order. If a connection is successful it is returned. If no connection is successful then all errors are returned. If a connection attempt returns a [NotPreferredError], then that host
(ctx context.Context, config *Config, connectOneConfigs []*connectOneConfig)
| 245 | // order. If a connection is successful it is returned. If no connection is successful then all errors are returned. If |
| 246 | // a connection attempt returns a [NotPreferredError], then that host will be used if no other hosts are successful. |
| 247 | func connectPreferred(ctx context.Context, config *Config, connectOneConfigs []*connectOneConfig) (*PgConn, []error) { |
| 248 | octx := ctx |
| 249 | var allErrors []error |
| 250 | |
| 251 | var fallbackConnectOneConfig *connectOneConfig |
| 252 | for i, c := range connectOneConfigs { |
| 253 | // ConnectTimeout restricts the whole connection process. |
| 254 | if config.ConnectTimeout != 0 { |
| 255 | // create new context first time or when previous host was different |
| 256 | if i == 0 || (connectOneConfigs[i].address != connectOneConfigs[i-1].address) { |
| 257 | var cancel context.CancelFunc |
| 258 | ctx, cancel = context.WithTimeout(octx, config.ConnectTimeout) |
| 259 | defer cancel() |
| 260 | } |
| 261 | } else { |
| 262 | ctx = octx |
| 263 | } |
| 264 | |
| 265 | pgConn, err := connectOne(ctx, config, c, false) |
| 266 | if pgConn != nil { |
| 267 | return pgConn, nil |
| 268 | } |
| 269 | |
| 270 | allErrors = append(allErrors, err) |
| 271 | |
| 272 | var pgErr *PgError |
| 273 | if errors.As(err, &pgErr) { |
| 274 | // pgx will try next host even if libpq does not in certain cases (see #2246) |
| 275 | // consider change for the next major version |
| 276 | |
| 277 | const ERRCODE_INVALID_PASSWORD = "28P01" |
| 278 | const ERRCODE_INVALID_CATALOG_NAME = "3D000" // db does not exist |
| 279 | const ERRCODE_INSUFFICIENT_PRIVILEGE = "42501" // missing connect privilege |
| 280 | |
| 281 | // auth failed due to invalid password, db does not exist or user has no permission |
| 282 | if pgErr.Code == ERRCODE_INVALID_PASSWORD || |
| 283 | pgErr.Code == ERRCODE_INVALID_CATALOG_NAME || |
| 284 | pgErr.Code == ERRCODE_INSUFFICIENT_PRIVILEGE { |
| 285 | return nil, allErrors |
| 286 | } |
| 287 | } |
| 288 | |
| 289 | var npErr *NotPreferredError |
| 290 | if errors.As(err, &npErr) { |
| 291 | fallbackConnectOneConfig = c |
| 292 | } |
| 293 | } |
| 294 | |
| 295 | if fallbackConnectOneConfig != nil { |
| 296 | fallbackCtx := octx |
| 297 | if config.ConnectTimeout != 0 { |
| 298 | var cancel context.CancelFunc |
| 299 | fallbackCtx, cancel = context.WithTimeout(octx, config.ConnectTimeout) |
| 300 | defer cancel() |
| 301 | } |
| 302 | pgConn, err := connectOne(fallbackCtx, config, fallbackConnectOneConfig, true) |
| 303 | if err == nil { |
| 304 | return pgConn, nil |
no test coverage detected