Hello Noah,

there is no simple way to know whether hostaddr was set at
the libPQ level

A solution could be to have a PQdoestheconnectionuseshostaddr(conn)
function, but I cannot say I'd be thrilled.

PQconninfo() is the official way to retrieve that.

Thanks for the pointer! I did not notice this one. At least the API looks better than the one I was suggesting:-)

ISTM that this function could be used to set other parameters, fixing some other issues such as ignoring special parameters on reconnections.

Anyway, attached an attempt at implementing the desired behavior wrt hostaddr.

--
Fabien.
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 695d6ba9f1..205ba3f602 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -2870,6 +2870,23 @@ param_is_newly_set(const char *old_val, const char *new_val)
 	return false;
 }
 
+/* return whether hostaddr was used for the connection. */
+static bool
+has_hostaddr(PGconn *conn)
+{
+	bool				used = false;
+	PQconninfoOption   *ciopt = PQconninfo(conn);
+
+	for (PQconninfoOption *p = ciopt; p->keyword != NULL; p++)
+	{
+		if (strcmp(p->keyword, "hostaddr") == 0 && p->val != NULL)
+			used = true;
+	}
+
+	PQconninfoFree(ciopt);
+	return used;
+}
+
 /*
  * do_connect -- handler for \connect
  *
@@ -2937,16 +2954,18 @@ do_connect(enum trivalue reuse_previous_specification,
 		if (host && strcmp(host, PQhost(o_conn)) == 0)
 		{
 			/*
-			 * if we are targeting the same host, reuse its hostaddr for
-			 * consistency
+			 * if we are targeting the same host, we reuse its hostaddr for
+			 * consistency if hostaddr was explicitely set.
 			 */
-			hostaddr = PQhostaddr(o_conn);
+			if (has_hostaddr(o_conn))
+				hostaddr = PQhostaddr(o_conn);
 		}
 		if (!host)
 		{
 			host = PQhost(o_conn);
-			/* also set hostaddr for consistency */
-			hostaddr = PQhostaddr(o_conn);
+			/* we also set hostaddr for consistency, if hostaddr was set */
+			if (has_hostaddr(o_conn))
+				hostaddr = PQhostaddr(o_conn);
 		}
 		if (!port)
 			port = PQport(o_conn);
@@ -3129,7 +3148,10 @@ do_connect(enum trivalue reuse_previous_specification,
 			char	   *host = PQhost(pset.db);
 			char	   *hostaddr = PQhostaddr(pset.db);
 
-			/* If the host is an absolute path, the connection is via socket */
+			/*
+			 * If the host is an absolute path, the connection is via socket
+			 * unless overriden by hostaddr
+			 */
 			if (is_absolute_path(host))
 			{
 				if (hostaddr && *hostaddr)
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index e58fa6742a..325d86e05e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -1536,9 +1536,7 @@ getHostaddr(PGconn *conn, char *host_addr, int host_addr_len)
 {
 	struct sockaddr_storage *addr = &conn->raddr.addr;
 
-	if (conn->connhost[conn->whichhost].type == CHT_HOST_ADDRESS)
-		strlcpy(host_addr, conn->connhost[conn->whichhost].hostaddr, host_addr_len);
-	else if (addr->ss_family == AF_INET)
+	if (addr->ss_family == AF_INET)
 	{
 		if (inet_net_ntop(AF_INET,
 						  &((struct sockaddr_in *) addr)->sin_addr.s_addr,
@@ -6463,6 +6461,11 @@ PQhost(const PGconn *conn)
 
 	if (conn->connhost != NULL)
 	{
+		/*
+		 * note this return the host/hosname=... value provided by the user,
+		 * even if it is an IP, thus it can include spaces and so,
+		 * whereas the next function uses the regenerated IP.
+		 */
 		if (conn->connhost[conn->whichhost].host != NULL &&
 			conn->connhost[conn->whichhost].host[0] != '\0')
 			return conn->connhost[conn->whichhost].host;
@@ -6480,15 +6483,12 @@ PQhostaddr(const PGconn *conn)
 	if (!conn)
 		return NULL;
 
-	if (conn->connhost != NULL)
-	{
-		if (conn->connhost[conn->whichhost].hostaddr != NULL &&
-			conn->connhost[conn->whichhost].hostaddr[0] != '\0')
-			return conn->connhost[conn->whichhost].hostaddr;
-
-		if (conn->connip != NULL)
-			return conn->connip;
-	}
+	/*
+	 * Always return the regenerated IP address string so that
+	 * the result is normalized.
+	 */
+	if (conn->connhost != NULL && conn->connip != NULL)
+		return conn->connip;
 
 	return "";
 }

Reply via email to