Use GUC lexer for recovery.conf parsing.
authorRobert Haas <rhaas@postgresql.org>
Fri, 3 Dec 2010 13:44:15 +0000 (08:44 -0500)
committerRobert Haas <rhaas@postgresql.org>
Fri, 3 Dec 2010 13:56:44 +0000 (08:56 -0500)
This eliminates some crufty, special-purpose code and, as a non-trivial
side benefit, allows recovery.conf parameters to be unquoted.

Dimitri Fontaine, with review and cleanup by Alvaro Herrera, Itagaki
Takahiro, and me.

src/backend/access/transam/xlog.c
src/backend/utils/misc/guc-file.l
src/backend/utils/misc/guc.c
src/include/utils/guc.h

index ede6ceb6affc30cdeb95f3cbb5b27deac5ee420f..ae9ed8fe4ceec9699d386d00667914e84190d86a 100644 (file)
@@ -5023,116 +5023,21 @@ str_time(pg_time_t tnow)
        return buf;
 }
 
-/*
- * 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.
  *
- * XXX longer term intention is to expand this to
- * cater for additional parameters and controls
- * possibly use a flex lexer similar to the GUC one
+ * The file is parsed using the main configuration parser.
  */
 static void
 readRecoveryCommandFile(void)
 {
        FILE       *fd;
-       char            cmdline[MAXPGPATH];
        TimeLineID      rtli = 0;
        bool            rtliGiven = false;
-       bool            syntaxError = false;
+       ConfigVariable *item,
+                                  *head = NULL,
+                                  *tail = NULL;
 
        fd = AllocateFile(RECOVERY_COMMAND_FILE, "r");
        if (fd == NULL)
@@ -5146,55 +5051,47 @@ readRecoveryCommandFile(void)
        }
 
        /*
-        * Parse the file...
-        */
-       while (fgets(cmdline, sizeof(cmdline), fd) != NULL)
-       {
-               char       *tok1;
-               char       *tok2;
+        * Since we're asking ParseConfigFp() to error out at FATAL, there's no
+        * need to check the return value.
+        */ 
+       ParseConfigFp(fd, RECOVERY_COMMAND_FILE, 0, FATAL, &head, &tail);
 
-               if (!parseRecoveryCommandFileLine(cmdline, &tok1, &tok2))
-               {
-                       syntaxError = true;
-                       break;
-               }
-               if (tok1 == NULL)
-                       continue;
-
-               if (strcmp(tok1, "restore_command") == 0)
+       for (item = head; item; item = item->next)
+       {
+               if (strcmp(item->name, "restore_command") == 0)
                {
-                       recoveryRestoreCommand = pstrdup(tok2);
+                       recoveryRestoreCommand = pstrdup(item->value);
                        ereport(DEBUG2,
                                        (errmsg("restore_command = '%s'",
                                                        recoveryRestoreCommand)));
                }
-               else if (strcmp(tok1, "recovery_end_command") == 0)
+               else if (strcmp(item->name, "recovery_end_command") == 0)
                {
-                       recoveryEndCommand = pstrdup(tok2);
+                       recoveryEndCommand = pstrdup(item->value);
                        ereport(DEBUG2,
                                        (errmsg("recovery_end_command = '%s'",
     &