Raising error in postgreSQL - postgresql

CREATE OR REPLACE FUNCTION msgfailerror() RETURNS trigger AS
' BEGIN
IF NEW.noces< new.first_column THEN
RAISE EXCEPTION 'cannot have a negative salary';
END IF;
return new;
END' LANGUAGE plpgsql
Trigger
create trigger msgfail before insert on first for each row
execute procedure msgfailerror()
Giving error:
syntax error at or near "cannot" LINE 5: RAISE
EXCEPTION 'cannot have a negative ...
I have almost one validation for each field of row. I want trigger to check all validations while insertion is being done and, raise error log afterwards once for all. Should I use raise exception on raise notice ?
For example:
Insert into first (first_column, noces,dob) values ('4545','75','545')
I am checking noces is less than first_column, for the same row i want to check if dob > 80 and if first_column is integer and raise error for all validations. Thanks in advance

The quoting is wrong. It's easier to use dollar quotes $$:
CREATE OR REPLACE FUNCTION msgfailerror()
RETURNS trigger AS
$$
BEGIN
IF NEW.noces< new.first_column THEN
RAISE EXCEPTION 'cannot have a negative salary';
END IF;
return new;
END;
$$
LANGUAGE plpgsql;
But on the other hand, what's wrong with a check constraint?

there is nothing wrong with you the only thing is using quotes
please change :
RAISE EXCEPTION 'cannot have a negative salary';
to:
RAISE EXCEPTION ''cannot have a negative salary'';
'' is different from "
'' = two single quotes

I agree with Frank that you could better use constraints, but you call it validation. Validation is typically done before insertion takes place. If you would like to validate insertions, you could use functions instead of triggers or constraints.
When you would write functions is the answer to your question to raise exceptions or notices that as long as there has been no write action a notice would suffice (together with leaving the function). Once there has been a write to the database, do you have to use exceptions as they perform a rollback.
Like this:
CREATE OR REPLACE FUNCTION field_validate(p_int int) RETURNS boolean AS $$
DECLARE
i_id int;
BEGIN
if p_int > 10 then
raise notice 'should be smaller then 10';
return false;
end if;
insert into tbl_numbers(firstfield) values(p_int) returning id in i_id;
insert into tbl_fake(nofield) values(i_id);
return true;
EXCEPTION
WHEN raise exception THEN
return false;
END;
$$ LANGUAGE plpgsql;

Related

Check function with IF statement in POSTGRESQL

I have 10 functions, all 10 return '1' if the function has no errors and '0' if function has errors. I want to create another function witch calls all this functions and which checks it out if the functions return 0 or 1. After that, I want to run this function in linux crontab and the function's output (some text from if conditions) to go in a log file.
I'm not sure if I can check this functions like this. Thanks for your time!
CREATE OR REPLACE FUNCTION public.test_al1()
RETURNS text
LANGUAGE 'plpgsql'
COST 100
AS $BODY$
DECLARE
BEGIN
select public.test();
if (select public.test()) = 1 then
RAISE NOTICE 'No errors'
else
RAISE NOTICE 'Errors'
end if;
END
$BODY$;
You were missing a return point for your query and there were also a few ; missing. I'm not really sure what you want to achieve with this function, since you declared the function would return TEXT and there is no RETURN statement.
One option would be to not return anything and use RAISE as you've been doing - keep in mind that the intention of RAISE (without INFO, EXCEPTION, etc.) alone is rather to report error messages:
CREATE OR REPLACE FUNCTION public.test_al1() RETURNS VOID LANGUAGE plpgsql
AS $BODY$
BEGIN
IF public.test() = 1 THEN
RAISE 'Errors';
ELSE
RAISE 'No errors';
END IF;
END
$BODY$;
.. or alternatively you can simplify it a bit by returning the message as TEXT in the RETURN clause.
CREATE OR REPLACE FUNCTION public.test_al1() RETURNS TEXT LANGUAGE plpgsql
AS $BODY$
DECLARE res TEXT DEFAULT 'No errors';
BEGIN
IF public.test() = 1 THEN
res := 'Errors';
END IF;
RETURN res;
END
$BODY$;
Further reading: CREATE FUNCTION

How to return Select * INTO STRICT variable from function

I am trying to return a single row of a table in a function and it is important that if there isn't any row or more then one there is an exception raised. I am using SELECT * INTO STRICT for that reason. However, I can't seem to find the correct way to return. Was wondering if someone knew the correct way of returning the single row?
I know I can separate the check and get it work but was curious if there was a way to get this to work.
CREATE OR REPLACE FUNCTION GameInfo.getAllPlayerInfo(
playerID GameInfo.Player.PID%Type)
RETURNS TABLE (PID VARCHAR,Name VARCHAR, Email VARCHAR,Password VARCHAR) AS
$$
DECLARE
found_player GameInfo.Player%ROWTYPE;
BEGIN
SELECT * INTO STRICT found_player FROM GameInfo.Player WHERE Player.PID =
$1;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE EXCEPTION 'PID % not found';
WHEN TOO_MANY_ROWS THEN
RAISE EXCEPTION 'PID % not unique';
RETURN found_player;
END;
$$ LANGUAGE plpgsql
STABLE
SECURITY DEFINER;
Your function is declared as returns table, so in PL/pgSQL you need to use return next... to return a row.
That return statements needs to be moved before the exception handling. Currently your function does not return anything, if a row is found.
You can also simplify the function declaration by using returns setof so you don't need to specify all columns.
CREATE OR REPLACE FUNCTION GameInfo.getAllPlayerInfo(playerID GameInfo.Player.PID%Type)
RETURNS setof gameinfo.player
AS $$
DECLARE
found_player GameInfo.Player%ROWTYPE;
BEGIN
SELECT *
INTO STRICT found_player
FROM GameInfo.Player
WHERE Player.PID = playerid;
RETURN NEXT found_player; --<< here
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE EXCEPTION 'PID % not found';
WHEN TOO_MANY_ROWS THEN
RAISE EXCEPTION 'PID % not unique';
END;
$$
LANGUAGE plpgsql
STABLE
SECURITY DEFINER;
Note that set returning functions need to be used in the FROM clause:
select *
from gameinfo.getallplayerinfo(1);

PostgreSQL: Return a trigger error (raise exception) in JSON format

I'm trying to find out is it possible in ANY way to exit a trigger procedure (return/raise exception, whatever) with a JSON output. I want to do something like this:
CREATE FUNCTION users_do_before_insert() RETURNS TRIGGER AS
$$
BEGIN
IF (NEW.username = '' OR NEW.full_name = '' OR NEW.email = '') THEN
RAISE EXCEPTION json_build_object('error', 'All fields are mandatory.');
END IF;
RETURN NEW;
END;
$$
LANGUAGE 'plpgsql';
CREATE TRIGGER users_bi_trigger
BEFORE INSERT ON users
FOR EACH ROW
EXECUTE PROCEDURE users_do_before_insert();
So, the expected output would be:
{"error" : "All fields are mandatory."}
I would appreciate any help with this. Thanks in advance!
RAISE statement requires format string or USING clause
RAISE EXCEPTION '%', json_build_object(..);
RAISE EXCEPTION USING MESSAGE=json_build_object(..);

Matching regular expression in an if statement in PostgreSQL

I have written the following function:
CREATE FUNCTION Validate_Password_Hash() RETURNS trigger AS $$
BEGIN
IF (NEW.Password ~* '^[a-f0-9]{64}$')
THEN
RAISE EXCEPTION 'The password hash is invalid! Please use SHA-256. You tried to insert: %', NEW.Password;
END IF;
RETURN NEW;
END;
$$ LANGUAGE PLPGSQL;
And I attach it to a trigger to fire before an INSERT. However, even if a provide a valid SHA-256 hash, the exception still gets raised, which implies the hash doesn't match the pattern. What could possibly be the problem here?
Reverse the logic.
You are raising exception if the hash is valid.
Try this:
CREATE FUNCTION Validate_Password_Hash() RETURNS trigger AS $$
BEGIN
IF (NEW.Password !~* '^[a-f0-9]{64}$')
THEN
RAISE EXCEPTION 'The password hash is invalid! Please use SHA-256. You tried to insert: %', NEW.Password;
END IF;
RETURN NEW;
END;
$$ LANGUAGE PLPGSQL;

How to return an integer from a plpgsql function AND rollback every modifications?

My application uses pl/pgsql functions that return integers.
The returned integer is used as a return code, to distinguish between different errors.
For example, if a function that insert datas returns -1, it means that some datas exist already and this is forbidden to try to insert the same data again. But if it returns -2, it means something else. That way the application knows the error and can display a useful error message to the user.
My problem now is that i want, at some points in the function, to return immediately when i detect an error, and rollback everything done so far in the function. If i use "raise exception", it will rollback, but not return an integer. If i use "return -1;", it will return an integer, but not rollback modifications. So i'm stuck, because obviously i can't do both
Here's a phony example function:
CREATE OR REPLACE FUNCTION create_flight_and_passengers(
_date timetamp,
_name text,
_passengers integer[]
)
RETURNS integer
LANGUAGE plpgsql
AS $$
DECLARE
return_code integer;
BEGIN
INSERT INTO flights
VALUES (_name);
SELECT function_1(_date, _passengers) into return_code;
if (return_code = -1) then
-- [1] rollback everything done since beginning of function
-- create_flight_and_passengers() and return -1
end if;
SELECT function_2(_date, _passengers) into return_code;
if (return_code = -1) then
-- [2] rollback everything done since beginning of function
-- create_flight_and_passengers() and return -2
end if;
return 0;
END;
$$;
In [1] and [2] i could use raise exception to rollback, but when i do this i don't have a returned integer.
I could set a local variable in [1] and [2], then raise exception, and in EXCEPTION do tests on this variable to know where the exception come from, but this is bloated, there must be something better !
I'm not even sure you can rollback effects of a function you have called and that has terminated (function_1() and function_2() in my example)
Any ideas ?
This is a pretty bizarre thing to want to do. If you really need to, you could do it like this:
DECLARE
retval integer;
BEGIN
retval := 0;
BEGIN
... make my changes ...
IF (... is something wrong? ...) THEN
RAISE EXCEPTION SQLSTATE '0U001';
END IF;
EXCEPTION
WHEN '0U001' THEN
retval := -1;
END;
END;
The concept here is that a BEGIN ... EXCEPTION block defines a subtransaction. A RAISE EXCEPTION within the block rolls back the subtransaction. We catch it at the outer level, preventing the exception from propagating outside the function and aborting the whole transaction.
See the PL/PgSQL documentation.