是否有可能找到PostgreSQL函数之间的依赖关系?

时间:2016-03-29 14:18:03

标签: sql postgresql

我正在使用PostgreSQL 9.2.10

假设您有2个PostgreSQL函数,'called_function'和'caller_function',第二个调用第一个函数。恰好:

CREATE FUNCTION called_function () RETURNS varchar AS
$BODY$
BEGIN
  RETURN 'something';
END;

CREATE FUNCTION caller_function () RETURNS varchar AS
$BODY$
BEGIN
  RETURN called_function ();
END;

现在,使用SQL并只知道函数名称,我想知道'caller_function'是否调用了其他函数。或者,如果某个其他函数调用了'called_function'。有可能吗?

我试图获取函数的OID(假设它是'123')然后我查看 pg_depend 表:

SELECT * FROM pg_catalog.pg_depend dep WHERE dep.objid = 123 OR dep.objsubid = 123 OR dep.refobjid = 123 OR dep.refobjsubid = 123 OR dep.refobjsubid = 123;

但它只找到 pg_language pg_namespace 依赖项。没什么。

3 个答案:

答案 0 :(得分:0)

请查看表格pg_proc,例如:

select nspname,proname,prosrc from pg_proc join  pg_namespace nsp on (pronamespace=nsp.oid) where prosrc like '%called_function%'

答案 1 :(得分:0)

我在定义函数时遇到了同样的问题,并且由于依赖关系,它不起作用。然后我通过在命令之前添加此命令解决了我的问题

SET check_function_bodies = false;

希望能帮助别人

答案 2 :(得分:0)

在一般情况下是不可能的;但是受限(受限域)解决方案是完全可行的---并可能足以满足您的需求。

(其中最明显的)局限性

  • 如果将被调用方(要调用的函数)的名称指定为带引号的标识符,则失败(错误否定)。
  • 如果将被叫方的名称作为参数传递,则失败(错误否定)。
  • 如果在运行时从关系中读取了被叫方的名称,则失败(错误否定)。
  • 如果被叫者的名字是由令牌组成的,则失败(否定否定)。
  • 如果被叫方的姓名与原义相同,则失败(误报)。
  • 如果多行注释中存在被叫方名称,则失败(误报)。
  • 不考虑函数重载。
  • 不考虑通过触发器调用的功能。
  • 不考虑根据查询重写规则调用的函数。
  • 不考虑查询重写规则的影响。
  • 不了解使用非解释PL(如C)编写的函数。

样本输出

Your routine... | ...calls these routines:
---------------------------------+-------------------------------------------------
create_silo_indexes | {get_config__f_l__ea_silo,subst_silo_id}
demux__id_creat_thread | {}
grow__sensor_thhourly | {containing_hhour_t_begin}

SQL

WITH routine_names AS (
    SELECT DISTINCT(Lower(proname)) AS name                              --#0
    FROM pg_proc
    WHERE proowner = To_Regrole(current_role)
)
SELECT
    name AS "Your routine...",
    Array_Remove(                                                        --#8
        Array(                                                           --#7
            SELECT Unnest(                                               --#5
                String_To_Array(                                         --#4
                    Regexp_Replace(                                      --#3
                        Regexp_Replace(                                  --#2
                            Lower(PG_Get_Functiondef(To_Regproc(name)))  --#1
                            , '--.*?\n', '', 'g'
                        )
                        , '\W+', ' ', 'g'
                    )
                    , ' '
                )
            )
            INTERSECT                                                    --#6
            SELECT name FROM routine_names
            ORDER BY 1
        )
        , name
    ) AS "...calls these routines:"
FROM
    routine_names;

工作原理

  • #0 收集所有可能是调用方和/或被调用方的例程的名称。无论如何我们都无法正确处理重载的函数,因此只需DISTINCT即可避免以后的麻烦; SQL除了区分引号的标识符外,不区分大小写,而引号标识符我们也不会打扰,因此我们只使用Lower()来简化以后的比较。
  • #1 PG_Get_Functiondef()提取CREATE FUNCTIONCREATE PROCEDURE命令的完整文本。同样,Lower()
  • #2 去除单行注释。请注意,懒惰的(非贪婪的)*?量词:常用的*量词(如果在此处使用)将删除所有后续行中的第一个单行注释 plus
  • #3 用空格替换字母和数字以及_以外的所有字符。请注意+量词:它确保2个以上连续的已删除字符被1个空格代替。
  • #4 按空格分成数组;该数组包含SQL语法,文字,数字和包括例程名称在内的标识符。
  • #5 将数组嵌套到行集中。
  • #6 INTERSECT,带有例程名称;结果将仅包含例程名称。
  • #7 将行集转换为数组。
  • #8 由于输入是CREATE FUNCTION f ...命令的完整文本,因此提取的例程名称显然将包含f本身;因此我们用Array_Remove()将其删除。


(SQL已在PostgreSQL 12.1上测试)