1

I have a postgresql tables. user may update records or delete records manually using interface or using query. I need to track how many records have been updated ,deleted into a log table.I had tried as below update operations count can be tracked successfully. But delete operations count are not logging to log table.

CREATE OR REPLACE FUNCTION edmonton.count_func() RETURNS TRIGGER AS $body$
DECLARE
v_old_data TEXT;
v_new_data TEXT;
log_count INTEGER;
BEGIN


IF (TG_OP = 'UPDATE') THEN
v_old_data := ROW(OLD.*);
v_new_data := ROW(NEW.*);
log_count = count(row(new));
RAISE NOTICE 'update operations';
INSERT INTO edmonton.log ("timestamp",message,type,project_area,count)
VALUES (CURRENT_TIMESTAMP,'records updated in Builder 
table','Information','edmonton',log_count);
RETURN NEW;
ELSIF (TG_OP = 'DELETE') THEN
v_old_data := ROW(OLD.*);
log_count = count(row(old));
RAISE NOTICE 'delete operations';
INSERT INTO edmonton.log ("timestamp",message,type,project_area,count)
VALUES (CURRENT_TIMESTAMP,'records deleted in Builder 
table','Information','edmonton',log_count);
RETURN OLD;
ELSIF (TG_OP = 'INSERT') THEN
v_new_data := ROW(NEW.*);
log_count = count(row(new));
RAISE NOTICE 'insert operations';
INSERT INTO edmonton.log ("timestamp",message,type,project_area,count)
VALUES (CURRENT_TIMESTAMP,'records inserted in Builder 
table','Information','edmonton',log_count);
RETURN NEW;
ELSE
RAISE WARNING '[EDMONTON.COUNT_FUNC] - Other action occurred: %, at 
%',TG_OP,now();
RETURN NULL;
END IF;

EXCEPTION
WHEN data_exception THEN
RAISE WARNING '[EDMONTON.COUNT_FUNC] - UDF ERROR [DATA EXCEPTION] - 
SQLSTATE: %, SQLERRM: %',SQLSTATE,SQLERRM;
RETURN NULL;
WHEN unique_violation THEN
RAISE WARNING '[EDMONTON.COUNT_FUNC] - UDF ERROR [UNIQUE] - SQLSTATE: %, 
SQLERRM: %',SQLSTATE,SQLERRM;
RETURN NULL;
WHEN OTHERS THEN
RAISE WARNING '[EDMONTON.COUNT_FUNC] - UDF ERROR [OTHER] - SQLSTATE: %, 
SQLERRM: %',SQLSTATE,SQLERRM;
RETURN NULL;
END;
$body$
LANGUAGE plpgsql
 SECURITY DEFINER
SET search_path = pg_catalog, edmonton;

And this is my trigger

CREATE TRIGGER count_audit
AFTER INSERT OR UPDATE OR DELETE
ON edmonton.builder
FOR EACH STATEMENT
EXECUTE PROCEDURE edmonton.count_func();

I am getting a warning message when updating a record and messages were not logged to log table.

WARNING:  [EDMONTON.COUNT_FUNC] - UDF ERROR [OTHER] - SQLSTATE: 55000, SQLERRM: record "old" is not assigned yet
CONTEXT:  PL/pgSQL function count_func() line 49 at RAISE
0

2 Answers 2

1

First, you are not able to count inserted/updated/deleted rows that way. The expression

count(row(new))

always returns 1 as row(new) is a single row.

Second, the records new and old are not set in a trigger for each statement. Per the documentation:

NEW

Data type RECORD; variable holding the new database row for INSERT/UPDATE operations in row-level triggers. This variable is unassigned in statement-level triggers and for DELETE operations.

Sign up to request clarification or add additional context in comments.

7 Comments

So statement level trigger can't be implemented?
Of course it can, but what value do you expect to be assigned to new when the trigger is executed only once for multiple rows?
Is there any way to log the count for each operation using statement level triggers?
It's possible with two triggers, one for each row before ins/upd/del and another for each statement after ins/upd/del. Using diagnostics is a simpler, more natural way.
If you want the solution to work for multiple inserts in a single transaction you should add a unique constraint in statements_log. See the modified example. However, I have to say I do not like the idea. I would rather search an alternative solution without triggers.
|
1

https://www.postgresql.org/docs/current/static/plpgsql-trigger.html

NEW

Data type RECORD; variable holding the new database row for INSERT/UPDATE operations in row-level triggers. This variable is unassigned in statement-level triggers and for DELETE operations.

OLD

Data type RECORD; variable holding the old database row for UPDATE/DELETE operations in row-level triggers. This variable is unassigned in statement-level triggers and for INSERT operations.

So the real question is

how does update/insert work?..

3 Comments

It can. But NEW and OLD are not assigned for it you can't refer to them
I dont think so. As I proposed already - use get diagnostics in plpgsql and returning +cte for sql
sure. no worries. don't forget to upvote/accept any/both answers if they helped

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.