I have a question, what is missing or wrong in the RETURN statement that it keeps crashing error 2F005
I am creating a table to log errors
drop table if exists public.funkcja_x;
create table public.funkcja_x
(
error_alert text
);
I am creating function
drop function if exists public.test();
create or replace function public.test()
returns text as
$body$
declare
v_error text;
begin
-- i intentionally create a table from a table that doesn't exist to force an error
drop table if exists public.tabela_final;
create table public.tabela_final as
select * from public.tabela_posrednia;
return 'OK';
exception when others then
v_error := SQLERRM;
insert into public.funkcja_x (error_alert) values (v_error);
end;
$body$
language plpgsql volatile cost 100;
alter function public.test() owner to postgres;
evokes:
select public.test();
and gets error:
BŁĄD: osiągnięto koniec funkcji, brakuje instrukcji RETURN
Stan SQL: 2F005
Kontekst: funkcja PL/pgSQL test()
You are missing RETURN statement. Any non void function in PL/pgSQL should to return data. Your function uses RETURNS text but returns nothing. Probably miss RETURN 'false'.
You can use boolean instead text as return type.
Hmmm I found a solution, you have to replace TEXT to VOID and then it works :)
but thank you for your interest and sorry for the spam :)
Related
How do i create a Procedure that returns a set of rows from a table?
or is it even possible to return a tabular result set with procedure.
I tried adding returns setof students like you do in a function and table(id int) but it doesn't work.
SAMPLE CODE:
CREATE OR REPLACE PROCEDURE getStudents()
LANGUAGE plpgsql
AS $$
BEGIN
SELECT * FROM STUDENTS
COMMIT;
RETURN;
END;
$$;
I can call it but it says query has no destination for result data
Procedures aren't meant to return data, that's what functions are for.
You can use a plain SQL function for this, no need for PL/pgSQL:
CREATE OR REPLACE funct get_students()
returns setof student
LANGUAGE sqö
AS $$
select *
from students;
$$;
Then use it like a table:
select *
from get_students();
There is also no need for a commit.
Try to use function instead of procedure. I usually use this.
You need to create a ctype for fetching the data.
Put whatever columns you have to fetch from STUDENTS table.
Syntax is as follows:
CREATE TYPE students_data_ctype AS
(
column_1 int4,
column_2 varchar(100),
column_3 varchar(500)
)
Then create a funcction :
CREATE
OR
REPLACE
FUNCTION PUBLIC.getStudents
()
RETURNS SETOF students_data_ctype AS $BODY$ DECLARE res
students_data_ctype;
BEGIN
FOR res IN
SELECT
column_1,
column_2,
column_3
FROM
STUDENTS
LOOP RETURN NEXT res;
END LOOP;
END
; $BODY$ LANGUAGE 'plpgsql'
GO
Function call :
Select * FROM getStudents()
Taddaaa! You will get your data.
I'm looking for some help with a SQL function I am defining under pgAdmin3 for PostGreSQL.
It is a simple function supposed to calculate a ratio given a certain id but when I try to add the function, I get an error message.
Here is the code for the function:
CREATE OR REPLACE FUNCTION data.func_net_exposure(id_fund_arg text)
RETURNS real AS
$BODY$
DECLARE
net_exposure real;
AUM smallint;
BEGIN
AUM := (SELECT sum(cash_fund_total) from main.main_cash where id_fund = id_fund_arg);
net_exposure := (SELECT ROUND(sum(exposure_eur)/(100*AUM)) from main.main_inventory where id_fund = id_fund_arg);
return net_exposure;
END;
$BODY$
And here is the error message I get when I try to add the function:
An error has occurred:
13:13:54: Error: ERROR: return type mismatch in function declared to
return real DETAIL: Function's final statement must be SELECT or
INSERT/UPDATE/DELETE RETURNING. CONTEXT: SQL function
"func_net_exposure"
Any clue on how to solve this error?
The system thinks the function's language is SQL and therefore expects the last statement to be a SELECT or ... RETURNING. The language should be PL/pgSQL. Add a language specification like:
CREATE OR REPLACE FUNCTION data.func_net_exposure(id_fund_arg text)
RETURNS real AS
$BODY$
...
$BODY$
LANGUAGE PLpgSQL;
I am creating a trigger that runs a check raises an exception if it passes. To do this I need to use a dynamic call because I only have the table name as a string. I am using PostgreSQL but I can't figure out how there execute command works. When I do this:
CREATE OR REPLACE FUNCTION bleep() RETURNS table(id INT) AS $bleep$
BEGIN
RETURN QUERY EXECUTE 'SELECT (id) from Applicant';
END;
$bleep$ LANGUAGE plpgsql;
SELECT * from bleep();
It works perfectly and I get back a table of id's from Applicant. But when I do this:
CREATE OR REPLACE FUNCTION bleep() RETURNS BOOLEAN AS $bleep$
BEGIN
IF (EXISTS (EXECUTE 'SELECT (id) from Applicant')) THEN
RETURN TRUE;
ELSE
RETURN FALSE;
END IF;
END;
$bleep$ LANGUAGE plpgsql;
It tells me:
ERROR: syntax error at or near "EXECUTE" Position: 87
This is just a toy example I made to figure out how this works and I have read lots of docs and guides. If I can figure out this toy example I can make the full trigger work since I tried it with hardcoding a table name. How can I make this work?
CREATE OR REPLACE FUNCTION bleep() RETURNS BOOLEAN AS $bleep$
DECLARE
res bool;
BEGIN
EXECUTE 'SELECT exists (select 1 from Applicant)' INTO res;
return res;
END;
$bleep$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION bleep() RETURNS BOOLEAN AS $bleep$
BEGIN
return query EXECUTE 'SELECT exists (select 1 from Applicant)';
END;
$bleep$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION bleep() RETURNS
BOOLEAN AS $bleep$
BEGIN
IF (EXISTS (SELECT id from Applicant)) THEN
RETURN TRUE;
ELSE
RETURN FALSE;
END IF;
END;
$bleep$ LANGUAGE plpgsql;
I misunderstood your question.
How about this?
CREATE FUNCTION bleep(integer) RETURNS boolean
AS 'select case when count(*) = 0 then false else true end from Applicant where id = $1;'
LANGUAGE SQL
IMMUTABLE
RETURNS NULL ON NULL INPUT;
You can test by SQLFiddle: http://sqlfiddle.com/#!15/33954/1
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 just starting out on functions in PostgreSQL, and this is probably pretty basic, but how is this done?
I would like to be able to use the following in a function:
PERFORM id_exists();
IF FOUND THEN
-- Do something
END IF;
where the id_exists() function (to be used with SELECT and PERFORM) is:
CREATE OR REPLACE FUNCTION id_exists() RETURNS int AS $$
DECLARE
my_id int;
BEGIN
SELECT id INTO my_id
FROM tablename LIMIT 1;
RETURN my_id;
END;
$$ LANGUAGE plpgsql;
Currently, even when my_id does not exist in the table, FOUND is true, presumably because a row is still being returned (a null integer)? How can this be re-written so that an integer is returned if found, otherwise nothing at all is?
Your assumption is correct, FOUND is set to TRUE if the last statement returned a row, regardless of the value (may be NULL in your case). Details in the manual here.
Rewrite to, for instance:
IF id_exists() IS NOT NULL THEN
-- Do something
END IF;
Or rewrite the return value of your function with SETOF so it can return multiple rows - or no row! Use RETURN QUERY like I demonstrate. You can use this function in your original setting.
CREATE OR REPLACE FUNCTION id_exists()
RETURNS SETOF int LANGUAGE plpgsql AS
$BODY$
BEGIN
RETURN QUERY
SELECT id
FROM tablename
LIMIT 1;
END;
$BODY$;
Or, even simpler with a language SQL function:
CREATE OR REPLACE FUNCTION id_exists()
RETURNS SETOF int LANGUAGE sql AS
$BODY$
SELECT id
FROM tablename
LIMIT 1;
$BODY$;