【问题标题】:How to return an integer from a plpgsql function AND rollback every modifications?如何从 plpgsql 函数返回整数并回滚每次修改?
【发布时间】:2014-03-26 00:43:06
【问题描述】:

我的应用程序使用返回整数的 pl/pgsql 函数。 返回的整数作为返回码,用于区分不同的错误。

例如,插入数据的函数返回-1,表示部分数据已经存在,禁止再次尝试插入相同的数据。但如果它返回 -2,则意味着别的东西。这样应用程序就可以知道错误并向用户显示有用的错误消息。

我现在的问题是,我希望在函数的某些点上在检测到错误时立即返回,并回滚到目前为止在函数中所做的所有事情。如果我使用“引发异常”,它将回滚,但不返回整数。如果我使用“return -1;”,它将返回一个整数,但不返回回滚修改。所以我被卡住了,因为显然我不能同时做这两件事

这是一个虚假的示例函数:

CREATE OR REPLACE FUNCTION create_flight_and_passengers(
    _date timetamp,
    _name text,
    _passengers integer[]
)
RETURNS integer
LANGUAGE plpgsql
AS $$
DECLARE
    return_code integer;
BEGIN
    INSERT INTO flights
    VALUES (_name);

    SELECT function_1(_date, _passengers) into return_code;
    if (return_code = -1) then
        -- [1] rollback everything done since beginning of function
        -- create_flight_and_passengers() and return -1
    end if;

    SELECT function_2(_date, _passengers) into return_code;
    if (return_code = -1) then
        -- [2] rollback everything done since beginning of function
        -- create_flight_and_passengers() and return -2
    end if;

    return 0;
END;
$$;

在 [1] 和 [2] 中,我可以使用 raise exception 来回滚,但是当我这样做时,我没有返回整数。

我可以在 [1] 和 [2] 中设置一个局部变量,然后 引发异常,并在 EXCEPTION 中对该变量进行测试以了解异常来自何处,但这很臃肿,一定有更好的东西!

我什至不确定您是否可以回滚已调用且已终止的函数的效果(在我的示例中为 function_1() 和 function_2())

有什么想法吗?

【问题讨论】:

    标签: postgresql plpgsql


    【解决方案1】:

    这是一件非常奇怪的事情。如果你真的需要,你可以这样做:

    DECLARE
      retval integer;
    BEGIN
      retval := 0;
      BEGIN
        ... make my changes ...
        IF (... is something wrong? ...) THEN
          RAISE EXCEPTION SQLSTATE '0U001';
        END IF;
      EXCEPTION
        WHEN '0U001' THEN
          retval := -1;
      END;
    END;
    

    这里的概念是BEGIN ... EXCEPTION 块定义了一个子事务。块内的RAISE EXCEPTION 回滚子事务。我们在外层捕获它,防止异常传播到函数外部并中止整个事务。

    the PL/PgSQL documentation

    【讨论】:

    • 错误:“'0U0001'”处或附近的 SQLSTATE 代码无效。 0U0001 不在错误代码中 (postgresql.org/docs/9.1/static/errcodes-appendix.html)。如何启用“用户定义”错误代码?
    • @user368507 我的错,它们是五位数而不是六位数。已编辑。
    • 好的,正确的语法是 WHEN SQLSTATE '0U001' THEN。现在它正在工作!但你为什么说这很奇怪?回滚很常见,但也许获得返回码并不常见?你怎么知道为什么你的函数没有返回码就失败了?
    • 遇到错误情况时简单地中止事务更为常见。
    • @CraigRinger 当你说中止时,你到底是什么意思?你的意思是postgresql.org/docs/9.3/static/sql-abort.html
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-30
    • 2023-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多