PostgreSQL - 当引发异常时,set_config 参数未在存储过程之间保留

问题描述 投票:0回答:1

我正在将 Oracle 解决方案转换为 PostgreSQL,其中 Oracle 解决方案利用 PL/SQL 全局变量在内部过程中发生异常时分配错误消息,以便可以在外部过程中引用它们,例如(非常基本):

BEGIN
  DBMS_OUTPUT.PUT_LINE(1/0);
  EXCEPTION
    WHEN OTHERS THEN
      gv_error_text := 'Failure during INNER_PRC. Oracle Error: '||SUBSTR(SQLERRM,1,512);
      RAISE ge_app_exception;
END;

PROCEDURE outer_prc IS
BEGIN
  inner_prc;
  EXCEPTION
    WHEN ge_app_exception THEN
      RAISE_APPLICATION_ERROR(-20000,gv_error_text);
END;

其中 gv_error_textge_app_exception 在 PL/SQL 包的上下文中是全局的。

对于 PostgreSQL,我尝试使用配置参数来做类似的事情,即

  1. 使用 set_config 在 INNER_PRC 的 EXCEPTION 块中设置配置参数
  2. 使用 current_setting 读取 OUTER_PRC 的 EXCEPTION 块中的配置参数

但是,OUTER_PRC 没有看到新值,可能是由于 WHEN OTHERS 块中的设置被回滚

为了使用一个非常基本的示例来演示这一点,我在 postgresql.conf 中分配了以下参数: test.test_config = 'ORIGINAL_DEFAULT_VALUE' 并创建以下两个存储过程:

DECLARE
  v_test_config VARCHAR(30);
  v_dbz         INTEGER;
BEGIN

  v_test_config := current_setting('test.test_config');
  RAISE NOTICE 'INNER_PRC: Starting test.test_config value: %',v_test_config;

  BEGIN
    PERFORM set_config('test.test_config','NEW_VALUE',false);
  END;

  v_test_config := current_setting('test.test_config');
  RAISE NOTICE 'INNER_PRC: Ending test.test_config value: %',v_test_config;

  --Raise Error
  v_dbz := 1/0;

  EXCEPTION
    WHEN OTHERS THEN

      RAISE NOTICE 'INNER_PRC WHEN OTHERS: test.test_config value: %',v_test_config;

      PERFORM set_config('test.test_config','EXCEPTION_VALUE',false);

      v_test_config := current_setting('test.test_config');
      RAISE NOTICE 'INNER_PRC WHEN OTHERS: Ending test.test_config value: %',v_test_config;

      RAISE EXCEPTION USING ERRCODE = 'T2000';

END; $$
LANGUAGE PLPGSQL


CREATE OR REPLACE PROCEDURE outer_prc () AS $$
DECLARE
  v_test_config VARCHAR(30);
BEGIN

  v_test_config := current_setting('test.test_config');
  RAISE NOTICE 'OUTER_PRC: Starting test.test_config value: %',v_test_config;

  CALL inner_prc();

  v_test_config := current_setting('test.test_config');
  RAISE NOTICE 'OUTER_PRC: Ending test.test_config value: %',v_test_config;


  EXCEPTION

    WHEN OTHERS THEN

      v_test_config := current_setting('test.test_config');
      RAISE NOTICE 'OUTER_PRC WHEN OTHERS: Ending test.test_config value: %',v_test_config;


END; $$
LANGUAGE PLPGSQL

当我在 INNER_PRC 中注释掉 v_dbz := 1/0; 并运行 OUTER_PRC 时,输出符合预期:

psql:test.OUTER_PRC.sql:5: NOTICE:  OUTER_PRC: Starting test.test_config value: ORIGINAL_DEFAULT_VALUE
psql:test.OUTER_PRC.sql:5: NOTICE:  INNER_PRC: Starting test.test_config value: ORIGINAL_DEFAULT_VALUE
psql:test.OUTER_PRC.sql:5: NOTICE:  INNER_PRC: Ending test.test_config value: NEW_VALUE
psql:test.OUTER_PRC.sql:5: NOTICE:  OUTER_PRC: Ending test.test_config value: NEW_VALUE

但是一旦我删除注释,即触发错误,输出就会变成:

psql:test.OUTER_PRC.sql:5: NOTICE:  OUTER_PRC: Starting test.test_config value: ORIGINAL_DEFAULT_VALUE
psql:test.OUTER_PRC.sql:5: NOTICE:  INNER_PRC: Starting test.test_config value: ORIGINAL_DEFAULT_VALUE
psql:test.OUTER_PRC.sql:5: NOTICE:  INNER_PRC: Ending test.test_config value: NEW_VALUE
psql:test.OUTER_PRC.sql:5: NOTICE:  INNER_PRC WHEN OTHERS: test.test_config value: NEW_VALUE
psql:test.OUTER_PRC.sql:5: NOTICE:  INNER_PRC WHEN OTHERS: Ending test.test_config value: EXCEPTION_VALUE
psql:test.OUTER_PRC.sql:5: NOTICE:  OUTER_PRC WHEN OTHERS: Ending test.test_config value: ORIGINAL_DEFAULT_VALUE

即test.test_config 在 INNER_PRC 的 EXCEPTION 块中被分配了新值,但在 OUTER_PRC 的 EXCEPTION 块中,它被检索为其默认值。

关于如何克服这个问题的任何帮助/建议都是可能的。

或者,如果有其他解决方案可以在不使用配置参数的情况下实现此行为,请告诉我。

谢谢 安德鲁

postgresql exception stored-procedures rollback
1个回答
0
投票

与其他所有操作一样,设置占位符参数将随子事务一起回滚。看这段代码:

SET my.param = 'before the call';
BEGIN
   CALL inner_proc();
EXCEPTION
   WHEN raise_exception THEN
      RAISE EXCEPTION '%', current_setting('my.param');
END;

无论

inner_proc()
做什么,当我们进入异常处理程序时,它都会被回滚,因此异常总是显示“调用之前”。

您将不得不重写您的代码。一种方法是捕获

inner_proc()
中的异常并将错误消息作为输出参数返回。

© www.soinside.com 2019 - 2024. All rights reserved.