Is it possible to cancel previous operations in a user defined function?
For example:
CREATE OR REPLACE FUNCTION transact_test () RETURNS BOOLEAN
AS $$
BEGIN
UPDATE table1 SET ...
UPDATE table2 SET ...
IF some_condition THEN
--Here is possible to cancel all above operations?
RETURN FALSE;
END IF;
RETURN TRUE;
END;
$$
LANGUAGE plpgsql;
Both answers so far are incorrect.
If you try to start a transaction or use a SAVEPOINT inside a plpgsql function you get an error message like this:
ERROR: cannot begin/end transactions in PL/pgSQL
HINT: Use a BEGIN block with an EXCEPTION clause instead.
CONTEXT: PL/pgSQL function "f_savepoint" line 6 at SQL statement
If you try a SAVEPOINT inside a plain SQL function:
ERROR: SAVEPOINT is not allowed in a SQL function
CONTEXT: SQL function "f_savepoint2" during startup
As the error message instructs, use a BEGIN block inside a plpgsql function instead. Your demo could look like this:
CREATE OR REPLACE FUNCTION transact_test(boolean)
RETURNS boolean AS
$func$
BEGIN -- start a nested BEGIN block
UPDATE t SET i = i+1 WHERE i = 1;
UPDATE t SET i = i+1 WHERE i = 3;
IF $1 THEN
RAISE EXCEPTION 'foo'; -- cancels all of the above
END IF;
RETURN TRUE;
EXCEPTION WHEN OTHERS THEN
RETURN FALSE;
-- do nothing
END
$func$ LANGUAGE plpgsql;
-> SQLfiddle demonstrating it all.
Related
I am creating a function that allow me to conditionally update specific columns in a table. However, I get an error indicating that there is a syntax error at or near "IF" when I try to run the following code. I'm a bit new to Postgres so it's quite possible. I can't understand some concept/syntax thing in Postgres. Can someone help me by pointing out the mistake I must be making?
CREATE OR REPLACE FUNCTION profiles.do_something(
p_id UUID,
p_condition1 BOOLEAN,
p_condition2 BOOLEAN,
p_condition3 BOOLEAN
)
RETURNS void AS $$
BEGIN
IF p_condition1 IS TRUE THEN
UPDATE tablename SET column1 = null WHERE member_id = p_id;
END IF;
IF p_condition2 IS TRUE THEN
UPDATE tablename SET column2 = null WHERE member_id = p_id;
END IF;
IF p_condition3 IS TRUE THEN
UPDATE tablename SET column3 = null WHERE member_id = p_id;
END IF;
END;
$$ LANGUAGE 'sql';
tl;dr $$ LANGUAGE 'plpgsql'
$$ LANGUAGE 'sql';
^^^^^
You're tell it to parse the body of the function as sql. In SQL, begin is a statement which starts a transaction.
create or replace function test1()
returns void
language sql
as $$
-- In SQL, begin starts a transaction.
-- note the ; to end the statement.
begin;
-- Do some valid SQL.
select 1;
-- In SQL, end ends the transaction.
end;
$$;
In SQL you wrote begin if ... which is a syntax error.
The language you're using is plpgsql. In plpgsql, begin is a keyword which starts a block.
create or replace function test1()
returns void
language plpgsql
as $$
-- In PL/pgSQL, begin starts a block
-- note the lack of ;
begin
-- Do some valid SQL.
select 1;
-- In PL/pgSQL, end ends the block
end;
$$;
I have to create a update procedure, so i created a function and given only below query
CREATE FUNCTION public.testf()
RETURNS boolean
LANGUAGE 'plpgsql'
AS $BODY$begin
update tt pp
set status = 'Ok'
return true;
end;$BODY$;
ALTER FUNCTION public.testf()
OWNER TO postgres;
returns error
ERROR: syntax error at or near "UPDATE" LINE 5: AS $BODY$UPDATE
return type I have given is int4range
What I am doing wrong
Please help
THanks
Pulling out my crystal ball, I see:
You created the function with LANGUAGE plpgsql.
You didn't surround the function body with BEGIN ... END;.
If your function is just a single SQL statement, use LANGUAGE sql.
Else, use the block-centered PL/pgSQL syntax properly.
You are missing an ; to end the UPDATE statement.
CREATE FUNCTION public.testf()
RETURNS boolean
LANGUAGE plpgsql
AS $BODY$
begin
update tt pp
set status = 'Ok'; --<< here
return true;
end;
$BODY$;
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
Is it possible to cancel previous operations in a user defined function?
For example:
CREATE OR REPLACE FUNCTION transact_test () RETURNS BOOLEAN
AS $$
BEGIN
UPDATE table1 SET ...
UPDATE table2 SET ...
IF some_condition THEN
--Here is possible to cancel all above operations?
RETURN FALSE;
END IF;
RETURN TRUE;
END;
$$
LANGUAGE plpgsql;
Both answers so far are incorrect.
If you try to start a transaction or use a SAVEPOINT inside a plpgsql function you get an error message like this:
ERROR: cannot begin/end transactions in PL/pgSQL
HINT: Use a BEGIN block with an EXCEPTION clause instead.
CONTEXT: PL/pgSQL function "f_savepoint" line 6 at SQL statement
If you try a SAVEPOINT inside a plain SQL function:
ERROR: SAVEPOINT is not allowed in a SQL function
CONTEXT: SQL function "f_savepoint2" during startup
As the error message instructs, use a BEGIN block inside a plpgsql function instead. Your demo could look like this:
CREATE OR REPLACE FUNCTION transact_test(boolean)
RETURNS boolean AS
$func$
BEGIN -- start a nested BEGIN block
UPDATE t SET i = i+1 WHERE i = 1;
UPDATE t SET i = i+1 WHERE i = 3;
IF $1 THEN
RAISE EXCEPTION 'foo'; -- cancels all of the above
END IF;
RETURN TRUE;
EXCEPTION WHEN OTHERS THEN
RETURN FALSE;
-- do nothing
END
$func$ LANGUAGE plpgsql;
-> SQLfiddle demonstrating it all.
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