Reputation: 352
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
Reputation: 95642
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
Reputation:
You might also want to consider using the pre-built addon that does that for you:
http://pgfoundry.org/projects/tablelog/
Upvotes: 1
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