Skip to content

Commit 1b188ea

Browse files
committed
Preparatory refactoring for compiling guc-file.c standalone
Mostly this involves moving ProcessConfigFileInternal() to guc.c and fixing the shared API to match. Reviewed by Andres Freund Discussion: https://www.postgresql.org/message-id/20220810171935.7k5zgnjwqzalzmtm%40awork3.anarazel.de Discussion: https://www.postgresql.org/message-id/CAFBsxsF8Gc2StS3haXofshHCzqNMRXiSxvQEYGwnFsTmsdwNeg@mail.gmail.com
1 parent 73b9d05 commit 1b188ea

File tree

3 files changed

+364
-365
lines changed

3 files changed

+364
-365
lines changed

src/backend/utils/misc/guc-file.l

+1-359
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,6 @@ static sigjmp_buf *GUC_flex_fatal_jmp;
4949

5050
static void FreeConfigVariable(ConfigVariable *item);
5151

52-
static void record_config_file_error(const char *errmsg,
53-
const char *config_file,
54-
int lineno,
55-
ConfigVariable **head_p,
56-
ConfigVariable **tail_p);
57-
5852
static int GUC_flex_fatal(const char *msg);
5953

6054
/* LCOV_EXCL_START */
@@ -160,358 +154,6 @@ ProcessConfigFile(GucContext context)
160154
MemoryContextDelete(config_cxt);
161155
}
162156

163-
/*
164-
* This function handles both actual config file (re)loads and execution of
165-
* show_all_file_settings() (i.e., the pg_file_settings view). In the latter
166-
* case we don't apply any of the settings, but we make all the usual validity
167-
* checks, and we return the ConfigVariable list so that it can be printed out
168-
* by show_all_file_settings().
169-
*/
170-
static ConfigVariable *
171-
ProcessConfigFileInternal(GucContext context, bool applySettings, int elevel)
172-
{
173-
bool error = false;
174-
bool applying = false;
175-
const char *ConfFileWithError;
176-
ConfigVariable *item,
177-
*head,
178-
*tail;
179-
int i;
180-
181-
/* Parse the main config file into a list of option names and values */
182-
ConfFileWithError = ConfigFileName;
183-
head = tail = NULL;
184-
185-
if (!ParseConfigFile(ConfigFileName, true,
186-
NULL, 0, 0, elevel,
187-
&head, &tail))
188-
{
189-
/* Syntax error(s) detected in the file, so bail out */
190-
error = true;
191-
goto bail_out;
192-
}
193-
194-
/*
195-
* Parse the PG_AUTOCONF_FILENAME file, if present, after the main file to
196-
* replace any parameters set by ALTER SYSTEM command. Because this file
197-
* is in the data directory, we can't read it until the DataDir has been
198-
* set.
199-
*/
200-
if (DataDir)
201-
{
202-
if (!ParseConfigFile(PG_AUTOCONF_FILENAME, false,
203-
NULL, 0, 0, elevel,
204-
&head, &tail))
205-
{
206-
/* Syntax error(s) detected in the file, so bail out */
207-
error = true;
208-
ConfFileWithError = PG_AUTOCONF_FILENAME;
209-
goto bail_out;
210-
}
211-
}
212-
else
213-
{
214-
/*
215-
* If DataDir is not set, the PG_AUTOCONF_FILENAME file cannot be
216-
* read. In this case, we don't want to accept any settings but
217-
* data_directory from postgresql.conf, because they might be
218-
* overwritten with settings in the PG_AUTOCONF_FILENAME file which
219-
* will be read later. OTOH, since data_directory isn't allowed in the
220-
* PG_AUTOCONF_FILENAME file, it will never be overwritten later.
221-
*/
222-
ConfigVariable *newlist = NULL;
223-
224-
/*
225-
* Prune all items except the last "data_directory" from the list.
226-
*/
227-
for (item = head; item; item = item->next)
228-
{
229-
if (!item->ignore &&
230-
strcmp(item->name, "data_directory") == 0)
231-
newlist = item;
232-
}
233-
234-
if (newlist)
235-
newlist->next = NULL;
236-
head = tail = newlist;
237-
238-
/*
239-
* Quick exit if data_directory is not present in file.
240-
*
241-
* We need not do any further processing, in particular we don't set
242-
* PgReloadTime; that will be set soon by subsequent full loading of
243-
* the config file.
244-
*/
245-
if (head == NULL)
246-
goto bail_out;
247-
}
248-
249-
/*
250-
* Mark all extant GUC variables as not present in the config file. We
251-
* need this so that we can tell below which ones have been removed from
252-
* the file since we last processed it.
253-
*/
254-
for (i = 0; i < num_guc_variables; i++)
255-
{
256-
struct config_generic *gconf = guc_variables[i];
257-
258-
gconf->status &= ~GUC_IS_IN_FILE;
259-
}
260-
261-
/*
262-
* Check if all the supplied option names are valid, as an additional
263-
* quasi-syntactic check on the validity of the config file. It is
264-
* important that the postmaster and all backends agree on the results of
265-
* this phase, else we will have strange inconsistencies about which
266-
* processes accept a config file update and which don't. Hence, unknown
267-
* custom variable names have to be accepted without complaint. For the
268-
* same reason, we don't attempt to validate the options' values here.
269-
*
270-
* In addition, the GUC_IS_IN_FILE flag is set on each existing GUC
271-
* variable mentioned in the file; and we detect duplicate entries in the
272-
* file and mark the earlier occurrences as ignorable.
273-
*/
274-
for (item = head; item; item = item->next)
275-
{
276-
struct config_generic *record;
277-
278-
/* Ignore anything already marked as ignorable */
279-
if (item->ignore)
280-
continue;
281-
282-
/*
283-
* Try to find the variable; but do not create a custom placeholder if
284-
* it's not there already.
285-
*/
286-
record = find_option(item->name, false, true, elevel);
287-
288-
if (record)
289-
{
290-
/* If it's already marked, then this is a duplicate entry */
291-
if (record->status & GUC_IS_IN_FILE)
292-
{
293-
/*
294-
* Mark the earlier occurrence(s) as dead/ignorable. We could
295-
* avoid the O(N^2) behavior here with some additional state,
296-
* but it seems unlikely to be worth the trouble.
297-
*/
298-
ConfigVariable *pitem;
299-
300-
for (pitem = head; pitem != item; pitem = pitem->next)
301-
{
302-
if (!pitem->ignore &&
303-
strcmp(pitem->name, item->name) == 0)
304-
pitem->ignore = true;
305-
}
306-
}
307-
/* Now mark it as present in file */
308-
record->status |= GUC_IS_IN_FILE;
309-
}
310-
else if (!valid_custom_variable_name(item->name))
311-
{
312-
/* Invalid non-custom variable, so complain */
313-
ereport(elevel,
314-
(errcode(ERRCODE_UNDEFINED_OBJECT),
315-
errmsg("unrecognized configuration parameter \"%s\" in file \"%s\" line %d",
316-
item->name,
317-
item->filename, item->sourceline)));
318-
item->errmsg = pstrdup("unrecognized configuration parameter");
319-
error = true;
320-
ConfFileWithError = item->filename;
321-
}
322-
}
323-
324-
/*
325-
* If we've detected any errors so far, we don't want to risk applying any
326-
* changes.
327-
*/
328-
if (error)
329-
goto bail_out;
330-
331-
/* Otherwise, set flag that we're beginning to apply changes */
332-
applying = true;
333-
334-
/*
335-
* Check for variables having been removed from the config file, and
336-
* revert their reset values (and perhaps also effective values) to the
337-
* boot-time defaults. If such a variable can't be changed after startup,
338-
* report that and continue.
339-
*/
340-
for (i = 0; i < num_guc_variables; i++)
341-
{
342-
struct config_generic *gconf = guc_variables[i];
343-
GucStack *stack;
344-
345-
if (gconf->reset_source != PGC_S_FILE ||
346-
(gconf->status & GUC_IS_IN_FILE))
347-
continue;
348-
if (gconf->context < PGC_SIGHUP)
349-
{
350-
/* The removal can't be effective without a restart */
351-
gconf->status |= GUC_PENDING_RESTART;
352-
ereport(elevel,
353-
(errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM),
354-
errmsg("parameter \"%s\" cannot be changed without restarting the server",
355-
gconf->name)));
356-
record_config_file_error(psprintf("parameter \"%s\" cannot be changed without restarting the server",
357-
gconf->name),
358-
NULL, 0,
359-
&head, &tail);
360-
error = true;
361-
continue;
362-
}
363-
364-
/* No more to do if we're just doing show_all_file_settings() */
365-
if (!applySettings)
366-
continue;
367-
368-
/*
369-
* Reset any "file" sources to "default", else set_config_option will
370-
* not override those settings.
371-
*/
372-
if (gconf->reset_source == PGC_S_FILE)
373-
gconf->reset_source = PGC_S_DEFAULT;
374-
if (gconf->source == PGC_S_FILE)
375-
gconf->source = PGC_S_DEFAULT;
376-
for (stack = gconf->stack; stack; stack = stack->prev)
377-
{
378-
if (stack->source == PGC_S_FILE)
379-
stack->source = PGC_S_DEFAULT;
380-
}
381-
382-
/* Now we can re-apply the wired-in default (i.e., the boot_val) */
383-
if (set_config_option(gconf->name, NULL,
384-
context, PGC_S_DEFAULT,
385-
GUC_ACTION_SET, true, 0, false) > 0)
386-
{
387-
/* Log the change if appropriate */
388-
if (context == PGC_SIGHUP)
389-
ereport(elevel,
390-
(errmsg("parameter \"%s\" removed from configuration file, reset to default",
391-
gconf->name)));
392-
}
393-
}
394-
395-
/*
396-
* Restore any variables determined by environment variables or
397-
* dynamically-computed defaults. This is a no-op except in the case
398-
* where one of these had been in the config file and is now removed.
399-
*
400-
* In particular, we *must not* do this during the postmaster's initial
401-
* loading of the file, since the timezone functions in particular should
402-
* be run only after initialization is complete.
403-
*
404-
* XXX this is an unmaintainable crock, because we have to know how to set
405-
* (or at least what to call to set) every non-PGC_INTERNAL variable that
406-
* could potentially have PGC_S_DYNAMIC_DEFAULT or PGC_S_ENV_VAR source.
407-
*/
408-
if (context == PGC_SIGHUP && applySettings)
409-
{
410-
InitializeGUCOptionsFromEnvironment();
411-
pg_timezone_abbrev_initialize();
412-
/* this selects SQL_ASCII in processes not connected to a database */
413-
SetConfigOption("client_encoding", GetDatabaseEncodingName(),
414-
PGC_BACKEND, PGC_S_DYNAMIC_DEFAULT);
415-
}
416-
417-
/*
418-
* Now apply the values from the config file.
419-
*/
420-
for (item = head; item; item = item->next)
421-
{
422-
char *pre_value = NULL;
423-
int scres;
424-
425-
/* Ignore anything marked as ignorable */
426-
if (item->ignore)
427-
continue;
428-
429-
/* In SIGHUP cases in the postmaster, we want to report changes */
430-
if (context == PGC_SIGHUP && applySettings && !IsUnderPostmaster)
431-
{
432-
const char *preval = GetConfigOption(item->name, true, false);
433-
434-
/* If option doesn't exist yet or is NULL, treat as empty string */
435-
if (!preval)
436-
preval = "";
437-
/* must dup, else might have dangling pointer below */
438-
pre_value = pstrdup(preval);
439-
}
440-
441-
scres = set_config_option(item->name, item->value,
442-
context, PGC_S_FILE,
443-
GUC_ACTION_SET, applySettings, 0, false);
444-
if (scres > 0)
445-
{
446-
/* variable was updated, so log the change if appropriate */
447-
if (pre_value)
448-
{
449-
const char *post_value = GetConfigOption(item->name, true, false);
450-
451-
if (!post_value)
452-
post_value = "";
453-
if (strcmp(pre_value, post_value) != 0)
454-
ereport(elevel,
455-
(errmsg("parameter \"%s\" changed to \"%s\"",
456-
item->name, item->value)));
457-
}
458-
item->applied = true;
459-
}
460-
else if (scres == 0)
461-
{
462-
error = true;
463-
item->errmsg = pstrdup("setting could not be applied");
464-
ConfFileWithError = item->filename;
465-
}
466-
else
467-
{
468-
/* no error, but variable's active value was not changed */
469-
item->applied = true;
470-
}
471-
472-
/*
473-
* We should update source location unless there was an error, since
474-
* even if the active value didn't change, the reset value might have.
475-
* (In the postmaster, there won't be a difference, but it does matter
476-
* in backends.)
477-
*/
478-
if (scres != 0 && applySettings)
479-
set_config_sourcefile(item->name, item->filename,
480-
item->sourceline);
481-
482-
if (pre_value)
483-
pfree(pre_value);
484-
}
485-
486-
/* Remember when we last successfully loaded the config file. */
487-
if (applySettings)
488-
PgReloadTime = GetCurrentTimestamp();
489-
490-
bail_out:
491-
if (error && applySettings)
492-
{
493-
/* During postmaster startup, any error is fatal */
494-
if (context == PGC_POSTMASTER)
495-
ereport(ERROR,
496-
(errcode(ERRCODE_CONFIG_FILE_ERROR),
497-
errmsg("configuration file \"%s\" contains errors",
498-
ConfFileWithError)));
499-
else if (applying)
500-
ereport(elevel,
501-
(errcode(ERRCODE_CONFIG_FILE_ERROR),
502-
errmsg("configuration file \"%s\" contains errors; unaffected changes were applied",
503-
ConfFileWithError)));
504-
else
505-
ereport(elevel,
506-
(errcode(ERRCODE_CONFIG_FILE_ERROR),
507-
errmsg("configuration file \"%s\" contains errors; no changes were applied",
508-
ConfFileWithError)));
509-
}
510-
511-
/* Successful or otherwise, return the collected data list */
512-
return head;
513-
}
514-
515157
/*
516158
* Given a configuration file or directory location that may be a relative
517159
* path, return an absolute one. We consider the location to be relative to
@@ -660,7 +302,7 @@ cleanup:
660302
* Capture an error message in the ConfigVariable list returned by
661303
* config file parsing.
662304
*/
663-
static void
305+
void
664306
record_config_file_error(const char *errmsg,
665307
const char *config_file,
666308
int lineno,

0 commit comments

Comments
 (0)