Thread: Add read-only param to set_config(...) / SET that effects (at least)customized runtime options

Hi,

in MS SQL Server you are able to make an entry of SESSION_CONTEXT read-only by passing the @read_only param to the sp_set_session_context function:
"[ @read_only= ] { 0 | 1 } A flag of type bit. If 1, then the value for the specified key cannot be changed again on this logical connection. If 0 (default), then the value can be changed."

I propose the same functionally for PostgreSQL - at least when setting "customized options" (the ones with a dot in the name: https://www.postgresql.org/docs/10/static/runtime-config-custom.html)

The set_config(...) method therefore would end up like:
set_config(setting_name, new_value, is_local, read_only)

The equalient SET command could look something like:
SET READONLY my_app.some_var = 'foo';
SET READONLY SESSION my_app.some_var = 'foo';
SET READONLY LOCAL my_app.some_var = 'foo';

Of course read-only would default to false for backwards compatibility.
When setting READONLY for on SESSION config then that config is not allowed to be changed anymore until the connection gets closed - even when running RESET ALL or DISCARD ALL.
When setting read-only for a transaction config "the effects of the SET LOCAL command disappear at function exit" will still be true, like written in https://www.postgresql.org/docs/10/static/sql-set.html.

What do you think?

Regards,
Matthias
On 04/20/2018 09:55 AM, Matthias Kurz wrote:

> SET READONLY my_app.some_var = 'foo';
> SET READONLY SESSION my_app.some_var = 'foo';
> SET READONLY LOCAL my_app.some_var = 'foo';
> 
> Of course read-only would default to false for backwards compatibility.
> When setting READONLY for on SESSION config then that config is not allowed
> to be changed anymore until the connection gets closed - even when running
> RESET ALL or DISCARD ALL.

There may be considerable overlap here with the idea of
cookie-protected settings discussed back in

https://www.postgresql.org/message-id/59127E4E.8090705%40anastigmatix.net

At one point in that thread was a suggestion to look at proposals
for "secure variables" or "package variables" that were pending,
but I didn't see anything then to convince me those proposals
addressed the same use case.

There's also a thing called "schema variables" currently registered
in the 2018-09 commitfest, but I haven't really seen how it would
serve the same purpose either.

https://commitfest.postgresql.org/18/1608/

But the cookie-protected idea in the first link seems easy to
implement and was aimed at the same purpose you seem to have here:
nail down some setting in advance of running some code you don't
want changing it.

It seemed to me at the time to be not hard to implement, even just
as an extension for proof of concept. One small obstacle is that the
check hook on a variable doesn't get called during attempted RESET,
so the only way to block a prohibited RESET would have to be from
an assign hook, which isn't expected to fail. It could surely throw
an error, but which would mess up the whole RESET, but might be
tolerable.

I had been thinking to implement such an extension. I haven't worked
on it, but might yet. It would be simplest for it to exercise such
control over variables the extension itself defines. Not so easy
to protect other variables (poking a new check hook or assign hook
into an existing variable definition isn't practical, as those are
on a list that's static within guc.c).

But if you are only concerned about custom options, the needed
pieces might already exist.

-Chap


>>>>> "Chapman" == Chapman Flack <chap@anastigmatix.net> writes:

 Chapman> It seemed to me at the time to be not hard to implement, even
 Chapman> just as an extension for proof of concept. One small obstacle
 Chapman> is that the check hook on a variable doesn't get called during
 Chapman> attempted RESET, so the only way to block a prohibited RESET
 Chapman> would have to be from an assign hook, which isn't expected to
 Chapman> fail. It could surely throw an error, but which would mess up
 Chapman> the whole RESET, but might be tolerable.

Assign hooks aren't allowed to throw errors under any circumstance
because they're called during transaction abort, and throwing an error
during abort is obviously not tolerable.

-- 
Andrew (irc:RhodiumToad)


On 04/20/2018 04:03 PM, Andrew Gierth wrote:
>>>>>> "Chapman" == Chapman Flack <chap@anastigmatix.net> writes:
>  Chapman> It seemed to me at the time to be not hard to implement, even
>  Chapman> just as an extension for proof of concept. One small obstacle
>  Chapman> is that the check hook on a variable doesn't get called during
>  Chapman> attempted RESET, so the only way to block a prohibited RESET
>  Chapman> would have to be from an assign hook, which isn't expected to
>  Chapman> fail. It could surely throw an error, but which would mess up
>  Chapman> the whole RESET, but might be tolerable.
> 
> Assign hooks aren't allowed to throw errors under any circumstance
> because they're called during transaction abort, and throwing an error
> during abort is obviously not tolerable.

Ah yes, now you remind me, that was why I had put my extension idea
on the table at the time.

It seems as if, for any of these ideas (cookie-protection of GUCs
or just SET READONLY for GUCs), at least some small patch to core
will be prerequisite, to allow either a flag or a reset check hook
able to make RESET skip protected GUCs.

-Chap



On 04/20/2018 04:18 PM, Chapman Flack wrote:
> On 04/20/2018 04:03 PM, Andrew Gierth wrote:

>> Assign hooks aren't allowed to throw errors under any circumstance
>> because they're called during transaction abort, and throwing an error
>> during abort is obviously not tolerable.
> 
> Ah yes, now you remind me, that was why I had put my extension idea
> on the table at the time.
> 
> It seems as if, for any of these ideas (cookie-protection of GUCs
> or just SET READONLY for GUCs), at least some small patch to core
> will be prerequisite, to allow either a flag or a reset check hook
> able to make RESET skip protected GUCs.

I suppose an extension could protect a GUC of its own from reset
without the cookie, despite the lack of a reset hook in core, by
simply maintaining its own copy of the original reset value, and
stuffing the protected value into the variable's reset_val for
the duration, no?

Wouldn't be usable to protect core GUCs, but could provide an API
for other extensions to make their GUCs protectable, by passing the
config_* struct pointer to a registration function.

-Chap