@@ -5023,116 +5023,21 @@ str_time(pg_time_t tnow)
50235023return buf ;
50245024}
50255025
5026- /*
5027- * Parse one line from recovery.conf. 'cmdline' is the raw line from the
5028- * file. If the line is parsed successfully, returns true, false indicates
5029- * syntax error. On success, *key_p and *value_p are set to the parameter
5030- * name and value on the line, respectively. If the line is an empty line,
5031- * consisting entirely of whitespace and comments, function returns true
5032- * and *keyp_p and *value_p are set to NULL.
5033- *
5034- * The pointers returned in *key_p and *value_p point to an internal buffer
5035- * that is valid only until the next call of parseRecoveryCommandFile().
5036- */
5037- static bool
5038- parseRecoveryCommandFileLine (char * cmdline ,char * * key_p ,char * * value_p )
5039- {
5040- char * ptr ;
5041- char * bufp ;
5042- char * key ;
5043- char * value ;
5044- static char * buf = NULL ;
5045-
5046- * key_p = * value_p = NULL ;
5047-
5048- /*
5049- * Allocate the buffer on first use. It's used to hold both the parameter
5050- * name and value.
5051- */
5052- if (buf == NULL )
5053- buf = malloc (MAXPGPATH + 1 );
5054- bufp = buf ;
5055-
5056- /* Skip any whitespace at the beginning of line */
5057- for (ptr = cmdline ;* ptr ;ptr ++ )
5058- {
5059- if (!isspace ((unsignedchar )* ptr ))
5060- break ;
5061- }
5062- /* Ignore empty lines */
5063- if (* ptr == '\0' || * ptr == '#' )
5064- return true;
5065-
5066- /* Read the parameter name */
5067- key = bufp ;
5068- while (* ptr && !isspace ((unsignedchar )* ptr )&&
5069- * ptr != '=' && * ptr != '\'' )
5070- * (bufp ++ )= * (ptr ++ );
5071- * (bufp ++ )= '\0' ;
5072-
5073- /* Skip to the beginning quote of the parameter value */
5074- ptr = strchr (ptr ,'\'' );
5075- if (!ptr )
5076- return false;
5077- ptr ++ ;
5078-
5079- /* Read the parameter value to *bufp. Collapse any '' escapes as we go. */
5080- value = bufp ;
5081- for (;;)
5082- {
5083- if (* ptr == '\'' )
5084- {
5085- ptr ++ ;
5086- if (* ptr == '\'' )
5087- * (bufp ++ )= '\'' ;
5088- else
5089- {
5090- /* end of parameter */
5091- * bufp = '\0' ;
5092- break ;
5093- }
5094- }
5095- else if (* ptr == '\0' )
5096- return false;/* unterminated quoted string */
5097- else
5098- * (bufp ++ )= * ptr ;
5099-
5100- ptr ++ ;
5101- }
5102- * (bufp ++ )= '\0' ;
5103-
5104- /* Check that there's no garbage after the value */
5105- while (* ptr )
5106- {
5107- if (* ptr == '#' )
5108- break ;
5109- if (!isspace ((unsignedchar )* ptr ))
5110- return false;
5111- ptr ++ ;
5112- }
5113-
5114- /* Success! */
5115- * key_p = key ;
5116- * value_p = value ;
5117- return true;
5118- }
5119-
51205026/*
51215027 * See if there is a recovery command file (recovery.conf), and if so
51225028 * read in parameters for archive recovery and XLOG streaming.
51235029 *
5124- * XXX longer term intention is to expand this to
5125- * cater for additional parameters and controls
5126- * possibly use a flex lexer similar to the GUC one
5030+ * The file is parsed using the main configuration parser.
51275031 */
51285032static void
51295033readRecoveryCommandFile (void )
51305034{
51315035FILE * fd ;
5132- char cmdline [MAXPGPATH ];
51335036TimeLineID rtli = 0 ;
51345037bool rtliGiven = false;
5135- bool syntaxError = false;
5038+ ConfigVariable * item ,
5039+ * head = NULL ,
5040+ * tail = NULL ;
51365041
51375042fd = AllocateFile (RECOVERY_COMMAND_FILE ,"r" );
51385043if (fd == NULL )
@@ -5146,55 +5051,47 @@ readRecoveryCommandFile(void)
51465051}
51475052
51485053/*
5149- * Parse the file...
5150- */
5151- while (fgets (cmdline ,sizeof (cmdline ),fd )!= NULL )
5152- {
5153- char * tok1 ;
5154- char * tok2 ;
5054+ * Since we're asking ParseConfigFp() to error out at FATAL, there's no
5055+ * need to check the return value.
5056+ */
5057+ ParseConfigFp (fd ,RECOVERY_COMMAND_FILE ,0 ,FATAL ,& head ,& tail );
51555058
5156- if (!parseRecoveryCommandFileLine (cmdline ,& tok1 ,& tok2 ))
5157- {
5158- syntaxError = true;
5159- break ;
5160- }
5161- if (tok1 == NULL )
5162- continue ;
5163-
5164- if (strcmp (tok1 ,"restore_command" )== 0 )
5059+ for (item = head ;item ;item = item -> next )
5060+ {
5061+ if (strcmp (item -> name ,"restore_command" )== 0 )
51655062{
5166- recoveryRestoreCommand = pstrdup (tok2 );
5063+ recoveryRestoreCommand = pstrdup (item -> value );
51675064ereport (DEBUG2 ,
51685065(errmsg ("restore_command = '%s'" ,
51695066recoveryRestoreCommand )));
51705067}
5171- else if (strcmp (tok1 ,"recovery_end_command" )== 0 )
5068+ else if (strcmp (item -> name ,"recovery_end_command" )== 0 )
51725069{
5173- recoveryEndCommand = pstrdup (tok2 );
5070+ recoveryEndCommand = pstrdup (item -> value );
51745071ereport (DEBUG2 ,
51755072(errmsg ("recovery_end_command = '%s'" ,
51765073recoveryEndCommand )));
51775074}
5178- else if (strcmp (tok1 ,"archive_cleanup_command" )== 0 )
5075+ else if (strcmp (item -> name ,"archive_cleanup_command" )== 0 )
51795076{
5180- archiveCleanupCommand = pstrdup (tok2 );
5077+ archiveCleanupCommand = pstrdup (item -> value );
51815078ereport (DEBUG2 ,
51825079(errmsg ("archive_cleanup_command = '%s'" ,
51835080archiveCleanupCommand )));
51845081}
5185- else if (strcmp (tok1 ,"recovery_target_timeline" )== 0 )
5082+ else if (strcmp (item -> name ,"recovery_target_timeline" )== 0 )
51865083{
51875084rtliGiven = true;
5188- if (strcmp (tok2 ,"latest" )== 0 )
5085+ if (strcmp (item -> value ,"latest" )== 0 )
51895086rtli = 0 ;
51905087else
51915088{
51925089errno = 0 ;
5193- rtli = (TimeLineID )strtoul (tok2 ,NULL ,0 );
5090+ rtli = (TimeLineID )strtoul (item -> value ,NULL ,0 );
51945091if (errno == EINVAL || errno == ERANGE )
51955092ereport (FATAL ,
51965093(errmsg ("recovery_target_timeline is not a valid number: \"%s\"" ,
5197- tok2 )));
5094+ item -> value )));
51985095}
51995096if (rtli )
52005097ereport (DEBUG2 ,
@@ -5203,20 +5100,20 @@ readRecoveryCommandFile(void)
52035100ereport (DEBUG2 ,
52045101(errmsg ("recovery_target_timeline = latest" )));
52055102}
5206- else if (strcmp (tok1 ,"recovery_target_xid" )== 0 )
5103+ else if (strcmp (item -> name ,"recovery_target_xid" )== 0 )
52075104{
52085105errno = 0 ;
5209- recoveryTargetXid = (TransactionId )strtoul (tok2 ,NULL ,0 );
5106+ recoveryTargetXid = (TransactionId )strtoul (item -> value ,NULL ,0 );
52105107if (errno == EINVAL || errno == ERANGE )
52115108ereport (FATAL ,
52125109 (errmsg ("recovery_target_xid is not a valid number: \"%s\"" ,
5213- tok2 )));
5110+ item -> value )));
52145111ereport (DEBUG2 ,
52155112(errmsg ("recovery_target_xid = %u" ,
52165113recoveryTargetXid )));
52175114recoveryTarget = RECOVERY_TARGET_XID ;
52185115}
5219- else if (strcmp (tok1 ,"recovery_target_time" )== 0 )
5116+ else if (strcmp (item -> name ,"recovery_target_time" )== 0 )
52205117{
52215118/*
52225119 * if recovery_target_xid specified, then this overrides
@@ -5231,62 +5128,54 @@ readRecoveryCommandFile(void)
52315128 */
52325129recoveryTargetTime =
52335130DatumGetTimestampTz (DirectFunctionCall3 (timestamptz_in ,
5234- CStringGetDatum (tok2 ),
5131+ CStringGetDatum (item -> value ),
52355132ObjectIdGetDatum (InvalidOid ),
52365133Int32GetDatum (-1 )));
52375134ereport (DEBUG2 ,
52385135(errmsg ("recovery_target_time = '%s'" ,
52395136timestamptz_to_str (recoveryTargetTime ))));
52405137}
5241- else if (strcmp (tok1 ,"recovery_target_inclusive" )== 0 )
5138+ else if (strcmp (item -> name ,"recovery_target_inclusive" )== 0 )
52425139{
52435140/*
52445141 * does nothing if a recovery_target is not also set
52455142 */
5246- if (!parse_bool (tok2 ,& recoveryTargetInclusive ))
5143+ if (!parse_bool (item -> value ,& recoveryTargetInclusive ))
52475144ereport (ERROR ,
52485145(errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
52495146errmsg ("parameter \"%s\" requires a Boolean value" ,"recovery_target_inclusive" )));
52505147ereport (DEBUG2 ,
5251- (errmsg ("recovery_target_inclusive = %s" ,tok2 )));
5148+ (errmsg ("recovery_target_inclusive = %s" ,item -> value )));
52525149}
5253- else if (strcmp (tok1 ,"standby_mode" )== 0 )
5150+ else if (strcmp (item -> name ,"standby_mode" )== 0 )
52545151{
5255- if (!parse_bool (tok2 ,& StandbyMode ))
5152+ if (!parse_bool (item -> value ,& StandbyMode ))
52565153ereport (ERROR ,
52575154(errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
52585155errmsg ("parameter \"%s\" requires a Boolean value" ,"standby_mode" )));
52595156ereport (DEBUG2 ,
5260- (errmsg ("standby_mode = '%s'" ,tok2 )));
5157+ (errmsg ("standby_mode = '%s'" ,item -> value )));
52615158}
5262- else if (strcmp (tok1 ,"primary_conninfo" )== 0 )
5159+ else if (strcmp (item -> name ,"primary_conninfo" )== 0 )
52635160{
5264- PrimaryConnInfo = pstrdup (tok2 );
5161+ PrimaryConnInfo = pstrdup (item -> value );
52655162ereport (DEBUG2 ,
52665163(errmsg ("primary_conninfo = '%s'" ,
52675164PrimaryConnInfo )));
52685165}
5269- else if (strcmp (tok1 ,"trigger_file" )== 0 )
5166+ else if (strcmp (item -> name ,"trigger_file" )== 0 )
52705167{
5271- TriggerFile = pstrdup (tok2 );
5168+ TriggerFile = pstrdup (item -> value );
52725169ereport (DEBUG2 ,
52735170(errmsg ("trigger_file = '%s'" ,
52745171TriggerFile )));
52755172}
52765173else
52775174ereport (FATAL ,
52785175(errmsg ("unrecognized recovery parameter \"%s\"" ,
5279- tok1 )));
5176+ item -> name )));
52805177}
52815178
5282- FreeFile (fd );
5283-
5284- if (syntaxError )
5285- ereport (FATAL ,
5286- (errmsg ("syntax error in recovery command file: %s" ,
5287- cmdline ),
5288- errhint ("Lines should have the format parameter = 'value'." )));
5289-
52905179/*
52915180 * Check for compulsory parameters
52925181 */
@@ -5332,6 +5221,9 @@ readRecoveryCommandFile(void)
53325221recoveryTargetTLI = findNewestTimeLine (recoveryTargetTLI );
53335222}
53345223}
5224+
5225+ FreeConfigVariables (head );
5226+ FreeFile (fd );
53355227}
53365228
53375229/*