Ruben Rizzi
Ruben Rizzi

Reputation: 352

Rule not fired after update statement in postgresql

Following the guide in www.postgresql.org

I created this statement:

CREATE TABLE shoelace_log (
sl_name    text,          -- shoelace changed
sl_avail   integer,       -- new available value
log_who    text,          -- who did it
log_when   timestamp      -- when);
CREATE RULE log_shoelace AS ON UPDATE TO shoelace_data
WHERE NEW.sl_avail <> OLD.sl_avail
DO INSERT INTO shoelace_log VALUES (
                                NEW.sl_name,
                                NEW.sl_avail,
                                current_user,
                                current_timestamp
                            );

When i try to execute the query in pgAdmin3 query console:

UPDATE shoelace_data SET sl_avail = 6 WHERE sl_name = 'sl7';

Only the update query are executed, and the rule isn't fired. I try to use the command EXPLAIN to understand why.

EXPLAIN UPDATE shoelace_log SET sl_avail = 6 WHERE sl_name = 'sl7';

The log says:

"Seq Scan on shoelace_log  (cost=0.00..19.66 rows=4 width=32)"
"  Filter: (sl_name = 'sl7'::text)"
"Seq Scan on shoelace_log  (cost=0.00..19.62 rows=4 width=78)"
"  Filter: (sl_name = 'sl7'::text)"

I also try to use VERBOSE option with EXPLAIN, but i can't understand why my event isn't trigged.

Upvotes: 2

Views: 394

Answers (3)

I tried the example, and it worked. But I had to create the shoelace_data table first. That table isn't in the example.

create table shoelace_data (
    sl_name text,
    sl_avail integer
);
insert into shoelace_data values ('Catcall', 3);
update shoelace_data set sl_avail = 5;

Now if you select from the log table . . .

select * from shoelace_log;
"Catcall";5;"postgres";"2011-03-31 20:40:10.906"

Note carefully that the rule says to insert into shoelace_log when there's an update to the sl_avail column in shoelace_data.

Upvotes: 0

user330315
user330315

Reputation:

You might also want to consider using the pre-built addon that does that for you:

http://pgfoundry.org/projects/tablelog/

Upvotes: 1

Tometzky
Tometzky

Reputation: 23910

You have chosen wrong feature. Forget rules altogether — they're very hard, almost impossible to do right.

What you need here is a trigger:

create or replace function shoelace_log_who_when()
returns trigger language plpgsql as
$$
begin
  if OLD.sl_avail is distinct from NEW.sl_avail then
    NEW.log_who = current_user;
    NEW.log_when = current_timestamp;
  end if;
  return NEW;
end;
$$;

create trigger shoelace_log_who_when before update on shoelace_log
  for each row execute procedure shoelace_log_who_when();

Try it:

insert into shoelace_log values ( 'foo', 1, NULL, NULL );
select * from shoelace_log;
sl_name | sl_avail | log_who | log_when 
---------+----------+---------+----------
foo     |        1 |         | 
update shoelace_log set sl_avail=2;
select * from shoelace_log;
 sl_name | sl_avail | log_who  |         log_when          
---------+----------+----------+---------------------------
 foo     |        2 | tometzky | 2011-03-30 17:06:21.07137

Upvotes: 3

Related Questions