如何为 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
我正在维护一个 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