I need to re-create a group of functions but I don't want to check their parameters to use drop if there are functions with the same names but different parameters.
Is this possible to drop/recreate them only by name?
Or is this possible to catch exceptions, raise errors and continue to execute the transaction?
I'm trying to do it using
DO $$
BEGIN
BEGIN
CREATE OR REPLACE FUNCTION public.test(id integer)
RETURNS text[]
LANGUAGE plpgsql
AS $function$
begin
end;
$function$
;
EXCEPTION
WHEN duplicate_function THEN RAISE NOTICE 'already exists';
END;
END;
$$;
But It completes scripts quietly and does not raise any errors.
You are correct in that 42723 is raised when a named object already, However, it is not a named exception. Thus your exception handles does not recognized, so it takes no action. You can get what you want by directly referencing the SQLSTATE and your error code.
DO $$
BEGIN
BEGIN
CREATE FUNCTION public.test(id integer)
RETURNS text[]
LANGUAGE plpgsql
AS $function$
begin
end;
$function$
;
EXCEPTION
WHEN SQLSTATE '42723' THEN RAISE NOTICE 'already exists';
END;
END;
$$;
Raise notice sends the text following to sysout, which is often not accessible in a production system. You might want to change to raise exception.
Related
Is there anything similar to setTimeout setTimeInterval in PostgreSQL which allows to execute piece of code (FUNCTION) at specified time interval?
As far as I know only thing that can execute a FUNCTION according to certain event is Triggers but it is not time based but operation driven (INSERT / UPDATE / DELETE / TRUNCATE)
While I could do this in application code, but prefer to have it delegated to database. Anyway I could achieve this in PostgreSQL? May be an extension?
Yes, there is a way to do this. It's called pg_sleep:
CREATE OR REPLACE FUNCTION my_function() RETURNS VOID AS $$
BEGIN
LOOP
PERFORM pg_sleep(1);
RAISE NOTICE 'This is a notice!';
END LOOP;
END;
$$ LANGUAGE plpgsql;
SELECT my_function();
This will raise the notice every second. You can also make it do other things instead of raising a notice.
OR
You can use PostgreSQL's Background Worker feature.
The following is a simple example of a background worker that prints a message every 5 seconds:
CREATE OR REPLACE FUNCTION print_message() RETURNS VOID AS $$
BEGIN
RAISE NOTICE 'Hello, world!';
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION schedule_print_message() RETURNS VOID AS $$
DECLARE
job_id BIGINT;
BEGIN
SELECT bgw_start_recurring_job(
'print-message',
'print_message',
'5 seconds'
) INTO job_id;
END;
$$ LANGUAGE plpgsql;
SELECT schedule_print_message();
I am trying to create a trigger in postgres that if you are trying to add an existing id within a customers table it will raise an error and won't allow you to do it.
Trigger Code:
create trigger id_check()
before insert on customers
for each row execute procedure duplicates()
Function:
create or replace function duplicates()
returns trigger as $BODY$
begin
if exists(select 1 from customers where id = new.id)
then raise notice 'cannot have a duplicate id'
return new;
end;
$BODY$ LANGUAGE plpgsql;
I keep getting errors either and I'm not understanding what's wrong? Any help would be great.
As indicated a unique constraint is the appropriate method to properly handle this. But if you insist on your trigger then then you must cleanup the syntax errors: need semi-colon after raise statement, and end if at conclusion of IF. Also, learn now to format your code.
create or replace function duplicates()
returns trigger as $BODY$
begin
if exists(select 1 from customers where id = new.id)
then raise notice 'cannot have a duplicate id'; --- added ;
end if; --- added line
return new;
end;
$BODY$ LANGUAGE plpgsql;
In my plpgsql procedure, I start with checking if primary key for the input table exists. If not I raise a notice and want to quit the procedure. Otherwise, I continue with the rest of procedure. I spent a bit of time searching online but no clear answer. Please note that I am referring to a procedure which doesn't return anything so I can't use RETURN.
You can use return.
create or replace procedure test(text)
language plpgsql as $$
begin
raise notice '%', $1;
return;
raise notice 'never executed';
end $$;
call test('hello');
NOTICE: hello
CONTEXT: PL/pgSQL function test(text) line 3 at RAISE
CALL
I am struggling to execute a PostgreSQL function. I am trying to read the documentation on the side but still no use. I am using Toad Extension for eclipse to develop/run the function
So far, this is what I have written
CREATE OR REPLACE FUNCTION dbName.function_name()
RETURNS VOID AS
$BODY$
DECLARE
x_cur CURSOR FOR select * from dbName.x;
x_row RECORD;
BEGIN
OPEN x_cur;
RAISE NOTICE 'Cursor opened';
LOOP
FETCH x_cur INTO x_row;
EXIT WHEN NOT FOUND;
END LOOP;
CLOSE x_cur;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
I executed the script and then ran select dbName.function_name(); in the sql worksheet and I don't see any output.
I remember writing functions on plsqldeveloper was so easy and interactive and i am struggling with PostgreSQL, could you guys help me getting a headstart.
I dont see any problem using pgAdmin.
The function return VOID, but the RAISE NOTICE show the message.
I simplify the function
CREATE OR REPLACE FUNCTION function_name()
RETURNS VOID AS
$BODY$
DECLARE
BEGIN
RAISE NOTICE 'Cursor opened';
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
And execute the function
SELECT function_name();
Explain me please, why I'm getting error here:
djabase=# CREATE or REPLACE FUNCTION upset(domain_name varchar)
RETURNS TABLE (id int, domain varchar(50)) AS $$
BEGIN
SELECT domain from separser_domains where domain=$1;
EXCEPTION
when sqlstate 'no_data' then
INSERT into separser_domains(domain) VALUES (domain_name);
END; $$
LANGUAGE 'sql' STABLE;
ERROR: syntax error at or near "SELECT"
LINE 4: SELECT domain from separser_domains where domain=$1;
You are using PLPGSQL syntax but declaring the function as SQL. This the reason, why the function fails with a SYNTAX ERROR. The language of the function is declared with the statement LANGUAGE and you declared it in the last line:
LANGUAGE 'sql' STABLE;
SQL functions do not support the BEGIN - END statement and exceptions trapping.
To fix it, simple change LANGUAGE 'sql' in LANGUAGE 'plpgsql'.
Some other considerations:
Catching a exception in this place is probably not necessary. Use the FOUND variable instead.
With the STABLE keyword, the function can not perform INSERT. Change STABLEto VOLATILE.
You declared RETURNS TABLE but the function does not return anything. Use RETURNS VOID instead.
Using SELECT and discarding the result is not allowed. Use PERFORM instead.
A valid version of your version could be this:
DROP FUNCTION IF EXISTS upset(varchar);
CREATE or REPLACE FUNCTION upset(domain_name varchar)
RETURNS VOID AS $$
BEGIN
PERFORM domain from separser_domains where domain=domain_name;
IF NOT FOUND THEN
INSERT into separser_domains(domain) VALUES (domain_name);
END IF;
RETURN;
END;
$$
LANGUAGE 'plpgsql' VOLATILE;