Simon Riggs wrote: > On Tue, 2010-04-06 at 16:07 +0900, Fujii Masao wrote: >> On Tue, Apr 6, 2010 at 3:47 PM, Heikki Linnakangas >> <heikki.linnakan...@enterprisedb.com> wrote: >>> To follow up on the discussion here: >>> >>> http://archives.postgresql.org/pgsql-docs/2010-02/msg00039.php >>> >>> It seems like a big oversight that there's no way to insert quotes in >>> strings in recovery.conf. In the long run, the parsing should be done >>> the same way as postgresql.conf, or the two files be merged altogether, >>> but right now I think we should just add support for escaping quotes. I >>> propose two quotes '' to mean a quote mark in the string, like in >>> strings in SQL queries. >> Agreed. This would be useful for users to specify the application_name >> containing a space in the primary_conninfo, for example. > > +1
Ok, here's what I came up with. -- Heikki Linnakangas EnterpriseDB http://www.enterprisedb.com
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index abdf4d8..73ef0f9 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -4894,6 +4894,100 @@ str_time(pg_time_t tnow) } /* + * Parse one line from recovery.conf. 'cmdline' is the raw line from the + * file. If the line is parsed successfully, returns true, false indicates + * syntax error. On success, *key_p and *value_p are set to the parameter + * name and value on the line, respectively. If the line is an empty line, + * consisting entirely of whitespace and comments, function returns true + * and *keyp_p and *value_p are set to NULL. + * + * The pointers returned in *key_p and *value_p point to an internal buffer + * that is valid only until the next call of parseRecoveryCommandFile(). + */ +static bool +parseRecoveryCommandFileLine(char *cmdline, char **key_p, char **value_p) +{ + char *ptr; + char *bufp; + char *key; + char *value; + static char *buf = NULL; + + *key_p = *value_p = NULL; + + /* + * Allocate the buffer on first use. It's used to hold both the + * parameter name and value. + */ + if (buf == NULL) + buf = malloc(MAXPGPATH + 1); + bufp = buf; + + /* Skip any whitespace at the beginning of line */ + for (ptr = cmdline; *ptr; ptr++) + { + if (!isspace((unsigned char) *ptr)) + break; + } + /* Ignore empty lines */ + if (*ptr == '\0' || *ptr == '#') + return true; + + /* Read the parameter name */ + key = bufp; + while (*ptr && !isspace((unsigned char) *ptr) && + *ptr != '=' && *ptr != '\'') + *(bufp++) = *(ptr++); + *(bufp++) = '\0'; + + /* Skip to the beginning quote of the parameter value */ + ptr = strchr(ptr, '\''); + if (!ptr) + return false; + ptr++; + + /* Read the parameter value to *bufp. Collapse any '' escapes as we go. */ + value = bufp; + for (;;) + { + if (*ptr == '\'') + { + ptr++; + if (*ptr == '\'') + *(bufp++) = '\''; + else + { + /* end of parameter */ + *bufp = '\0'; + break; + } + } + else if (*ptr == '\0') + return false; /* unterminated quoted string */ + else + *(bufp++) = *ptr; + + ptr++; + } + *(bufp++) = '\0'; + + /* Check that there's no garbage after the value */ + while (*ptr) + { + if (*ptr == '#') + break; + if (!isspace((unsigned char) *ptr)) + return false; + ptr++; + } + + /* Success! */ + *key_p = key; + *value_p = value; + return true; +} + +/* * See if there is a recovery command file (recovery.conf), and if so * read in parameters for archive recovery and XLOG streaming. * @@ -4926,39 +5020,16 @@ readRecoveryCommandFile(void) */ while (fgets(cmdline, sizeof(cmdline), fd) != NULL) { - /* skip leading whitespace and check for # comment */ - char *ptr; char *tok1; char *tok2; - for (ptr = cmdline; *ptr; ptr++) - { - if (!isspace((unsigned char) *ptr)) - break; - } - if (*ptr == '\0' || *ptr == '#') - continue; - - /* identify the quoted parameter value */ - tok1 = strtok(ptr, "'"); - if (!tok1) - { - syntaxError = true; - break; - } - tok2 = strtok(NULL, "'"); - if (!tok2) - { - syntaxError = true; - break; - } - /* reparse to get just the parameter name */ - tok1 = strtok(ptr, " \t="); - if (!tok1) + if (!parseRecoveryCommandFileLine(cmdline, &tok1, &tok2)) { syntaxError = true; break; } + if (tok1 == NULL) + continue; if (strcmp(tok1, "restore_command") == 0) {
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers