如何在PL/pgSQL中创建嵌套函数?

Gre*_*ius 6 postgresql scope plpgsql postgresql-9.5

我想在PL/pgSQL中创建一个函数,其中包含几个嵌套(或内部)函数.通过这种方式,我可以将问题分解成更小的部分,但不能在此功能之外访问我的小部件.

是否可以在PL/pgSQL中执行此操作?如果是这样,怎么样?

Pav*_*ule 11

PLpgSQL 不支持嵌套函数。仿真没有任何意义,而且没有生产力(可能会对性能产生负面影响)。

  • 乍一看,kiwi 描述的模拟是有效的。我在较小的数据集上测试了它,看起来不错。然而,当使用较大的日期集时,它总是会失败并出现非常奇怪的锁定错误。我认为阅读本文的人最好不要尝试强制嵌套函数在 PL/pgSQL 中工作。 (4认同)
  • @GregoryArenius:我做了一些玩弄这个例子,每次调用函数“outer”时,它都会创建/替换函数“inner”(与“outer”函数在相同的范围内),因此会出现奇怪的错误。它根本不是“内部函数”,并且它也无法访问“外部”的内部作用域。 (2认同)

apt*_*ryx 8

试试吧:

CREATE OR REPLACE FUNCTION outer() RETURNS void AS $outer$
DECLARE s text;
BEGIN
  CREATE OR REPLACE FUNCTION inner() RETURNS text AS $inner$
  BEGIN
    RETURN 'inner';
  END;
  $inner$ language plpgsql;

  SELECT inner() INTO s;
  RAISE NOTICE '%', s;

  DROP FUNCTION inner();
END;
$outer$ language plpgsql;
Run Code Online (Sandbox Code Playgroud)

在postgres 9.5 SELECT outer();输出

 psql:/vagrant/f.sql:14: NOTICE:  inner
Run Code Online (Sandbox Code Playgroud)

编辑:如果你不删除外部函数末尾的内部函数,它将对数据库的其余部分保持可见.

  • @Gregory:更重要的一点:如果两个并发事务尝试调用此函数,则第二个事务将阻塞内部`CREATE`直到第一个提交,这是由于数据库对函数名的唯一性约束.你可以通过将内部函数放在会话的临时模式中来解决这个问题,即使用`CREATE FUNCTION pg_temp.inner()`.额外的好处是内部功能永远不会在外部可见,并在会话后自动清理. (3认同)
  • 有几点要指出其他人试图这样做:你不能只使用`AS $$`来实现内部和外部功能.此外,如果您的函数有参数,则必须在删除该函数时传递类型.而且你不能在外部函数的`DECLARE`部分调用你的函数,因为它们尚未创建.只需创建变量并在创建嵌套函数后为其赋值. (2认同)
  • @Gregory:顺便说一句,`DECLARE ... BEGIN ... END`块可以嵌套,所以你可以在创建内部函数后进行声明 (2认同)