Understanding the BEFORE UPDATE trigger in SQL - sql

In PostgreSQL, if I want to make changes on the UPDATE command, apparently I should trigger on BEFORE UPDATE. For example:
CREATE OR REPLACE FUNCTION trigger_update_fn() RETURNS trigger AS
$$ BEGIN
new.updated := current_timestamp;
new.created := old.created; -- override changes with original value
RETURN new;
END $$ LANGUAGE plpgsql;
CREATE TRIGGER trigger_update
BEFORE UPDATE ON data
FOR EACH ROW
EXECUTE PROCEDURE trigger_update_fn();
In SQL Server there isn’t a BEFORE UPDATE trigger, and you make do with an AFTER UPDATE trigger. The point is that it seems to me that the trigger should work if it’s applied after the update in PostgreSQL, but it doesn’t, of course.
The question is why is the correct trigger a BEFORE UPDATE trigger, and what should I use the AFTER UPDATE trigger for?

The BEFORE trigger can modify the row about to be inserted into the table (NEW). The AFTER trigger runs after the table has been modified, so any changes to NEW have no effect on the persisted data.

Related

Postgres: Update table sorting on new record inserted or removed

I'm trying to sort table automatically by specified row each time a new record is added (or removed or updated).
For that, I've create a function
CREATE FUNCTION pid_cluster_function()
RETURNS TRIGGER
LANGUAGE PLPGSQL
AS $$
BEGIN
-- trigger logic
cluster verbose public.pid using pid_idx;
END;
$$
and add a trigger
CREATE trigger pid_cluster_trigger
after INSERT or update or DELETE on public.pid
FOR EACH row
execute procedure pid_cluster_function();
but with adding a record
INSERT INTO public.pid (pid,pid_name) VALUES ('111','new 111');
I've received such an error
SQL Error [55006]: ERROR: cannot CLUSTER "pid" because it is being used by active queries in this session
Where: SQL statement "cluster verbose public.pid using pid_idx"
PL/pgSQL function pid_cluster_function() line 5 at SQL statement
What is the reason for this error?
Or is it possible to achieve sorting by adding or modifying the records in some other way?
Ok, thank you, everyone, in the comments. I see that my idea is not clever =)

Postgres: How to prevent anyone from updating a table?

I've been trying to stop any user from updating a table
I tried
REVOKE UPDATE ON TABLE NYAidCrimeMean FROM CURRENT_USER;
but when I try to update the table it still goes through, any pointers?
Well, I do not particular like triggers, but they have their uses. If you cannot find all the previous grants, you can get close here with one. See demo.
create or replace function no_no_no()
returns trigger
language plpgsql
as $$
begin
raise exception 'Cannot update table %s.', tg_table_name;
return null;
end;
$$;
create trigger No_no_no_NYAidCrimeMeanA
before update on NYAidCrimeMean
for each statement
execute function no_no_no();
If you really want to lock it down change before update to before insert or update or delete or truncate.
Of course a superuser can disable the trigger, then do whatever they want, but eventually get to where you must trust someone at some point.
The solution is as trivial as it is obvious: don't use superusers for anything but administative tasks.

Row Not Being Deleted After ON DELETE Trigger Runs

I am working in PostgreSQL 8.4 and have written a trigger function like so:
CREATE OR REPLACE FUNCTION otherschema.order_delete_log_procedure() RETURNS TRIGGER AS
$$
BEGIN
DELETE FROM otherschema.order_log AS thelog WHERE thelog.log_order_id=OLD.order_id;
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER order_deletion_log_trigger BEFORE DELETE ON public.order FOR EACH ROW EXECUTE PROCEDURE
otherschema.order_delete_log_procedure();
My problem is, the trigger fires perfectly (the trigger is deleting the log row), however the row that is supposed to be deleted from the table that is firing the trigger is not getting deleted (the order isn't getting deleted).
If I try to delete the order row manually, it just says that no rows were affected and it gives no error. Any thoughts?
Thanks!
Returning NULL from a BEFORE DELETE trigger aborts the delete operation. You should return old instead, or make it an AFTER DELETE trigger.

Trigger After Update In SQL Compiles But Does Not Seem To Fire

I have a trigger that should update a certain column, Points, after an update is made to a record in that same row. To do this, I have created a series of functions calc_extrapoint and calc_fieldgoalpoint to facilitate the process. Both of these functions work and return the correct values when run manually.
However, when I try to have the trigger fire after an update to the table, which most likely will happen with the columns ExtraPoint or FieldGoal the Points column is not updated as I'd expect.
For example iniitally in my table all values of each record starts as 0, 0, 0 for points, extra point, and field goal columns respectively. When I update the extra point column though to say 2, I expect the Points column to be 2. If I update again this time with field goal points to 2, I expect my Points column to be set to 8.
create or replace function calc_points() returns trigger as $$
begin
NEW."Points" := calc_extrapoint(NEW."ExtraPoint") + calc_fieldgoalpoint(NEW."FieldGoal");
return NEW;
end
$$ LANGUAGE plpgsql;
DROP TRIGGER calc_points on playerdata;
CREATE TRIGGER calc_points AFTER UPDATE ON playerdata
FOR EACH ROW EXECUTE PROCEDURE calc_points();
The trigger and functions all compile appropriately, but are not firing as expected. Is there something I'm missing to complete the action?
Modifying NEW in an AFTER trigger won't do anything. The row has already been written. Put a RAISE NOTICE 'Trigger fired'; in there; you'll get the notice. It's just that the trigger fires, but does nothing.
That's why we have BEFORE triggers. If you want to modify the row to be written to the table, you must use a BEFORE trigger.

Solving the mutating table problem in Oracle SQL produces a deadlock

Hey, I'm trying to create a trigger in my Oracle database that changes all other records except the one that has just been changed and launched the trigger to 0. Because I am updating records in the same table as the one that launched the trigger I got the mutating table error. To solve this, I put the code as an anonymous transaction, however this causes a deadlock.
Trigger code:
CREATE OR REPLACE TRIGGER check_thumbnail AFTER INSERT OR UPDATE OF thumbnail ON photograph
FOR EACH ROW
BEGIN
IF :new.thumbnail = 1 THEN
check_thumbnail_set_others(:new.url);
END IF;
END;
Procedure code:
CREATE OR REPLACE PROCEDURE check_thumbnail_set_others(p_url IN VARCHAR2)
IS PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
UPDATE photograph SET thumbnail = 0 WHERE url <> p_url;
COMMIT;
END;
I assume I'm causing a deadlock because the trigger is launching itself within itself. Any ideas?
Using an autonomous transaction for this sort of thing is almost certainly a mistake. What happens if the transaction that inserted the new thumbnail needs to rollback? You've already committed the change to the other rows in the table.
If you want the data to be transactionally consistent, you would need multiple triggers and some way of storing state. The simplest option would be to create a package with a collection of thumbnail.url%type then create three triggers on the table. A before statement trigger would clear out the collection. A row-level trigger would insert the :new.url value into the collection. An after statement trigger would then read the values from the collection and call the check_thumbnail_set_others procedure (which would not be an autonomous transaction).