Thread: RESET, NULL and empty-string valued settings and transaction isolation
Hi, according to the docs, RESET sets the value of a setting to
"The default value is defined as the value that the parameter would have had, if no
SET
had ever been issued for it in the current session"Which confuses me given that the value starts being NULL in the session and then turns into an empty string:
$ psql
=> select current_setting('my.test', true) is null; -- true
=> set my.test = 'abc';
=> reset my.test;
=> select current_setting('my.test', true) is null; -- false
=> select current_setting('my.test', true)=''; -- true
=> set my.test = 'abc';
=> reset my.test;
=> select current_setting('my.test', true) is null; -- false
=> select current_setting('my.test', true)=''; -- true
A similar effect happens with transactions and SET LOCAL:
=> begin;
=*> set local my.test='abc';
=*> rollback; -- commit works too
=> select current_setting('my.test', true) = ''; -- true
=*> set local my.test='abc';
=*> rollback; -- commit works too
=> select current_setting('my.test', true) = ''; -- true
Is this expected? I thought even if I misunderstand the docs, the effect isn't very nice because SQL like current_setting('my.some_boolean_setting')::boolean will fail after a transaction with SET LOCAL sets it, a side-effect that can be particularly confusing and basically requires usage of nullif(.., '') or other explicit checks around every current_setting call-site in practice.
Thanks in advance,
Marcelo.
Re: RESET, NULL and empty-string valued settings and transaction isolation
From
"David G. Johnston"
Date:
On Saturday, October 19, 2024, Marcelo Zabani <mzabani@gmail.com> wrote:
Hi, according to the docs, RESET sets the value of a setting to"The default value is defined as the value that the parameter would have had, if noSET
had ever been issued for it in the current session"Which confuses me given that the value starts being NULL in the session and then turns into an empty string:$ psql=> select current_setting('my.test', true) is null; -- true
=> set my.test = 'abc';
=> reset my.test;
=> select current_setting('my.test', true) is null; -- false
=> select current_setting('my.test', true)=''; -- trueA similar effect happens with transactions and SET LOCAL:=> begin;
=*> set local my.test='abc';
=*> rollback; -- commit works too
=> select current_setting('my.test', true) = ''; -- trueIs this expected? I thought even if I misunderstand the docs, the effect isn't very nice because SQL like current_setting('my.some_boolean_setting')::boolean will fail after a transaction with SET LOCAL sets it, a side-effect that can be particularly confusing and basically requires usage of nullif(.., '') or other explicit checks around every current_setting call-site in practice.
The observed behavior is also the documented behavior.
A setting value can never actually be the NULL value. NULL is only an indicator that a setting doesn’t exist - i.e., when current_setting returns null it is not giving you the value of the named setting but instead giving you an alternative representation to an error message that the setting doesn’t exist.
You can only reset a setting that does exist at which point it resets to its default/initial value. For custom settings this is always text and the default/initial value for a text setting is the empty string.
There is a pending documentation patch about NULL values that enhances the coverage of this in the documentation.
If you design a system that has to deal with a setting not existing in the session then you at least have the ability to test for that case without provoking an error. But it’s better IMO to design the system to ensure the setting always exists up front and let its absence be an error that indicates a coding bug that needs to be fixed.
There is also an open patch to add proper session variables and formally deprecate this hack-ish usage of the settings subsystem for this use case.
David J.
Marcelo Zabani <mzabani@gmail.com> writes: > Hi, according to the docs, RESET sets the value of a setting to > "The default value is defined as the value that the parameter would have > had, if no SET had ever been issued for it in the current session" This is, I guess, strictly true only for built-in settings. Custom settings act a little differently in that they don't exist at all before you assign to them. Thus > $ psql > => select current_setting('my.test', true) is null; -- true my.test doesn't exist here. current_setting(..., true) returns NULL instead of throwing an error, although SHOW reacts differently: regression=# show my.test; ERROR: unrecognized configuration parameter "my.test" > => set my.test = 'abc'; > => reset my.test; Now it does exist, but its reset value is an empty string. > => select current_setting('my.test', true) is null; -- false > => select current_setting('my.test', true)=''; -- true > Is this expected? I thought even if I misunderstand the docs, the effect > isn't very nice because SQL like > current_setting('my.some_boolean_setting')::boolean will fail after a > transaction with SET LOCAL sets it, a side-effect that can be particularly > confusing and basically requires usage of nullif(.., '') or other explicit > checks around every current_setting call-site in practice. [ shrug... ] This whole area is an undocumented, unsupported abuse of a behavior that's only meant to support GUCs defined by loadable extensions. (To wit, allowing postgresql.conf to set values for GUCs that aren't loaded yet.) Without a way to declare a GUC's type, reset value, etc, there's no way to have custom GUCs act really consistently with built-in ones. Pavel Stehule has spent years pushing forward a patch to invent a better-thought-out implementation of custom session variables [1]. Every time I look at it, I come away with the feeling that it's a giant patch with a much smaller patch struggling to get out. But certainly the area needs some nontrivial thought, and I'm not sure that extending the GUC mechanism is a better answer. regards, tom lane [1] https://www.postgresql.org/message-id/flat/CAFj8pRD053CY_N4%3D6SvPe7ke6xPbh%3DK50LUAOwjC3jm8Me9Obg%40mail.gmail.com
Re: RESET, NULL and empty-string valued settings and transaction isolation
From
Marcelo Zabani
Date:
Thank you both for the explanations and the link to the discussion of Pavel's patches.