Forum OpenACS Q&A: Bizarre Postgres Behavior

Collapse
Posted by Carl Coryell-Martin on
I find this behavior very odd and am concerned that it's a deep flaw in postgres:
lta=# begin;
BEGIN
lta=# select count(*) from sec_sessions where user_id = 71;
 count 
-------
     2
(1 row)

lta=# delete from sec_sessions where user_id = 71;
DELETE 0
lta=#
So the WHERE clause returns two rows from a SELECT but deletes zero rows! Anyone have any ideas?

Thank you,

Carl C-M

Collapse
Posted by Jonathan Ellis on
did you check to make sure the rows still existed afterwards?  sec_sweep_sessions is scheduled to delete old stuff out every hour.
Collapse
Posted by Roberto Mello on
Are you sure sec_sessions is not a VIEW (can't check right now)? In can't remember if that threw an error or not in Postgres.
Collapse
Posted by Jonathan Ellis on
1) it's a table

2) postgres will complain, "ERROR:  Cannot delete from a view without an appropriate rule" if you try it

Collapse
Posted by Carl Coryell-Martin on
It is a table. and the rows still exist.  That is why I am very perplexed.

cheers,

Collapse
Posted by David Walker on
Something to do with the rules I'd guess.  I don't have a lot of
understanding of foreign keys and such.  sec_sessions and
sec_session_properties are linked by a foreign key
Collapse
Posted by Jonathan Ellis on
There is an "on delete cascade" for the foreign key you are referring to, meaning that when the key is deleted from sec_sessions, the corresponding rows are also deleted from sec_session_properties (silently; AFAIK there is no indication that another table has been effected in what postgres returns).  If you try to delete a row is referenced by a FK w/o the cascade, you will get an error.
Collapse
Posted by Jonathan Ellis on
What I would do is stop postgres, make a backup of the PGDATA directory, then recreate the db from a dump.  See if the restore into a clean db helps... and either way, mail the pg bugs list.
Collapse
9: Solution: Triggers! (response to 1)
Posted by Carl Coryell-Martin on
It turns out there there was an ON DELETE trigger on the row that looked a little like this:

create trigger clean_up_other_tables
before delete on sec_sesssions
execute clean_up_other_tables_tr;

Where clean_up_other_tables_tr looked a little like this:

delete from foo where session_id = OLD.session_id;
return NULL;

-----------------
So the return null was breaking the delete and when I think about it, It makes some sense.

Cheers,

Carl C-M

Collapse
Posted by Don Baccus on
Yes, indeed it makes sense.  Returning NULL is how you cancel the operation on the row from within a trigger.  The statement continues though, so the DELETE doesn't return an error, just the fact that in this case your trigger cancelled the delete on each and every row.

(to abort the entire transaction you'd use RAISE ERROR)