Handle empty value '' on function numeric variable - postgresql

I'm trying to handle empty '' values in FUNCTION variable.
What should be the correct way to return nothing when calling the function with empty value like below
SELECT *
FROM metadata.fn_get_id('mea', 'sau', '');
DROP FUNCTION IF EXISTS metadata.fn_get_id(VARCHAR, VARCHAR, NUMERIC);
CREATE OR REPLACE FUNCTION metadata.fn_get_id(a1 CHARACTER VARYING, b2 CHARACTER VARYING,
c3 NUMERIC DEFAULT 0
) RETURNS INT
LANGUAGE plpgsql
AS
$$
DECLARE
linked_id INT;
BEGIN
EXECUTE
'SELECT linked_id::INT FROM ' || $1 || '_region
WHERE 1=1 AND iso=upper(' || QUOTE_LITERAL($2) || ') AND id = '|| $3 ||' limit 1;'
INTO linked_id;
RETURN linked_id;
END
$$;
-- TEST LINK_ID 1213506417 (PASS)
SELECT *
FROM metadata.fn_get_id('mea', 'sau', 414803422);
-- TEST Null (PASS)
SELECT *
FROM metadata.fn_get_id('mea', 'sau');
-- TEST empty (FAILS ... HOW to Handle)
SELECT *
FROM metadata.fn_get_id('mea', 'sau', '');

Make c3 function argument type text default null and check for empty string first thing in the function body.
create or replace function metadata.fn_get_id(a1 text, b2 text, c3 text default null)
RETURNS integer language plpgsql as
$$
declare
-- your declarations
begin
if nullif(c3, '') is null then
return null;
end if;
-- your function body
$$;
Call:
SELECT *
FROM metadata.fn_get_id('mea', 'sau', 414803422::text);
Btw the function in the example is injection prone.

Simply call the function like this:
metadata.fn_get_id('mea', 'sau', nullif('', ''))
So that an empty string is replaced with NULL.

Related

Use parameter inside subquery

How can i use my parameters inside a subquery with ' '? (Postgres v.10)
create or replace function test(p_1 character varying, p_2 character varying)
returns table (id integer, total integer, fruit character varying)
LANGUAGE plpgsql
AS $$
begin
return query
Select * from dblink(
'host=myhost
user=myuser
password=mypw
dbname=mydb',
'select id,total,fruit from fruits
where fruit in (p_1,p_2)') as x(id integer,total integer,fruit varchar);
end;
$$
If i call the function
select * from test('apple','orange')
I get this ERROR: colum "p_1" and "p_2" does not exist..
Instead of saying p_1 it's possible to call parameters with $ signs or something. I don't know if that's the real approach but i can't find any documentation about it anywhere?
You can try this (not tested) :
return query
Select * from dblink(
'host=myhost
user=myuser
password=mypw
dbname=mydb',
'select id,total,fruit from fruits
where fruit in (' || p_1 || ',' || p_2 || ')') as x(id integer,total integer,fruit varchar);

postgresql dynamic query

I need to replace schema and table name by parameters in following function (that is currently working perfectly):
CREATE OR REPLACE FUNCTION public.my_function_119()
RETURNS integer
LANGUAGE plpgsql
AS $function$
DECLARE _check INTEGER;
BEGIN
SELECT SUM("length"/1000)
FROM public."National_Grid_multiline"
INTO _check;
RETURN _check;
END
$function$
I have tried following solution (and its numerous variations) :
CREATE OR REPLACE FUNCTION public.my_function_119(schema text, tablename text)
RETURNS INTEGER
LANGUAGE plpgsql
AS
$function$
DECLARE _check INTEGER;
BEGIN
RETURN
'(SELECT SUM((length/1000))::integer FROM ' || schema || '."' || tablename || '")::integer INTO _check' ;
RETURN _check;
END
$function$
but keep running into following error code :
psycopg2.errors.InvalidTextRepresentation: invalid input syntax for type integer: "(SELECT SUM((length/1000))::integer FROM public."National_Grid_multiline")::integer INTO _check"
CONTEXT: PL/pgSQL function my_function_119(text,text) while casting return value to function's return type
Why is this not working ? The 'length' column contains float values.
You have to use dynamic SQL, because you cannot use a parameter for an identifier.
Also, make sure to avoid SQL injection by using format rather than concatenating strings:
EXECUTE
format(
'SELECT SUM((length/1000))::integer FROM %I.%I',
schema,
table_name
)
INTO _check';
You can try this :
CREATE OR REPLACE FUNCTION public.my_function_119(schema text, tablename text)
RETURNS INTEGER
LANGUAGE plpgsql
AS
$function$
DECLARE
res integer ;
BEGIN
EXECUTE E'
(SELECT SUM((length/1000))::integer INTO res FROM ' || schema || '."' || tablename || '"):: integer' ;
RETURN res ;
END ;
$function$

Postgres SQL function with null argument produces null for simple case/when/else

Please explain why I get:
select reducer('a', null);
-- null ???
when:
CREATE or replace FUNCTION reducer(varchar, varchar)
RETURNS varchar AS
$$
SELECT case
when $1 = 'DEL' or $2 = 'DEL' then 'DEL'
when $1 = 'READ' or $2 = 'READ' then 'READ'
else 'NEW'
end;
$$ LANGUAGE 'sql' STRICT;
select reducer('a', 'b');
-- 'NEW'
That is because you defined the function as STRICT (which is the same as RETURNS NULL ON NULL INPUT). Since one of the arguments is NULL, the function is not even called, and NULL is returned.
If you don't want that, run
ALTER FUNCTION reducer(varchar, varchar)
CALLED ON NULL INPUT;

plpgsql function creates sequences for row based tenancy?

Trying to create a function that looks for sequence with particular name if does not exist should create it. Then returns function value of sequence. Part of function that does not seem to be working is where it tests if sequence already exists. Below is code for function
CREATE OR REPLACE FUNCTION public."tenantSequence"(
vtenantid integer,
vtablename character)
RETURNS bigint AS
$BODY$DECLARE
vSeqName character varying;
vSQL character varying;
BEGIN
select ('t' || trim(to_char(vtenantid,'0000')) || vtablename) INTO vSeqName;
if not exists(SELECT 0 FROM pg_class where relkind = 'S' and relname = vSeqName )
then
vSQL := 'create sequence '||vSeqName||';';
execute vSQL;
ELSE
return 0;
end if;
return nextval(vSeqName) * 10000 + vtenantid;
END$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION public."tenantSequence"(integer, character)
OWNER TO postgres;
Problem was case as mentioned by a_horse_with_no_name
changed line assign vSeqName to the following
vSeqName := lower('t' || trim(to_char(vtenantid,'0000')) || vtablename);
Now function works as expected.

Structure of query does not match function result type, RETURNS TABLE

I need a simple function to return dynamic set of columns. I've found couple of examples on SO and end up with the following:
CREATE or replace FUNCTION getColumn(_column1 text, _column2 text, _column3 text, _table text)
RETURNS TABLE(cmf1 text, cmf2 text, cmf3 text) AS $$
BEGIN
RETURN QUERY EXECUTE
'SELECT '
|| quote_ident(_column1)::text || ' as cmf1,'
|| quote_ident(_column2)::text || ' as cmf2,'
|| quote_ident(_column3)::text || ' as cmf3'
' FROM '
|| quote_ident(_table);
END;
$$ LANGUAGE plpgsql;
I need this function to work only with varchar/text columns so I created this testing table:
create table test20130205 (
a text,
b text,
c varchar,
d text)
;
Finally, I can run some tests:
select * from getColumn('a','b','d','test20130205');
-- ok
select * from getColumn('a','b','c','test20130205');
-- error
ERROR: structure of query does not match function result type
DETAIL: Returned type character varying does not match expected type text in column 3.
CONTEXT: PL/pgSQL function getcolumn(text,text,text,text) line 3 at RETURN QUERY
It seems like type for column c (varchar) is checked before cast - this seems strange, but I guess I've missed something.
How can I fix my function?
(PostgreSQL 9.1)
In your current function, the casts to text do not apply to the output columns values, they apply to their names (the result of quote_ident).
The cast should be moved inside the query itself:
CREATE or replace FUNCTION getColumn(_column1 text, _column2 text, _column3 text, _table text)
RETURNS TABLE(cmf1 text, cmf2 text, cmf3 text) AS $$
BEGIN
RETURN QUERY EXECUTE
'SELECT '
|| quote_ident(_column1) || '::text as cmf1,'
|| quote_ident(_column2) || '::text as cmf2,'
|| quote_ident(_column3) || '::text as cmf3'
' FROM '
|| quote_ident(_table);
END;
$$ LANGUAGE plpgsql;