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

Posted

技术标签:

【中文标题】如何在 PL/pgSQL 中创建嵌套函数?【英文标题】:How do I create a nested function in PL/pgSQL? 【发布时间】:2017-02-20 08:14:53 【问题描述】:

我想在 PL/pgSQL 中创建一个函数,其中包含几个嵌套(或内部)函数。这样我可以将问题分解成更小的部分,但不能在这个函数之外访问我的小部分。

在 PL/pgSQL 中可以做到这一点吗?如果有,怎么做?

【问题讨论】:

你为什么要这样做?对我来说似乎不切实际。您可以将问题分解为没有很多功能的较小部分,或者如果您确实需要它 - 调整它们的权限。 @KamilGosciminski - 你提到你“可以将问题分解成更小的部分而没有很多功能” - 想知道你会怎么做? 【参考方案1】:

试试看:

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;

在 postgres 9.5 SELECT outer(); 输出中

 psql:/vagrant/f.sql:14: NOTICE:  inner

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

【讨论】:

有几件事要向其他尝试此操作的人指出:您不能只将AS $$ 用于内部和外部功能。此外,如果您的函数有参数,则必须在删除该函数时传递类型。而且你不能在外部函数的DECLARE 部分调用你的函数,因为它们还没有被创建。只需在创建嵌套函数后创建变量并为其赋值即可。 @Gregory:更重要的一点:如果两个并发事务尝试调用此函数,则第二个事务将阻塞内部CREATE,直到第一个事务提交,因为数据库的唯一性约束函数名称。您可以通过将内部函数放入会话的临时模式来解决此问题,即使用CREATE FUNCTION pg_temp.inner()。额外的好处是内部函数永远不会在外部可见,并且会在您的会话结束后自动清理。 @Gregory:顺便说一句,DECLARE ... BEGIN ... END 块可以嵌套,所以你可以在创建内部函数后进行声明 在每个(外部)函数调用上创建一个新的(内部)函数似乎很浪费。【参考方案2】:

PLpgSQL 不支持嵌套函数。仿真没有任何意义,而且是非生产性的。

【讨论】:

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

以上是关于如何在 PL/pgSQL 中创建嵌套函数?的主要内容,如果未能解决你的问题,请参考以下文章

PL/pgSQL 函数在 pgAdmin 之外无法正确运行

如何在嵌套的 MongoDB 集合中创建索引?

如何在另一个函数中使用嵌套函数作为球拍语言的参数?

如何在 Laravel 中创建嵌套集合?

如何在 python 的多处理中创建嵌套共享对象?

如何从 C++ 代码调用 PL/pgSQL 函数