Postgresql function return trigger - postgresql

I am having a problem with a trigger. I created a trigger and a function
for when performing an INSERT update a field in the same table.
Is returning:
Error: function "loss_func" in FROM has return type trigger that is
not supported LINE 1: SELECT * FROM table.loss_func ()
Function
CREATE OR REPLACE FUNCTION loss_func()
RETURNS trigger AS $loss_func$
BEGIN
NEW.dt_creation := to_char(now(), 'YYYY-MM-DD');
RETURN NULL;
END;
$loss_func$ LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION loss_func()
OWNER TO postgres;
Trigger
CREATE TRIGGER tgr_loss
AFTER INSERT ON loss
FOR EACH ROW
EXECUTE PROCEDURE loss_func();
What am I doing wrong?

A working version of your code.
- The trigger now fires BEFORE insert and updates the value of dt_creation and returns the NEW version of the record :
drop table loss;
create table loss (
id int ,
dt_created varchar);
CREATE OR REPLACE FUNCTION loss_func()
RETURNS trigger AS $loss_func$
BEGIN
NEW.dt_created := to_char(now(), 'YYYY-MM-DD');
RETURN NEW;
END;
$loss_func$ LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION loss_func()
OWNER TO postgres;
CREATE TRIGGER tgr_loss
BEFORE INSERT ON loss
FOR EACH ROW
EXECUTE PROCEDURE loss_func();
insert into loss(id) values(1);
Another solution that i can propose to avoid the usage of a trigger is to use a default value for dt_creation when you create the table (and use timestamp instead of storing the date as varchar) :
...
dt_creation timestamp default now(),
...
or you can alter your table to set the default value to now() :
alter table loss
alter column dt_creation set default now();

Related

Postgresql update timestamp trigger in inherited table

I used this example and it worked well when all my tables were in public schema.
But trigger hasn't been working since I separated tables into different schemas and applied inheriting.
Here is example of my structure:
CREATE SCHEMA common;
CREATE SCHEMA video;
CREATE TABLE common.file (
file_id SERIAL PRIMARY KEY,
url VARCHAR(255) NOT NULL,
mime_type VARCHAR(31) DEFAULT '' NOT NULL,
size INTEGER NOT NULL,
modified TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL
);
CREATE TABLE video.file (
width INTEGER NOT NULL,
height INTEGER NOT NULL,
local_path VARCHAR(255) DEFAULT '' NOT NULL
)
INHERITS (common.file);
CREATE FUNCTION common.update_modified()
RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
NEW.modified = now();
RETURN NEW;
END;
CREATE TRIGGER update_modified
BEFORE UPDATE ON common.file
FOR EACH ROW EXECUTE PROCEDURE common.update_modified();
When I do UPDATE common.file ... or UPDATE video.file ... field common.file.modified doesn't change itself. It seems trigger doesn't run, but I don't understand why.
What should I do to repair the behavior?
In described issue trigger is set only on common.file, so UPDATE common.file ... doesn't work if row inserted in video.file
Documentation says: INSERT always inserts into exactly the table specified
So trigger should be applied to both common.file and video.file.
-- Creating schemas and tables the same
-- Let function be in public scheme
CREATE FUNCTION update_modified()
RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
NEW.modified = now();
RETURN NEW;
END;
CREATE TRIGGER update_modified
BEFORE UPDATE ON common.file
FOR EACH ROW EXECUTE PROCEDURE update_modified();
CREATE TRIGGER update_modified
BEFORE UPDATE ON video.file
FOR EACH ROW EXECUTE PROCEDURE update_modified();
In that case when we update rows inserted either in common.file or in video.file corresponding trigger will call.

Dynamic Change Column Values with NEW in Trigger Function

Is it possible to dynamically change column values in NEW with a Trigger Function?
Triggers:
CREATE TRIGGER lowercase_username_on_insert_trigger BEFORE INSERT OR UPDATE ON users
FOR EACH ROW EXECUTE PROCEDURE lowercase_on_insert('username');
CREATE TRIGGER lowercase_email_on_insert_trigger BEFORE INSERT OR UPDATE ON users
FOR EACH ROW EXECUTE PROCEDURE lowercase_on_insert('email');
Trigger Function:
CREATE OR REPLACE FUNCTION lowercase_on_insert()
RETURNS trigger
AS $lowercase_on_insert$
BEGIN
-- e.g., NEW.username = LOWER(NEW.username)
-- -OR- NEW.email = LOWER(NEW.email)
EXECUTE FORMAT('NEW.%s = LOWER(NEW.%s);', TG_ARGV[0], TG_ARGV[0]);
RETURN NEW;
END
$lowercase_on_insert$ LANGUAGE plpgsql;
I get an ERROR: syntax error at or new "NEW" whenever I run an INSERT.
This is my table:
CREATE TABLE users (
id BIGSERIAL PRIMARY KEY,
username VARCHAR(55) NOT NULL UNIQUE,
email VARCHAR(120) NOT NULL UNIQUE
);
Change your Trigger function as below
CREATE OR REPLACE FUNCTION lowercase() RETURNS trigger AS $$
BEGIN
NEW.username = LOWER(NEW.username);
NEW.email = LOWER(NEW.email);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
and assign
CREATE TRIGGER tgrr BEFORE INSERT OR UPDATE ON users
FOR EACH ROW EXECUTE PROCEDURE lowercase();
OR
You can directly apply lower() function in Insert/Update like this
insert into users(username,email) values (lower('Jerry'),lower('JeRRY#mail.COM'));
update users set username=lower('JERRY'),email=lower('JERRY#MAIL.COM') where id =1

Infinite recursion detected when updating from function (psycopg2, python 2.7, postgres 9.3)

I have a simple table:
CREATE TABLE IF NOT EXISTS someTable (
row_id smallserial PRIMARY KEY,
name text NOT NULL,
creation_date timestamp with time zone DEFAULT current_timestamp,
last_updated_date timestamp with time zone DEFAULT current_timestamp,
created_by text DEFAULT "current_user"(),
last_updated_by text DEFAULT "current_user"()
);
with the following rule:
CREATE OR REPLACE RULE log_update_some_table AS
ON UPDATE TO someTable
DO ALSO
UPDATE someTable
SET last_updated_date = current_timestamp,
last_updated_by = current_user;
and a very simple function in plpgsql:
CREATE OR REPLACE FUNCTION test_update ()
RETURNS void AS $$
BEGIN
UPDATE someTable
SET name = 'test'
WHERE row_id = 1;
END;
$$ LANGUAGE plpgsql;
One would think the function would run just fine, but I get the following error:
psycopg2.ProgrammingError: infinite recursion detected in rules for relation "sometable"
CONTEXT: SQL statement "UPDATE someTable
SET name = 'test'
WHERE row_id = 1"
PL/pgSQL function test_update() line 3 at SQL statement
Why isn't this working and how do I fix it? Thanks!
So your update rule on someTable triggers an update on someTable which executes the rule which updates someTable which executes the rule...
I'd use a simple trigger instead, something like this:
create or replace function log_update_some_table() returns trigger as $$
begin
NEW.last_updated_date = current_timestamp;
NEW.last_updated_by = current_user;
return NEW;
end;
$$ language plpgsql;
create trigger log_update_some_table_trigger
before update on someTable
for each row execute procedure log_update_some_table();
should do the trick. That will modify the row before the update happens rather than adding another update (which triggers the recursion problem) to the queue.

Postgresql : insert record using trigger

CREATE TABLE users
(
id integer NOT NULL DEFAULT nextval('userseq'::regclass)
........
)
CREATE TABLE History
(
userid integer,
createdat timestamp with time zone
)
CREATE OR REPLACE FUNCTION recordcreatetime()
RETURNS trigger AS
$BODY$
BEGIN
NEW.createdAt = NOW();
RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
User and History has one-one relationship. How i can insert new record in History table before creating new user.
CREATE OR REPLACE FUNCTION recordcreatetime()
RETURNS trigger
language plpgsql
AS $$
DECLARE
BEGIN
INSERT INTO History values(new.id,NOW() );
RETURN NEW;
END;
$$;
and write trigger statement as
CREATE TRIGGER user_hist
BEFORE INSERT ON users
FOR EACH ROW EXECUTE function recordcreatetime() ;

Not able to access the Primary Key value in PostgreSQL Trigger Function

I am just started writing the PL/pgSQL Trigger function. I am having couple of tables called Student and Result. Student having the following columns. ID,name,subject,mark (ID is the primary key) and the Result table is having two columns like ID,Status
Whenever one record has added in the student table, I want to update the Result table by checking the mark in the Student table, If the mark entered is greater than 50 then one record should be inserted in the Result table with ID and Status = Pass and if it is less than 50 then status will be fail.
I have the following Trigger function to achieve this
CREATE OR REPLACE FUNCTION "UpdateResult"() RETURNS trigger AS $BODY$
BEGIN
IF NEW.mark < 50 THEN
INSERT INTO "Result" SELECT 92,'fail';
RETURN NEW;
ELSE
INSERT INTO "Result" SELECT 92,'pass';
RETURN NEW;
END IF;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE STRICT SECURITY DEFINER
COST 100;
ALTER FUNCTION "UpdateResult"() OWNER TO postgres;
CREATE TRIGGER "Result"
AFTER INSERT
ON "Student"
FOR EACH ROW
EXECUTE PROCEDURE "UpdateResult"();
By this function trigger has worked as expected since I have hard coded the primary key value.
But When I modify the SQL inside Trigger function like the following
INSERT INTO "Result" SELECT NEW.ID,'fail'; (or)
INSERT INTO "Result" SELECT NEW.ID,'pass';
It is throwing error like
> ***Record "new" has no field "id" Context : PL/pgSQL function
> "UpdateResult" line 3 at SQL statement***
Means it is able to take the values of non primary key values from NEW variable not the primary key value. Can any one please tell me is there a restriction in PL/pgSQL or Am I doing anything wrong !
Just a hint: why are you using quoted names? When doing this, you have to care about capitalisation.
See if this works:
CREATE OR REPLACE FUNCTION UpdateResult() RETURNS trigger AS $BODY$
BEGIN
IF NEW.mark < 50 THEN
INSERT INTO result (id, status) values (92,'fail');
RETURN NEW;
ELSE
INSERT INTO result (id, status) values (92,'pass');
RETURN NEW;
END IF;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE STRICT SECURITY DEFINER
COST 100;
ALTER FUNCTION UpdateResult() OWNER TO postgres;
CREATE TRIGGER Result
AFTER INSERT
ON Student
FOR EACH ROW
EXECUTE PROCEDURE UpdateResult();