【问题标题】:How to get a statement calling the function from inside the function itself?如何从函数本身内部获取调用函数的语句?
【发布时间】:2012-10-17 00:49:19
【问题描述】:

假设我有一个函数show_files(IN file text, IN suffix text, OUT statement text)。在下一步中调用该函数:

 SELECT * FROM show_files(file := 'example', suffix := '.png');

我的问题是:是否有任何解决方案可以让我从该函数内部获得调用该函数的语句?

我的意思是,在运行SELECT 后,函数(OUT statement text) 的输出应该是:'SELECT * FROM show_files(file := 'example', suffix := '.png');',或者是否可以将此语句分配给函数内部的变量?

我需要像TG_NAMETG_OP等在触发过程中的功能。

也许可以从 SELECT current_query FROM pg_stat_activity 中检索此语句?

当我尝试在函数中使用它时,我得到了一个空记录:

CREATE OR REPLACE FUNCTION f_snitch(text)
  RETURNS text AS
$BODY$
declare
rr text;
BEGIN
    RAISE NOTICE '.. from f_snitch.';
    -- do stuff
    SELECT current_query  into rr FROM pg_stat_activity 
    WHERE current_query ilike 'f_snitch';
    RETURN rr;
END
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;

欢迎任何帮助和建议!

【问题讨论】:

  • 您可以使用SELECT current_query() 获得顶级 查询...但这不会给您直接调用者,它会为您提供顶级用户语句。我不知道有什么方法可以获得立即调用声明;没有真正要检查的“堆栈”。
  • 谢谢,但是 current_query() 给了我结果:'CREATE OR REPLACE FUNCTION f_snitch(text)' 我想要:'SELECT f_snitch('foo')';

标签: postgresql stored-procedures plpgsql postgresql-9.1


【解决方案1】:

TG_NAME 和朋友是只存在于触发函数的特殊变量。常规的 plpgsql 函数没有这样的东西。我对如何在 plpgsql 中的 called 函数中获得这个想法感到新鲜。

可以RAISE NOTICE 添加到您的函数中,以便获得所需的信息

CREATE OR REPLACE FUNCTION f_snitch(text)
  RETURNS text LANGUAGE plpgsql AS
$func$
BEGIN
    RAISE NOTICE '.. from f_snitch.';
    -- do stuff
    RETURN 'Snitch says hi!';
END
$func$;

呼叫:

SELECT f_snitch('foo')

除了结果之外,这还返回一个通知:

NOTICE:  .. from f_snitch.

在两个方面未能取悦:

  1. 来电声明不在通知中。
  2. 通知中没有CONTEXT

对于 1.,您可以改用 RAISE LOG(或者也将您的集群设置为记录 NOTICES - 我通常不会这样做,对我来说太冗长了)。使用标准设置,您会在数据库日志中获得带有 STATEMENT 的附加行:

LOG:  .. from f_snitch.
STATEMENT:  SELECT f_snitch('foo')

对于2.,请查看此related question at dba.SECONTEXT 看起来像:

CONTEXT:  SQL statement "SELECT f_raise('LOG', 'My message')"
    PL/pgSQL function "f_snitch" line 5 at PERFORM

【讨论】:

    【解决方案2】:

    好的,我知道了!

    CREATE OR REPLACE FUNCTION f_snitch(text)
      RETURNS setof record AS
    $BODY$
    BEGIN
       RETURN QUERY
        SELECT current_query 
        FROM pg_stat_activity 
        <strike>ORDER BY length(current_query) DESC LIMIT 1;</strike>
        where current_query ilike 'select * from f_snitch%';
        -- much more reliable solution
    
    END
    $BODY$
      LANGUAGE plpgsql VOLATILE
      COST 100;
    
      select * from f_snitch('koper') AS (tt text);
    

    结果如下:

    这可能不是 100% 可靠的解决方案,但对于小型系统(对于少数用户而言)来说还可以。

    【讨论】:

    • 当有多个并发会话时,这将产生随机、奇怪和意外的结果。您需要按pid = pg_backend_pid() 过滤以排除其他会话。我也不相信它实际上是正确的。
    • 我同意你的看法。这就是为什么我更改了 where 子句并添加了几行新行来捕获这一行的结果。就我而言 - 考虑到我正在开发的系统 - 不必担心执行此功能的多个会话。它很小,专用于少数人,但对于更大的项目,我必须同意 - pid 操作是必要的。
    猜你喜欢
    • 2019-04-19
    • 1970-01-01
    • 1970-01-01
    • 2020-12-03
    • 2012-02-08
    • 1970-01-01
    • 2015-05-18
    • 2010-12-09
    相关资源
    最近更新 更多