无法从 Postgres plpgsql 过程和异常处理最佳实践中捕获异常?
Cannot catch Exception from Postgres plpgsql Procedure and Exception handling best practices?
我有一个 plpgsql 程序,我只是在其中尝试处理任何可能的异常,因为我将 运行 这些程序 pg_cron(自动)并且我不希望任何事情失败。该过程的基本框架如下所示:
CREATE OR REPLACE PROCEDURE marketing_offers.stackover_overflow_ex_question(limit_size integer)
LANGUAGE plpgsql
AS
$procedure$
DECLARE
n_rec_cnt bigint;
BEGIN
LOOP
EXIT WHEN n_rec_cnt = 0;
WITH cte AS (SELECT *
FROM master_table mt
where mt.created_date <= '1999-01-01'::time
LIMIT limit_size)
INSERT INTO some_archive_table (SELECT * FROM cte)
COMMIT;
GET DIAGNOSTICS n_rec_cnt = row_count;
RAISE EXCEPTION 'Max retry count exceeded';
begin
EXCEPTION
WHEN OTHERS then
GET STACKED DIAGNOSTICS text_var1 = message_text,
text_var2 = PG_EXCEPTION_DETAIL,
text_var3 = PG_EXCEPTION_HINT;
RAISE NOTICE 'error msg is %', text_var1;
UPDATE job_log
SET error_msg = text_var1
return;
end;
END LOOP;
END;
$procedure$
;
问题是带有 text_var1
的 RAISE NOTICE,它应该包含 SQL 异常消息,但从未被记录,UPDATE
语句对我的 job_log table 也应该保存消息。
我还想补充一点,我不得不用另一个 begin
和 end
包围 EXCEPTION
块,因为如果不这样做,我会得到语法错误.
我只是想从我的 SQL 脚本中捕获异常 - 我应该使用不同的异常类型吗?我应该寻找特定的 SQL 代码吗?我对这里的最佳做法感到困惑
您真的应该开始缩进您的代码。这不仅是为了美观,而且会立即向您显示代码的问题。
正确缩进后的代码如下所示:
BEGIN
LOOP
EXIT WHEN n_rec_cnt = 0;
COMMIT;
RAISE EXCEPTION 'Max retry count exceeded';
begin
EXCEPTION
WHEN OTHERS then
RAISE NOTICE 'error msg is %', text_var1;
UPDATE job_log
SET error_msg = text_var1
return;
end;
END LOOP;
END;
有两点很明显:
你忘了前面的分号RETURN
→语法错误
EXCEPTION
子句是前一行以 BEGIN
开头的块的一部分。
由于 EXCEPTION
子句只会捕获在它所属的块中抛出的异常,而该块是空的,执行永远无法到达异常处理程序。
您显然在与 COMMIT
不能在带有 EXCEPTION
子句的块内执行的限制作斗争。但是由于不清楚你要做什么(比如无条件的RAISE EXCEPTION
好像没有意义),很难帮到你。
我有一个 plpgsql 程序,我只是在其中尝试处理任何可能的异常,因为我将 运行 这些程序 pg_cron(自动)并且我不希望任何事情失败。该过程的基本框架如下所示:
CREATE OR REPLACE PROCEDURE marketing_offers.stackover_overflow_ex_question(limit_size integer)
LANGUAGE plpgsql
AS
$procedure$
DECLARE
n_rec_cnt bigint;
BEGIN
LOOP
EXIT WHEN n_rec_cnt = 0;
WITH cte AS (SELECT *
FROM master_table mt
where mt.created_date <= '1999-01-01'::time
LIMIT limit_size)
INSERT INTO some_archive_table (SELECT * FROM cte)
COMMIT;
GET DIAGNOSTICS n_rec_cnt = row_count;
RAISE EXCEPTION 'Max retry count exceeded';
begin
EXCEPTION
WHEN OTHERS then
GET STACKED DIAGNOSTICS text_var1 = message_text,
text_var2 = PG_EXCEPTION_DETAIL,
text_var3 = PG_EXCEPTION_HINT;
RAISE NOTICE 'error msg is %', text_var1;
UPDATE job_log
SET error_msg = text_var1
return;
end;
END LOOP;
END;
$procedure$
;
问题是带有 text_var1
的 RAISE NOTICE,它应该包含 SQL 异常消息,但从未被记录,UPDATE
语句对我的 job_log table 也应该保存消息。
我还想补充一点,我不得不用另一个 begin
和 end
包围 EXCEPTION
块,因为如果不这样做,我会得到语法错误.
我只是想从我的 SQL 脚本中捕获异常 - 我应该使用不同的异常类型吗?我应该寻找特定的 SQL 代码吗?我对这里的最佳做法感到困惑
您真的应该开始缩进您的代码。这不仅是为了美观,而且会立即向您显示代码的问题。
正确缩进后的代码如下所示:
BEGIN
LOOP
EXIT WHEN n_rec_cnt = 0;
COMMIT;
RAISE EXCEPTION 'Max retry count exceeded';
begin
EXCEPTION
WHEN OTHERS then
RAISE NOTICE 'error msg is %', text_var1;
UPDATE job_log
SET error_msg = text_var1
return;
end;
END LOOP;
END;
有两点很明显:
你忘了前面的分号
RETURN
→语法错误EXCEPTION
子句是前一行以BEGIN
开头的块的一部分。由于
EXCEPTION
子句只会捕获在它所属的块中抛出的异常,而该块是空的,执行永远无法到达异常处理程序。
您显然在与 COMMIT
不能在带有 EXCEPTION
子句的块内执行的限制作斗争。但是由于不清楚你要做什么(比如无条件的RAISE EXCEPTION
好像没有意义),很难帮到你。