为何current_setting()值在PostgreSQL异常块中显示未定义?
PostgreSQL中set_config设置的参数在异常块中读取不到的原因
问题描述
使用set_config()设置配置参数后,正常执行块中可通过current_setting()读取该参数,但触发异常进入异常块后,参数显示未定义。
代码示例
do $$declare l_ctx_prm text := 'some_value'; l_dummy numeric; begin raise notice 'test before set_config: [utl_log.test_ctx=%]', current_setting('utl_log.test_ctx', true); perform set_config('utl_log.test_ctx', l_ctx_prm, false); raise notice 'test after set_config: [utl_log.test_ctx=%]', current_setting('utl_log.test_ctx', true); l_dummy := 1/0; -- 触发异常 exception when others then raise notice 'test in exception block: [utl_log.test_ctx=%]', current_setting('utl_log.test_ctx', true); end$$;
执行结果
test before set_config: [utl_log.test_ctx=<NULL>] test after set_config: [utl_log.test_ctx=some_value] test in exception block: [utl_log.test_ctx=]
原因解释
这是PostgreSQL事务机制的特性导致的:
- 整个
DO块会作为一个独立事务执行; - 当事务内触发异常时,所有事务内的变更都会被回滚,包括通过
set_config('utl_log.test_ctx', l_ctx_prm, false)对会话级参数的修改; - 异常块的执行是在事务回滚完成之后,此时该参数已恢复到修改前的未定义状态,因此
current_setting返回空值。
解决方案
如果需要在异常块中获取该参数值,推荐直接将参数存储到PL/pgSQL变量中,异常块可直接读取变量值,无需依赖会话参数:
do $$declare l_ctx_prm text := 'some_value'; l_dummy numeric; begin raise notice 'test before set_config: [utl_log.test_ctx=%]', current_setting('utl_log.test_ctx', true); perform set_config('utl_log.test_ctx', l_ctx_prm, false); raise notice 'test after set_config: [utl_log.test_ctx=%]', current_setting('utl_log.test_ctx', true); l_dummy := 1/0; -- 触发异常 exception when others then -- 直接读取变量而非会话参数 raise notice 'test in exception block: [l_ctx_prm=%]', l_ctx_prm; end$$;
内容的提问来源于stack exchange,提问作者DonatasM
相关产品推荐
相关产品推荐

