Обсуждение: [PATCH] trenary reloption type

Поиск
Список
Период
Сортировка

[PATCH] trenary reloption type

От
Nikolay Shaplov
Дата:
Hi, All!

There is ongoing tendency in PostgreSQL to replace boolean reloptions that has 
"on" and "off" state, with other option types that has "on", "off" and "use 
defaults" states.

Some of these options are implemented as enum options. They are
"vacuum_index_cleanup" and gist's "buffering"

and one recently converted option "vacuum_truncate" that uses extra 
"vacuum_truncate_set" flag to indicate it's unset state.

This patch introduce trenary reloptions type, that replaces both 
implementation with separate data-type that behaves in the same way as bool 
type does, but has one extra state that indicate that option have not been set 
to "on" or "off" state. 

This third state, I call it "unset" state, can either  be only reached by not 
setting "true" or "false" value to an option, as it is done in vacuum_truncate 
option. Or option designer can assign this third state a custom name, so user 
can explicitly  set option to the "third" slate. As it is done in 
`vacuum_index_cleanup` and gist's `buffering` option, using "auto" keyword.

This patch changes implementation of `vacuum_truncate`, `vacuum_index_cleanup` 
and gist's `buffering` to trinary options. This make code more neat and 
consistent. I'd suggest to commit it to the master branch.

Possible flaws and drawbacks:

1. I've added trenary enum type to c.h. It might be a bit too global, but I 
did not find any better place for it, since it is needed globally and it is 
kind of similar to boolean. If you know better place, please speak.

2. `vacuum_index_cleanup` and gist's `buffering` will now accepts all possible 
"true" and "false" aliases as in boolean type, the way they did not do it 
before. Like "1" or "FAL".  I see no great harm in it, but it is still 
behaviour change.

3. Error messages for `vacuum_index_cleanup` and gist's `buffering` are now 
less informative. It is not right, but I do not see right now a way to improve 
that. May be it is a price to pay for code consistency. If you have any idea 
how to fix it, please speak.

As for the rest, other behavior should not be changed.

I've added as many tests as I can. local_reloption support is also 
implemented.

I've split patch into four part so it can be read and reviewed step by step:
1. Tests that ensures old behaviour
2. Trenary option for `vacuum_truncate` reloption
3. Add "unset_alias" feature to implement "auto" alias for 
`vacuum_index_cleanup` and gist's `buffering`
4. More tests

But I guess they should be commit as a single commit.

-- 
Nikolay Shaplov aka Nataraj
Fuzzing Engineer at Postgres Professional
Matrix IM: @dhyan:nataraj.su

Вложения

Re: [PATCH] ternary reloption type

От
Nikolay Shaplov
Дата:
My English is bad :-(

It is either trinary, or ternary, but not what I've written in previous 
message.

Thanks to Timur for pointing to this issue.

Here goes a new version of the patch with proper naming for an new option 
type. 



-- 
Nikolay Shaplov aka Nataraj
Fuzzing Engineer at Postgres Professional
Matrix IM: @dhyan:nataraj.su

Вложения

Re: [PATCH] ternary reloption type

От
Timur Magomedov
Дата:

Hello Nikolay!

Found a typo in reloptions.h, treaed -> treated.

Can ternary enum be added in a separate header file, say,
src/include/ternary.h instead of adding it to c.h? I'm just not sure if
c.h is it the right place for relation-options-specific code.
Of course, I can be wrong.

--
Regards,
Timur Magomedov




Re: [PATCH] ternary reloption type

От
Nikolay Shaplov
Дата:
В письме от пятница, 12 сентября 2025 г. 16:46:19 MSK пользователь Timur
Magomedov написал:
> Hello Nikolay!
>
> Found a typo in reloptions.h, treaed -> treated.
Oups. Fixed that in the attached version.

> Can ternary enum be added in a separate header file, say,
> src/include/ternary.h instead of adding it to c.h? I'm just not sure if
> c.h is it the right place for relation-options-specific code.
> Of course, I can be wrong.

I am not sure either. But my guess is that spamming into c.h is lesser crime
then adding another useless header file.

Moreover, ternary value is not relation-options-specific, it is actually
relation specific, if you think about it thoroughly. Relation code uses it, and
there is no way to avoid that.

Are there any other notions about the code?

I tried to make thongs more neat and more consistent here. Did I succeed?

--
Nikolay Shaplov aka Nataraj
Fuzzing Engineer at Postgres Professional
Matrix IM: @dhyan:nataraj.su

Вложения

Re: [PATCH] ternary reloption type

От
Álvaro Herrera
Дата:
I took a quick look at 0001+0002 and I think it's quite reasonable.
Here it is again with some minor fixups.  (I'm omitting the further
patches for now, we can rebase them later.)

I'm CCing Nathan as committer of the vacuum_truncate_set stuff which
Nikolay so strongly disliked.  Any objections to going with this
approach?

Thanks,


(Please note that Gmail is sabotaging my kurilemu.de domain, so there's
significant delay in my emails to the list from that address.  I guess
I'm lucky that Nikolay decided to CC my old address in this thread.)

-- 
Álvaro Herrera         PostgreSQL Developer  —  https://www.EnterpriseDB.com/
"The problem with the future is that it keeps turning into the present"
(Hobbes)

Вложения

Re: [PATCH] ternary reloption type

От
Nathan Bossart
Дата:
On Fri, Jan 16, 2026 at 04:14:52PM +0100, Álvaro Herrera wrote:
> I'm CCing Nathan as committer of the vacuum_truncate_set stuff which
> Nikolay so strongly disliked.  Any objections to going with this
> approach?

Looks generally reasonable.

> This could also be used for other options such as `vacuum_index_cleanup`
> and `buffering`, but lets get the scaffolding in first.

Part of me wonders if we should just modify the Boolean relopt
implementation instead of using ternary only when needed.

> +                parsed = parse_bool(value, &b);
> +                option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE;
> +                if (validate && !parsed)
> +                    ereport(ERROR,
> +                            (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
> +                             errmsg("invalid value for ternary option \"%s\": %s",
> +                                    option->gen->name, value)));

Shouldn't this say "invalid value for boolean option"?  IIUC the intent is
for ternary to be exactly like bool, except it defaults to an "unset" value
that can't be chosen by the user.  In that sense, I think "ternary" is kind
of a misnomer, but I wouldn't count this as an objection.

-- 
nathan