如何从plpgsql函数返回一个整数并回滚每个修改?

时间:2014-03-26 00:43:07

标签: postgresql plpgsql

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

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

我现在的问题是,我希望在函数的某些点上,当我检测到错误时立即返回,并回滚到目前为止在函数中完成的所有操作。如果我使用"引发异常",它将回滚,但不返回整数。如果我使用"返回-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]中我可以使用引发异常来回滚,但是当我这样做时,我没有返回的整数。

我可以在[1]和[2]中设置局部变量,然后引发异常,并在EXCEPTION中对此变量进行测试以了解异常的来源,但这是臃肿的,必须有更好的东西!

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

有什么想法吗?

1 个答案:

答案 0 :(得分:3)

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

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