如何为 psql 脚本的一部分暂停 PostgreSQL 的 ON_ERROR_STOP?

How to suspend PostgreSQL's ON_ERROR_STOP for just part of a psql script?

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

所以我正在考虑去哪个地方

\set ON_ERROR_STOP on

开头,或指示用户运行脚本与

 psql -v ON_ERROR_STOP=on -f my_script.sql

但是,脚本的一部分故意失败(并回滚)。由于该脚本用于教育和演示目的,并且该部分演示了一个 CONSTRAINT 实际上按其应有的方式工作(通过使随后的违反约束的 INSERT 失败),我真的不能 "fix" 那部分不失败,所以 How to save and restore value of 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 元命令。

我认为你做不到。

然而,您可以做的是对 运行 语句使用 PL/pgSQL 块并捕获并报告错误,有点像这样:

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

那会报错,但不会导致psql停止。

\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