@@ -1107,7 +1107,71 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
1107
1107
}
1108
1108
1109
1109
/*
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.
1111
1175
*/
1112
1176
static char *
1113
1177
escape_quotes (const char * src )
@@ -1130,6 +1194,8 @@ GenerateRecoveryConf(PGconn *conn)
1130
1194
{
1131
1195
PQconninfoOption * connOptions ;
1132
1196
PQconninfoOption * option ;
1197
+ PQExpBufferData conninfo_buf ;
1198
+ char * escaped ;
1133
1199
1134
1200
recoveryconfcontents = createPQExpBuffer ();
1135
1201
if (!recoveryconfcontents )
@@ -1146,12 +1212,10 @@ GenerateRecoveryConf(PGconn *conn)
1146
1212
}
1147
1213
1148
1214
appendPQExpBufferStr (recoveryconfcontents , "standby_mode = 'on'\n" );
1149
- appendPQExpBufferStr (recoveryconfcontents , "primary_conninfo = '" );
1150
1215
1216
+ initPQExpBuffer (& conninfo_buf );
1151
1217
for (option = connOptions ; option && option -> keyword ; option ++ )
1152
1218
{
1153
- char * escaped ;
1154
-
1155
1219
/*
1156
1220
* Do not emit this setting if: - the setting is "replication",
1157
1221
* "dbname" or "fallback_application_name", since these would be
@@ -1165,24 +1229,37 @@ GenerateRecoveryConf(PGconn *conn)
1165
1229
(option -> val != NULL && option -> val [0 ] == '\0' ))
1166
1230
continue ;
1167
1231
1232
+ /* Separate key-value pairs with spaces */
1233
+ if (conninfo_buf .len != 0 )
1234
+ appendPQExpBufferStr (& conninfo_buf , " " );
1235
+
1168
1236
/*
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 .
1171
1239
*/
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 );
1176
1242
free (escaped );
1177
1243
}
1178
1244
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 ))
1181
1256
{
1182
1257
fprintf (stderr , _ ("%s: out of memory\n" ), progname );
1183
1258
disconnect_and_exit (1 );
1184
1259
}
1185
1260
1261
+ termPQExpBuffer (& conninfo_buf );
1262
+
1186
1263
PQconninfoFree (connOptions );
1187
1264
}
1188
1265
0 commit comments