I have a user-defined function in PostgreSQL 11.2 created as follows. It basically inserts values to two different tables:
CREATE OR REPLACE FUNCTION public.insertTest(
IN ID1 integer,
IN Value1 character varying,
IN Value2 character varying,
IN Value3 character varying,
IN Status character varying,
IN Active_Flag integer,
IN Stuff1 smallint,
IN stuff2 smallint)
RETURNS void
LANGUAGE 'plpgsql'
AS $BODY$
BEGIN
Insert into TableA
(TA_ID,
TA_Value1,
TA_Value2,
TA_Value3,
TA_Value4,
TA_Time,
TA_Flag)
values
(ID1,
Value1,
Value2,
Value3,
Status,
now(),
1);
Insert into TableB
(TA_ID,
TB_ID, Confidence, Sev_Rate,
Last_Update_Time, TB_Flag)
values
(currval('tablea_t_id_seq'), --TableA has an auto-increment field
Active_Flag, Stuff1, Stuff2,
now(),
0);
END;
$BODY$;
Now when I try to execute this function, the following does not works:
SELECT * FROM public.insertTest (
550, 'Test_Value1',
'Test_Value2', 'Test_Value3',
'DEL', 55, 1, 1)
and throws this error:
ERROR: function insertTest(integer, unknown, unknown, unknown, unknown, integer, integer, integer) does not exist
LINE 1: select insertTest(550,'Test_Value1', 'Test_...
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
But the following works:
SELECT * FROM public.insertTest (
550::integer, 'Test_Value1'::character varying,
'Test_Value2'::character varying, 'Test_Value3'::character varying,
'DEL'::character varying, 55::integer, 1::smallint, 1::smallint);
Can someone tell me why the 1st execution of the function does not work?
Can someone tell me why the 1st execution of the function does not work?
The exact answer is: Function Type Resolution.
The varchar columns are not the problem (unlike another answer suggests). String literals (with single quotes) are initially type unknown and there is an implicit conversion to varchar for that.
The int2 columns at the end are the "problem" (or rather, the mismatched input for those). The numeric literals 1 (without quotes!) are initially assumed to be type integer. And there is no implicit cast from integer (int4) to smallint (int2). See:
SELECT castsource::regtype, casttarget::regtype, castcontext
FROM pg_cast
WHERE castsource = 'int'::regtype
AND casttarget = 'int2'::regtype;
The manual about castcontext:
e means only as an explicit cast (using CAST or :: syntax). a means implicitly in assignment to a target column, as well as explicitly. i means implicitly in expressions, as well as the other cases
With an explicit cast, the function call succeeds:
SELECT * FROM pg_temp.insertTest (
550, 'Test_Value1',
'Test_Value2', 'Test_Value3',
'DEL', 55, int2 '1', int2 '1');
Or even just:
SELECT * FROM pg_temp.insertTest (
550, 'Test_Value1',
'Test_Value2', 'Test_Value3',
'DEL', 55, '1', '1');
Now, with added quotes, those are string literals, initially type unknown, and there is an implicit conversion to int2 for those.
db<>fiddle here
Closely related, with step-by-step explanation:
No function matches the given name and argument types
Is there a way to disable function overloading in Postgres
As you can see from the error message, PostgreSQL expects that you call function insertTest(integer, unknown, unknown, unknown, unknown, integer, integer, integer). All parameters of type character varying are not regarded as such and therefore the inputs will be cast to unknown.
You'll find an adequate explanation in this Stackoverflow post (look at the comments). Fortunately, you already have a potential solution by providing type declarations explicitly, at least for your character varying parameters.
Related
CREATE
OR REPLACE FUNCTION public.sp_production_snapshot(periodid integer, flagdc integer) RETURNS TABLE(
prod_period_id integer,
period character varying,
nosp character varying,
policy_no character varying,
policy_name character varying,
status_id integer,
pol_status character varying,
family_bisnis character varying,
tahun_ke integer,
year_comm integer,
payment integer,
plan_code character varying,
life_premium double precision,
rider_premium double precision,
extra_premium double precision,
total_premium double precision,
mop integer,
ccy_code character varying,
ccy_rate double precision,
post_date date,
commence_date date,
issue_date date,
stream_start_date date,
due_date date,
app_code character varying,
policy_cat character varying,
apcrd_a_amt double precision,
apcrd_b_amt double precision,
apcrd_d_amt double precision,
fyip_credit_amt double precision,
comm_npk_id integer,
comm_npk integer,
comm_npk_name character varying,
comm_rank_id integer,
comm_rank_code integer,
comm_rank_name character varying,
) LANGUAGE plpgsql AS $function$ BEGIN RETURN QUERY . . . . . . . . .
;
When I'm running it like this:
select * from sp_production_snapshot(865, 1);
I get the error:
SQL Error [42804]: ERROR: structure of query does not match function result type
Detail: Returned type bigint does not match expected type integer in column 1.
Where: PL/pgSQL function sp_production_snapshot(integer,integer) line 3 at RETURN QUERY
What is wrong with my script? I just migrated from gorm v1 to gorm v2. Before everything was fine, but many things break after moving to gorm v2.
Your statement after RETURN QUERY in the function body is likely selecting an identifier defined as bigint/bigserial type. It's not always safe to assume that this bigint value will map to your output integer because bigint can accommodate a higher values than integer can. From the documentation:
integer can be anything from -2147483648 to +2147483647
bigint can go from -9223372036854775808 to +9223372036854775807
bigserial can go from +1 to +9223372036854775807
If you stumbled upon a prod_period_id of 2147483648, you'd get an ERROR: integer out of range. To fix this you need to change the output types of your function accordingly:
DROP FUNCTION public.sp_production_snapshot(integer,integer);
CREATE FUNCTION public.sp_production_snapshot(
periodid integer, --should be bigint too if it corresponds to prod_period_id
flagdc integer)
RETURNS TABLE(
prod_period_id bigint,--change from integer to bigint
period character varying,
...
Depending on the structure of your RETURN QUERY and its sources, it's likely that it won't be the only output integer value you'll have to change to bigint. Note that you'll have to furst DROP then re-CREATE the function to avoid ERROR: cannot change return type of existing function thrown if you tried CREATE OR REPLACE instead.
If your output table follows the structure of some other table, instead of copying that into the function output table definition, you can use LIKE syntax:
DROP FUNCTION public.sp_production_snapshot(integer,integer);
CREATE FUNCTION public.sp_production_snapshot(
periodid integer,
flagdc integer)
RETURNS TABLE (LIKE your_table_schema.your_table_name) as
$function$
...
$function$ language plpgsql;
or RETURNS SETOF:
DROP FUNCTION public.sp_production_snapshot(integer,integer);
CREATE FUNCTION public.sp_production_snapshot(
periodid integer,
flagdc integer)
RETURNS SETOF your_table_schema.your_table_name language plpgsql as
$function$
...
$function$;
Also, if all you do is return a query, without using PL/pgSQL variables, loops, exception handling, you can stick with plain LANGUAGE SQL for better performance thanks to inlining. If all it does is look things up elsewhere, without modifying anything, it might be worth it to also make it STABLE and PARALLEL SAFE to enable better optimisation and execution planning.
DROP FUNCTION public.sp_production_snapshot(integer,integer);
CREATE FUNCTION public.sp_production_snapshot(
periodid integer,
flagdc integer)
RETURNS SETOF your_table_schema.your_table_name
STABLE PARALLEL SAFE LANGUAGE SQL AS
$function$
SELECT * FROM your_table_schema.your_table_name AS a
WHERE a.prod_period_id = $1 AND a.flagdc = $2;
$function$;
This function created as
CREATE OR REPLACE FUNCTION myschema._add1( vjson json, vtype smallint, vdate date)
returns void language 'plpgsql' cost 100 volatile security definer set search_path=myschema
as $$
begin
insert into myschema.tbl(cjson, ctype, cdate)
values(vjson, vtype, vdate);
end;
$$
Tbl definition:
create table myschema.tbl(cjson json, ctype smallint, cdate date)
Running the function
select myschema._add1('{"j":["j1", "j2"]}', 1, '2021-02-26') get
ERROR: function myschema._add1hidoc(unknown, integer, unknown) does not
exist HINT: No function matches the given name and argument types.
you might need to add explicit type casts.
select myschema._add1('{"j":["j1", "j2"]}'::json, 1, '2021-02-26'::date) get
ERROR: function myschema._add1hidoc(json, integer, date) does not
exist HINT: No function matches the given name and argument types.
you might need to add explicit type casts.
The only parameter you did not cast explicitly was the smallint parameter, but I am sure, that's the problem. I tried in the fiddle and it worked, after casting only the int to smallint:
select _add1('{"j":["j1", "j2"]}', 1::smallint, '2021-02-26')
I've created a stored procedure in PostgreSQL using DBeaver.
& I'm trying to insert data into table by calling the procedure from DBeaver.
But it's giving me an error
SQL Error [42883]: ERROR: function public.proc_insert_test(integer, unknown, unknown, unknown, unknown, timestamp with time zone, integer, integer, integer, timestamp with time zone) does not exist
Hint: No function matches the given name and argument types. You might need to add explicit type casts.
Position: 8
Procedure:
CREATE OR REPLACE FUNCTION public.proc_insert_test(p_brndcode integer,
p_brndname varchar(100),
p_brndsname varchar(100),
p_prdtype char(1),
p_discontinue char(1),
p_crddate date,
p_status integer,
p_recstat integer,
p_brndgrpseqno integer,
p_wefrom date)
RETURNS char
LANGUAGE plpgsql
AS $body$
BEGIN
Insert into arc_mmstbrndgroup(brndcode, brndname, brndsname, prdtype, discontinue, crddate, status, recstat, brndgrpseqno, wefrom)
values(p_brndcode, p_brndname, p_brndsname, p_prdtype, p_discontinue, p_crddate, p_status, p_recstat, p_brndgrpseqno, p_wefrom);
END;
$body$
;
Calling the procedure:
select public.proc_insert_test(123, 'Test2', 'Test2', 'T', 'T', now(), 1, 9, 1234, now());
What can be the issue?
I'm totally new to this.
Update:
Procedure calling:
select public.proc_insert_test(123, 'Test2'::varchar(100), 'Test2'::varchar(100), 'T'::char(1), 'T'::char(1), now(), 1, 9, 1234, now());
Error:
SQL Error [42883]: ERROR: function public.proc_insert_test(integer, character varying, character varying, character, character, timestamp with time zone, integer, integer, integer, timestamp with time zone) does not exist
Hint: No function matches the given name and argument types. You might need to add explicit type casts.
Position: 8
Postgres doesn't allow implicit conversion from timestamp to date data type. Attention - Postgres date type is different from Oracle's date type.
CREATE OR REPLACE FUNCTION public.test(v date)
RETURNS void
LANGUAGE plpgsql
AS $function$
BEGIN
RAISE NOTICE '%', v;
END;
$function$
postgres=# SELECT test(now());
ERROR: function test(timestamp with time zone) does not exist
LINE 1: SELECT test(now());
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
postgres=# SELECT test(current_date);
NOTICE: 2019-11-14
+------+
| test |
+------+
| |
+------+
(1 row)
postgres=# SELECT test(now()::date);
NOTICE: 2019-11-14
+------+
| test |
+------+
| |
+------+
(1 row)
The conversion from timestamp (result type of now() function) to date is losing conversions. It is not allowed by default. So you should to enforce it (by explicit casting), or you should to use pseudo constant current_date that returns date type, and there is not necessary any conversion.
I'm facing a strange behaviour when using a function to cast to composite type in Postgres 9.6.
I have declared a composite type "vector" as x,y,z - each of double precision as well as a cast as follows:
create type vector as(
x double precision,
y double precision,
z double precision
);
create cast (text as vector)
with function vector_from_text(text) as implicit;
Function vector_from_text looks like this:
create or replace function vector_from_text(text, out result vector) strict immutable language plpgsql as $$
declare
d double precision[];
begin
result := null;
if ($1 is null) then
return;
end if;
begin
with c1 as (
select $1::jsonb src
)
select row((src->>'x')::double precision, (src->>'y')::double precision, (src->>'z')::double precision)::vector
**into result** -- see below
from c1;
exception
when others then
d := translate($1, '()', '{}')::double precision[];
result := row(d[1], d[2], d[3])::vector;
end;
end$$
;
The function returns null on null, or a vector type for both input formats either a json-string like '{"x":0, "y":0, "z":0}' or a constructor expression like '(0,0,0)'.
The Problem:
For json-like inputs the functions returns the error
invalid input syntax for type double precision: "(0,0,0)"
as soon the select statement contains the line into result. If I remove this line or change the output variable from result to something of type text the functions works as expected.
Why is it not possible to assign an already to type vector casted value into a vector? Don't get it!
You do not need to (and in fact should not) create a cast from text. When you create a composite type you can cast a text to the type without any additional steps:
create type my_record as(
x int,
y int,
z int
);
select '(1,2,3)'::my_record;
my_record
-----------
(1,2,3)
(1 row)
If you want to use jsonb, create a cast from jsonb to the type:
create or replace function my_record_from_jsonb(obj jsonb, out result my_record)
strict immutable language plpgsql as $$
begin
select (obj->>'x')::int, (obj->>'y')::int, (obj->>'z')::int
into result;
end
$$;
create cast (jsonb as my_record)
with function my_record_from_jsonb(jsonb);
select '{"x":1, "y":2, "z":3}'::jsonb::my_record;
my_record
-----------
(1,2,3)
(1 row)
Do not try to interpret text literals in two different ways. If you want to use jsonb syntax, use jsonb type. Creating a custom implicit cast from text is particularly unreasonable. Read in the documentation::
It is wise to be conservative about marking casts as implicit. An overabundance of implicit casting paths can cause PostgreSQL to choose surprising interpretations of commands, or to be unable to resolve commands at all because there are multiple possible interpretations. A good rule of thumb is to make a cast implicitly invokable only for information-preserving transformations between types in the same general type category. For example, the cast from int2 to int4 can reasonably be implicit, but the cast from float8 to int4 should probably be assignment-only. Cross-type-category casts, such as text to int4, are best made explicit-only.
I have created a procedure like :
CREATE OR REPLACE FUNCTION insert_user_ax_register(
user_name character varying(50),
password character varying(300),
role_id character varying(10),
created_dt date,
status boolean,
email character varying(50),
join_date character varying(30),
phone_no bigint,
client_address character varying(200),
full_name character varying(100),
financial_year character varying(10))
RETURNS void
AS $BODY$
declare
begin
INSERT INTO ax_register(user_name,password,role_id,created_dt,status,email,join_date,phone_no,client_address,full_name,financial_year)
VALUES (user_name,password,role_id,now(),true,email,join_date,phone_no,client_address,full_name,financial_year);
end
$BODY$
LANGUAGE plpgsql VOLATILE
and tried to execute it like this:
SELECT * from insert_user_ax_register('debasrita','debasrita','client001',now(),'t','abc#gmail.com',now(),'ctc','debasrita','2014-15',9090909090);
but it throws the following error :
ERROR: function insert_user_ax_register(unknown, unknown, unknown, timestamp with time zone, unknown, unknown, timestamp with time zone, unknown, unknown, unknown, bigint) does not exist
SQL state: 42883
Hint: No function matches the given name and argument types. You might need to add explicit type casts.
Character: 16
Please help me out on this. I am new to pgsql and not able to find out any solution from google. I am using pgsql 9.1.3
May I know what is the correct way to achieve my objective?
The error message tells you what you need to be looking for:
"No function matches the given name and argument types"
As the function name seems correct, it can only be the parameters you are passing. So write down which value is passed for which parameter:
'debasrita' --> user_name character varying(50)
'debasrita' --> password character varying(300)
'client001' --> role_id character varying(10)
created_dt date --> now()
status boolean, --> 't'
email varchar(50) --> 'abc#gmail.com'
join_date varchar(30) --> now() << first error: now() is not a character constant
phone_no bigint --> 'ctc' << second error: 'ctc' is not a bigint
client_address varchar(200) --> 'debasrita'
full_name varchar(100) --> '2014-15'
financial_year varchar(10) --> 9090909090 << third error: 9090909090 is not a character literal
So you need to either adjust the parameter types, e.g. define join_date as date, not as varchar or adjust the values that you pass for each parameter.
And finally you need to call the function like this:
SELECT insert_user_ax_register(...);
rather than select * from ...
If you are using pgAdmintool just right click on the function or Stored Proc under a schema and select properties and then paramaeters .Now insert the value which you wannna insert.