diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index 7f01fcc148..d39b044d3b 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -1263,6 +1263,30 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname
+
+ socket_timeout
+
+
+ Maximum wait in seconds (write as a decimal integer, e.g. 10) for
+ socket read/write operation before closing the connection. A value
+ of zero (the default) turns this off, which means wait indefinitely.
+ The minimum allowed timeout is 2 seconds, so a value of 1 is
+ interpreted as 2.
+
+
+
+ Although this can be used as a stopgap timeout measure, it is
+ recommended to set a value higher than the other timeout
+ parameters (statement_timeout,
+ TCP_KEEP_ALIVES,
+ TCP_USER_TIMEOUT) because setting a smaller
+ value will make the other configured timeout parameters meaningless
+ and can cause undesirable disconnection.
+
+
+
+
+
tty
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index c800d7921e..7e6dccc676 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -214,6 +214,10 @@ static const internalPQconninfoOption PQconninfoOptions[] = {
"Connect-timeout", "", 10, /* strlen(INT32_MAX) == 10 */
offsetof(struct pg_conn, connect_timeout)},
+ {"socket_timeout", NULL, NULL, NULL,
+ "Socket-timeout", "", 10, /* strlen(INT32_MAX) == 10 */
+ offsetof(struct pg_conn, pgsocket_timeout)},
+
{"dbname", "PGDATABASE", NULL, NULL,
"Database-Name", "", 20,
offsetof(struct pg_conn, dbName)},
@@ -423,6 +427,8 @@ static char *passwordFromFile(const char *hostname, const char *port, const char
const char *username, const char *pgpassfile);
static void pgpassfileWarning(PGconn *conn);
static void default_threadlock(int acquire);
+static bool parse_int_param(const char *value, int *result, PGconn *conn,
+ const char *context);
/* global variable because fe-auth.c needs to access it */
@@ -1289,6 +1295,24 @@ connectOptions2(PGconn *conn)
goto oom_error;
}
+ if (conn->pgsocket_timeout)
+ {
+ if (!parse_int_param(conn->pgsocket_timeout,
+ &conn->socket_timeout, conn, "socket_timeout"))
+ {
+ conn->status = CONNECTION_BAD;
+ printfPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("invalid integer value for socket_timeout\n"));
+ return false;
+ }
+ /*
+ * Rounding could cause communication to fail;
+ * insist on at least two seconds.
+ */
+ if(conn->socket_timeout > 0 && conn->socket_timeout < 2)
+ conn->socket_timeout = 2;
+ }
+
/*
* Validate target_session_attrs option.
*/
@@ -3903,6 +3927,8 @@ freePGconn(PGconn *conn)
free(conn->pgtty);
if (conn->connect_timeout)
free(conn->connect_timeout);
+ if (conn->pgsocket_timeout)
+ free(conn->pgsocket_timeout);
if (conn->pgtcp_user_timeout)
free(conn->pgtcp_user_timeout);
if (conn->pgoptions)
diff --git a/src/interfaces/libpq/fe-misc.c b/src/interfaces/libpq/fe-misc.c
index 2d44845ccb..4a18b726ad 100644
--- a/src/interfaces/libpq/fe-misc.c
+++ b/src/interfaces/libpq/fe-misc.c
@@ -1020,6 +1020,32 @@ pqFlush(PGconn *conn)
int
pqWait(int forRead, int forWrite, PGconn *conn)
{
+ int result;
+
+ if (conn->socket_timeout > 0)
+ {
+ time_t finish_time;
+
+ finish_time = time(NULL) + conn->socket_timeout;
+ result = pqSocketCheck(conn, forRead, forWrite, finish_time);
+
+ if (result < 0)
+ return EOF;
+
+ if (result == 0)
+ {
+ printfPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("timeout expired\n"));
+ conn->status = CONNECTION_BAD;
+ pqsecure_close(conn);
+ closesocket(conn->sock);
+ conn->sock = PGINVALID_SOCKET;
+ return EOF;
+ }
+
+ return 0;
+ }
+
return pqWaitTimed(forRead, forWrite, conn, (time_t) -1);
}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index c0b8e3f8ce..a329fbff8b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -336,6 +336,8 @@ struct pg_conn
char *pgtty; /* tty on which the backend messages is
* displayed (OBSOLETE, NOT USED) */
char *connect_timeout; /* connection timeout (numeric string) */
+ char *pgsocket_timeout; /* socket timeout (numeric string) */
+ int socket_timeout; /* socket timeout (numeric)*/
char *pgtcp_user_timeout; /* tcp user timeout (numeric string) */
char *client_encoding_initial; /* encoding to use */
char *pgoptions; /* options to start the backend with */