【问题标题】:How to change schema for recursive function如何更改递归函数的架构
【发布时间】:2019-11-01 10:47:35
【问题描述】:

作为 ETL 过程的一部分,我正在尝试更改递归函数的架构。喜欢

CREATE FUNCTION some_recursive()
 RETURNS some_type
 LANGUAGE sql
AS $function$ 
 -- do stuff
 some_recursive()
 --do more
$function$
;

我这样做是用

ALTER FUNCTION some_recursive() SET SCHEMA new_schema

这会正确更新,例如依赖视图,将它们从调用some_recursive() 更改为new_schema.some_recursive()。但是递归本身(在函数体内)没有更新,所以当函数被调用时,它会失败。 IE。函数定义后架构更改如下所示:

CREATE FUNCTION new_schema.some_recursive()
 RETURNS some_type
 LANGUAGE sql
AS $function$ 
 -- do stuff
 -- note the next line (no new_schema.-prefix)
 some_recursive()
 --do more
$function$
;

有没有办法改变递归函数的架构?

如果做不到这一点,我也许可以让功能维护者更改其实现。 有没有办法让函数调用类似“self”的东西(即隐式而不指定自己的名称)?

【问题讨论】:

    标签: postgresql etl data-warehouse


    【解决方案1】:

    函数中使用的search_path取决于调用函数的会话中设置的search_path。默认情况下,您可以通过更改用户来更改调用该函数的任何用户:

    ALTER USER some_user SET search_path TO new_schema,...;  -- you may also want public or others after new_schema
    

    或者,您可以通过稍微修改代码来更改函数中使用的 search_path:

    CREATE FUNCTION new_schema.some_recursive()
     RETURNS some_type
     LANGUAGE sql
     SET search_path TO new_schema -- this line changes search_path while inside the function.  It will be reset on function exit.
    AS $function$ 
     -- do stuff
     -- note the next line (no new_schema.-prefix)
     some_recursive()
     --do more
    $function$
    ;
    

    您也可以使用此处概述的 PG_CONTEXT:https://stackoverflow.com/a/41889304/895640 但这有点hacky...

    CREATE OR REPLACE FUNCTION recursive_test() RETURNS int AS $$
    DECLARE
      stack text;
      fcesig regprocedure;
    BEGIN
      GET DIAGNOSTICS stack = PG_CONTEXT;
      RAISE NOTICE 'stack: %', stack;
      fcesig := substring(stack from 'function (.*?) line');
      EXECUTE 'SELECT ' || fcesig;
    END;
    $$ LANGUAGE plpgsql
    ;
    
    CREATE SCHEMA test2;
    alter function recursive_test set schema test2;
    NOTICE:  stack: PL/pgSQL function test2.recursive_test() line 6 at GET DIAGNOSTICS
    NOTICE:  stack: PL/pgSQL function test2.recursive_test() line 6 at GET DIAGNOSTICS
    SQL statement "SELECT test2.recursive_test()"
    PL/pgSQL function test2.recursive_test() line 9 at EXECUTE
    NOTICE:  stack: PL/pgSQL function test2.recursive_test() line 6 at GET DIAGNOSTICS
    SQL statement "SELECT test2.recursive_test()"
    PL/pgSQL function test2.recursive_test() line 9 at EXECUTE
    SQL statement "SELECT test2.recursive_test()"
    PL/pgSQL function test2.recursive_test() line 9 at EXECUTE
    NOTICE:  stack: PL/pgSQL function test2.recursive_test() line 6 at GET DIAGNOSTICS
    SQL statement "SELECT test2.recursive_test()"
    PL/pgSQL function test2.recursive_test() line 9 at EXECUTE
    SQL statement "SELECT test2.recursive_test()"
    PL/pgSQL function test2.recursive_test() line 9 at EXECUTE
    ...
    

    【讨论】:

    • 这是一个很好的解决方法。一些注意事项:search_path 也可以使用ALTER DATABASE the_db SET search_path TO ... 在数据库级别(对于任何用户)进行设置。值得注意的是,要么只对新会话生效。影响当前会话调用SET search_path ...(即没有ALTER...
    • 另外,如果函数定义具有模式限定它的自引用,这将不起作用。
    • 我用另一种可行的方法编辑了我的回复,但我不确定我是否建议实际使用它...
    猜你喜欢
    • 2021-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-16
    • 1970-01-01
    • 2019-03-01
    相关资源
    最近更新 更多