我创建了 4 个 postgresql 模拟函数,用于测试具有多个函数的事务控制,如下所示,
create table test
(
text varchar(20)
);
create table log
(
text varchar(20)
);
create or replace function test1
(
p_data in text,
p_result out text
)
as $$
begin
insert into test (text)
values(1);
p_result := '';
exception
when others then
PERFORM log_entry
(
'test1 error'
);
p_result := '';
end
$$ LANGUAGE plpgsql;
create or replace function test2
(
p_data in text,
p_result out text
)
as $$
begin
insert into test (text)
values(2);
p_result := '';
exception
when others then
PERFORM log_entry
(
'test2 error'
);
p_result := '';
end;
$$ LANGUAGE plpgsql;
create or replace function test3
(
p_data in text,
p_result out text
)
as $$
begin
insert into test (text)
values(3333333333333333333333333333333333333333333333333333333333333333333);
p_result := '';
exception
when others then
PERFORM log_entry
(
'test3 error'
);
p_result := '';
end;
$$ LANGUAGE plpgsql;
create or replace function log_entry
(
p_data in text
)
returns void as $$
begin
insert into log (text)
values(p_data);
end;
$$ LANGUAGE plpgsql;
我调用函数的方式是,
DO $$ BEGIN
PERFORM "test1"('');
PERFORM "test2"('');
PERFORM "test3"('');
END $$;
因此,当函数“test3”执行时,由于它尝试插入到测试表中的数据太长而失败,我可以看到表 test 有 2 行,值 1 和 2;并且表日志有 1 行,值 test3 错误。
我的问题是,
如果我想要实现的是,回滚由函数test1和test2完成的事务,但只提交日志条目(意味着表test应该为空,并且表日志应该有1行是test3错误),该怎么做那?
注意:我不想将3个函数合并为1个,因为在实际情况下,参数输入太多,几乎有100个输入,函数签名太大,而且我也不想使用dblink。
非常感谢。
无需进行一行修改即可实现这一目标。您必须重新设计代码。
一种可能性是向包含日志消息的函数添加另一个输出参数。那么代码可能是这样的:
DO
$$DECLARE
result text;
errmsg text;
BEGIN
SELECT test1(NULL) INTO result, errmsg;
IF errmsg IS NOT NULL THEN
RAISE EXCEPTION '%', errmsg;
END IF;
SELECT test2(NULL) INTO result, errmsg;
IF errmsg IS NOT NULL THEN
RAISE EXCEPTION '%', errmsg;
END IF;
SELECT test2(NULL) INTO result, errmsg;
IF errmsg IS NOT NULL THEN
RAISE EXCEPTION '%', errmsg;
END IF;
EXCEPTION
WHEN raise_exception THEN
GET STACKED DIAGNOSTICS errmsg := MESSAGE_TEXT;
PERFORM log_entry(errmsg);
END;$$;