diff -cr cvs/pgsql/doc/src/sgml/config.sgml cvs.build/pgsql/doc/src/sgml/config.sgml
*** cvs/pgsql/doc/src/sgml/config.sgml 2005-11-20 13:42:44.000000000 +0100
--- cvs.build/pgsql/doc/src/sgml/config.sgml 2005-12-02 00:05:38.000000000 +0100
***************
*** 71,76 ****
--- 71,78 ----
postmaster -c log_connections=yes -c log_destination='syslog'
+ (The special option include however can not be specified
+ on the command line).
Command-line options override any conflicting settings in
postgresql.conf. Note that this means you won't
be able to change the value on-the-fly by editing
***************
*** 224,229 ****
--- 226,247 ----
+
+
+ include (string)
+
+ include> configuration parameter
+
+
+
+ Specifies another configuration file that is read in by the starting
+ postgres> process. You can use this option multiple
+ times and you can also read in configuration files recursively. Later
+ values for configuration options will overwrite previous assignments.
+ This option can not be specified on the command line.
+
+
+
***************
*** 260,268 ****
! When setting any of these options, a relative path will be interpreted
with respect to the directory in which the postmaster
! is started.
--- 278,289 ----
! When setting any of these options except for the
! include option, a relative path will be interpreted
with respect to the directory in which the postmaster
! is started. For the include option, a relative path
! will always be relative to the path of the file that contained the
! include option.
diff -cr cvs/pgsql/src/backend/utils/misc/guc-file.l cvs.build/pgsql/src/backend/utils/misc/guc-file.l
*** cvs/pgsql/src/backend/utils/misc/guc-file.l 2005-09-22 14:31:21.000000000 +0200
--- cvs.build/pgsql/src/backend/utils/misc/guc-file.l 2005-12-01 23:24:07.000000000 +0100
***************
*** 115,165 ****
}
! /*
! * Official function to read and process the configuration file. The
! * parameter indicates in what context the file is being read --- either
! * postmaster startup (including standalone-backend startup) or SIGHUP.
! * All options mentioned in the configuration file are set to new values.
! * If an error occurs, no values will be changed.
*/
- void
- ProcessConfigFile(GucContext context)
- {
- int elevel;
- int token, parse_state;
- char *opt_name, *opt_value;
- struct name_value_pair *item, *head, *tail;
- FILE *fp;
! Assert(context == PGC_POSTMASTER || context == PGC_SIGHUP);
!
! if (context == PGC_SIGHUP)
! {
! /*
! * To avoid cluttering the log, only the postmaster bleats loudly
! * about problems with the config file.
! */
! elevel = IsUnderPostmaster ? DEBUG2 : LOG;
}
else
! elevel = ERROR;
!
! fp = AllocateFile(ConfigFileName, "r");
! if (!fp)
! {
ereport(elevel,
(errcode_for_file_access(),
errmsg("could not open configuration file \"%s\": %m",
! ConfigFileName)));
! return;
! }
! /*
! * Parse
! */
! yyin = fp;
! parse_state = 0;
! head = tail = NULL;
opt_name = opt_value = NULL;
ConfigFileLineno = 1;
--- 115,202 ----
}
! /* Function that calls itself recursively for each configuration file that gets
! * included via the "include = 'file.conf'" directive.
! * The first time it gets called by ProcessConfigFile()
! * See below for notes on the parameters ConfigFileName and BasePath.
! *
! * The function returns
! * 0 if OK
! * -1 on error
*/
! static int
! ParseConfigFile(char* ConfigFileName,
! char* BasePath,
! GucContext context, int elevel,
! struct name_value_pair **head_p,
! struct name_value_pair **tail_p) {
!
! struct name_value_pair *item;
! YY_BUFFER_STATE lex_buffer;
! int token, parse_state;
! int LocalConfigFileLineno;
! char *opt_name;
! char *opt_value;
! char *ConfigFileNameCopy;
! char *NewBasePath;
! char *p;
! FILE *fp;
!
! /* when the function gets called for the first time by ProcessConfigFile,
! * we get a BasePath == NULL but the ConfigFileName is absolute in every
! * case (because the filename the user specified is transformed by
! * make_absolute_path()). If we encounter another include = '...' in the
! * configuration file however we can be sure that BasePath has been set to
! * the path of the including file. */
!
! if (!is_absolute_path(ConfigFileName)) {
! /* If the path is not absolute, make it absolute by prepending the
! * BasePath */
! int length;
! Assert(BasePath != NULL);
! length = strlen(BasePath)
! + 1
! + strlen(ConfigFileName)
! + 1;
! ConfigFileNameCopy = (char*) palloc(length);
! strcpy(ConfigFileNameCopy, BasePath);
! strcat(ConfigFileNameCopy, "/");
! strcat(ConfigFileNameCopy, ConfigFileName);
}
else
! {
! ConfigFileNameCopy = pstrdup(ConfigFileName);
! }
! /* Calculate the new base path, i.e. the path where the new config file is
! * in. We have an absolute path to the configuration file we're reading
! * already (it might be /usr/local/etc/../etc/include.conf however but it
! * doesn't matter).
! * What we do is basically just copying over the whole and then stripping
! * off everything behind the last slash. */
!
! NewBasePath = pstrdup(ConfigFileNameCopy);
! p = NewBasePath + strlen(NewBasePath);
! while (*p != '/' && p > NewBasePath) {
! *p-- = '\0';
! }
! /* strip off the slash as well */
! if (*p == '/')
! *p = '\0';
! fp = AllocateFile(ConfigFileNameCopy, "r");
! if (!fp)
! {
ereport(elevel,
(errcode_for_file_access(),
errmsg("could not open configuration file \"%s\": %m",
! ConfigFileNameCopy)));
! return -1;
! }
! lex_buffer = yy_create_buffer(fp, YY_BUF_SIZE);
! yy_switch_to_buffer(lex_buffer);
!
! parse_state = 0;
opt_name = opt_value = NULL;
ConfigFileLineno = 1;
***************
*** 209,220 ****
{
pfree(opt_name);
pfree(opt_value);
FreeFile(fp);
! goto cleanup_exit;
}
pfree(opt_name);
pfree(opt_value);
}
else
{
/* append to list */
--- 246,277 ----
{
pfree(opt_name);
pfree(opt_value);
+ pfree(NewBasePath);
+ pfree(ConfigFileNameCopy);
FreeFile(fp);
! free_name_value_list(*head_p);
! return 0;
}
pfree(opt_name);
pfree(opt_value);
}
+ else if (strcmp(opt_name, "include") == 0)
+ {
+ LocalConfigFileLineno = ConfigFileLineno;
+ yypush_buffer_state(lex_buffer);
+ if (ParseConfigFile(opt_value,
+ NewBasePath,
+ context, elevel,
+ head_p, tail_p) != 0) {
+ yy_delete_buffer(lex_buffer);
+ pfree(NewBasePath);
+ pfree(ConfigFileNameCopy);
+ FreeFile(fp);
+ return -1;
+ }
+ yypop_buffer_state();
+ ConfigFileLineno = LocalConfigFileLineno;
+ }
else
{
/* append to list */
***************
*** 222,232 ****
item->name = opt_name;
item->value = opt_value;
item->next = NULL;
! if (!head)
! head = item;
else
! tail->next = item;
! tail = item;
}
parse_state = 0;
--- 279,289 ----
item->name = opt_name;
item->value = opt_value;
item->next = NULL;
! if (!(*head_p))
! *head_p = item;
else
! (*tail_p)->next = item;
! (*tail_p) = item;
}
parse_state = 0;
***************
*** 234,278 ****
}
}
FreeFile(fp);
!
! /*
! * Check if all options are valid
! */
! for(item = head; item; item=item->next)
! {
! if (!set_config_option(item->name, item->value, context,
! PGC_S_FILE, false, false))
! goto cleanup_exit;
! }
!
! /* If we got here all the options parsed okay, so apply them. */
! for(item = head; item; item=item->next)
! {
! set_config_option(item->name, item->value, context,
! PGC_S_FILE, false, true);
! }
!
! cleanup_exit:
! free_name_value_list(head);
! return;
parse_error:
FreeFile(fp);
! free_name_value_list(head);
if (token == GUC_EOL)
ereport(elevel,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("syntax error in file \"%s\" line %u, near end of line",
! ConfigFileName, ConfigFileLineno - 1)));
else
ereport(elevel,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("syntax error in file \"%s\" line %u, near token \"%s\"",
! ConfigFileName, ConfigFileLineno, yytext)));
}
/*
* scanstr
--- 291,374 ----
}
}
+ pfree(NewBasePath);
+ pfree(ConfigFileNameCopy);
FreeFile(fp);
! return 0;
parse_error:
FreeFile(fp);
! free_name_value_list(*head_p);
if (token == GUC_EOL)
ereport(elevel,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("syntax error in file \"%s\" line %u, near end of line",
! ConfigFileNameCopy, ConfigFileLineno - 1)));
else
ereport(elevel,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("syntax error in file \"%s\" line %u, near token \"%s\"",
! ConfigFileNameCopy, ConfigFileLineno, yytext)));
! yy_delete_buffer(lex_buffer);
! pfree(NewBasePath);
! pfree(ConfigFileNameCopy);
! return -1;
}
+ /*
+ * Official function to read and process the configuration file. The
+ * parameter indicates in what context the file is being read --- either
+ * postmaster startup (including standalone-backend startup) or SIGHUP.
+ * All options mentioned in the configuration file are set to new values.
+ * If an error occurs, no values will be changed.
+ */
+ void
+ ProcessConfigFile(GucContext context)
+ {
+ int elevel;
+ struct name_value_pair *item, *head, *tail;
+
+ Assert(context == PGC_POSTMASTER || context == PGC_SIGHUP);
+
+ if (context == PGC_SIGHUP)
+ {
+ /*
+ * To avoid cluttering the log, only the postmaster bleats loudly
+ * about problems with the config file.
+ */
+ elevel = IsUnderPostmaster ? DEBUG2 : LOG;
+ }
+ else
+ elevel = ERROR;
+
+ /*
+ * Parse
+ */
+ head = tail = NULL;
+ if (ParseConfigFile(ConfigFileName, NULL, context, elevel, &head, &tail) == 0) {
+ /*
+ * Check if all options are valid
+ */
+ for(item = head; item; item=item->next)
+ {
+ if (!set_config_option(item->name, item->value, context,
+ PGC_S_FILE, false, false))
+ {
+ free_name_value_list(head);
+ return;
+ }
+ }
+
+ /* If we got here all the options parsed okay, so apply them. */
+ for(item = head; item; item=item->next)
+ {
+ set_config_option(item->name, item->value, context,
+ PGC_S_FILE, false, true);
+ }
+ }
+ }
+
/*
* scanstr