I've tried to encrypt a password in a PostgreSQL database by using a trigger but I can't get it to work, and I don't know where my mistake is.
Here is the code:
CREATE TABLE mms_user (
uid serial,
mail text NOT NULL,
passwd text NOT NULL,
usertype integer NOT NULL,
PRIMARY KEY (uid)
);
CREATE FUNCTION encrypt_password() RETURNS TRIGGER AS $$
BEGIN
NEW.passwd = digest(NEW.passwd, 'sha1');
RETURN NEW; END; $$LANGUAGE 'plpgsql';
CREATE TRIGGER encrypt_userdata AFTER INSERT ON mms_user EXECUTE PROCEDURE encrypt_password();
INSERT INTO mms_user values (default, 'who', 'me', 1);
It says this when executing:
ERROR: record "new" is not assigned yet
DETAIL: The tuple structure of a not-yet-assigned record is indeterminate.
CONTEXT: PL/pgSQL function encrypt_password() line 3 at assignment
How do I access the record I'm inserting if it's not with NEW?
Security and cryptographic considerations aside (see comments), to address your actual PL/pgSQL question:
The trigger function is basically ok. Some cleanup:
CREATE FUNCTION encrypt_password()
RETURNS TRIGGER AS
$func$
BEGIN
NEW.passwd := digest(NEW.passwd, 'sha1'); -- or some other function?
RETURN NEW;
END
$func$ LANGUAGE plpgsql; -- don't quote the language name
But to make it work, you have to make the trigger BEFORE INSERT:
CREATE TRIGGER encrypt_userdata
BEFORE INSERT ON mms_user
EXECUTE PROCEDURE encrypt_password();
I suggest the manual here and here.
Related
colleagues! I created 'product' table with the next query:
CREATE TABLE product (
id serial not null,
product_name text not null,
description varchar(50),
delivery_date timestamp,
warehouse jsonb
)
And I'm trying to use trigger before delete with the sort by list:
CREATE OR REPLACE FUNCTION product_delete_trigger()
RETURNS TRIGGER AS $$
BEGIN
IF (OLD.product_name IN ('Milk','Egg','Cheese'))
THEN
DELETE FROM product WHERE product_name = OLD.product_name;
ELSE
RAISE EXCEPTION
'Value out of list. Fix the product_delete_trigger() function!';
END IF;
RETURN NULL;
END;
$$
LANGUAGE plpgsql;
CREATE TRIGGER delete_product_trigger
BEFORE DELETE ON product
FOR EACH ROW EXECUTE PROCEDURE product_delete_trigger();
How I got it I need to use 'OLD' special parameter , but If I when I use it, I have an issue:
ERROR: ERROR: Stack depth limit exceeded
HINT: Increase the configuration parameter "max_stack_depth" (the current value is 2048 KB), first making sure that the OS provides sufficient stack size.
Is it possible to do this by this query?
DELETE FROM product where product_name = 'Cheese';
There is no point in running DELETE in your BEFORE trigger – that happens anyway if you let the database have its course. So all you have to do is throw an error if you are unhappy with the proceedings:
CREATE OR REPLACE FUNCTION product_delete_trigger()
RETURNS TRIGGER AS $$
BEGIN
IF ((OLD.product_name IN ('Milk','Egg','Cheese')) IS NOT TRUE)
THEN
RAISE EXCEPTION
'Value out of list. Fix the product_delete_trigger() function!';
END IF;
/* proceed with the DELETE */
RETURN OLD;
END;
$$
LANGUAGE plpgsql;
When a row is inserted or updated in a specific table (in this example it's the table called 'fpl'). How can I include the affected table and schema in the notification?
SQL as follows:
CREATE TRIGGER fpl_event
AFTER INSERT OR UPDATE ON fpl
FOR EACH ROW
EXECUTE PROCEDURE fpl_notify();
CREATE OR REPLACE FUNCTION fpl_notify()
RETURNS trigger AS $$
BEGIN
NOTIFY dbNotification, 'something got insereted in fpl!';
RETURN NULL;
END;
$$ LANGUAGE PLPGSQL;
Update:
CREATE OR REPLACE FUNCTION fpl_notify() RETURNS trigger
AS
$$
BEGIN
EXECUTE format('notify dbNotification, ''%s''', TG_TABLE_SCHEMA);
RETURN NULL;
END;
$$ LANGUAGE PLPGSQL;
read trigger special variables
I have two functions that return the good value. But when I call those functions inside of a trigger they always returns 0 instead of the good value.
The return type of those functions is real. The direct and dramatic consequence is that the trigger inserts wrong values in tables when it is called.
The function:
create or replace function get_remaining_hour(id_user_v integer,id_absence_v_type integer,id_year_v integer) returns real as
$BODY$
BEGIN
return (select sum(number_hour)
from remaining_absence_day
where id_user= $1
and id_absence_type=$2
and id_year=$3 );
END;
$BODY$
LANGUAGE 'plpgsql' ;
The trigger function (modified for testing!):
create OR REPLACE function update_absence() returns TRIGGER AS
$BODY$
DECLARE
old_number_hour real;
BEGIN
old_number_hour:=get_remaining_hour(3,2,8);
insert into debugging(col,val) values('old_number_hour', old_number_hour);
return null;
END;
$BODY$
LANGUAGE 'plpgsql' ;
The trigger definition:
drop trigger if exists update_absence on absence;
CREATE TRIGGER update_absence
after update of type,duration_hour,duration_day on absence
for each ROW
execute procedure update_absence();
The presented code should work.
It is particularly odd that you see 0 as result. If no matching row is found in remaining_absence_day, you would see NULL, not 0. But if you call the function with the same parameters in the same environment you should see the same result to begin with.
The remaining possible explanation I can think of: confusion with the schema search path. Like: you have a second instance of the function get_remaining_hour() or the table remaining_absence_day in a different schema. And you call the function with a different setting for search_path.
Did you run your comparison in the same session?
How does the search_path influence identifier resolution and the "current schema"
Or, since you work with an AFTER trigger: there might be other triggers on table absence that modify the table remaining_absence_day, which are fired before your trigger.
All other modifications I made are of cosmetic nature or minor simplifications.
CREATE OR REPLACE FUNCTION get_remaining_hour(id_user_v int
, id_absence_v_type int
, id_year_v int)
RETURNS real AS
$func$
BEGIN
RETURN (
SELECT sum(number_hour)
FROM remaining_absence_day -- referencing the right table? see search_path
WHERE id_user = $1
AND id_absence_type = $2
AND id_year = $3
);
END
$func$ LANGUAGE plpgsql STABLE; -- don't quote the language name
CREATE OR REPLACE FUNCTION update_absence()
RETURNS TRIGGER AS
$func$
BEGIN
INSERT INTO debugging(col, val)
VALUES('old_number_hour', get_remaining_hour(3,2,8)); -- hard coded only for testing?
RETURN null; -- only good for AFTER trigger
END
$func$ LANGUAGE plpgsql;
DROP TRIGGER IF EXISTS update_absence ON absence;
CREATE TRIGGER update_absence
AFTER UPDATE OF type, duration_hour, duration_day ON absence
FOR EACH ROW EXECUTE PROCEDURE update_absence();
I am learning triggers in PostgreSQL.
I have created a trigger function update_name():
CREATE OR REPLACE FUNCTION update_name()
RETURNS trigger AS
$BODY$
BEGIN
NEW.name := "ankit";
RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION update_name()
OWNER TO postgres;
My table user_table is:
CREATE TABLE user_table (
name character varying(20) NOT NULL,
password character varying(20),
email character varying(20),
gender character varying(20),
phone bigint,
CONSTRAINT user_table_pkey PRIMARY KEY (name)
);
and the trigger for the table is :
CREATE TRIGGER "change-name"
BEFORE INSERT OR UPDATE
ON user_table
FOR EACH ROW
EXECUTE PROCEDURE update_name();
when I am inserting data to my table using query:
INSERT INTO user_table(name, password, email, gender, phone)
VALUES ('aa', '9874', 'poi#ka.in', 'male', 8978987896);
I've got the error:
ERROR: column "ankit" does not exist
LINE 1: SELECT "ankit"
^
QUERY: SELECT "ankit"
CONTEXT: PL/pgSQL function update_name() line 3 at assignment
********** Error **********
ERROR: column "ankit" does not exist
SQL state: 42703
Context: PL/pgSQL function update_name() line 3 at assignment
What am I doing wrong?
This is about PostgreSQL syntax. I removed irrelevant references to pgAdmin from the question.
In Postgres, literal values (constants) are enclosed in single quotes: 'value'.
Double quotes are reserved for identifiers but optional as long as it consists of legal, lower-case letters: "Odd Name" vs. odd_name.
This is also the SQL standard. Start by reading the chapter "Lexical Structure" in the manual.
The ERROR has gone by changing just:
NEW.name := "ankit";
to
NEW.name := 'ankit';
Why is it so???
CREATE OR REPLACE FUNCTION update_name()
RETURNS trigger AS
$BODY$
BEGIN
RAISE NOTICE 'RECORD IS INSERTED %',NEW.name;
INSERT INTO user_table VALUES("ankit",NEW.password,NEW.email,NEW.gender,NEW.phone);
RETURN NEW;
end if;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION update_name()
OWNER TO postgres;
Try this out this will help you.
I have a trigger function I'm trying to have execute in Postgres.
It compiles and adds the trigger, however it does not insert the value into the table as I had hoped.
The function it uses looks like this:
CREATE OR REPLACE FUNCTION
calc_gnpDifference(n integer, o integer)
RETURNS NUMERIC AS $$
SELECT $1 ::numeric - $2::numeric AS gnpDifference;
$$ LANGUAGE SQL;
And the Trigger part:
CREATE OR REPLACE FUNCTION autoCalculate() RETURNS TRIGGER AS $$
BEGIN
IF NEW.gnp_old > NEW.gnp_old THEN
NEW.gnpDifference := calc_gnpDifference(NEW.gnp_old, NEW.gnp);
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
DROP TRIGGER insertDifference ON country;
CREATE TRIGGER insertDifference BEFORE INSERT ON country
FOR EACH ROW EXECUTE PROCEDURE autoCalculate();
However, when I insert data, the trigger does not update the gnpDifference field as I had hoped. Thoughts on why this might be happening?
Obviously this condition: IF NEW.gnp_old > NEW.gnp_old will never be true so the trigger will never have any effect.