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;
Related
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);
I use trigger after the update and insert one table to synchronize one table on one server with a foreign table on a different server.
My problem is that different servers can be down and I need my functions to be able to handle that (not with error).
CREATE OR REPLACE FUNCTION public.gapless_seq_update_forein()
RETURNS trigger
LANGUAGE plpgsql
AS $function$
begin
update gapless_seq_b set drain=new.drain, end_batch=new.end_batch,
file_name=new.file_name
where seq=new.seq and lobid = new.lobid and neid = new.neid;
END IF;
return new;
end;
$function$
;
easy solution (that is for some reason hard to google)
CREATE OR REPLACE FUNCTION public.gapless_seq_update_forein()
RETURNS trigger
LANGUAGE plpgsql
AS $function$
begin
update gapless_seq_b set drain=new.drain, end_batch=new.end_batch,
file_name=new.file_name
where seq=new.seq and lobid = new.lobid and neid = new.neid;
return new;
exception when others THEN
-- Do nothing.
return new;
END;
$function$
;
note: my error is 08001 sqlclient_unable_to_establish_sqlconnection but for some reason it works only with "others"...
more here: https://www.postgresql.org/docs/9.4/plpgsql-control-structures.html
I have the following stored procedure or function defined in my Postgresql database:
CREATE OR REPLACE FUNCTION insert_val(int)
$body$
BEGIN
FOR i IN 1..10 LOOP
insert into test (val)
values($23);
END LOOP;
END;
$body$ Language 'plpgsql' VOLATILE;
I just want to insert this data inside of a loop, but I get always this error:
Syntaxfehler bei »begin«
Is maybe that I missed something in my function?
I don't understand the error message since it's not in English, but I can see a few problems in your code
CREATE OR REPLACE FUNCTION insert_val(IN val int) RETURNS VOID AS
$body$
BEGIN
FOR i IN 1..10 LOOP
insert into test (val)
values($23);
END LOOP;
END;
$body$ Language 'plpgsql' VOLATILE;
You were missing the return type, you were missing AS and you have forgotten to name the in argument.
You forgot
RETURNS void AS
between the first and the second line.
But that will only take care of the syntax. The $23 is clearly wrong since there are no 23 function arguments. Did you mean $1?
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;
How to raise error from PostgreSQL SQL statement if some condition is met?
I tried code below but got error.
CREATE OR REPLACE FUNCTION "exec"(text)
RETURNS text AS
$BODY$
BEGIN
EXECUTE $1;
RETURN $1;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
-- ERROR: syntax error at or near "raise"
-- LINE 1: raise 'test'
SELECT exec('raise ''test'' ') WHERE TRUE
In real application TRUE is replaced by some condition.
Update
I tried to extend answer to pass exception message parameters.
Tried code below but got syntax error.
How to pass message parameters ?
CREATE OR REPLACE FUNCTION exec(text, variadic )
RETURNS void LANGUAGE plpgsql AS
$BODY$
BEGIN
RAISE EXCEPTION $1, $2;
END;
$BODY$;
SELECT exec('Exception Param1=% Param2=%', 'param1', 2 );
You cannot call RAISE dynamically (with EXECUTE) in PL/pgSQL - that only works for SQL statements, and RAISE is a PL/pgSQL command.
Use this simple function instead:
CREATE OR REPLACE FUNCTION f_raise(text)
RETURNS void
LANGUAGE plpgsql AS
$func$
BEGIN
RAISE EXCEPTION '%', $1;
END
$func$;
Call:
SELECT f_raise('My message is empty!');
Related:
Generate an exception with a Context
Additional answer to comment
CREATE OR REPLACE FUNCTION f_raise1(VARIADIC text[])
RETURNS void
LANGUAGE plpgsql AS
$func$
BEGIN
RAISE EXCEPTION 'Reading % % %!', $1[1], $1[2], $1[3];
END
$func$;
Call:
SELECT f_raise1('the','manual','educates');
VARIADIC is not a data type, but an argument mode.
Elements have to be handled like any other array element.
To use multiple variables in a RAISE statement, put multiple % into the message text.
The above example will fail if no $3 is passed. You'd have to assemble a string from the variable number of input elements. Example:
CREATE OR REPLACE FUNCTION f_raise2(VARIADIC _arr text[])
RETURNS void
LANGUAGE plpgsql AS
$func$
DECLARE
_msg text := array_to_string(_arr, ' and '); -- simple string construction
BEGIN
RAISE EXCEPTION 'Reading %!', _msg;
END
$func$;
Call:
SELECT f_raise2('the','manual','educates');
I doubt you need a VARIADIC parameter for this at all. Read the manual here.
Instead, define all parameters, maybe add defaults:
CREATE OR REPLACE FUNCTION f_raise3(_param1 text = ''
, _param2 text = ''
, _param3 text = 'educates')
RETURNS void
LANGUAGE plpgsql AS
$func$
BEGIN
RAISE EXCEPTION 'Reading % % %!', $1, $2, $3;
END
$func$;
Call:
SELECT f_raise3('the','manual','educates');
Or:
SELECT f_raise3(); -- defaults kick in