Recently, David Capwell was commenting on constraints in one of Slack
threads (1) in dev channel and he suggested that the current form of "not
null" constraint we have right now in place, e.g like this

create table ks.tb (id int primary key, val int check not_null(val));

could be instead of that form used like this:

create table ks.tb (id int primary key, val int check not null);

That is - without the name of a column in the constraint's argument. The
reasoning behind that was that it is not only easier to read but there is
also this concept in transactions (cep-15) where there is also "not null"
used in some fashion and it would be nice if this was aligned so a user
does not encounter two usages of "not null"-s which are written down
differently, syntax-wise.

Could the usage of "not null" in transactions be confirmed?

This rather innocent suggestion brought an idea to us that constraints
could be quite simplified when it comes to their syntax, consider this:

val int check not_null(val)
val text check json(val)
val text check lenght(val) < 1000

to be used like this:

val int check not null
val text check json
val text check length() < 1000

more involved checks like this:

val text check not_null(val) and json(val) and length(val) < 1000

might be just simplified to:

val text check not null and json and length() < 1000

It almost reads like plain English. Isn't this just easier for an eye?

The reason we kept the column names in constraint definitions is that,
frankly speaking, we just did not know any better at the time it was about
to be implemented. It is a little bit more tricky to be able to use it
without column names because in Parser.g / Antlr we just bound the grammar
around constraints to a column name directly there. When column names are
not going to be there anymore, we need to bind it later in the code behind
the parser in server code. It is doable, it was just about being a little
bit more involved there.

Also, one reason to keep the name of a column was that we might specify
different columns in a constraint from a column that is defined on to have
cross-column constraints but we abandoned this idea altogether for other
reasons which rendered the occurrence of a column name in a constraint
definition redundant.

To have some overview of what would be possible to do with this proposal:

val3 text CHECK SOMECONSTRAINT('a');
val3 text CHECK JSON;
val3 text CHECK SOMECONSTRAINT('a') > 1;
val3 text CHECK SOMECONSTRAINT('a', 'b', 'c') > 1;
val3 text CHECK JSON AND LENGTH() < 600;
afternoon time CHECK afternoon >= '12:00:00' AND afternoon =< '23:59:59';
val3 text CHECK NOT NULL AND JSON AND LENGTH() < 1024

In addition to the specification of constraints without columns, what would
be possible to do is to also specify arguments to constraints. It is
currently not possible and there is no constraint which would accept
arguments to its function but I think that to be as flexible as possible
and prepare for the future, we might implement it as well.

Constraints in their current form are already usable however I just think
that if we do not simplify, align and extend the syntax right now, before
it is baked in in a release, then we will never do it as it will be quite
tricky to extend this without breaking it and maintaining two grammars at
the same time would be very complex if not flat out impossible.

Are you open to the simplification of constraint definitions as suggested
and what is your feedback about that? I already have a working POC which
just needs to be polished and tests fixed to accommodate the new approach.

Regards

(1) https://the-asf.slack.com/archives/CK23JSY2K/p1742409054164389

Reply via email to