fwiw this was tested on 7.2 and 7.4 devel. test case: DROP TABLE locktest; CREATE TABLE locktest (a INTEGER, c TIMESTAMPTZ DEFAULT now() NOT NULL); INSERT INTO locktest VALUES (0);
CREATE OR REPLACE FUNCTION locktest1(integer) RETURNS INTEGER AS ' DECLARE x INTEGER :=1; y ALIAS FOR $1; foo INTEGER; BEGIN LOCK TABLE locktest IN EXCLUSIVE MODE; INSERT INTO locktest(a) VALUES (y); LOOP x:= x + 1; EXIT WHEN x >= 1000000; END LOOP; INSERT INTO locktest(a) VALUES (y+1); SELECT a FROM locktest ORDER BY c ASC LIMIT 1 INTO foo; RAISE NOTICE \'original entry in column a is %\', foo; UPDATE locktest SET a=a+y; SELECT a FROM locktest ORDER BY c ASC LIMIT 1 INTO foo; RAISE NOTICE \'original entry in column a is now %\', foo; return y; END; ' language 'plpgsql'; In two separate windows, I select the function locktest at (roughly) the same time: window#1 foo=# select locktest1(10); NOTICE: original column a is 0 NOTICE: original column a is 10 locktest1 ----------- 10 (1 row) foo=# window#2 foo=# select locktest1(20); NOTICE: original column a is 0 NOTICE: original column a is 0 locktest1 ----------- 20 (1 row) foo=# foo=# select * from locktest order by c; a | c ----+------------------------------- 30 | 2002-12-16 16:37:15.728062-05 20 | 2002-12-16 16:37:23.067412-05 21 | 2002-12-16 16:37:23.067412-05 40 | 2002-12-16 16:37:25.802827-05 41 | 2002-12-16 16:37:25.802827-05 (5 rows) foo=# internally the second function gives conflicting results: it never sees the updated information for the first entry (at 15 seconds into the minute) as far as the select statements are concerned as evidenced by the raise notices both being 0. In fact, it also does not see the changes of it's own update command, even though the first function call at least saw that. However on some level it does see the actual updated information from the first function, because the initial entry ends up as 30 (0 + 10 + 20). Furthermore, concurrency between the two is broken because while the second function sees the update changes made by the first function and updates them accordingly, it doesn't see the insert changes made by the first function, and so they are not updated. "this is broken on so many levels..." If functions ran like they were in read committed mode, then my final resutset should look like this: a | c ----+------------------------------- 30 | 2002-12-16 16:43:02.374575-05 40 | 2002-12-16 16:43:11.640649-05 41 | 2002-12-16 16:43:11.640649-05 40 | 2002-12-16 16:43:16.705811-05 41 | 2002-12-16 16:43:16.705811-05 (5 rows) since the second function call would wait for the first call to finish before attempting to make changes, would see all three records in the resultset of the first function, and would update all of those records accordingly. OTOH if functions ran as if they we're in serializable mode, the second function would, upon attempt to update the first record, see that the record was already updated, and throw a "ERROR: Can't serialize access due to concurrent update", which could then be dealt with accordingly. As it stands now we have a bastardization of the two transaction levels. Robert Treat ---------------------------(end of broadcast)--------------------------- TIP 6: Have you searched our list archives? http://archives.postgresql.org