POSTGRESQL Database Triggers anf functions - postgresql

I am trying to create a trigger in postgres that if you are trying to add an existing id within a customers table it will raise an error and won't allow you to do it.
Trigger Code:
create trigger id_check()
before insert on customers
for each row execute procedure duplicates()
Function:
create or replace function duplicates()
returns trigger as $BODY$
begin
if exists(select 1 from customers where id = new.id)
then raise notice 'cannot have a duplicate id'
return new;
end;
$BODY$ LANGUAGE plpgsql;
I keep getting errors either and I'm not understanding what's wrong? Any help would be great.

As indicated a unique constraint is the appropriate method to properly handle this. But if you insist on your trigger then then you must cleanup the syntax errors: need semi-colon after raise statement, and end if at conclusion of IF. Also, learn now to format your code.
create or replace function duplicates()
returns trigger as $BODY$
begin
if exists(select 1 from customers where id = new.id)
then raise notice 'cannot have a duplicate id'; --- added ;
end if; --- added line
return new;
end;
$BODY$ LANGUAGE plpgsql;

Related

How to re-create function with same name in postgres?

I need to re-create a group of functions but I don't want to check their parameters to use drop if there are functions with the same names but different parameters.
Is this possible to drop/recreate them only by name?
Or is this possible to catch exceptions, raise errors and continue to execute the transaction?
I'm trying to do it using
DO $$
BEGIN
BEGIN
CREATE OR REPLACE FUNCTION public.test(id integer)
RETURNS text[]
LANGUAGE plpgsql
AS $function$
begin
end;
$function$
;
EXCEPTION
WHEN duplicate_function THEN RAISE NOTICE 'already exists';
END;
END;
$$;
But It completes scripts quietly and does not raise any errors.
You are correct in that 42723 is raised when a named object already, However, it is not a named exception. Thus your exception handles does not recognized, so it takes no action. You can get what you want by directly referencing the SQLSTATE and your error code.
DO $$
BEGIN
BEGIN
CREATE FUNCTION public.test(id integer)
RETURNS text[]
LANGUAGE plpgsql
AS $function$
begin
end;
$function$
;
EXCEPTION
WHEN SQLSTATE '42723' THEN RAISE NOTICE 'already exists';
END;
END;
$$;
Raise notice sends the text following to sysout, which is often not accessible in a production system. You might want to change to raise exception.

I Want to stop an update for one column in relation using trigger function.But instead of not updating,code the code is updating the records

I have written for preventing a update using trigger function in pgsql.
Here lamtapproved is the column for which i want to stop an update
create or replace function Prevent_update() returns trigger as $$
begin
if new.lamtapproved=old.lamtapproved
then raise exception 'Update is not allowed';
end if;
return new;
end;
$$ language 'plpgsql'
Using the above trigger function i want to prevent the updates in the

A trigger that detects that an UPDATE wouldn't change a row

I wrote the following trigger:
CREATE FUNCTION trig_func() RETURNS trigger AS $$
BEGIN
IF NEW = OLD
THEN -- update would do nothing, doing something...
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER trig BEFORE UPDATE ON some_table
FOR EACH ROW EXECUTE PROCEDURE trig_func();
It makes it clear what I'd like to achieve, but what is the proper thing to put in place of NEW = OLD?
The is distinct from operator can compare complete rows and will handle nulls correctly.
So you want
if new is not distinct from old then
...
end if;

Prevent deletion of table records for one user and allow deletion for another in postgresql

I have a requirement that i have to disable deletion of table records for all users except one user i.e user1. So for that i have used triggers which is as follows.
CREATE OR REPLACE FUNCTION prevent_deletion() RETURNS trigger AS $$
declare
cur_user varchar(30);
BEGIN
Select current_user into cur_user;
IF cur_user != 'user1' THEN
RAISE EXCEPTION 'You cannot delete records from this table!';
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
The trigger is preventing from deleting table records for users other than user1 which is fine but its not working for user user1. I mean its not deleting the table records for user1.
Where am i wrong in my code?
Thanks in advance.
A trigger executed before delete should return old.
CREATE OR REPLACE FUNCTION prevent_deletion()
RETURNS trigger AS $$
BEGIN
IF current_user != 'user1' THEN
RAISE EXCEPTION 'You cannot delete records from this table!';
END IF;
RETURN OLD;
END;
$$ LANGUAGE plpgsql;

Alias a table (read/write view)

I'm wondering if it's possible in postgresql to create an additional name for a table, such that the table can be referred to by either its new alias or the original name?
Like adding a view for the table, but which writes to the underlying table when you update or insert on the 'view'.
The purpose of this is to be able to rename a table without having to update all of the db clients at once (no downtime).
You can use Postgres RULES to do this.
Check out this article.
#CraigRinger mentions this answer:
CREATE VIEW alias_as_view as SELECT * FROM original_table;
CREATE FUNCTION write_to_underlying_table() RETURNS TRIGGER AS $$
BEGIN
IF TG_OP = 'INSERT' then
raise notice 'INSERT trigger, NEW = [%]', NEW;
ELSIF TG_OP = 'UPDATE' then
raise notice 'UPDATE trigger, OLD = [%], NEW = [%]', OLD, NEW;
ELSE
raise notice 'DELETE trigger, OLD = [%]', OLD;
END IF;
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER view_writable_trigger INSTEAD OF INSERT OR UPDATE OR DELETE
ON alias_as_view FOR EACH ROW EXECUTE PROCEDURE write_to_underlying_table();
I've rejected it for the moment as e.g. a failing query:
INSERT INTO alias_as_view VALUES ('existing_key', 'some_value');
Seems to have executed successfully, even though the actual INSERT statement on original_table failed due to a unique key violation.