Обсуждение: Atomicity?
I am getting an error that I think I understand, but that I didn't think
should happen.
Below is the output from psql that I am getting to trigger this error.
If the violation of the constraint really is being caused WITHIN the
query, doesn't that violate the principle of atomicity? I.e., operations
and entities should be considered a single entire construct rather than
a collection of smaller, discrete parts. Or do I have my understanding
all wrong?
In any case, how do I get around this problem?
Regards,
- Naz.
conwatch=# \d replies;
Table "conwatch.replies"
Column | Type | Modifiers
-----------+--------------------------+-----------------------------------------------------------
replyid | integer | not null default
nextval('replies_replyid_seq'::regclass)
postid | integer | not null
lft | smallint | not null
rgt | smallint | not null
poster | integer | not null
posted | timestamp with time zone | not null default now()
title | character varying(100) | not null
body | text |
anonymous | boolean | not null default false
Indexes:
"replies_pkey" PRIMARY KEY, btree (replyid)
"replies_lft_postid" UNIQUE, btree (lft, postid)
"replies_rgt_postid" UNIQUE, btree (rgt, postid)
"replies_lft_index" btree (lft)
"replies_rgt_index" btree (rgt)
Foreign-key constraints:
"replies_poster_fkey" FOREIGN KEY (poster) REFERENCES users(userid)
"replies_postid_fkey" FOREIGN KEY (postid) REFERENCES posts(postid)
conwatch=# select replyid, postid, lft, rgt, title from replies where
postid = 18 order by lft;
replyid | postid | lft | rgt | title
---------+--------+-----+-----+----------------------
24 | 18 | 1 | 14 | Invisible root post.
25 | 18 | 2 | 7 | Re: Pronto
26 | 18 | 3 | 6 | Re: Pronto
27 | 18 | 4 | 5 | Re: Pronto
29 | 18 | 8 | 13 | Re: Pronto
31 | 18 | 9 | 12 | Re: Pronto
32 | 18 | 10 | 11 | Re: Pronto
(7 rows)
conwatch=# UPDATE replies SET rgt = rgt + 2 WHERE postid = 18 AND rgt >= 11;
ERROR: duplicate key violates unique constraint "replies_rgt_postid"
conwatch=# UPDATE replies SET rgt = rgt + 2 WHERE postid = 18 AND rgt = 14;
UPDATE 1
conwatch=# UPDATE replies SET rgt = rgt + 2 WHERE postid = 18 AND rgt = 13;
UPDATE 1
conwatch=# UPDATE replies SET rgt = rgt + 2 WHERE postid = 18 AND rgt = 12;
UPDATE 1
conwatch=# UPDATE replies SET rgt = rgt + 2 WHERE postid = 18 AND rgt = 11;
UPDATE 1
conwatch=#
Naz Gassiep wrote: > If the violation of the constraint really is being caused > WITHIN the query, doesn't that violate the principle of atomicity? > I.e., operations and entities should be considered a single entire > construct rather than a collection of smaller, discrete parts. The principle of atomicity merely says that transactions are either performed entirely or not at all. If the transaction is not performed, then there is no violation of atomicity. > conwatch=# UPDATE replies SET rgt = rgt + 2 WHERE postid = 18 AND rgt > >= 11; > ERROR: duplicate key violates unique constraint "replies_rgt_postid" This is a well-known deficiency in PostgreSQL. You will have to work around it somehow (by changing the query, the schema, or the index). -- Peter Eisentraut http://developer.postgresql.org/~petere/
Naz Gassiep wrote:
> I am getting an error that I think I understand, but that I didn't think
> should happen.
>
> Below is the output from psql that I am getting to trigger this error.
> If the violation of the constraint really is being caused WITHIN the
> query, doesn't that violate the principle of atomicity? I.e., operations
> and entities should be considered a single entire construct rather than
> a collection of smaller, discrete parts. Or do I have my understanding
> all wrong?
>
> In any case, how do I get around this problem?
If you do not specify the beginning of a transaction, all statements are
run within their own transaction.. e;g:
Your example actually means:
begin;
> conwatch=# UPDATE replies SET rgt = rgt + 2 WHERE postid = 18 AND rgt >=
> 11;
commit;
begin;
> conwatch=# UPDATE replies SET rgt = rgt + 2 WHERE postid = 18 AND rgt = 14;
commit;
What you want is:
begin;
> UPDATE 1
> conwatch=# UPDATE replies SET rgt = rgt + 2 WHERE postid = 18 AND rgt = 13;
> UPDATE 1
> conwatch=# UPDATE replies SET rgt = rgt + 2 WHERE postid = 18 AND rgt = 12;
> UPDATE 1
> conwatch=# UPDATE replies SET rgt = rgt + 2 WHERE postid = 18 AND rgt = 11;
> UPDATE 1
> conwatch=#
commit;
Joshua D. Drake
>
> ---------------------------(end of broadcast)---------------------------
> TIP 6: explain analyze is your friend
>
--
=== The PostgreSQL Company: Command Prompt, Inc. ===
Sales/Support: +1.503.667.4564 || 24x7/Emergency: +1.800.492.2240
Providing the most comprehensive PostgreSQL solutions since 1997
http://www.commandprompt.com/
Peter Eisentraut wrote:
Naz Gassiep wrote:
If the violation of the constraint really is being caused
WITHIN the query, doesn't that violate the principle of atomicity?
I.e., operations and entities should be considered a single entire
construct rather than a collection of smaller, discrete parts.
The principle of atomicity merely says that transactions are either
performed entirely or not at all. If the transaction is not performed,
then there is no violation of atomicity.
conwatch=# UPDATE replies SET rgt = rgt + 2 WHERE postid = 18 AND rgt
= 11;
ERROR: duplicate key violates unique constraint "replies_rgt_postid"
This is a well-known deficiency in PostgreSQL. You will have to work
around it somehow (by changing the query, the schema, or the index).
Do we have an ETA on fixing it? Or is it a long term outstanding issue
with no ETA as yet?
Thanks for the reply,
- Naz
On Aug 29, 2006, at 4:46 , Peter Eisentraut wrote:
> Naz Gassiep wrote:
>> conwatch=# UPDATE replies SET rgt = rgt + 2 WHERE postid = 18 AND rgt
>>> = 11;
>> ERROR: duplicate key violates unique constraint "replies_rgt_postid"
>
> This is a well-known deficiency in PostgreSQL. You will have to work
> around it somehow (by changing the query, the schema, or the index).
One such workaround is:
BEGIN;
UPDATE replies
SET rgt = -1 * (rgt + 2)
WHERE postid = 18
AND rgt >= 11;
UPDATE replies
SET rgt = -1 * rgt
WHERE rgt < 0;
COMMIT;
Michael Glaesemann
grzm seespotcode net
No, the subsequent UPDATEs were just there to show you they worked... I was only interested in the failed update, and why it failed. The DB was consistent before the query, and it would have been after the query, so I did not understand why the query failed unless the query made teh DB inconsistent at some point DURING its execution. This seems odd to me, as queries should not trigger errors like that if the DB is only out of consistency DURING its execution, as long as it is consistent before and after. Regards, - Naz. Joshua D. Drake wrote: > Naz Gassiep wrote: >> I am getting an error that I think I understand, but that I didn't >> think should happen. >> >> Below is the output from psql that I am getting to trigger this >> error. If the violation of the constraint really is being caused >> WITHIN the query, doesn't that violate the principle of atomicity? >> I.e., operations and entities should be considered a single entire >> construct rather than a collection of smaller, discrete parts. Or do >> I have my understanding all wrong? >> >> In any case, how do I get around this problem? > > If you do not specify the beginning of a transaction, all statements > are run within their own transaction.. e;g: > > Your example actually means: > > begin; > >> conwatch=# UPDATE replies SET rgt = rgt + 2 WHERE postid = 18 AND rgt >> >= 11; > > commit; > > begin; >> conwatch=# UPDATE replies SET rgt = rgt + 2 WHERE postid = 18 AND rgt >> = 14; > commit; > > What you want is: > > begin; > >> UPDATE 1 >> conwatch=# UPDATE replies SET rgt = rgt + 2 WHERE postid = 18 AND rgt >> = 13; >> UPDATE 1 >> conwatch=# UPDATE replies SET rgt = rgt + 2 WHERE postid = 18 AND rgt >> = 12; >> UPDATE 1 >> conwatch=# UPDATE replies SET rgt = rgt + 2 WHERE postid = 18 AND rgt >> = 11; >> UPDATE 1 >> conwatch=# > > commit; > > Joshua D. Drake > > >> >> ---------------------------(end of broadcast)--------------------------- >> TIP 6: explain analyze is your friend >> > >
I would like more information on this deficiency and what causes it so I know when to anticipate it. This resulted in a rather nasty bug which took me ages to track down. Is anyone able+willing to explain a little here or should I ask in -hackers ? Regards, - Naz. Michael Glaesemann wrote: > > On Aug 29, 2006, at 4:46 , Peter Eisentraut wrote: > >> Naz Gassiep wrote: >>> conwatch=# UPDATE replies SET rgt = rgt + 2 WHERE postid = 18 AND rgt >>>> = 11; >>> ERROR: duplicate key violates unique constraint "replies_rgt_postid" >> >> This is a well-known deficiency in PostgreSQL. You will have to work >> around it somehow (by changing the query, the schema, or the index). > > One such workaround is: > > BEGIN; > > UPDATE replies > SET rgt = -1 * (rgt + 2) > WHERE postid = 18 > AND rgt >= 11; > > UPDATE replies > SET rgt = -1 * rgt > WHERE rgt < 0; > > COMMIT; > > Michael Glaesemann > grzm seespotcode net > > > >
Naz Gassiep wrote:
> No, the subsequent UPDATEs were just there to show you they worked... I
> was only interested in the failed update, and why it failed. The DB was
> consistent before the query, and it would have been after the query, so
> I did not understand why the query failed unless the query made teh DB
> inconsistent at some point DURING its execution. This seems odd to me,
> as queries should not trigger errors like that if the DB is only out of
> consistency DURING its execution, as long as it is consistent before and
> after.
Yeah I misunderstood your question. See PeterE's response.
Sincerely,
Joshua D. Drake
> Regards,
> - Naz.
>
> Joshua D. Drake wrote:
>> Naz Gassiep wrote:
>>> I am getting an error that I think I understand, but that I didn't
>>> think should happen.
>>>
>>> Below is the output from psql that I am getting to trigger this
>>> error. If the violation of the constraint really is being caused
>>> WITHIN the query, doesn't that violate the principle of atomicity?
>>> I.e., operations and entities should be considered a single entire
>>> construct rather than a collection of smaller, discrete parts. Or do
>>> I have my understanding all wrong?
>>>
>>> In any case, how do I get around this problem?
>>
>> If you do not specify the beginning of a transaction, all statements
>> are run within their own transaction.. e;g:
>>
>> Your example actually means:
>>
>> begin;
>>
>>> conwatch=# UPDATE replies SET rgt = rgt + 2 WHERE postid = 18 AND rgt
>>> >= 11;
>>
>> commit;
>>
>> begin;
>>> conwatch=# UPDATE replies SET rgt = rgt + 2 WHERE postid = 18 AND rgt
>>> = 14;
>> commit;
>>
>> What you want is:
>>
>> begin;
>>
>>> UPDATE 1
>>> conwatch=# UPDATE replies SET rgt = rgt + 2 WHERE postid = 18 AND rgt
>>> = 13;
>>> UPDATE 1
>>> conwatch=# UPDATE replies SET rgt = rgt + 2 WHERE postid = 18 AND rgt
>>> = 12;
>>> UPDATE 1
>>> conwatch=# UPDATE replies SET rgt = rgt + 2 WHERE postid = 18 AND rgt
>>> = 11;
>>> UPDATE 1
>>> conwatch=#
>>
>> commit;
>>
>> Joshua D. Drake
>>
>>
>>>
>>> ---------------------------(end of broadcast)---------------------------
>>> TIP 6: explain analyze is your friend
>>>
>>
>>
>
--
=== The PostgreSQL Company: Command Prompt, Inc. ===
Sales/Support: +1.503.667.4564 || 24x7/Emergency: +1.800.492.2240
Providing the most comprehensive PostgreSQL solutions since 1997
http://www.commandprompt.com/
Naz Gassiep <naz@mira.net> writes:
> I would like more information on this deficiency and what causes it so I
> know when to anticipate it.
The uniqueness constraint is checked on a row-by-row basis, so if you
update one row to hold the same value as another row holds, you get an
error immediately. It doesn't matter that if the query had been allowed
to finish, it would have updated that other row to some non-conflicting
value. (You might be able to work around this if you could control the
order in which rows are updated, but you can't.)
This is not what the SQL spec says should happen, but so far no one has
proposed a reimplementation that doesn't give up unreasonable amounts
of performance. It's on the TODO list ...
regards, tom lane
On Tue, Aug 29, 2006 at 06:17:39AM +1000, Naz Gassiep wrote: > I would like more information on this deficiency and what causes it so I > know when to anticipate it. This resulted in a rather nasty bug which > took me ages to track down. Is anyone able+willing to explain a little > here or should I ask in -hackers ? Sure, UNIQUE constraints are not deferrable. With normal constraints you can defer the check until the end of transaction and be in an inconsistant state for while. However, PostgreSQL doesn't support this for uniqueness checks. However, temporary inconsistancy in unique columns doesn't some up that often so it's not that big a deal. This has been a problem for a long time and will quite possibly be for a while still, mainly because no-one really has any idea how to fix it... Have a nice day, -- Martijn van Oosterhout <kleptog@svana.org> http://svana.org/kleptog/ > From each according to his ability. To each according to his ability to litigate.
Вложения
> Naz Gassiep <naz@mira.net> writes: > > I would like more information on this deficiency and what causes it so I > > know when to anticipate it. > > The uniqueness constraint is checked on a row-by-row basis, so if you > update one row to hold the same value as another row holds, you get an > error immediately. It doesn't matter that if the query had been allowed > to finish, it would have updated that other row to some non-conflicting > value. (You might be able to work around this if you could control the > order in which rows are updated, but you can't.) > > This is not what the SQL spec says should happen, but so far no one has > proposed a reimplementation that doesn't give up unreasonable amounts > of performance. It's on the TODO list ... Is this related to the current limitations of "SET CONSTRAINTS"? http://www.postgresql.org/docs/8.1/interactive/sql-set-constraints.html Regards, Richard Broersma Jr.
Martijn van Oosterhout <kleptog@svana.org> writes:
> Sure, UNIQUE constraints are not deferrable. With normal constraints
> you can defer the check until the end of transaction and be in an
> inconsistant state for while. However, PostgreSQL doesn't support this
> for uniqueness checks.
Actually, what the spec says is (SQL92 4.10.1)
The checking of a constraint depends on its constraint mode within
the current SQL-transaction. If the constraint mode is immedi-
ate, then the constraint is effectively checked at the end of
each SQL-statement. If the constraint mode is deferred, then the
constraint is effectively checked when the constraint mode is
changed to immediate either explicitly by execution of a <set con-
straints mode statement>, or implicitly at the end of the current
SQL-transaction.
So even for a non-deferred unique constraint, it should be legal to
update multiple rows to new non-conflicting values within a single
UPDATE command. Plus, as Martijn says, we have no support at all
for the defer-to-end-of-transaction case.
We've discussed this before, and I thought it was on the TODO list,
but AFAICS the only entry there is
* Allow DEFERRABLE UNIQUE constraints?
which is misfiled under "Triggers" and doesn't cover the existing
spec violation anyway. Bruce?
regards, tom lane
Richard Broersma Jr wrote: > Is this related to the current limitations of "SET CONSTRAINTS"? Only in a vague and nonspecific way. -- Peter Eisentraut http://developer.postgresql.org/~petere/
Martijn van Oosterhout wrote: > Sure, UNIQUE constraints are not deferrable. With normal constraints > you can defer the check until the end of transaction and be in an > inconsistant state for while. However, PostgreSQL doesn't support > this for uniqueness checks. Note that even a nondeferred unique constraint would let the command proceed because a nondeferred constraint is checked after the statement, not at seemingly random points during it. -- Peter Eisentraut http://developer.postgresql.org/~petere/
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 > I would like more information on this deficiency and what causes it so I > know when to anticipate it. This resulted in a rather nasty bug which > took me ages to track down. Is anyone able+willing to explain a little > here or should I ask in -hackers ? This has some workarounds and explanations that may help: http://people.planetpostgresql.org/greg/index.php?/archives/2006/06/10.html - -- Greg Sabino Mullane greg@endpoint.com greg@turnstep.com End Point Corporation 610-983-9073 PGP Key: 0x14964AC8 200608281703 http://biglumber.com/x/web?pk=2529DF6AB8F79407E94445B4BC9B906714964AC8 -----BEGIN PGP SIGNATURE----- iD8DBQFE81pHvJuQZxSWSsgRAvETAJ9u22as0X76y9XHGyhfPyOEa70RNQCgxsjA IPV3jK0DAHzr7OD3xY2jFMA= =2JJL -----END PGP SIGNATURE-----
Tom Lane wrote:
> Martijn van Oosterhout <kleptog@svana.org> writes:
> > Sure, UNIQUE constraints are not deferrable. With normal constraints
> > you can defer the check until the end of transaction and be in an
> > inconsistant state for while. However, PostgreSQL doesn't support this
> > for uniqueness checks.
>
> Actually, what the spec says is (SQL92 4.10.1)
>
> The checking of a constraint depends on its constraint mode within
> the current SQL-transaction. If the constraint mode is immedi-
> ate, then the constraint is effectively checked at the end of
> each SQL-statement. If the constraint mode is deferred, then the
> constraint is effectively checked when the constraint mode is
> changed to immediate either explicitly by execution of a <set con-
> straints mode statement>, or implicitly at the end of the current
> SQL-transaction.
>
> So even for a non-deferred unique constraint, it should be legal to
> update multiple rows to new non-conflicting values within a single
> UPDATE command. Plus, as Martijn says, we have no support at all
> for the defer-to-end-of-transaction case.
>
> We've discussed this before, and I thought it was on the TODO list,
> but AFAICS the only entry there is
>
> * Allow DEFERRABLE UNIQUE constraints?
>
> which is misfiled under "Triggers" and doesn't cover the existing
> spec violation anyway. Bruce?
TODO updated:
* Allow DEFERRABLE and end-of-statement UNIQUE constraints?
This would allow UPDATE tab SET col = col + 1 to work if col has
a unique index. Currently, uniqueness checks are done while the
command is being executed, rather than at the end of the statement
or transaction.
and moved to "referential integrity" section.
--
Bruce Momjian bruce@momjian.us
EnterpriseDB http://www.enterprisedb.com
+ If your life is a hard drive, Christ can be your backup. +
Greg Sabino Mullane wrote: [ There is text before PGP section. ] > > -----BEGIN PGP SIGNED MESSAGE----- > Hash: SHA1 > > > > I would like more information on this deficiency and what causes it so I > > know when to anticipate it. This resulted in a rather nasty bug which > > took me ages to track down. Is anyone able+willing to explain a little > > here or should I ask in -hackers ? > > This has some workarounds and explanations that may help: > > http://people.planetpostgresql.org/greg/index.php?/archives/2006/06/10.html URL added to TODO. -- Bruce Momjian bruce@momjian.us EnterpriseDB http://www.enterprisedb.com + If your life is a hard drive, Christ can be your backup. +
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Naz Gassiep wrote:
> I am getting an error that I think I understand, but that I didn't think
> should happen.
>
> Below is the output from psql that I am getting to trigger this error.
> If the violation of the constraint really is being caused WITHIN the
> query, doesn't that violate the principle of atomicity? I.e., operations
> and entities should be considered a single entire construct rather than
> a collection of smaller, discrete parts. Or do I have my understanding
> all wrong?
>
> In any case, how do I get around this problem?
>
> conwatch=# UPDATE replies SET rgt = rgt + 2 WHERE postid = 18 AND rgt >=
> 11;
Another work-around would be a loop.
Pseudo-code:
BEGIN
FOR :X IN
SELECT RGT, REPLYID
FROM REPLIES
WHERE POSTID = 18
AND RGT >= 11
DO
UPDATE REPLIES
SET RGT = RGT + 2
WHERE REPLIYID = :X.REPLYID;
END FOR;
END;
- --
Ron Johnson, Jr.
Jefferson LA USA
Is "common sense" really valid?
For example, it is "common sense" to white-power racists that
whites are superior to blacks, and that those with brown skins
are mud people.
However, that "common sense" is obviously wrong.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.5 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
iD8DBQFE9GSjS9HxQb37XmcRArqiAJ90r+NPOzs312kav/682DiH16YBzgCgriDt
pCy0mK/74NvnHim5uaLeYrU=
=hJ1s
-----END PGP SIGNATURE-----