如何在 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 中创建嵌套函数?的主要内容,如果未能解决你的问题,请参考以下文章