@@ -1107,7 +1107,71 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
11071107}
11081108
11091109/*
1110- * Escape single quotes used in connection parameters
1110+ * Escape a parameter value so that it can be used as part of a libpq
1111+ * connection string, e.g. in:
1112+ *
1113+ * application_name=<value>
1114+ *
1115+ * The returned string is malloc'd. Return NULL on out-of-memory.
1116+ */
1117+ static char *
1118+ escapeConnectionParameter (const char * src )
1119+ {
1120+ bool need_quotes = false;
1121+ bool need_escaping = false;
1122+ const char * p ;
1123+ char * dstbuf ;
1124+ char * dst ;
1125+
1126+ /*
1127+ * First check if quoting is needed. Any quote (') or backslash (\)
1128+ * characters need to be escaped. Parameters are separated by whitespace,
1129+ * so any string containing whitespace characters need to be quoted. An
1130+ * empty string is represented by ''.
1131+ */
1132+ if (strchr (src , '\'' ) != NULL || strchr (src , '\\' ) != NULL )
1133+ need_escaping = true;
1134+
1135+ for (p = src ; * p ; p ++ )
1136+ {
1137+ if (isspace (* p ))
1138+ {
1139+ need_quotes = true;
1140+ break ;
1141+ }
1142+ }
1143+
1144+ if (* src == '\0' )
1145+ return pg_strdup ("''" );
1146+
1147+ if (!need_quotes && !need_escaping )
1148+ return pg_strdup (src ); /* no quoting or escaping needed */
1149+
1150+ /*
1151+ * Allocate a buffer large enough for the worst case that all the source
1152+ * characters need to be escaped, plus quotes.
1153+ */
1154+ dstbuf = pg_malloc (strlen (src ) * 2 + 2 + 1 );
1155+
1156+ dst = dstbuf ;
1157+ if (need_quotes )
1158+ * (dst ++ ) = '\'' ;
1159+ for (; * src ; src ++ )
1160+ {
1161+ if (* src == '\'' || * src == '\\' )
1162+ * (dst ++ ) = '\\' ;
1163+ * (dst ++ ) = * src ;
1164+ }
1165+ if (need_quotes )
1166+ * (dst ++ ) = '\'' ;
1167+ * dst = '\0' ;
1168+
1169+ return dstbuf ;
1170+ }
1171+
1172+ /*
1173+ * Escape a string so that it can be used as a value in a key-value pair
1174+ * a configuration file.
11111175 */
11121176static char *
11131177escape_quotes (const char * src )
@@ -1130,6 +1194,8 @@ GenerateRecoveryConf(PGconn *conn)
11301194{
11311195 PQconninfoOption * connOptions ;
11321196 PQconninfoOption * option ;
1197+ PQExpBufferData conninfo_buf ;
1198+ char * escaped ;
11331199
11341200 recoveryconfcontents = createPQExpBuffer ();
11351201 if (!recoveryconfcontents )
@@ -1146,12 +1212,10 @@ GenerateRecoveryConf(PGconn *conn)
11461212 }
11471213
11481214 appendPQExpBufferStr (recoveryconfcontents , "standby_mode = 'on'\n" );
1149- appendPQExpBufferStr (recoveryconfcontents , "primary_conninfo = '" );
11501215
1216+ initPQExpBuffer (& conninfo_buf );
11511217 for (option = connOptions ; option && option -> keyword ; option ++ )
11521218 {
1153- char * escaped ;
1154-
11551219 /*
11561220 * Do not emit this setting if: - the setting is "replication",
11571221 * "dbname" or "fallback_application_name", since these would be
@@ -1165,24 +1229,37 @@ GenerateRecoveryConf(PGconn *conn)
11651229 (option -> val != NULL && option -> val [0 ] == '\0' ))
11661230 continue ;
11671231
1232+ /* Separate key-value pairs with spaces */
1233+ if (conninfo_buf .len != 0 )
1234+ appendPQExpBufferStr (& conninfo_buf , " " );
1235+
11681236 /*
1169- * Write "keyword=' value' " pieces, the value string is escaped if
1170- * necessary and doubled single quotes around the value string .
1237+ * Write "keyword=value" pieces, the value string is escaped and/or
1238+ * quoted if necessary .
11711239 */
1172- escaped = escape_quotes (option -> val );
1173-
1174- appendPQExpBuffer (recoveryconfcontents , "%s=''%s'' " , option -> keyword , escaped );
1175-
1240+ escaped = escapeConnectionParameter (option -> val );
1241+ appendPQExpBuffer (& conninfo_buf , "%s=%s" , option -> keyword , escaped );
11761242 free (escaped );
11771243 }
11781244
1179- appendPQExpBufferStr (recoveryconfcontents , "'\n" );
1180- if (PQExpBufferBroken (recoveryconfcontents ))
1245+ /*
1246+ * Escape the connection string, so that it can be put in the config file.
1247+ * Note that this is different from the escaping of individual connection
1248+ * options above!
1249+ */
1250+ escaped = escape_quotes (conninfo_buf .data );
1251+ appendPQExpBuffer (recoveryconfcontents , "primary_conninfo = '%s'\n" , escaped );
1252+ free (escaped );
1253+
1254+ if (PQExpBufferBroken (recoveryconfcontents ) ||
1255+ PQExpBufferDataBroken (conninfo_buf ))
11811256 {
11821257 fprintf (stderr , _ ("%s: out of memory\n" ), progname );
11831258 disconnect_and_exit (1 );
11841259 }
11851260
1261+ termPQExpBuffer (& conninfo_buf );
1262+
11861263 PQconninfoFree (connOptions );
11871264}
11881265
0 commit comments