commit 8783a78011e3aaa84c2fd32152cc42490eed316b
Author: kuroda.hayato%40jp.fujitsu.com <kuroda.hayato@jp.fujitsu.com>
Date:   Thu Aug 26 05:11:37 2021 +0000

    add application_name to postgres_fdw

diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index a3e1c59a82..ee5a8ede06 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -82,7 +82,7 @@
 #include "utils/guc.h"
 #include "utils/memutils.h"
 #include "utils/ps_status.h"
-
+#include "common/string.h"
 
 /* In this module, access gettext() via err_gettext() */
 #undef _
@@ -177,7 +177,6 @@ static void set_errdata_field(MemoryContextData *cxt, char **ptr, const char *st
 static void write_console(const char *line, int len);
 static void setup_formatted_log_time(void);
 static void setup_formatted_start_time(void);
-static const char *process_log_prefix_padding(const char *p, int *padding);
 static void log_line_prefix(StringInfo buf, ErrorData *edata);
 static void write_csvlog(ErrorData *edata);
 static void send_message_to_server_log(ErrorData *edata);
@@ -2338,41 +2337,6 @@ setup_formatted_start_time(void)
 				pg_localtime(&stamp_time, log_timezone));
 }
 
-/*
- * process_log_prefix_padding --- helper function for processing the format
- * string in log_line_prefix
- *
- * Note: This function returns NULL if it finds something which
- * it deems invalid in the format string.
- */
-static const char *
-process_log_prefix_padding(const char *p, int *ppadding)
-{
-	int			paddingsign = 1;
-	int			padding = 0;
-
-	if (*p == '-')
-	{
-		p++;
-
-		if (*p == '\0')			/* Did the buf end in %- ? */
-			return NULL;
-		paddingsign = -1;
-	}
-
-	/* generate an int version of the numerical string */
-	while (*p >= '0' && *p <= '9')
-		padding = padding * 10 + (*p++ - '0');
-
-	/* format is invalid if it ends with the padding number */
-	if (*p == '\0')
-		return NULL;
-
-	padding *= paddingsign;
-	*ppadding = padding;
-	return p;
-}
-
 /*
  * Format tag info for log lines; append to the provided buffer.
  */
@@ -2427,7 +2391,7 @@ log_line_prefix(StringInfo buf, ErrorData *edata)
 
 		/*
 		 * Process any formatting which may exist after the '%'.  Note that
-		 * process_log_prefix_padding moves p past the padding number if it
+		 * process_padding moves p past the padding number if it
 		 * exists.
 		 *
 		 * Note: Since only '-', '0' to '9' are valid formatting characters we
@@ -2441,7 +2405,7 @@ log_line_prefix(StringInfo buf, ErrorData *edata)
 		 */
 		if (*p > '9')
 			padding = 0;
-		else if ((p = process_log_prefix_padding(p, &padding)) == NULL)
+		else if ((p = process_padding(p, &padding)) == NULL)
 			break;
 
 		/* process the option */
diff --git a/src/common/string.c b/src/common/string.c
index 3aa378c051..9f8b5c3468 100644
--- a/src/common/string.c
+++ b/src/common/string.c
@@ -128,3 +128,38 @@ pg_strip_crlf(char *str)
 
 	return len;
 }
+
+/*
+ * process_padding --- helper function for processing the format
+ * string
+ *
+ * Note: This function returns NULL if it finds something which
+ * it deems invalid in the format string.
+ */
+const char *
+process_padding(const char *p, int *ppadding)
+{
+	int			paddingsign = 1;
+	int			padding = 0;
+
+	if (*p == '-')
+	{
+		p++;
+
+		if (*p == '\0')			/* Did the buf end in %- ? */
+			return NULL;
+		paddingsign = -1;
+	}
+
+	/* generate an int version of the numerical string */
+	while (*p >= '0' && *p <= '9')
+		padding = padding * 10 + (*p++ - '0');
+
+	/* format is invalid if it ends with the padding number */
+	if (*p == '\0')
+		return NULL;
+
+	padding *= paddingsign;
+	*ppadding = padding;
+	return p;
+}
diff --git a/src/include/common/string.h b/src/include/common/string.h
index 686c158efe..1f14e3124f 100644
--- a/src/include/common/string.h
+++ b/src/include/common/string.h
@@ -19,6 +19,7 @@ extern int	strtoint(const char *pg_restrict str, char **pg_restrict endptr,
 extern void pg_clean_ascii(char *str);
 extern int	pg_strip_crlf(char *str);
 extern bool pg_is_ascii(const char *str);
+extern const char* process_padding(const char *p, int *ppadding);
 
 /* functions in src/common/pg_get_line.c */
 extern char *pg_get_line(FILE *stream);
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 49eec3e835..55fbad3087 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -427,6 +427,8 @@ static void default_threadlock(int acquire);
 static bool sslVerifyProtocolVersion(const char *version);
 static bool sslVerifyProtocolRange(const char *min, const char *max);
 
+static void parse_and_rewrite_appnames(PGconn *conn);
+static void parse_and_rewrite_appname_internal(PGconn *conn, char **name);
 
 /* global variable because fe-auth.c needs to access it */
 pgthreadlock_t pg_g_threadlock = default_threadlock;
@@ -1436,6 +1438,13 @@ connectOptions2(PGconn *conn)
 			goto oom_error;
 	}
 
+	/*
+	 * if we have application_name or fallback_application_name,
+	 * parse it and rewrite escape characters
+	 */
+	if (conn->appname || conn->fbappname)
+		parse_and_rewrite_appnames(conn);
+
 	/*
 	 * Only if we get this far is it appropriate to try to connect. (We need a
 	 * state flag, rather than just the boolean result of this function, in
@@ -3834,6 +3843,76 @@ error_return:
 	return PGRES_POLLING_FAILED;
 }
 
+static void
+parse_and_rewrite_appnames(PGconn *conn)
+{
+	if (conn->appname && conn->appname[0] != '\0')
+		parse_and_rewrite_appname_internal(conn, &conn->appname);
+	else if (conn->fbappname && conn->fbappname[0] != '\0')
+		parse_and_rewrite_appname_internal(conn, &conn->fbappname);
+}
+
+/*
+ * Almost same as log_line_prefix
+ */
+static void
+parse_and_rewrite_appname_internal(PGconn *conn, char **name)
+{
+	PQExpBuffer buf = createPQExpBuffer();
+	const char *p;
+	int padding;
+
+	for (p = *name; *p != '\0'; p++)
+	{
+		if (*p != '%')
+		{
+			/* literal char, just copy */
+			appendPQExpBufferChar(buf, *p);
+			continue;
+		}
+
+		/* must be a '%', so skip to the next char */
+		p++;
+		if (*p == '\0')
+			break;				/* format error - ignore it */
+		else if (*p == '%')
+		{
+			/* string contains %% */
+			appendPQExpBufferChar(buf, '%');
+			continue;
+		}
+
+		/* calculate padding, same as log_line_prefix */
+		if (*p > '9')
+			padding = 0;
+		else if ((p = process_padding(p, &padding)) == NULL)
+			break;
+
+		/* process the option */
+		switch (*p)
+		{
+			case 'p':
+				{
+					int pid = (int) getpid();
+
+					if (padding != 0)
+						appendPQExpBuffer(buf, "%*d", padding, pid);
+					else
+						appendPQExpBuffer(buf, "%d", pid);
+				}
+				break;
+			default:
+				/* format error - ignore it */
+				break;
+		}
+	}
+
+	/* Finnaly replace the string */
+	free(*name);
+	*name = strdup(buf->data);
+
+	destroyPQExpBuffer(buf);
+}
 
 /*
  * internal_ping
