Re: Proposal: knowing detail of config files via SQL

From: Stephen Frost <sfrost(at)snowman(dot)net>
To: Sawada Masahiko <sawada(dot)mshk(at)gmail(dot)com>
Cc: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>, David Johnston <david(dot)g(dot)johnston(at)gmail(dot)com>, David Fetter <david(at)fetter(dot)org>, Robert Haas <robertmhaas(at)gmail(dot)com>, "pgsql-hackers(at)postgresql(dot)org" <pgsql-hackers(at)postgresql(dot)org>
Subject: Re: Proposal: knowing detail of config files via SQL
Date: 2015-02-28 05:27:53
Message-ID: 20150228052753.GC29780@tamriel.snowman.net
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Sawada,

* Sawada Masahiko (sawada(dot)mshk(at)gmail(dot)com) wrote:
> Attached patch is latest version including following changes.
> - This view is available to super use only
> - Add sourceline coulmn

Alright, first off, to Josh's point- I'm definitely interested in a
capability to show where the heck a given config value is coming from.
I'd be even happier if there was a way to *force* where config values
have to come from, but that ship sailed a year ago or so. Having this
be for the files, specifically, seems perfectly reasonable to me. I
could see having another function which will report where a currently
set GUC variable came from (eg: ALTER ROLE or ALTER DATABASE), but
having a function for "which config file is this GUC set in" seems
perfectly reasonable to me.

To that point, here's a review of this patch.

> diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
> index 6df6bf2..f628cb0 100644
> --- a/src/backend/catalog/system_views.sql
> +++ b/src/backend/catalog/system_views.sql
> @@ -412,6 +412,11 @@ 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;

While this generally "works", the usual expectation is that functions
that should be superuser-only have a check in the function rather than
depending on the execute privilege. I'm certainly happy to debate the
merits of that approach, but for the purposes of this patch, I'd suggest
you stick an if (!superuser()) ereport("must be superuser") into the
function itself and not work about setting the correct permissions on
it.

> + ConfigFileVariable *guc;

As this ends up being an array, I'd call it "guc_array" or something
along those lines. GUC in PG-land has a pretty specific single-entity
meaning.

> @@ -344,6 +346,21 @@ ProcessConfigFile(GucContext context)
> PGC_BACKEND, PGC_S_DYNAMIC_DEFAULT);
> }
>
> + guc_file_variables = (ConfigFileVariable *)
> + guc_malloc(FATAL, num_guc_file_variables * sizeof(struct ConfigFileVariable));

Uh, perhaps I missed it, but what happens on a reload? Aren't we going
to realloc this every time? Seems like we should be doing a
guc_malloc() the first time through but doing guc_realloc() after, or
we'll leak memory on every reload.

> + /*
> + * Apply guc config parameters to guc_file_variable
> + */
> + guc = guc_file_variables;
> + for (item = head; item; item = item->next, guc++)
> + {
> + guc->name = guc_strdup(FATAL, item->name);
> + guc->value = guc_strdup(FATAL, item->value);
> + guc->filename = guc_strdup(FATAL, item->filename);
> + guc->sourceline = item->sourceline;
> + }

Uh, ditto and double-down here. I don't see a great solution other than
looping through the previous array and free'ing each of these, since we
can't depend on the memory context machinery being up and ready at this
point, as I recall.

> diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
> index 931993c..c69ce66 100644
> --- a/src/backend/utils/misc/guc.c
> +++ b/src/backend/utils/misc/guc.c
> @@ -3561,9 +3561,17 @@ static const char *const map_old_guc_names[] = {
> */
> static struct config_generic **guc_variables;
>
> +/*
> + * lookup of variables for pg_file_settings view.
> + */
> +static struct ConfigFileVariable *guc_file_variables;
> +
> /* Current number of variables contained in the vector */
> static int num_guc_variables;
>
> +/* Number of file variables */
> +static int num_guc_file_variables;
> +

I'd put these together, and add a comment explaining that
guc_file_variables is an array of length num_guc_file_variables..

> /*
> + * Return the total number of GUC File variables
> + */
> +int
> +GetNumConfigFileOptions(void)
> +{
> + return num_guc_file_variables;
> +}

I don't see the point of this function..

> +Datum
> +show_all_file_settings(PG_FUNCTION_ARGS)
> +{
> + 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, "name",
> + TEXTOID, -1, 0);
> + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "setting",
> + TEXTOID, -1, 0);
> + TupleDescInitEntry(tupdesc, (AttrNumber) 3, "sourcefile",
> + TEXTOID, -1, 0);
> + TupleDescInitEntry(tupdesc, (AttrNumber) 4, "sourceline",
> + INT4OID, -1, 0);

As the sourcefile and sourceline were discussed as being the 'key' for
this, I expected them to be the first columns.. Any reason to not do
that? It's certainly look cleaner, at least to me, that way.

> + if (call_cntr < max_calls)
> + {
> + char *values[NUM_PG_FILE_SETTINGS_ATTS];
> + HeapTuple tuple;
> + Datum result;
> + ConfigFileVariable conf;
> + char buffer[256];
> +
> + conf = guc_file_variables[call_cntr];

I'm a bit nervous that a sighup in the middle could screw this up. Have
you considered that? At a minimum, I'd suggest a check along the lines
of:

if (call_cntr > num_guc_file_variables)
SRF_RETURNDONE();

To try and avoid going past the end of the array.

> + values[0] = conf.name;
> + values[1] = conf.value;
> + values[2] = conf.filename;
> + snprintf(buffer, sizeof(buffer), "%d", conf.sourceline);

Seems like we might be able to use pg_ltoa() there..

> + if (call_cntr >= max_calls)
> + SRF_RETURN_DONE(funcctx);

Isn't this redundant? We wouldn't be here if this was true.

Just a quick review.

Thanks!

Stephen

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Michael Paquier 2015-02-28 05:30:22 Re: Bug in pg_dump
Previous Message Pavel Stehule 2015-02-28 05:27:50 Re: Providing catalog view to pg_hba.conf file - Patch submission