How to find if a function exists in PostgreSQL?
Solution 1
Yes, you cannot to find functions in pg_class
because functions are stored on system table pg_proc
postgres-# \df
List of functions
Schema | Name | Result data type | Argument data types | Type
--------+--------------------+------------------+----------------------+--------
public | foo | integer | a integer, b integer | normal
public | function_arguments | text | oid | normal
(2 rows)
Query for list of custom functions based on pg_proc
is simply
postgres=# select p.oid::regprocedure
from pg_proc p
join pg_namespace n
on p.pronamespace = n.oid
where n.nspname not in ('pg_catalog', 'information_schema');
oid
-------------------------
foo(integer,integer)
function_arguments(oid)
(2 rows)
Most simply and fastest tests on functions existence are casting (without parameters) to regproc or regprocedure (with parameters):
postgres=# select 'foo'::regproc;
regproc
---------
foo
(1 row)
postgres=# select 'foox'::regproc;
ERROR: function "foox" does not exist
LINE 1: select 'foox'::regproc;
^
postgres=# select 'foo(int, int)'::regprocedure;
regprocedure
----------------------
foo(integer,integer)
(1 row)
postgres=# select 'foo(int, text)'::regprocedure;
ERROR: function "foo(int, text)" does not exist
LINE 1: select 'foo(int, text)'::regprocedure;
^
or you can do some similar with test against pg_proc
postgres=# select exists(select * from pg_proc where proname = 'foo');
exists
--------
t
(1 row)
postgres=# select exists(select *
from pg_proc
where proname = 'foo'
and function_arguments(oid) = 'integer, integer');
exists
--------
t
(1 row)
where:
CREATE OR REPLACE FUNCTION public.function_arguments(oid)
RETURNS text LANGUAGE sql AS $function$
select string_agg(par, ', ')
from (select format_type(unnest(proargtypes), null) par
from pg_proc where oid = $1) x
$function$
or you can use buildin functions:pg_get_function_arguments
p.s. trick for simply orientation in system catalog. Use a psql
option -E
:
[pavel@localhost ~]$ psql -E postgres
psql (9.2.8, server 9.5devel)
Type "help" for help.
postgres=# \df
********* QUERY **********
SELECT n.nspname as "Schema",
p.proname as "Name",
pg_catalog.pg_get_function_result(p.oid) as "Result data type",
pg_catalog.pg_get_function_arguments(p.oid) as "Argument data types",
CASE
WHEN p.proisagg THEN 'agg'
WHEN p.proiswindow THEN 'window'
WHEN p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype THEN 'trigger'
ELSE 'normal'
END as "Type"
FROM pg_catalog.pg_proc p
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace
WHERE pg_catalog.pg_function_is_visible(p.oid)
AND n.nspname <> 'pg_catalog'
AND n.nspname <> 'information_schema'
ORDER BY 1, 2, 4;
**************************
List of functions
Schema | Name | Result data type | Argument data types | Type
--------+--------------------+------------------+----------------------+--------
public | foo | integer | a integer, b integer | normal
public | function_arguments | text | oid | normal
(2 rows)
Solution 2
I think the easiest way would be to use pg_get_functiondef()
.
If it returns something, the function is there, otherwise the function does not exist:
select pg_get_functiondef('some_function()'::regprocedure);
select pg_get_functiondef('some_function(integer)'::regprocedure);
The drawback is that it will produce an error if the function isn't there instead of simply returning an empty result. But this could e.g. be overcome by writing a PL/pgSQL function that catches the exception and returns false instead.
Solution 3
Based on @PavelStehule answer this is how I am checking this in my scripts (using postgres exceptions and available exception codes)
DO $_$
BEGIN
BEGIN
SELECT 'some_schema.some_function(text)'::regprocedure;
EXCEPTION WHEN undefined_function THEN
-- do something here, i.e. create function
END;
END $_$;
Pavel V.
I'm a beginning expert on computer applications in archaeology - especially GIS (ArcGIS, QGIS) and databases (PostgreSQL, MySQL), but I also dabble in making websites (html/css and I learn php and JavaScript). He on SO, I'm sort of a "noob pioneer", asking stupid questions that other noobs wanted to know but are afraid to ask themselves. I hope I'll be able to share information about my native language here on SE.
Updated on July 09, 2022Comments
-
Pavel V. almost 2 years
Unlike tables or sequences, user-defined functions cannot be found through pg_class. There are questions on how find a list of all functions to delete or grant them, but how to find an individual function (with known name and argument types) is not self-evident from them. So how to find whether a function exists or not?
EDIT: I want to use it in a function, in automated manner. Which solution is the best performance-wise? Trapping errors is quite expensive, so I guess the best solution for me would be something without the extra step of translating error to false, but I might be wrong in this assumption.
-
Pavel V. almost 10 yearsWhich of these approaches is best to use in a function (i.e. with taking cost of handling the errors into account)?
-
Pavel Stehule almost 10 yearsIt depends - exception have some cost, but you access a system cache directly, what can be faster than query to system tables. So if you can handle exception, then more simply (and preferable) is casting to regproc* method, else you have to use test over pg_proc. Both methods should be fast enough - se use what is more comfortable for you.
-
Pavel V. almost 10 yearsOK. I tried the casting approach and it works fine unless the function is overloaded. For overloaded functions, is there any trick to test them easily, or is checking pg_proc better?
-
Pavel Stehule almost 10 yearsFunction signature should be unique, so casting to regprocedure should work too.
-
Pavel V. almost 10 yearsI missed the "regprocedure" part of your answer. It works now. Thank you, +1 and accepted.
-
pratpor over 4 yearsWorks well for my use case. Thanks.