Deferrable constraint execution not respecting "initially immediate"?

Started by David G. Johnstonalmost 9 years ago3 messagesbugs
Jump to latest
#1David G. Johnston
david.g.johnston@gmail.com

In bug # 14739 Tom Lane wrote the following. My response follows but I
decided to create a new thread since the topic for 14739 is about encoding
and not the constraint itself.

On Mon, Jul 10, 2017 at 9:25 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

fbd@datasapiens.com writes:

I am testing PG on this query :
CREATE TABLE T_UNIK (ID INT UNIQUE);
INSERT INTO T_UNIK VALUES (1), (2), (3), (4), (5);
UPDATE T_UNIK SET ID = ID + 1;

I know that PG is unable to do this set based operation properly because

it

does it row by row (which is a nonsense since it works on many RDBMS)

The solution for that is documented: declare the unique constraint as
deferrable.

regression=# CREATE TABLE T_UNIK (ID INT UNIQUE deferrable );
CREATE TABLE
regression=#
​​
INSERT INTO T_UNIK VALUES (1), (2), (3), (4), (5);
INSERT 0 5
regression=# U
​​
PDATE T_UNIK SET ID = ID + 1;
UPDATE 5

​I was expecting the above to require a "set constraints deferred" since
"initially immediate" is the default.

create table t_unik (id int unique deferrable initially immediate);

It appears to be useful, but undocumented, that changing the primary mode
to "deferrable" also changes the default timing to "initially deferred" -
irrespective of whether the constraint itself is defined as initially
immediate or initially deferred. i.e., changing just the create table to
explicitly "deferrable initially immediate" doesn't provoke the duplicate
key error like I was expecting it to.

Thinking on it further I believe the issue is that regardless of whether
the timing is immediate or deferred a deferrable constraint never validates
during the execution of an individual command while an immediate constraint
does.

From "CREATE TABLE":

"A constraint that is not deferrable will be checked immediately after
every command."

I think the above should be "after every row" instead of "after every
command". My reading of this is that "command" and "statement" are the
same thing and since the only way to get a unique violation is to be
checking intra-command the above is wrong.

I read the sequence "deferrable initially immediate" as "deferrable
initially "not deferred"" and expect the same behavior as a constraint not
defined as "deferrable" unless some other action, at the transaction level,
is taken. In this case the example doesn't "set constraints" and so the
original failure should persist.

Ultimately my interpretation ends up working just fine because issuing set
constraints in a transaction is just a more liberal directive.

David J.

#2Tom Lane
tgl@sss.pgh.pa.us
In reply to: David G. Johnston (#1)
Re: Deferrable constraint execution not respecting "initially immediate"?

"David G. Johnston" <david.g.johnston@gmail.com> writes:

On Mon, Jul 10, 2017 at 9:25 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

The solution for that is documented: declare the unique constraint as
deferrable.

regression=# CREATE TABLE T_UNIK (ID INT UNIQUE deferrable );
CREATE TABLE
regression=# INSERT INTO T_UNIK VALUES (1), (2), (3), (4), (5);
INSERT 0 5
regression=# UPDATE T_UNIK SET ID = ID + 1;
UPDATE 5

​I was expecting the above to require a "set constraints deferred" since
"initially immediate" is the default.

Right, but "deferrable initially immediate" still means "at the end of the
statement", not "after each row". "deferrable initially deferred" means
"at the end of the transaction". In this example there's no real
difference between those two behaviors.

From "CREATE TABLE":
"A constraint that is not deferrable will be checked immediately after
every command."

I think the above should be "after every row" instead of "after every
command".

I believe that FK constraints work differently from indexes in this
regard. Not sure that we want to get into that level of detail here.

regards, tom lane

--
Sent via pgsql-bugs mailing list (pgsql-bugs@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-bugs

#3David G. Johnston
david.g.johnston@gmail.com
In reply to: Tom Lane (#2)
Re: Deferrable constraint execution not respecting "initially immediate"?

On Mon, Jul 10, 2017 at 10:25 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

From "CREATE TABLE":
"A constraint that is not deferrable will be checked immediately after
every command."

I think the above should be "after every row" instead of "after every
command".

I believe that FK constraints work differently from indexes in this
regard. Not sure that we want to get into that level of detail here.

​Since three of the 4 types are done "after every row" if we want to
simplify (I'm leaning toward being precise here) I'd rather be imprecise
about the FK.​ Pretending that a FK change is checked sooner than it
really is seems like a minor omission since the observed behavior isn't
likely to be noticeable. Wondering why "update pk = pk + 1" doesn't work
by default when PK constraints are checked "after every command" has been
shown to be noticeable.

David J.