Skip to content

Commit afd7d9a

Browse files
committed
Add PQping and PQpingParams to libpq to allow detection of the server's
status, including a status where the server is running but refuses a postgres connection. Have pg_ctl use this new function. This fixes the case where pg_ctl reports that the server is not running (cannot connect) but in fact it is running.
1 parent 212a1c7 commit afd7d9a

File tree

5 files changed

+146
-16
lines changed

5 files changed

+146
-16
lines changed

doc/src/sgml/libpq.sgml

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1511,6 +1511,74 @@ int PQbackendPID(const PGconn *conn);
15111511
</listitem>
15121512
</varlistentry>
15131513

1514+
<varlistentry id="libpq-pqpingparams">
1515+
<term><function>PQpingParams</function><indexterm><primary>PQpingParams</></></term>
1516+
<listitem>
1517+
<para>
1518+
<function>PQpingParams</function> indicates the status of the
1519+
server. The currently recognized parameter key words are the
1520+
same as <function>PQconnectParams</>.
1521+
1522+
<synopsis>
1523+
PGPing PQpingParams(const char **keywords, const char **values, int expand_dbname);
1524+
</synopsis>
1525+
1526+
It returns one of the following values:
1527+
1528+
<variablelist>
1529+
<varlistentry id="libpq-pqpingparams-pqaccess">
1530+
<term><literal>PQACCESS</literal></term>
1531+
<listitem>
1532+
<para>
1533+
The server is running and allows access.
1534+
</para>
1535+
</listitem>
1536+
</varlistentry>
1537+
1538+
<varlistentry id="libpq-pqpingparams-pqreject">
1539+
<term><literal>PQREJECT</literal></term>
1540+
<listitem>
1541+
<para>
1542+
The server is running but rejected a connection request.
1543+
</para>
1544+
</listitem>
1545+
</varlistentry>
1546+
1547+
<varlistentry id="libpq-pqpingparams-pqnoresponse">
1548+
<term><literal>PQNORESPONSE</literal></term>
1549+
<listitem>
1550+
<para>
1551+
The server did not respond.
1552+
</para>
1553+
</listitem>
1554+
</varlistentry>
1555+
</variablelist>
1556+
1557+
</para>
1558+
1559+
</listitem>
1560+
</varlistentry>
1561+
1562+
<varlistentry id="libpq-pqping">
1563+
<term><function>PQping</function><indexterm><primary>PQping</></></term>
1564+
<listitem>
1565+
<para>
1566+
Returns the status of the server.
1567+
1568+
<synopsis>
1569+
PGPing PQping(const char *conninfo);
1570+
</synopsis>
1571+
</para>
1572+
1573+
<para>
1574+
This function uses the same <literal>conninfo</literal> parameter
1575+
key words as <function>PQconnectdb</>. It returns the same
1576+
values as <function>PQpingParams</> above.
1577+
</para>
1578+
1579+
</listitem>
1580+
</varlistentry>
1581+
15141582
<varlistentry id="libpq-pqconnectionneedspassword">
15151583
<term><function>PQconnectionNeedsPassword</function><indexterm><primary>PQconnectionNeedsPassword</></></term>
15161584
<listitem>

src/bin/pg_ctl/pg_ctl.c

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ static char **readfile(const char *path);
136136
static int start_postmaster(void);
137137
static void read_post_opts(void);
138138

139-
static bool test_postmaster_connection(bool);
139+
static PGPing test_postmaster_connection(bool);
140140
static bool postmaster_is_alive(pid_t pid);
141141

142142
static char postopts_file[MAXPGPATH];
@@ -400,11 +400,10 @@ start_postmaster(void)
400400
* Note that the checkpoint parameter enables a Windows service control
401401
* manager checkpoint, it's got nothing to do with database checkpoints!!
402402
*/
403-
static bool
403+
static PGPing
404404
test_postmaster_connection(bool do_checkpoint)
405405
{
406-
PGconn *conn;
407-
bool success = false;
406+
PGPing ret = PQACCESS; /* assume success for zero wait */
408407
int i;
409408
char portstr[32];
410409
char *p;
@@ -508,18 +507,10 @@ test_postmaster_connection(bool do_checkpoint)
508507

509508
for (i = 0; i < wait_seconds; i++)
510509
{
511-
if ((conn = PQconnectdb(connstr)) != NULL &&
512-
(PQstatus(conn) == CONNECTION_OK ||
513-
PQconnectionNeedsPassword(conn)))
514-
{
515-
PQfinish(conn);
516-
success = true;
517-
break;
518-
}
510+
if ((ret = PQping(connstr)) != PQNORESPONSE)
511+
return ret;
519512
else
520513
{
521-
PQfinish(conn);
522-
523514
#if defined(WIN32)
524515
if (do_checkpoint)
525516
{
@@ -543,7 +534,8 @@ test_postmaster_connection(bool do_checkpoint)
543534
}
544535
}
545536

546-
return success;
537+
/* value of last call to PQping */
538+
return ret;
547539
}
548540

549541

@@ -746,9 +738,11 @@ do_start(void)
746738

747739
if (do_wait)
748740
{
741+
int status;
742+
749743
print_msg(_("waiting for server to start..."));
750744

751-
if (test_postmaster_connection(false) == false)
745+
if ((status = test_postmaster_connection(false)) == PQNORESPONSE)
752746
{
753747
write_stderr(_("%s: could not start server\n"
754748
"Examine the log output.\n"),
@@ -759,6 +753,9 @@ do_start(void)
759753
{
760754
print_msg(_(" done\n"));
761755
print_msg(_("server started\n"));
756+
if (status == PQREJECT)
757+
write_stderr(_("warning: could not connect, perhaps due to invalid authentication or\n"
758+
"misconfiguration.\n"));
762759
}
763760
}
764761
else

src/interfaces/libpq/exports.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,3 +157,5 @@ PQescapeLiteral 154
157157
PQescapeIdentifier 155
158158
PQconnectdbParams 156
159159
PQconnectStartParams 157
160+
PQping 158
161+
PQpingParams 159

src/interfaces/libpq/fe-connect.c

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,7 @@ static bool connectOptions1(PGconn *conn, const char *conninfo);
285285
static bool connectOptions2(PGconn *conn);
286286
static int connectDBStart(PGconn *conn);
287287
static int connectDBComplete(PGconn *conn);
288+
static PGPing internal_ping(PGconn *conn);
288289
static PGconn *makeEmptyPGconn(void);
289290
static void fillPGconn(PGconn *conn, PQconninfoOption *connOptions);
290291
static void freePGconn(PGconn *conn);
@@ -375,6 +376,20 @@ PQconnectdbParams(const char **keywords,
375376

376377
}
377378

379+
PGPing
380+
PQpingParams(const char **keywords,
381+
const char **values,
382+
int expand_dbname)
383+
{
384+
PGconn *conn = PQconnectStartParams(keywords, values, expand_dbname);
385+
PGPing ret;
386+
387+
ret = internal_ping(conn);
388+
PQfinish(conn);
389+
390+
return ret;
391+
}
392+
378393
/*
379394
* PQconnectdb
380395
*
@@ -408,6 +423,18 @@ PQconnectdb(const char *conninfo)
408423
return conn;
409424
}
410425

426+
PGPing
427+
PQping(const char *conninfo)
428+
{
429+
PGconn *conn = PQconnectStart(conninfo);
430+
PGPing ret;
431+
432+
ret = internal_ping(conn);
433+
PQfinish(conn);
434+
435+
return ret;
436+
}
437+
411438
/*
412439
* PQconnectStartParams
413440
*
@@ -2513,6 +2540,32 @@ PQconnectPoll(PGconn *conn)
25132540
}
25142541

25152542

2543+
/*
2544+
* internal_ping
2545+
* Determine if a server is running and if we can connect to it.
2546+
*/
2547+
PGPing
2548+
internal_ping(PGconn *conn)
2549+
{
2550+
if (conn && conn->status != CONNECTION_BAD)
2551+
{
2552+
(void) connectDBComplete(conn);
2553+
2554+
/*
2555+
* If the connection needs a password, we can consider the
2556+
* server as accepting connections.
2557+
*/
2558+
if (conn && (conn->status != CONNECTION_BAD ||
2559+
PQconnectionNeedsPassword(conn)))
2560+
return PQACCESS;
2561+
else
2562+
return PQREJECT;
2563+
}
2564+
else
2565+
return PQNORESPONSE;
2566+
}
2567+
2568+
25162569
/*
25172570
* makeEmptyPGconn
25182571
* - create a PGconn data structure with (as yet) no interesting data

src/interfaces/libpq/libpq-fe.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,13 @@ typedef enum
107107
PQERRORS_VERBOSE /* all the facts, ma'am */
108108
} PGVerbosity;
109109

110+
typedef enum
111+
{
112+
PQACCESS, /* connected to server */
113+
PQREJECT, /* server rejected access */
114+
PQNORESPONSE /* server did not respond */
115+
} PGPing;
116+
110117
/* PGconn encapsulates a connection to the backend.
111118
* The contents of this struct are not supposed to be known to applications.
112119
*/
@@ -403,6 +410,9 @@ extern int PQendcopy(PGconn *conn);
403410
extern int PQsetnonblocking(PGconn *conn, int arg);
404411
extern int PQisnonblocking(const PGconn *conn);
405412
extern int PQisthreadsafe(void);
413+
extern PGPing PQping(const char *conninfo);
414+
extern PGPing PQpingParams(const char **keywords,
415+
const char **values, int expand_dbname);
406416

407417
/* Force the write buffer to be written (or at least try) */
408418
extern int PQflush(PGconn *conn);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy