I have the following function stored in a Postgres 15 database.
I use dbeaver to connect to the database.
CREATE OR REPLACE FUNCTION schema_name.function_name(
in input_user_id int2
)
RETURNS TABLE(
column_1 smallint,
column_2 character varying,
column_3 character varying,
column_4 timestamp with time zone,
column_5 timestamp with time zone,
column_6 character varying,
column_7 int2,
column_8 int2
)
LANGUAGE plpgsql
AS $function$
begin
return query
select *
from schema_name.table_name
where table_name.column_5 = input_user_id;
end;
$function$
;
If I run the query part directly on dbeaver, I get the expected results:
select * from schema_name.table_name where column_5 = 1;
If I run the function I get errors:
select * from schema_name.function_name(1);
SQL Error [42883]: ERROR: function schema_name.function_name(integer) does not exist Hint: No function matches the given name and argument types. You might need to add explicit type casts. Position: 15
All of these get me a different error:
select * from schema_name.function_name(int2 '1');
select * from schema_name.function_name(1::int2);
select * from schema_name.function_name(1::smallint);
SQL Error [42804]: ERROR: structure of query does not match function result type Detail: Returned type text does not match expected type smallint in column 7. Where: SQL statement "select * from schema_name.table_name where table_name.column_5 = input_user_id" PL/pgSQL function schema_name.function_name(smallint) line 3 at RETURN QUERY
I also typecasted to integer and got another error.
What am I doing wrong?
Note, I added the full list of columns since the error mentions the specific columns, but I didn't edited the error messages.
There is no implicit cast from
int4→int2(for good reasons). So you must pass an actualint2(int2 '1') or an untyped string literal ('1'). Detailed assessment and more options:More problems:
smallserialis not an actual data type. You must useint2(a.k.a.smallint) inRETURNS TABLE. See:Don't use
SELECT *when the function returns a list of columns. Use a matchingSELECTlist.Use a table alias and table-qualify all column names that might conflict with
OUTparameters. (All columns listed inRETURNS TABLEareOUTparameters effectively.)This would work:
Call:
If you truly want to return the whole row as defined by
schema_name.table_name, useRETURNS SETOF schema_name.table_nameinstead. Now it's ok to useSELECT *in the function body. Also, fewer naming collisions:Also demonstrating a simpler SQL function, which does the simple job.