我的应用程序使用返回整数的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())
有什么想法吗?
答案 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
回滚子事务。我们在外层捕获它,防止异常传播到函数外部并中止整个事务。