如何查找 PostgreSQL 中是不是存在函数?

Posted

技术标签:

【中文标题】如何查找 PostgreSQL 中是不是存在函数?【英文标题】:How to find if a function exists in PostgreSQL?如何查找 PostgreSQL 中是否存在函数? 【发布时间】:2014-07-16 06:25:35 【问题描述】:

与表或序列不同,用户定义的函数无法通过pg_class 找到。关于how find a list of all functions to delete 或grant 他们有一些问题,但是如何找到一个单独的函数(具有已知的名称和参数类型)并不是不言而喻的。那么如何判断一个函数是否存在呢?

编辑:我想以自动方式在函数中使用它。哪种解决方案在性能方面最好?捕获错误非常昂贵,所以我想对我来说最好的解决方案是没有将错误转换为错误的额外步骤,但我可能在这个假设上是错误的。

【问题讨论】:

为它们查询pg_proc,组成参数类型的oidvector。或查询information_schema.routines 我澄清说我需要在函数中使用它 - 请参阅我的编辑段落。 【参考方案1】:

是的,您无法在pg_class 中找到函数,因为函数存储在系统表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)

根据pg_proc查询自定义函数列表很简单

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)

对函数存在的最简单和最快的测试是将(不带参数)强制转换为 regproc 或 regprocedure(带参数):

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;
               ^

或者你可以对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)

地点:

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$

或者你可以使用内置函数:pg_get_function_arguments

附言在系统目录中简单定位的技巧。使用psql 选项-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)

【讨论】:

这些方法中哪一种最适合在函数中使用(即考虑到处理错误的成本)? 这取决于 - 异常有一些成本,但您直接访问系统缓存,这比查询系统表更快。因此,如果您可以处理异常,那么更简单(并且更可取)是强制转换为 regproc* 方法,否则您必须在 pg_proc 上使用测试。这两种方法都应该足够快 - 请使用对您来说更舒适的方法。 好的。我尝试了强制转换方法,除非函数重载,否则它工作正常。对于重载的函数,有什么技巧可以轻松测试它们,还是检查 pg_proc 更好? 函数签名应该是唯一的,所以转换为 regprocedure 也应该起作用。 我错过了您答案的“regprocedure”部分。现在可以了。谢谢,+1 并接受。【参考方案2】:

我认为最简单的方法是使用pg_get_functiondef()

如果有返回,则函数存在,否则函数不存在:

select pg_get_functiondef('some_function()'::regprocedure);
select pg_get_functiondef('some_function(integer)'::regprocedure);

缺点是如果函数不存在会产生错误,而不是简单地返回空结果。但这可以例如可以通过编写一个捕获异常并返回 false 的 PL/pgSQL 函数来克服。

【讨论】:

非常适合我的用例。谢谢。【参考方案3】:

根据@PavelStehule 的回答,这就是我在脚本中检查的方式(使用postgres exceptions 和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 $_$;

【讨论】:

【参考方案4】:

聚会迟到了, 但它可能是这样的(如果您不使用结果,请不要使用select 而不是perform,否则您会收到抱怨它的错误:

错误:查询没有结果数据的目的地

所以下面的代码可以工作:

DO $$
BEGIN
    BEGIN
        perform pg_get_functiondef('some_function()'::regprocedure);
        raise notice 'it exists!';
    EXCEPTION WHEN undefined_function THEN
        raise notice 'Does not exist';
    END;
END $$;

【讨论】:

以上是关于如何查找 PostgreSQL 中是不是存在函数?的主要内容,如果未能解决你的问题,请参考以下文章

PostgreSQL 如何查找并删除重复数据

PostgreSQL 如何查找并删除重复数据

如何在 PostgreSQL 中查找重复记录

如何查找 jQuery 中是不是存在具有特定 id 的 div?

Postgresql 10 plpgsql 测试列是不是存在于记录变量中

Javascript在调用之前查找函数/类是不是存在