@ -1107,7 +1107,71 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
}
/*
* Escape single quotes used in connection parameters
* Escape a parameter value so that it can be used as part of a libpq
* connection string , e . g . in :
*
* application_name = < value >
*
* The returned string is malloc ' d . Return NULL on out - of - memory .
*/
static char *
escapeConnectionParameter ( const char * src )
{
bool need_quotes = false ;
bool need_escaping = false ;
const char * p ;
char * dstbuf ;
char * dst ;
/*
* First check if quoting is needed . Any quote ( ' ) or backslash ( \ )
* characters need to be escaped . Parameters are separated by whitespace ,
* so any string containing whitespace characters need to be quoted . An
* empty string is represented by ' ' .
*/
if ( strchr ( src , ' \' ' ) ! = NULL | | strchr ( src , ' \\ ' ) ! = NULL )
need_escaping = true ;
for ( p = src ; * p ; p + + )
{
if ( isspace ( * p ) )
{
need_quotes = true ;
break ;
}
}
if ( * src = = ' \0 ' )
return pg_strdup ( " '' " ) ;
if ( ! need_quotes & & ! need_escaping )
return pg_strdup ( src ) ; /* no quoting or escaping needed */
/*
* Allocate a buffer large enough for the worst case that all the source
* characters need to be escaped , plus quotes .
*/
dstbuf = pg_malloc ( strlen ( src ) * 2 + 2 + 1 ) ;
dst = dstbuf ;
if ( need_quotes )
* ( dst + + ) = ' \' ' ;
for ( ; * src ; src + + )
{
if ( * src = = ' \' ' | | * src = = ' \\ ' )
* ( dst + + ) = ' \\ ' ;
* ( dst + + ) = * src ;
}
if ( need_quotes )
* ( dst + + ) = ' \' ' ;
* dst = ' \0 ' ;
return dstbuf ;
}
/*
* Escape a string so that it can be used as a value in a key - value pair
* a configuration file .
*/
static char *
escape_quotes ( const char * src )
@ -1130,6 +1194,8 @@ GenerateRecoveryConf(PGconn *conn)
{
PQconninfoOption * connOptions ;
PQconninfoOption * option ;
PQExpBufferData conninfo_buf ;
char * escaped ;
recoveryconfcontents = createPQExpBuffer ( ) ;
if ( ! recoveryconfcontents )
@ -1146,12 +1212,10 @@ GenerateRecoveryConf(PGconn *conn)
}
appendPQExpBufferStr ( recoveryconfcontents , " standby_mode = 'on' \n " ) ;
appendPQExpBufferStr ( recoveryconfcontents , " primary_conninfo = ' " ) ;
initPQExpBuffer ( & conninfo_buf ) ;
for ( option = connOptions ; option & & option - > keyword ; option + + )
{
char * escaped ;
/*
* Do not emit this setting if : - the setting is " replication " ,
* " dbname " or " fallback_application_name " , since these would be
@ -1165,24 +1229,37 @@ GenerateRecoveryConf(PGconn *conn)
( option - > val ! = NULL & & option - > val [ 0 ] = = ' \0 ' ) )
continue ;
/* Separate key-value pairs with spaces */
if ( conninfo_buf . len ! = 0 )
appendPQExpBufferStr ( & conninfo_buf , " " ) ;
/*
* Write " keyword='value' " pieces , the value string is escaped if
* necessary and doubled single quotes around the value string .
* Write " keyword=value " pieces , the value string is escaped and / or
* quoted if necessary .
*/
escaped = escape_quotes ( option - > val ) ;
appendPQExpBuffer ( recoveryconfcontents , " %s=''%s'' " , option - > keyword , escaped ) ;
escaped = escapeConnectionParameter ( option - > val ) ;
appendPQExpBuffer ( & conninfo_buf , " %s=%s " , option - > keyword , escaped ) ;
free ( escaped ) ;
}
appendPQExpBufferStr ( recoveryconfcontents , " ' \n " ) ;
if ( PQExpBufferBroken ( recoveryconfcontents ) )
/*
* Escape the connection string , so that it can be put in the config file .
* Note that this is different from the escaping of individual connection
* options above !
*/
escaped = escape_quotes ( conninfo_buf . data ) ;
appendPQExpBuffer ( recoveryconfcontents , " primary_conninfo = '%s' \n " , escaped ) ;
free ( escaped ) ;
if ( PQExpBufferBroken ( recoveryconfcontents ) | |
PQExpBufferDataBroken ( conninfo_buf ) )
{
fprintf ( stderr , _ ( " %s: out of memory \n " ) , progname ) ;
disconnect_and_exit ( 1 ) ;
}
termPQExpBuffer ( & conninfo_buf ) ;
PQconninfoFree ( connOptions ) ;
}