如何在psql脚本的部分内容中暂停PostgreSQL的ON_ERROR_STOP?

4

我正在维护一个 psql 脚本,当其中任何部分失败时,我通常希望立即中止它,并返回非零退出代码。

因此,我考虑将以下语句之一放置在脚本的开头:

\set ON_ERROR_STOP on

在开始时,或者指导用户使用脚本运行

 psql -v ON_ERROR_STOP=on -f my_script.sql

但是,脚本中有一部分是故意失败的(并且被回滚)。由于该脚本是用于教育和演示目的,并且该部分演示了约束条件实际上按照应有的方式工作(通过使随后违反约束条件的插入操作失败),因此我无法真正“修复”那部分使其不会失败,所以如何保存和恢复ON_ERROR_STOP的值?中的被接受答案并不能解决我的问题。
因此,在那部分之前禁用ON_ERROR_STOP,在该部分之后恢复设置。如果我知道在一般情况下启用了ON_ERROR_STOP,那么这很容易实现:
\set ON_ERROR_STOP off
BEGIN;
-- [ part of the script that purposfully fails ]
ROLLBACK;
\set ON_ERROR_STOP on

或者

\unset ON_ERROR_STOP
BEGIN;
-- [ part of the script that purposefully fails ]
ROLLBACK;
\set ON_ERROR_STOP on

然而,这会盲目地重新启用 ON_ERROR_STOP,无论之前是否已启用。
\set previous_ON_ERROR_STOP :ON_ERROR_STOP
\unset ON_ERROR_STOP
BEGIN;
-- [ part of the script that purposefully fails ]
ROLLBACK;
\set ON_ERROR_STOP :previous_ON_ERROR_STOP

如果之前明确禁用了 ON_ERROR_STOP(例如设置为 off),则可以正常工作,但如果未设置(因此只是隐式禁用),则会失败。

我希望脚本仍然向后兼容 PostgreSQL 9.x,因此我目前无法使用 PostgreSQL 10 中引入的 \if 元命令。


1
ON_ERROR_STOP 默认为空,只适用于 psql 版本 < 10。对于 10 或更高版本,它将被评估为 off。虽然这对于 9.x 没有帮助,但重点是如果您针对 PG10,则不需要 \if 测试。而且,您链接的答案在该版本中已过时。 - Daniel Vérité
2个回答

4

我认为你无法这样做。

但是,你可以使用PL/pgSQL块来运行语句并捕获和报告错误,类似于以下内容:

DO
$$BEGIN
   INSERT INTO mytab VALUES (...);
EXCEPTION
   WHEN integrity_constraint_violation THEN
      RAISE NOTICE 'Caught error: %', SQLERRM;
END;$$;

这会报告错误,但不会导致 psql 停止。


0
\set CACHE_ON_ERROR_STOP :ON_ERROR_STOP

SELECT CASE 
  WHEN :'CACHE_ON_ERROR_STOP' = ':CACHE_ON_ERROR_STOP' THEN 'off'
  WHEN :'CACHE_ON_ERROR_STOP'::BOOLEAN is true THEN 'on'
  ELSE 'off'
END::boolean AS CACHE_ON_ERROR_STOP
\gset

\set ON_ERROR_STOP off

-- your code here

\set ON_ERROR_STOP :CACHE_ON_ERROR_STOP

1
你能详细解释一下你的答案吗?例如,:'CACHE_ON_ERROR_STOP'(引号前有冒号)和 ':CACHE_ON_ERROR_STOP'(引号内有冒号)之间的语义差异是什么?将它们与 = 进行比较的目的是什么?(我怀疑这可能与设置可能未设置有关?) - das-g
1
你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心找到有关如何编写良好答案的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接