Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 52a1022

Browse files
committed
Uniformly identify the target host in libpq connection failure reports.
Prefix "could not connect to host-or-socket-path:" to all connection failure cases that occur after the socket() call, and remove the ad-hoc server identity data that was appended to a few of these messages. This should produce much more intelligible error reports in multiple-target-host situations, especially for error cases that are off the beaten track to any degree (because none of those provided any server identity info). As an example of the change, formerly a connection attempt with a bad port number such as "psql -p 12345 -h localhost,/tmp" might produce psql: error: could not connect to server: Connection refused Is the server running on host "localhost" (::1) and accepting TCP/IP connections on port 12345? could not connect to server: Connection refused Is the server running on host "localhost" (127.0.0.1) and accepting TCP/IP connections on port 12345? could not connect to server: No such file or directory Is the server running locally and accepting connections on Unix domain socket "/tmp/.s.PGSQL.12345"? Now it looks like psql: error: could not connect to host "localhost" (::1), port 12345: Connection refused Is the server running on that host and accepting TCP/IP connections? could not connect to host "localhost" (127.0.0.1), port 12345: Connection refused Is the server running on that host and accepting TCP/IP connections? could not connect to socket "/tmp/.s.PGSQL.12345": No such file or directory Is the server running locally and accepting connections on that socket? This requires adjusting a couple of regression tests to allow for variation in the contents of a connection failure message. Discussion: https://postgr.es/m/BN6PR05MB3492948E4FD76C156E747E8BC9160@BN6PR05MB3492.namprd05.prod.outlook.com
1 parent 800d93f commit 52a1022

File tree

3 files changed

+62
-65
lines changed

3 files changed

+62
-65
lines changed

src/bin/pg_dump/t/002_pg_dump.pl

+1-1
Original file line numberDiff line numberDiff line change
@@ -3460,7 +3460,7 @@
34603460
34613461
command_fails_like(
34623462
[ 'pg_dump', '-p', "$port", 'qqq' ],
3463-
qr/\Qpg_dump: error: connection to database "qqq" failed: FATAL: database "qqq" does not exist\E/,
3463+
qr/pg_dump: error: connection to database "qqq" failed: could not connect to .*: FATAL: database "qqq" does not exist/,
34643464
'connecting to a non-existent database');
34653465
34663466
#########################################

src/interfaces/ecpg/test/expected/connect-test5.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
[NO_PID]: sqlca: code: 0, state: 00000
3737
[NO_PID]: ECPGconnect: opening database <DEFAULT> on <DEFAULT> port <DEFAULT> for user regress_ecpg_user2
3838
[NO_PID]: sqlca: code: 0, state: 00000
39-
[NO_PID]: ECPGconnect: could not open database: FATAL: database "regress_ecpg_user2" does not exist
39+
[NO_PID]: ECPGconnect: could not open database: could not connect: FATAL: database "regress_ecpg_user2" does not exist
4040

4141
[NO_PID]: sqlca: code: 0, state: 00000
4242
[NO_PID]: ecpg_finish: connection main closed
@@ -73,7 +73,7 @@
7373
[NO_PID]: sqlca: code: -220, state: 08003
7474
[NO_PID]: ECPGconnect: opening database <DEFAULT> on <DEFAULT> port <DEFAULT> for user regress_ecpg_user2
7575
[NO_PID]: sqlca: code: 0, state: 00000
76-
[NO_PID]: ECPGconnect: could not open database: FATAL: database "regress_ecpg_user2" does not exist
76+
[NO_PID]: ECPGconnect: could not open database: could not connect: FATAL: database "regress_ecpg_user2" does not exist
7777

7878
[NO_PID]: sqlca: code: 0, state: 00000
7979
[NO_PID]: ecpg_finish: connection main closed

src/interfaces/libpq/fe-connect.c

+59-62
Original file line numberDiff line numberDiff line change
@@ -1669,15 +1669,17 @@ getHostaddr(PGconn *conn, char *host_addr, int host_addr_len)
16691669
}
16701670

16711671
/* ----------
1672-
* connectFailureMessage -
1673-
* create a friendly error message on connection failure.
1672+
* emitCouldNotConnect -
1673+
* Speculatively append "could not connect to ...: " to conn->errorMessage
1674+
* once we've identified the current connection target address. This ensures
1675+
* that any subsequent error message will be properly attributed to the
1676+
* server we couldn't connect to. conn->raddr must be valid, and the result
1677+
* of getHostaddr() must be supplied.
16741678
* ----------
16751679
*/
16761680
static void
1677-
connectFailureMessage(PGconn *conn, int errorno)
1681+
emitCouldNotConnect(PGconn *conn, const char *host_addr)
16781682
{
1679-
char sebuf[PG_STRERROR_R_BUFLEN];
1680-
16811683
#ifdef HAVE_UNIX_SOCKETS
16821684
if (IS_AF_UNIX(conn->raddr.addr.ss_family))
16831685
{
@@ -1688,25 +1690,15 @@ connectFailureMessage(PGconn *conn, int errorno)
16881690
service, sizeof(service),
16891691
NI_NUMERICSERV);
16901692
appendPQExpBuffer(&conn->errorMessage,
1691-
libpq_gettext("could not connect to server: %s\n"
1692-
"\tIs the server running locally and accepting\n"
1693-
"\tconnections on Unix domain socket \"%s\"?\n"),
1694-
SOCK_STRERROR(errorno, sebuf, sizeof(sebuf)),
1693+
libpq_gettext("could not connect to socket \"%s\": "),
16951694
service);
16961695
}
16971696
else
16981697
#endif /* HAVE_UNIX_SOCKETS */
16991698
{
1700-
char host_addr[NI_MAXHOST];
17011699
const char *displayed_host;
17021700
const char *displayed_port;
17031701

1704-
/*
1705-
* Optionally display the network address with the hostname. This is
1706-
* useful to distinguish between IPv4 and IPv6 connections.
1707-
*/
1708-
getHostaddr(conn, host_addr, NI_MAXHOST);
1709-
17101702
/* To which host and port were we actually connecting? */
17111703
if (conn->connhost[conn->whichhost].type == CHT_HOST_ADDRESS)
17121704
displayed_host = conn->connhost[conn->whichhost].hostaddr;
@@ -1722,26 +1714,46 @@ connectFailureMessage(PGconn *conn, int errorno)
17221714
* looked-up IP address.
17231715
*/
17241716
if (conn->connhost[conn->whichhost].type != CHT_HOST_ADDRESS &&
1725-
strlen(host_addr) > 0 &&
1717+
host_addr[0] &&
17261718
strcmp(displayed_host, host_addr) != 0)
17271719
appendPQExpBuffer(&conn->errorMessage,
1728-
libpq_gettext("could not connect to server: %s\n"
1729-
"\tIs the server running on host \"%s\" (%s) and accepting\n"
1730-
"\tTCP/IP connections on port %s?\n"),
1731-
SOCK_STRERROR(errorno, sebuf, sizeof(sebuf)),
1720+
libpq_gettext("could not connect to host \"%s\" (%s), port %s: "),
17321721
displayed_host, host_addr,
17331722
displayed_port);
17341723
else
17351724
appendPQExpBuffer(&conn->errorMessage,
1736-
libpq_gettext("could not connect to server: %s\n"
1737-
"\tIs the server running on host \"%s\" and accepting\n"
1738-
"\tTCP/IP connections on port %s?\n"),
1739-
SOCK_STRERROR(errorno, sebuf, sizeof(sebuf)),
1725+
libpq_gettext("could not connect to host \"%s\", port %s: "),
17401726
displayed_host,
17411727
displayed_port);
17421728
}
17431729
}
17441730

1731+
/* ----------
1732+
* connectFailureMessage -
1733+
* create a friendly error message on connection failure,
1734+
* using the given errno value. Use this for error cases that
1735+
* imply that there's no server there.
1736+
* ----------
1737+
*/
1738+
static void
1739+
connectFailureMessage(PGconn *conn, int errorno)
1740+
{
1741+
char sebuf[PG_STRERROR_R_BUFLEN];
1742+
1743+
appendPQExpBuffer(&conn->errorMessage,
1744+
"%s\n",
1745+
SOCK_STRERROR(errorno, sebuf, sizeof(sebuf)));
1746+
1747+
#ifdef HAVE_UNIX_SOCKETS
1748+
if (IS_AF_UNIX(conn->raddr.addr.ss_family))
1749+
appendPQExpBufferStr(&conn->errorMessage,
1750+
libpq_gettext("\tIs the server running locally and accepting connections on that socket?\n"));
1751+
else
1752+
#endif
1753+
appendPQExpBufferStr(&conn->errorMessage,
1754+
libpq_gettext("\tIs the server running on that host and accepting TCP/IP connections?\n"));
1755+
}
1756+
17451757
/*
17461758
* Should we use keepalives? Returns 1 if yes, 0 if no, and -1 if
17471759
* conn->keepalives is set to a value which is not parseable as an
@@ -2476,30 +2488,30 @@ PQconnectPoll(PGconn *conn)
24762488
goto keep_going;
24772489
}
24782490

2479-
/* Remember current address for possible error msg */
2491+
/* Remember current address for possible use later */
24802492
memcpy(&conn->raddr.addr, addr_cur->ai_addr,
24812493
addr_cur->ai_addrlen);
24822494
conn->raddr.salen = addr_cur->ai_addrlen;
24832495

2484-
/* set connip */
2496+
/*
2497+
* Set connip, too. Note we purposely ignore strdup
2498+
* failure; not a big problem if it fails.
2499+
*/
24852500
if (conn->connip != NULL)
24862501
{
24872502
free(conn->connip);
24882503
conn->connip = NULL;
24892504
}
2490-
24912505
getHostaddr(conn, host_addr, NI_MAXHOST);
2492-
if (strlen(host_addr) > 0)
2506+
if (host_addr[0])
24932507
conn->connip = strdup(host_addr);
24942508

2495-
/*
2496-
* purposely ignore strdup failure; not a big problem if
2497-
* it fails anyway.
2498-
*/
2499-
2509+
/* Try to create the socket */
25002510
conn->sock = socket(addr_cur->ai_family, SOCK_STREAM, 0);
25012511
if (conn->sock == PGINVALID_SOCKET)
25022512
{
2513+
int errorno = SOCK_ERRNO;
2514+
25032515
/*
25042516
* Silently ignore socket() failure if we have more
25052517
* addresses to try; this reduces useless chatter in
@@ -2512,12 +2524,20 @@ PQconnectPoll(PGconn *conn)
25122524
conn->try_next_addr = true;
25132525
goto keep_going;
25142526
}
2527+
emitCouldNotConnect(conn, host_addr);
25152528
appendPQExpBuffer(&conn->errorMessage,
25162529
libpq_gettext("could not create socket: %s\n"),
2517-
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
2530+
SOCK_STRERROR(errorno, sebuf, sizeof(sebuf)));
25182531
goto error_return;
25192532
}
25202533

2534+
/*
2535+
* Once we've identified a target address, all errors
2536+
* except the preceding socket()-failure case should be
2537+
* prefixed with "could not connect to <target>: ".
2538+
*/
2539+
emitCouldNotConnect(conn, host_addr);
2540+
25212541
/*
25222542
* Select socket options: no delay of outgoing data for
25232543
* TCP sockets, nonblock mode, close-on-exec. Try the
@@ -3608,9 +3628,6 @@ PQconnectPoll(PGconn *conn)
36083628
}
36093629
case CONNECTION_CHECK_WRITABLE:
36103630
{
3611-
const char *displayed_host;
3612-
const char *displayed_port;
3613-
36143631
conn->status = CONNECTION_OK;
36153632
if (!PQconsumeInput(conn))
36163633
goto error_return;
@@ -3634,19 +3651,8 @@ PQconnectPoll(PGconn *conn)
36343651
PQclear(res);
36353652

36363653
/* Append error report to conn->errorMessage. */
3637-
if (conn->connhost[conn->whichhost].type == CHT_HOST_ADDRESS)
3638-
displayed_host = conn->connhost[conn->whichhost].hostaddr;
3639-
else
3640-
displayed_host = conn->connhost[conn->whichhost].host;
3641-
displayed_port = conn->connhost[conn->whichhost].port;
3642-
if (displayed_port == NULL || displayed_port[0] == '\0')
3643-
displayed_port = DEF_PGPORT_STR;
3644-
3645-
appendPQExpBuffer(&conn->errorMessage,
3646-
libpq_gettext("could not make a writable "
3647-
"connection to server "
3648-
"\"%s:%s\"\n"),
3649-
displayed_host, displayed_port);
3654+
appendPQExpBufferStr(&conn->errorMessage,
3655+
libpq_gettext("session is read-only\n"));
36503656

36513657
/* Close connection politely. */
36523658
conn->status = CONNECTION_OK;
@@ -3679,17 +3685,8 @@ PQconnectPoll(PGconn *conn)
36793685
PQclear(res);
36803686

36813687
/* Append error report to conn->errorMessage. */
3682-
if (conn->connhost[conn->whichhost].type == CHT_HOST_ADDRESS)
3683-
displayed_host = conn->connhost[conn->whichhost].hostaddr;
3684-
else
3685-
displayed_host = conn->connhost[conn->whichhost].host;
3686-
displayed_port = conn->connhost[conn->whichhost].port;
3687-
if (displayed_port == NULL || displayed_port[0] == '\0')
3688-
displayed_port = DEF_PGPORT_STR;
3689-
appendPQExpBuffer(&conn->errorMessage,
3690-
libpq_gettext("test \"SHOW transaction_read_only\" failed "
3691-
"on server \"%s:%s\"\n"),
3692-
displayed_host, displayed_port);
3688+
appendPQExpBufferStr(&conn->errorMessage,
3689+
libpq_gettext("test \"SHOW transaction_read_only\" failed\n"));
36933690

36943691
/* Close connection politely. */
36953692
conn->status = CONNECTION_OK;

0 commit comments

Comments
 (0)