diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index 4b79958b35..2756652be2 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -7559,6 +7559,11 @@ parameter settings + + pg_file_settings + file location of parameter settings + + pg_shadow database users @@ -9173,6 +9178,79 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx + + <structname>pg_file_settings</structname> + + + pg_file_settings + + + + The view pg_file_settings provides the file + name, line number and value of all parameters which are set through + configuration files. + In contrast to pg_settings, a row is provided for + each occurrence of the parameter across all configuration files. This is helpful + for discovering why one value may have been used in preference to another + when the parameters were loaded. + + + + <structname>pg_file_settings</> Columns + + + + + Name + Type + Description + + + + + sourcefile + text + Path to and name of the configration file + + + sourceline + integer + + Line number within the configuration file where the value was set + + + + seqno + integer + Order in which the setting was loaded + + + name + text + Run-time configuration parameter name + + + setting + text + value of the parameter + + + +
+ + + See for more information about the various + ways to change these parameters. + + + + The pg_file_settings view cannot be modified + directly as it represents information, as read in at server start or + reload time, about all parameter settings across all configuration files. + + +
+ <structname>pg_shadow</structname> diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index 2ad01f4cb4..18921c4bc5 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -411,6 +411,12 @@ CREATE RULE pg_settings_n AS GRANT SELECT, UPDATE ON pg_settings TO PUBLIC; +CREATE VIEW pg_file_settings AS + SELECT * FROM pg_show_all_file_settings() AS A; + +REVOKE ALL on pg_file_settings FROM PUBLIC; +REVOKE EXECUTE ON FUNCTION pg_show_all_file_settings() FROM PUBLIC; + CREATE VIEW pg_timezone_abbrevs AS SELECT * FROM pg_timezone_abbrevs(); diff --git a/src/backend/utils/misc/guc-file.l b/src/backend/utils/misc/guc-file.l index c5e0fac467..a04d35d3c9 100644 --- a/src/backend/utils/misc/guc-file.l +++ b/src/backend/utils/misc/guc-file.l @@ -120,6 +120,7 @@ ProcessConfigFile(GucContext context) *head, *tail; int i; + int file_variables_count = 0; /* * Config files are processed on startup (by the postmaster only) @@ -255,6 +256,7 @@ ProcessConfigFile(GucContext context) error = true; ConfFileWithError = item->filename; } + file_variables_count++; } /* @@ -341,6 +343,54 @@ ProcessConfigFile(GucContext context) PGC_BACKEND, PGC_S_DYNAMIC_DEFAULT); } + /* + * Check if we have allocated the array yet. + * + * If not, allocate it based on the number of file variables we have seen. + */ + if (!guc_file_variables) + { + /* For the first call */ + num_guc_file_variables = file_variables_count; + guc_file_variables = (ConfigFileVariable *) guc_malloc(FATAL, + num_guc_file_variables * sizeof(struct ConfigFileVariable)); + } + else + { + int i; + + /* Free all of the previously allocated entries */ + for (i = 0; i < num_guc_file_variables; i++) + { + free(guc_file_variables[i].name); + free(guc_file_variables[i].value); + free(guc_file_variables[i].filename); + } + + /* Update the global count and realloc based on the new size */ + num_guc_file_variables = file_variables_count; + guc_file_variables = (ConfigFileVariable *) guc_realloc(FATAL, + guc_file_variables, + num_guc_file_variables * sizeof(struct ConfigFileVariable)); + } + + /* + * Copy the settings which came from the files read into the + * guc_file_variables array which backs the pg_show_file_settings() + * function. + */ + for (item = head, i = 0; item && i < num_guc_file_variables; + item = item->next, i++) + { + guc_file_variables[i].name = guc_strdup(FATAL, item->name); + guc_file_variables[i].value = guc_strdup(FATAL, item->value); + guc_file_variables[i].filename = guc_strdup(FATAL, item->filename); + guc_file_variables[i].sourceline = item->sourceline; + } + + /* We had better have made it through the loop above to a clean ending. */ + Assert(!item && i == num_guc_file_variables); + /* * Now apply the values from the config file. */ diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8727ee3b74..5f71dedff3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -3678,6 +3678,22 @@ static struct config_generic **guc_variables; /* Current number of variables contained in the vector */ static int num_guc_variables; +/* + * Lookup of variables for pg_file_settings view. + * guc_file_variables is an array of length num_guc_file_variables. + */ +typedef struct ConfigFileVariable +{ + char *name; + char *value; + char *filename; + int sourceline; +} ConfigFileVariable; +static struct ConfigFileVariable *guc_file_variables; + +/* Number of file variables */ +static int num_guc_file_variables; + /* Vector capacity */ static int size_guc_variables; @@ -8148,6 +8164,110 @@ show_all_settings(PG_FUNCTION_ARGS) } } +/* + * show_all_file_settings + * + * returns a table of all parameter settings in all configuration files + * which includes the config file path/name, filename, a sequence number + * indicating when we loaded it, the parameter name, and the value it is + * set to. + * + * Note: no filtering is done here, instead we depend on the GRANT system + * to prevent unprivileged users from accessing this function or the view + * built on top of it. + */ +Datum +show_all_file_settings(PG_FUNCTION_ARGS) +{ +#define NUM_PG_FILE_SETTINGS_ATTS 5 + FuncCallContext *funcctx; + TupleDesc tupdesc; + int call_cntr; + int max_calls; + AttInMetadata *attinmeta; + MemoryContext oldcontext; + + if (SRF_IS_FIRSTCALL()) + { + funcctx = SRF_FIRSTCALL_INIT(); + + oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); + + /* + * need a tuple descriptor representing NUM_PG_SETTINGS_ATTS columns + * of the appropriate types + */ + + tupdesc = CreateTemplateTupleDesc(NUM_PG_FILE_SETTINGS_ATTS, false); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "sourcefile", + TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "sourceline", + INT4OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 3, "seqno", + INT4OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 4, "name", + TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 5, "setting", + TEXTOID, -1, 0); + + attinmeta = TupleDescGetAttInMetadata(tupdesc); + funcctx->attinmeta = attinmeta; + funcctx->max_calls = num_guc_file_variables; + MemoryContextSwitchTo(oldcontext); + } + + funcctx = SRF_PERCALL_SETUP(); + + call_cntr = funcctx->call_cntr; + max_calls = funcctx->max_calls; + attinmeta = funcctx->attinmeta; + + if (call_cntr < max_calls) + { + char *values[NUM_PG_FILE_SETTINGS_ATTS]; + HeapTuple tuple; + Datum result; + ConfigFileVariable conf; + char buffer[12]; /* must be at least 12, per pg_ltoa */ + + /* Check to avoid going past end of array */ + if (call_cntr > num_guc_file_variables) + SRF_RETURN_DONE(funcctx); + + conf = guc_file_variables[call_cntr]; + + /* sourcefile */ + values[0] = conf.filename; + + /* sourceline */ + pg_ltoa(conf.sourceline, buffer); + values[1] = pstrdup(buffer); + + /* seqno */ + pg_ltoa(call_cntr + 1, buffer); + values[2] = pstrdup(buffer); + + /* name */ + values[3] = conf.name; + + /* setting */ + values[4] = conf.value; + + /* build a tuple */ + tuple = BuildTupleFromCStrings(attinmeta, values); + + /* make the tuple into a datum */ + result = HeapTupleGetDatum(tuple); + + SRF_RETURN_NEXT(funcctx, result); + } + else + { + SRF_RETURN_DONE(funcctx); + } + +} + static char * _ShowOption(struct config_generic * record, bool use_units) { diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index bd67d72797..76f9abf9fd 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -3060,6 +3060,8 @@ DATA(insert OID = 2078 ( set_config PGNSP PGUID 12 1 0 0 0 f f f f f f v 3 0 2 DESCR("SET X as a function"); DATA(insert OID = 2084 ( pg_show_all_settings PGNSP PGUID 12 1 1000 0 0 f f f f t t s 0 0 2249 "" "{25,25,25,25,25,25,25,25,25,25,25,1009,25,25,25,23}" "{o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{name,setting,unit,category,short_desc,extra_desc,context,vartype,source,min_val,max_val,enumvals,boot_val,reset_val,sourcefile,sourceline}" _null_ _null_ show_all_settings _null_ _null_ _null_ )); DESCR("SHOW ALL as a function"); +DATA(insert OID = 3329 ( pg_show_all_file_settings PGNSP PGUID 12 1 1000 0 0 f f f f t t s 0 0 2249 "" "{25,23,23,25,25}" "{o,o,o,o,o}" "{sourcefile,sourceline,seqno,name,setting}" _null_ _null_ show_all_file_settings _null_ _null_ _null_ )); +DESCR("show config file settings"); DATA(insert OID = 1371 ( pg_lock_status PGNSP PGUID 12 1 1000 0 0 f f f f t t v 0 0 2249 "" "{25,26,26,23,21,25,28,26,26,21,25,23,25,16,16}" "{o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{locktype,database,relation,page,tuple,virtualxid,transactionid,classid,objid,objsubid,virtualtransaction,pid,mode,granted,fastpath}" _null_ _null_ pg_lock_status _null_ _null_ _null_ )); DESCR("view system lock information"); DATA(insert OID = 1065 ( pg_prepared_xact PGNSP PGUID 12 1 1000 0 0 f f f f t t v 0 0 2249 "" "{28,25,1184,26,26}" "{o,o,o,o,o}" "{transaction,gid,prepared,ownerid,dbid}" _null_ _null_ pg_prepared_xact _null_ _null_ _null_ )); diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index e8104f01a1..926421d996 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -1100,6 +1100,7 @@ extern Datum quote_nullable(PG_FUNCTION_ARGS); extern Datum show_config_by_name(PG_FUNCTION_ARGS); extern Datum set_config_by_name(PG_FUNCTION_ARGS); extern Datum show_all_settings(PG_FUNCTION_ARGS); +extern Datum show_all_file_settings(PG_FUNCTION_ARGS); /* lockfuncs.c */ extern Datum pg_lock_status(PG_FUNCTION_ARGS); diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index 2df24c0de1..a379a7279c 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -1312,6 +1312,12 @@ pg_cursors| SELECT c.name, c.is_scrollable, c.creation_time FROM pg_cursor() c(name, statement, is_holdable, is_binary, is_scrollable, creation_time); +pg_file_settings| SELECT a.sourcefile, + a.sourceline, + a.seqno, + a.name, + a.setting + FROM pg_show_all_file_settings() a(sourcefile, sourceline, seqno, name, setting); pg_group| SELECT pg_authid.rolname AS groname, pg_authid.oid AS grosysid, ARRAY( SELECT pg_auth_members.member