Re: PostgreSQL domains and NOT NULL constraint

From: Vik Fearing <vik(at)postgresfriends(dot)org>
To: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
Cc: Erki Eessaar <erki(dot)eessaar(at)taltech(dot)ee>, "pgsql-hackers(at)lists(dot)postgresql(dot)org" <pgsql-hackers(at)lists(dot)postgresql(dot)org>
Subject: Re: PostgreSQL domains and NOT NULL constraint
Date: 2023-10-14 02:23:08
Message-ID: a13db59c-c68f-4a30-87a5-177fe135665e@postgresfriends.org
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

On 10/13/23 06:37, Tom Lane wrote:
> Vik Fearing <vik(at)postgresfriends(dot)org> writes:
>> Regardless of what the spec may or may not say about v1.d, it still
>> remains that nulls should not be allowed in a *base table* if the domain
>> says nulls are not allowed. Not mentioned in this thread but the
>> constraints are also applied when CASTing to the domain.
>
> Hmph. The really basic problem here, I think, is that the spec
> wants to claim that a domain is a data type, but then it backs
> off and limits where the domain's constraints need to hold.

I don't think that is an accurate depiction of domains.

First of all, I am not seeing where it says that a domain is a data
type. It allows domains to be used in some places where a data type is
used, but that is not equivalent to a domain /being/ a data type.

Section 4.14 says, "A domain is a set of permissible values." and then
goes on to say that that is a combination of a predefined type and zero
or more search conditions. It can also have a default value, but it
does not seem relevant to talk about that in this discussion.

Section 4.25.4, "Domain constraints" has this to say (emphasis mine):

- A domain constraint is satisfied by SQL-data *if and only if*, for
every *table* T that has a column named C based on that domain, the
applicable <search condition> recorded in the appropriate domain
constraint usage evaluates to True or Unknown.

- A domain constraint is satisfied by the result of a <cast
specification> if and only if the specified template <search condition>,
with each occurrence of the <general value specification> VALUE replaced
by that result, evaluates to True or Unknown.

This tells me that the constraints should only be checked at those two
points.

Secondly, why are you so concerned about outer join nulls here and not
for any other column marked NOT NULL?

> That's fundamentally inconsistent. It's like claiming that
> 'foobarbaz' is a valid value of type numeric as long as it's
> only in flight within a query and you haven't tried to store it
> into a table.

It's like claiming that null is a valid value of type numeric as long as
it's only in flight within a query and you haven't tried to store it
into a table with that column marked NOT NULL.

> Practical problems with this include:
>
> * If a function declares its argument as being of a domain type,
> can it expect that the passed value obeys the constraints?
>
> * If a function declares its result as being of a domain type,
> is it required to return a result that obeys the constraints?
> (This has particular force for RETURNS NULL ON NULL INPUT
> functions, for which we just automatically return NULL given
> a NULL input without any consideration of whether the result
> type nominally prohibits that.)
>
> * If a plpgsql function has a variable that is declared to be of
> domain type, do we enforce the domain's constraints when assigning?

Routines are not allowed to have domains in their parameters or result
types.

I am all for PostgreSQL expanding the spec wherever we can, but in the
above cases we have to define things ourselves.

> * If a composite type has a column of a domain type, do we enforce
> the domain's constraints when assigning or casting to that?

I don't see that a composite type is able to have a member of a domain.
As for what PostgreSQL should do in this case, my opinion is "yes".

> AFAICS, the spec's position leaves all of these as judgment calls,
> or else you might claim that none of the above cases are even allowed
> to be declared per spec. I don't find either of those satisfactory,
> so I reiterate my position that the committee hasn't thought this
> through.

My claim is indeed that these cases are not allowed per-spec and
therefore the spec doesn't *need* to think about them. We do.

>> As you know, I am more than happy to (try to) amend the spec where
>> needed, but Erki's complaint of a null value being allowed in a base
>> table is clearly a bug in our implementation regardless of what we do
>> with views.
>
> I agree it's not a good behavior, but I still say it's traceable
> to schizophenia in the spec. If the result of a sub-select is
> nominally of a domain type, we should not have to recheck the
> domain constraints in order to assign it to a domain-typed target.

Well, yes, we should.

Allowing a null to be stored in a column where the user has specified
NOT NULL, no matter how the user did that, is unacceptable and I am
frankly surprised that you are defending it.

> If it's not nominally of a domain type, please cite chapter and
> verse that says it isn't.

I don't see anything for or against this, I just see that the domain
constraints are only checked on storage or casting.

And therefore, I think with these definitions:

CREATE DOMAIN dom AS INTEGER CHECK (VALUE >= 0);
CREATE TABLE t (d dom);
INSERT INTO t (d) VALUES (1);

this should be valid according to the spec:

SELECT -d FROM t;

and this should error:

SELECT CAST(-d AS dom) FROM t;
--
Vik Fearing

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Andres Freund 2023-10-14 02:33:44 Re: Performance degradation on concurrent COPY into a single relation in PG16.
Previous Message Erik Wienhold 2023-10-14 01:04:05 Re: Fix output of zero privileges in psql