From: Justin Pryzby Date: Wed, 8 Dec 2021 12:06:35 -0600 Subject: [PATCH 2/2] Expose GUC flags in SQL function; retire ./check_guc --- doc/src/sgml/func.sgml | 15 ++++ src/backend/utils/misc/check_guc | 29 ------- src/backend/utils/misc/guc.c | 37 +++++++++ src/include/catalog/pg_proc.dat | 6 ++ src/include/utils/guc.h | 3 +- src/test/regress/expected/guc.out | 122 ++++++++++++++++++++++++++++++ src/test/regress/sql/guc.sql | 72 ++++++++++++++++++ 7 files changed, 254 insertions(+), 30 deletions(-) delete mode 100755 src/backend/utils/misc/check_guc diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 0ee6974f1c6..cbdbccb63d1 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -23596,6 +23596,21 @@ SELECT pg_type_is_visible('myschema.widget'::regtype); + + + + pg_get_get_flags + + pg_get_get_flags ( guc text ) + text[] + + + Return an array of flags associated with the given GUC, or NULL if the + GUC does not exist. Not all flags are exposed; the set of flags which + are exposed is subject to change. + + + diff --git a/src/backend/utils/misc/check_guc b/src/backend/utils/misc/check_guc deleted file mode 100755 index 323ca13191b..00000000000 --- a/src/backend/utils/misc/check_guc +++ /dev/null @@ -1,29 +0,0 @@ -#! /bin/sh -set -e - -## this script makes some assumptions about the formatting of files it parses. -## in postgresql.conf.sample: -## 1) the valid config settings may be preceded by a '#', but NOT '# ' -## (we use this to skip comments) - -### What options are listed in postgresql.conf.sample, but don't appear -### in guc.c? - -# grab everything that looks like a setting -SETTINGS=`sed '/^#[[:alnum:]]/!d; s/^#//; s/ =.*//; /^include/d' postgresql.conf.sample` - -for i in $SETTINGS ; do - ## it sure would be nice to replace this with an sql "not in" statement - grep -i "\"$i\"" guc.c >/dev/null || - echo "$i seems to be missing from guc.c"; -done - -### What options are listed in guc.c, but don't appear -### in postgresql.conf.sample? - -# grab everything that looks like a setting and convert it to lower case -SETTINGS=`gawk -F '[",]' 'BEGIN{RS="\n\t\\\\{\n"} /",[[:space:]]*PGC_.*.*gettext_noop/ && !/NOT_IN_SAMPLE/{print tolower($2)}' guc.c` -for i in $SETTINGS ; do - grep "#$i " postgresql.conf.sample >/dev/null || - echo "$i seems to be missing from postgresql.conf.sample"; -done diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 4c94f09c645..d3b56b2007c 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -9634,6 +9634,43 @@ GetConfigOptionByName(const char *name, const char **varname, bool missing_ok) return _ShowOption(record, true); } +/* + * Return some flags for the specified GUC, or NULL if it doesn't exist. + */ +Datum +pg_get_guc_flags(PG_FUNCTION_ARGS) +{ + char *varname = TextDatumGetCString(PG_GETARG_DATUM(0)); + struct config_generic *record; + int cnt = 0; +#define MAX_NUM_FLAGS 5 + Datum flags[MAX_NUM_FLAGS]; + ArrayType *a; + + record = find_option(varname, false, true, ERROR); + + /* return NULL if no such variable */ + if (record == NULL) + PG_RETURN_NULL(); + + if (record->flags & GUC_NO_SHOW_ALL) + flags[cnt++] = CStringGetTextDatum("NO_SHOW_ALL"); + if (record->flags & GUC_NO_RESET_ALL) + flags[cnt++] = CStringGetTextDatum("NO_RESET_ALL"); + if (record->flags & GUC_NOT_IN_SAMPLE) + flags[cnt++] = CStringGetTextDatum("NOT_IN_SAMPLE"); + if (record->flags & GUC_EXPLAIN) + flags[cnt++] = CStringGetTextDatum("EXPLAIN"); + if (record->flags & GUC_RUNTIME_COMPUTED) + flags[cnt++] = CStringGetTextDatum("RUNTIME_COMPUTED"); + + Assert(cnt <= MAX_NUM_FLAGS); + + /* Returns the record as Datum */ + a = construct_array(flags, cnt, TEXTOID, -1, false, TYPALIGN_INT); + PG_RETURN_ARRAYTYPE_P(a); +} + /* * Return GUC variable value by variable number; optionally return canonical * form of name. Return value is palloc'd. diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 0859dc81cac..562c1d779cb 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -6096,6 +6096,12 @@ proargmodes => '{o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}', proargnames => '{name,setting,unit,category,short_desc,extra_desc,context,vartype,source,min_val,max_val,enumvals,boot_val,reset_val,sourcefile,sourceline,pending_restart}', prosrc => 'show_all_settings' }, + +{ oid => '8921', descr => 'return flags for specified GUC', + proname => 'pg_get_guc_flags', provolatile => 's', + prorettype => '_text', proargtypes => 'text', + prosrc => 'pg_get_guc_flags' }, + { oid => '3329', descr => 'show config file settings', proname => 'pg_show_all_file_settings', prorows => '1000', proretset => 't', provolatile => 'v', prorettype => 'record', proargtypes => '', diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 6bb81707b09..1ac20f85ab3 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -198,8 +198,9 @@ typedef enum #define GUC_QUALIFIER_SEPARATOR '.' -/* +/* -- * bit values in "flags" of a GUC variable + * Consider if any new flags should be exposed in pg_get_guc_flags(). */ #define GUC_LIST_INPUT 0x0001 /* input can be list format */ #define GUC_LIST_QUOTE 0x0002 /* double-quote list elements */ diff --git a/src/test/regress/expected/guc.out b/src/test/regress/expected/guc.out index 59da91ff04d..29173f3ce8e 100644 --- a/src/test/regress/expected/guc.out +++ b/src/test/regress/expected/guc.out @@ -813,3 +813,125 @@ set default_with_oids to f; -- Should not allow to set it to true. set default_with_oids to t; ERROR: tables declared WITH OIDS are not supported +-- +-- Test GUC categories and flags. +-- +CREATE TABLE pg_settings_flags AS SELECT name, category, + 'NO_SHOW_ALL' =ANY(flags) AS no_show_all, + 'NO_RESET_ALL' =ANY(flags) AS no_reset_all, + 'NOT_IN_SAMPLE' =ANY(flags) AS not_in_sample, + 'EXPLAIN' =ANY(flags) AS guc_explain, + 'COMPUTED' =ANY(flags) AS guc_computed + FROM pg_show_all_settings() AS psas, pg_get_guc_flags(psas.name) AS flags; +-- test that GUCS are in postgresql.conf +SELECT lower(name) FROM pg_settings_flags WHERE NOT not_in_sample EXCEPT +SELECT regexp_replace(ln, '^#?([_[:alpha:]]+) (= .*|[^ ]*$)', '\1') AS guc +FROM (SELECT regexp_split_to_table(pg_read_file('postgresql.conf'), '\n') AS ln) conf +WHERE ln ~ '^#?[[:alpha:]]' +ORDER BY 1; + lower +----------------------------- + config_file + plpgsql.check_asserts + plpgsql.extra_errors + plpgsql.extra_warnings + plpgsql.print_strict_params + plpgsql.variable_conflict +(6 rows) + +-- test that lines in postgresql.conf that look like GUCs are GUCs +SELECT regexp_replace(ln, '^#?([_[:alpha:]]+) (= .*|[^ ]*$)', '\1') AS guc +FROM (SELECT regexp_split_to_table(pg_read_file('postgresql.conf'), '\n') AS ln) conf +WHERE ln ~ '^#?[[:alpha:]]' +EXCEPT SELECT lower(name) FROM pg_settings_flags WHERE NOT not_in_sample +ORDER BY 1; + guc +------------------- + include + include_dir + include_if_exists +(3 rows) + +-- test that section:DEVELOPER GUCs are flagged GUC_NOT_IN_SAMPLE: +SELECT * FROM pg_settings_flags +WHERE category='Developer Options' AND NOT not_in_sample +ORDER BY 1; + name | category | no_show_all | no_reset_all | not_in_sample | guc_explain | guc_computed +------+----------+-------------+--------------+---------------+-------------+-------------- +(0 rows) + +-- Maybe the converse: +SELECT * FROM pg_settings_flags +WHERE category NOT IN ('Developer Options', 'Preset Options') AND not_in_sample +ORDER BY 1; + name | category | no_show_all | no_reset_all | not_in_sample | guc_explain | guc_computed +------------------------+-------------------------------------------------+-------------+--------------+---------------+-------------+-------------- + application_name | Reporting and Logging / What to Log | f | f | t | f | f + transaction_deferrable | Client Connection Defaults / Statement Behavior | f | t | t | f | f + transaction_isolation | Client Connection Defaults / Statement Behavior | f | t | t | f | f + transaction_read_only | Client Connection Defaults / Statement Behavior | f | t | t | f | f +(4 rows) + +-- Most Query Tuning GUCs are flagged as EXPLAIN: +SELECT * FROM pg_settings_flags +WHERE category ~ '^Query Tuning' AND NOT guc_explain +ORDER BY 1; + name | category | no_show_all | no_reset_all | not_in_sample | guc_explain | guc_computed +---------------------------+--------------------------------------+-------------+--------------+---------------+-------------+-------------- + default_statistics_target | Query Tuning / Other Planner Options | f | f | f | f | f +(1 row) + +-- Maybe the converse: +SELECT * FROM pg_settings_flags +WHERE guc_explain AND NOT category ~ '^Query Tuning|^Resource Usage' +ORDER BY 1; + name | category | no_show_all | no_reset_all | not_in_sample | guc_explain | guc_computed +---------------------+-------------------------------------------------+-------------+--------------+---------------+-------------+-------------- + force_parallel_mode | Developer Options | f | f | t | t | f + search_path | Client Connection Defaults / Statement Behavior | f | f | f | t | f +(2 rows) + +-- GUCs flagged RUNTIME are Preset +SELECT * FROM pg_settings_flags +WHERE guc_computed AND NOT category='Preset Options' +ORDER BY 1; + name | category | no_show_all | no_reset_all | not_in_sample | guc_explain | guc_computed +------+----------+-------------+--------------+---------------+-------------+-------------- +(0 rows) + +-- PRESET GUCs are flagged NOT_IN_SAMPLE +SELECT * FROM pg_settings_flags +WHERE category='Preset Options' AND NOT not_in_sample +ORDER BY 1; + name | category | no_show_all | no_reset_all | not_in_sample | guc_explain | guc_computed +------+----------+-------------+--------------+---------------+-------------+-------------- +(0 rows) + +-- NO_SHOW_ALL implies NO_RESET_ALL: +SELECT * FROM pg_settings_flags +WHERE no_show_all AND NOT no_reset_all +ORDER BY 1; + name | category | no_show_all | no_reset_all | not_in_sample | guc_explain | guc_computed +------+----------+-------------+--------------+---------------+-------------+-------------- +(0 rows) + +-- Usually the converse: +SELECT * FROM pg_settings_flags +WHERE NOT no_show_all AND no_reset_all +ORDER BY 1; + name | category | no_show_all | no_reset_all | not_in_sample | guc_explain | guc_computed +------------------------+-------------------------------------------------+-------------+--------------+---------------+-------------+-------------- + transaction_deferrable | Client Connection Defaults / Statement Behavior | f | t | t | f | f + transaction_isolation | Client Connection Defaults / Statement Behavior | f | t | t | f | f + transaction_read_only | Client Connection Defaults / Statement Behavior | f | t | t | f | f +(3 rows) + +-- NO_SHOW_ALL implies NOT_IN_SAMPLE: +SELECT * FROM pg_settings_flags +WHERE no_show_all AND NOT not_in_sample +ORDER BY 1; + name | category | no_show_all | no_reset_all | not_in_sample | guc_explain | guc_computed +------+----------+-------------+--------------+---------------+-------------+-------------- +(0 rows) + +DROP TABLE pg_settings_flags; diff --git a/src/test/regress/sql/guc.sql b/src/test/regress/sql/guc.sql index c39c11388d5..47b6a233d5c 100644 --- a/src/test/regress/sql/guc.sql +++ b/src/test/regress/sql/guc.sql @@ -311,3 +311,75 @@ reset check_function_bodies; set default_with_oids to f; -- Should not allow to set it to true. set default_with_oids to t; + +-- +-- Test GUC categories and flags. +-- +CREATE TABLE pg_settings_flags AS SELECT name, category, + 'NO_SHOW_ALL' =ANY(flags) AS no_show_all, + 'NO_RESET_ALL' =ANY(flags) AS no_reset_all, + 'NOT_IN_SAMPLE' =ANY(flags) AS not_in_sample, + 'EXPLAIN' =ANY(flags) AS guc_explain, + 'COMPUTED' =ANY(flags) AS guc_computed + FROM pg_show_all_settings() AS psas, pg_get_guc_flags(psas.name) AS flags; + +-- test that GUCS are in postgresql.conf +SELECT lower(name) FROM pg_settings_flags WHERE NOT not_in_sample EXCEPT +SELECT regexp_replace(ln, '^#?([_[:alpha:]]+) (= .*|[^ ]*$)', '\1') AS guc +FROM (SELECT regexp_split_to_table(pg_read_file('postgresql.conf'), '\n') AS ln) conf +WHERE ln ~ '^#?[[:alpha:]]' +ORDER BY 1; + +-- test that lines in postgresql.conf that look like GUCs are GUCs +SELECT regexp_replace(ln, '^#?([_[:alpha:]]+) (= .*|[^ ]*$)', '\1') AS guc +FROM (SELECT regexp_split_to_table(pg_read_file('postgresql.conf'), '\n') AS ln) conf +WHERE ln ~ '^#?[[:alpha:]]' +EXCEPT SELECT lower(name) FROM pg_settings_flags WHERE NOT not_in_sample +ORDER BY 1; + +-- test that section:DEVELOPER GUCs are flagged GUC_NOT_IN_SAMPLE: +SELECT * FROM pg_settings_flags +WHERE category='Developer Options' AND NOT not_in_sample +ORDER BY 1; + +-- Maybe the converse: +SELECT * FROM pg_settings_flags +WHERE category NOT IN ('Developer Options', 'Preset Options') AND not_in_sample +ORDER BY 1; + +-- Most Query Tuning GUCs are flagged as EXPLAIN: +SELECT * FROM pg_settings_flags +WHERE category ~ '^Query Tuning' AND NOT guc_explain +ORDER BY 1; + +-- Maybe the converse: +SELECT * FROM pg_settings_flags +WHERE guc_explain AND NOT category ~ '^Query Tuning|^Resource Usage' +ORDER BY 1; + +-- GUCs flagged RUNTIME are Preset +SELECT * FROM pg_settings_flags +WHERE guc_computed AND NOT category='Preset Options' +ORDER BY 1; + +-- PRESET GUCs are flagged NOT_IN_SAMPLE +SELECT * FROM pg_settings_flags +WHERE category='Preset Options' AND NOT not_in_sample +ORDER BY 1; + +-- NO_SHOW_ALL implies NO_RESET_ALL: +SELECT * FROM pg_settings_flags +WHERE no_show_all AND NOT no_reset_all +ORDER BY 1; + +-- Usually the converse: +SELECT * FROM pg_settings_flags +WHERE NOT no_show_all AND no_reset_all +ORDER BY 1; + +-- NO_SHOW_ALL implies NOT_IN_SAMPLE: +SELECT * FROM pg_settings_flags +WHERE no_show_all AND NOT not_in_sample +ORDER BY 1; + +DROP TABLE pg_settings_flags; -- 2.17.1 --i3WE5m5QLioBhvvb--