Thread: Transactional issue that begs for explanation
I am having problems explaining the following course of events: I created table test_keys(key int,val varchar(10)); No PK, no indexes. I populated the table using the following SQL: insert into test_keys values(1,'Key1'); insert into test_keys values(2,'Key2'); insert into test_keys values(3,'Key3'); insert into test_keys values(4,'Key4'); insert into test_keys values(5,'Key5'); insert into test_keys values(6,'Key6'); insert into test_keys values(7,'Key7'); insert into test_keys values(8,'Key8'); insert into test_keys values(9,'Key9'); insert into test_keys values(10,'Key10'); insert into test_keys values(11,'Key11'); insert into test_keys values(12,'Key12'); insert into test_keys values(13,'Key13'); insert into test_keys values(14,'Key14'); insert into test_keys values(15,'Key15'); insert into test_keys values(16,'Key16'); insert into test_keys values(17,'Key17'); insert into test_keys values(18,'Key18'); insert into test_keys values(19,'Key19'); insert into test_keys values(20,'Key20'); To make the story more interesting, I added the following: CREATE or REPLACE FUNCTION logtrg() RETURNS trigger AS $$ open(STDOUT,">>/tmp/logfile") or die("Cannot open log:$!\n"); $key=$_TD->{old}{key}; $val=$_TD->{old}{val}; print "Firing on: $key $val\n"; return; $$ LANGUAGE plperlu; CREATE TRIGGER log_upd BEFORE UPDATE on test_keys FOR EACH ROW EXECUTE PROCEDURE logtrg(); Essentially, I added trigger that records the values that the trigger fires upon and puts those values into /tmp/logfile Next, opened 2 sessions and executed the following: Session 1: Session 2: ---------------- ---------------- begin; begin; update test_keys update test_keys set val='EVEN' set val='DIV5' where key%2=0; where key%5=0; rollback; commit; Here is the content of my logfile: root@ubuntu:~# tail -f /tmp/logfile Firing on: 2 Key2 Firing on: 4 Key4 Firing on: 6 Key6 Firing on: 8 Key8 Firing on: 10 Key10 Firing on: 12 Key12 Firing on: 14 Key14 Firing on: 16 Key16 Firing on: 18 Key18 Firing on: 20 EVEN Firing on: 5 Key5 Firing on: 10 Key10 Firing on: 15 Key15 Question: where did "EVEN" on the key 20 come from? The first transaction was rolled back, the 2nd transaction shouldn't have seen any changes made by the first transaction. I am using PgSQL 8.4.4 on Ubuntu 10, 32bit version (laptop). I repeated the experiment several times, and this happens rather consistently. -- Mladen Gogala Sr. Oracle DBA 1500 Broadway New York, NY 10036 (212) 329-5251 www.vmsinfo.com The Leader in integrated Media Intelligence Solutions
On 10 September 2010 09:49, Mladen Gogala <mladen.gogala@vmsinfo.com> wrote: > I am having problems explaining the following course of events: > > I created table test_keys(key int,val varchar(10)); No PK, no indexes. > I populated the table using the following SQL: > insert into test_keys values(1,'Key1'); > insert into test_keys values(2,'Key2'); > insert into test_keys values(3,'Key3'); > insert into test_keys values(4,'Key4'); > insert into test_keys values(5,'Key5'); > insert into test_keys values(6,'Key6'); > insert into test_keys values(7,'Key7'); > insert into test_keys values(8,'Key8'); > insert into test_keys values(9,'Key9'); > insert into test_keys values(10,'Key10'); > insert into test_keys values(11,'Key11'); > insert into test_keys values(12,'Key12'); > insert into test_keys values(13,'Key13'); > insert into test_keys values(14,'Key14'); > insert into test_keys values(15,'Key15'); > insert into test_keys values(16,'Key16'); > insert into test_keys values(17,'Key17'); > insert into test_keys values(18,'Key18'); > insert into test_keys values(19,'Key19'); > insert into test_keys values(20,'Key20'); > > To make the story more interesting, I added the following: > CREATE or REPLACE FUNCTION logtrg() RETURNS trigger AS $$ > open(STDOUT,">>/tmp/logfile") or die("Cannot open log:$!\n"); > $key=$_TD->{old}{key}; > $val=$_TD->{old}{val}; > print "Firing on: $key $val\n"; > return; > $$ LANGUAGE plperlu; > > CREATE TRIGGER log_upd BEFORE UPDATE on test_keys > FOR EACH ROW EXECUTE PROCEDURE logtrg(); > > Essentially, I added trigger that records the values that the trigger fires > upon and puts those values into /tmp/logfile > > Next, opened 2 sessions and executed the following: > Session 1: Session 2: > ---------------- > ---------------- > begin; begin; > update test_keys update test_keys > set val='EVEN' set val='DIV5' > where key%2=0; where key%5=0; > rollback; commit; > > Here is the content of my logfile: > > > root@ubuntu:~# tail -f /tmp/logfile > Firing on: 2 Key2 > Firing on: 4 Key4 > Firing on: 6 Key6 > Firing on: 8 Key8 > Firing on: 10 Key10 > Firing on: 12 Key12 > Firing on: 14 Key14 > Firing on: 16 Key16 > Firing on: 18 Key18 > Firing on: 20 EVEN > Firing on: 5 Key5 > Firing on: 10 Key10 > Firing on: 15 Key15 > > Question: where did "EVEN" on the key 20 come from? The first transaction > was rolled back, the 2nd transaction shouldn't have seen any changes made by > the first transaction. I am using PgSQL 8.4.4 on Ubuntu 10, 32bit version > (laptop). > > I repeated the experiment several times, and this happens rather > consistently. This is quite odd. I've done exactly the same thing on 8.4.4 Gentoo x64 and it returns the expected result so I haven't been able to recreate it. What does the table contain after that series of events? -- Thom Brown Twitter: @darkixion IRC (freenode): dark_ixion Registered Linux user: #516935
On 10 September 2010 11:27, Mladen Gogala <mladen.gogala@vmsinfo.com> wrote: > Thom Brown wrote: >> >> This is quite odd. I've done exactly the same thing on 8.4.4 Gentoo >> x64 and it returns the expected result so I haven't been able to >> recreate it. What does the table contain after that series of events? >> >> > > Oh, the content is correct, 4 records are modified, 5,10,15 and 20 have all > value 'DIV5'. I've been bitten by triggers before so I am testing the > trigger behavior. The good news is that "before update" trigger doesn't fire > twice, as is the case with Oracle. BTW, is there any simpler method to > simulate DBMS_OUTPUT, other than using plperlu the way I did? Please reply to all so everyone else can see your response. :) (list copied in again for this message) But I personally don't know of the best way to produce the logging you're after. -- Thom Brown Twitter: @darkixion IRC (freenode): dark_ixion Registered Linux user: #516935
Mladen Gogala <mladen.gogala@vmsinfo.com> writes: > To make the story more interesting, I added the following: > CREATE or REPLACE FUNCTION logtrg() RETURNS trigger AS $$ > open(STDOUT,">>/tmp/logfile") or die("Cannot open log:$!\n"); > $key=$_TD->{old}{key}; > $val=$_TD->{old}{val}; > print "Firing on: $key $val\n"; > return; > $$ LANGUAGE plperlu; I suspect you're shooting yourself in the foot by repeatedly re-opening the backend's stdout and not fflush'ing anywhere along the line: somehow the data going to the log file is getting mangled. I don't see any strange behavior here when using a less dangerous logging technique, such as CREATE or REPLACE FUNCTION logtrg() RETURNS trigger AS $$ $key=$_TD->{old}{key}; $val=$_TD->{old}{val}; elog(NOTICE, "Firing on: $key $val\n"); return; $$ LANGUAGE plperlu; (Actually, I don't see anything funny when using your original version of the function, either; but it's probably dependent on a lot of platform-specific libc details exactly how you got that result.) regards, tom lane
Tom Lane wrote: > I suspect you're shooting yourself in the foot by repeatedly re-opening > the backend's stdout and not fflush'ing anywhere along the line: somehow > the data going to the log file is getting mangled. I don't see any > strange behavior here when using a less dangerous logging technique, > such as > > CREATE or REPLACE FUNCTION logtrg() RETURNS trigger AS $$ > $key=$_TD->{old}{key}; > $val=$_TD->{old}{val}; > elog(NOTICE, "Firing on: $key $val\n"); > return; > $$ LANGUAGE plperlu; > > (Actually, I don't see anything funny when using your original version > of the function, either; but it's probably dependent on a lot of > platform-specific libc details exactly how you got that result.) > > regards, tom lane > Tom, you are a great guy. I didn't know about the elog function, I've just tried to re-invent the wheel. Thanks for the pointer, I will try with elog. Actually, I was trying to check what from the following article is applicable to Postgres: http://tkyte.blogspot.com/2005/08/something-different-part-i-of-iii.html http://tkyte.blogspot.com/2005/08/part-ii-seeing-restart.html http://tkyte.blogspot.com/2005/09/part-iii-why-is-restart-important-to.html What I did figure out is a) Postgres doesn't restart the transaction the same way that Oracle does or the trigger would fire twice. b) There is no DBMS_OUTPUT, so I tried to re-invent the wheel. I still don't know what does Postgres do when the data in a block needed by current transaction changes the value? Oracle simply restarts the transaction, in order to have a clean slate. -- Mladen Gogala Sr. Oracle DBA 1500 Broadway New York, NY 10036 (212) 329-5251 www.vmsinfo.com
Mladen Gogala wrote on 11.09.2010 05:32: > b) There is no DBMS_OUTPUT, so I tried to re-invent the wheel. RAISE NOTICE is the Postgres equivalent to DBMS_OUTPUT http://www.postgresql.org/docs/current/static/plpgsql-errors-and-messages.html