commit c1dd11d072eb6abaa6f9bb22ae375c90a62b3810
Author: mithun <mithun@localhost.localdomain>
Date:   Mon Dec 5 23:26:16 2016 +0530

    Fix for , in URI

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index e890844..9ba265c 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -333,8 +333,9 @@ static const PQEnvironmentOption EnvironmentOptions[] =
 static const char uri_designator[] = "postgresql://";
 static const char short_uri_designator[] = "postgres://";
 
-static bool connectOptions1(PGconn *conn, const char *conninfo);
-static bool connectOptions2(PGconn *conn);
+static bool connectOptions1(PGconn *conn, const char *conninfo,
+							bool *decode_hostname);
+static bool connectOptions2(PGconn *conn, bool decode_hostname);
 static int	connectDBStart(PGconn *conn);
 static int	connectDBComplete(PGconn *conn);
 static PGPing internal_ping(PGconn *conn);
@@ -346,14 +347,16 @@ static void release_all_addrinfo(PGconn *conn);
 static void sendTerminateConn(PGconn *conn);
 static PQconninfoOption *conninfo_init(PQExpBuffer errorMessage);
 static PQconninfoOption *parse_connection_string(const char *conninfo,
-						PQExpBuffer errorMessage, bool use_defaults);
+						PQExpBuffer errorMessage, bool use_defaults,
+						bool *decode_hostname);
 static int	uri_prefix_length(const char *connstr);
 static bool recognized_connection_string(const char *connstr);
 static PQconninfoOption *conninfo_parse(const char *conninfo,
 			   PQExpBuffer errorMessage, bool use_defaults);
 static PQconninfoOption *conninfo_array_parse(const char *const * keywords,
 					 const char *const * values, PQExpBuffer errorMessage,
-					 bool use_defaults, int expand_dbname);
+					 bool use_defaults, int expand_dbname,
+					 bool *decode_hostname);
 static bool conninfo_add_defaults(PQconninfoOption *options,
 					  PQExpBuffer errorMessage);
 static PQconninfoOption *conninfo_uri_parse(const char *uri,
@@ -575,6 +578,7 @@ PQconnectStartParams(const char *const * keywords,
 {
 	PGconn	   *conn;
 	PQconninfoOption *connOptions;
+	bool		decode_hostname = false;
 
 	/*
 	 * Allocate memory for the conn structure
@@ -588,7 +592,8 @@ PQconnectStartParams(const char *const * keywords,
 	 */
 	connOptions = conninfo_array_parse(keywords, values,
 									   &conn->errorMessage,
-									   true, expand_dbname);
+									   true, expand_dbname,
+									   &decode_hostname);
 	if (connOptions == NULL)
 	{
 		conn->status = CONNECTION_BAD;
@@ -613,7 +618,7 @@ PQconnectStartParams(const char *const * keywords,
 	/*
 	 * Compute derived options
 	 */
-	if (!connectOptions2(conn))
+	if (!connectOptions2(conn, decode_hostname))
 		return conn;
 
 	/*
@@ -651,6 +656,7 @@ PGconn *
 PQconnectStart(const char *conninfo)
 {
 	PGconn	   *conn;
+	bool	   decode_hostname = false;
 
 	/*
 	 * Allocate memory for the conn structure
@@ -662,13 +668,13 @@ PQconnectStart(const char *conninfo)
 	/*
 	 * Parse the conninfo string
 	 */
-	if (!connectOptions1(conn, conninfo))
+	if (!connectOptions1(conn, conninfo, &decode_hostname))
 		return conn;
 
 	/*
 	 * Compute derived options
 	 */
-	if (!connectOptions2(conn))
+	if (!connectOptions2(conn, decode_hostname))
 		return conn;
 
 	/*
@@ -734,14 +740,15 @@ fillPGconn(PGconn *conn, PQconninfoOption *connOptions)
  * and so is conn->status).
  */
 static bool
-connectOptions1(PGconn *conn, const char *conninfo)
+connectOptions1(PGconn *conn, const char *conninfo, bool *decode_hostname)
 {
 	PQconninfoOption *connOptions;
 
 	/*
 	 * Parse the conninfo string
 	 */
-	connOptions = parse_connection_string(conninfo, &conn->errorMessage, true);
+	connOptions = parse_connection_string(conninfo, &conn->errorMessage, true,
+										  decode_hostname);
 	if (connOptions == NULL)
 	{
 		conn->status = CONNECTION_BAD;
@@ -776,7 +783,7 @@ connectOptions1(PGconn *conn, const char *conninfo)
  * and so is conn->status).
  */
 static bool
-connectOptions2(PGconn *conn)
+connectOptions2(PGconn *conn, bool decode_hostname)
 {
 	/*
 	 * Allocate memory for details about each host to which we might possibly
@@ -819,6 +826,7 @@ connectOptions2(PGconn *conn)
 		while (1)
 		{
 			char   *e = s;
+			char   *currhost = NULL;
 
 			/*
 			 * Search for the end of the current hostname; a comma or
@@ -828,12 +836,23 @@ connectOptions2(PGconn *conn)
 				++e;
 
 			/* Copy the hostname whose bounds we just identified. */
-			conn->connhost[i].host =
-				(char *) malloc(sizeof(char) * (e - s + 1));
-			if (conn->connhost[i].host == NULL)
+			currhost = (char *) malloc(sizeof(char) * (e - s + 1));
+			if (currhost == NULL)
 				goto oom_error;
-			memcpy(conn->connhost[i].host, s, e - s);
-			conn->connhost[i].host[e - s] = '\0';
+			memcpy(currhost, s, e - s);
+			currhost[e - s] = '\0';
+			if (decode_hostname)
+			{
+				conn->connhost[i].host =
+							conninfo_uri_decode(currhost, &conn->errorMessage);
+				if (conn->connhost[i].host == NULL)
+				{
+					conn->status = CONNECTION_BAD;
+					return false;
+				}
+			}
+			else
+				conn->connhost[i].host = currhost;
 
 			/* Identify the type of host. */
 			conn->connhost[i].type = CHT_HOST_NAME;
@@ -1125,6 +1144,7 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions,
 			 const char *pwd)
 {
 	PGconn	   *conn;
+	bool	   decode_hostname = false;
 
 	/*
 	 * Allocate memory for the conn structure
@@ -1139,7 +1159,7 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions,
 	 */
 	if (dbName && recognized_connection_string(dbName))
 	{
-		if (!connectOptions1(conn, dbName))
+		if (!connectOptions1(conn, dbName, &decode_hostname))
 			return conn;
 	}
 	else
@@ -1148,7 +1168,7 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions,
 		 * Old-style path: first, parse an empty conninfo string in order to
 		 * set up the same defaults that PQconnectdb() would use.
 		 */
-		if (!connectOptions1(conn, ""))
+		if (!connectOptions1(conn, "", &decode_hostname))
 			return conn;
 
 		/* Insert dbName parameter value into struct */
@@ -1168,6 +1188,7 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions,
 	 */
 	if (pghost && pghost[0] != '\0')
 	{
+		decode_hostname = false;
 		if (conn->pghost)
 			free(conn->pghost);
 		conn->pghost = strdup(pghost);
@@ -1223,7 +1244,7 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions,
 	/*
 	 * Compute derived options
 	 */
-	if (!connectOptions2(conn))
+	if (!connectOptions2(conn, decode_hostname))
 		return conn;
 
 	/*
@@ -4560,7 +4581,7 @@ PQconninfoParse(const char *conninfo, char **errmsg)
 	initPQExpBuffer(&errorBuf);
 	if (PQExpBufferDataBroken(errorBuf))
 		return NULL;			/* out of memory already :-( */
-	connOptions = parse_connection_string(conninfo, &errorBuf, false);
+	connOptions = parse_connection_string(conninfo, &errorBuf, false, NULL);
 	if (connOptions == NULL && errmsg)
 		*errmsg = errorBuf.data;
 	else
@@ -4613,11 +4634,15 @@ conninfo_init(PQExpBuffer errorMessage)
  */
 static PQconninfoOption *
 parse_connection_string(const char *connstr, PQExpBuffer errorMessage,
-						bool use_defaults)
+						bool use_defaults, bool *decode_hostname)
 {
 	/* Parse as URI if connection string matches URI prefix */
 	if (uri_prefix_length(connstr) != 0)
+	{
+		if (decode_hostname)
+			*decode_hostname = true;
 		return conninfo_uri_parse(connstr, errorMessage, use_defaults);
+	}
 
 	/* Parse as default otherwise */
 	return conninfo_parse(connstr, errorMessage, use_defaults);
@@ -4846,7 +4871,7 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage,
 static PQconninfoOption *
 conninfo_array_parse(const char *const * keywords, const char *const * values,
 					 PQExpBuffer errorMessage, bool use_defaults,
-					 int expand_dbname)
+					 int expand_dbname, bool *decode_hostname)
 {
 	PQconninfoOption *options;
 	PQconninfoOption *dbname_options = NULL;
@@ -4872,7 +4897,9 @@ conninfo_array_parse(const char *const * keywords, const char *const * values,
 			 */
 			if (recognized_connection_string(pvalue))
 			{
-				dbname_options = parse_connection_string(pvalue, errorMessage, false);
+				dbname_options = parse_connection_string(pvalue, errorMessage,
+														 false,
+														 decode_hostname);
 				if (dbname_options == NULL)
 					return NULL;
 			}
@@ -5327,9 +5354,18 @@ conninfo_uri_parse_options(PQconninfoOption *options, const char *uri,
 	/* Save final values for host and port. */
 	if (PQExpBufferDataBroken(hostbuf) || PQExpBufferDataBroken(portbuf))
 		goto cleanup;
+
+	/*
+	 * Delay URI decoding of hostname till connectOptions2(). The ',' is
+	 * treated as separator in case of multihost connection string. If we
+	 * decode the escaped comma here then it becomes impossible say what ','
+	 * represent.  Frist let us split the hostname then decode the uri.
+	 * We can decode port immediately now, as it takes only digits to represent
+	 * them.
+	 */
 	if (hostbuf.data[0] &&
 		!conninfo_storeval(options, "host", hostbuf.data,
-						   errorMessage, false, true))
+						   errorMessage, false, false))
 		goto cleanup;
 	if (portbuf.data[0] &&
 		!conninfo_storeval(options, "port", portbuf.data,
