PostgreSQL 的函数中抛出意外错误但未被捕获
Unexpected error thrown in PostgreSQL's function and not catched
我正在尝试创建一个已修改用户的列表,然后在交易结束时我想处理该列表。以下是我尝试执行此操作的方法:
CREATE TABLE "user"(
user_id bigserial NOT NULL,
username varchar(255) NOT NULL,
CONSTRAINT pk_5 PRIMARY KEY (user_id)
);
CREATE FUNCTION enlist_user ()
RETURNS trigger
LANGUAGE plpgsql
AS $$
DECLARE
rec record;
BEGIN
IF TG_OP = 'INSERT' OR TG_OP = 'UPDATE' THEN
rec := NEW;
ELSE
rec := OLD;
END IF;
CREATE TEMPORARY TABLE IF NOT EXISTS user_list (
user_id bigint NOT NULL,
CONSTRAINT user_queue_pk PRIMARY KEY (user_id)
);
INSERT INTO user_list
VALUES (rec.user_id);
EXCEPTION WHEN OTHERS THEN
RAISE NOTICE 'Unable to add %', rec.user_id;
RETURN rec;
END;
$$;
CREATE TRIGGER user_modified
AFTER INSERT OR DELETE OR UPDATE
ON "user"
FOR EACH ROW
EXECUTE PROCEDURE enlist_user();
INSERT INTO "user" VALUES (default, 'qwe');
但是运行上面的代码导致以下错误:
ERROR: control reached end of trigger procedure without RETURN
CONTEXT: PL/pgSQL function enlist_user()
这是怎么回事?为什么 RETURN rec
不起作用?
您的缩进具有误导性。 exception
部分在逻辑上与第一个 begin
:
属于同一级别
CREATE FUNCTION enlist_user ()
RETURNS trigger
LANGUAGE plpgsql
AS $$
DECLARE
rec record;
BEGIN
...
EXCEPTION WHEN OTHERS THEN
RAISE NOTICE 'Unable to add %', rec.user_id;
RETURN rec; -- << only reached if an exception is thrown.
END;
$$;
所以 RETURN
是异常块的一部分,因此只有在 发生异常时才会达到 。你真正想要的是:
CREATE FUNCTION enlist_user ()
RETURNS trigger
LANGUAGE plpgsql
AS $$
DECLARE
rec record;
BEGIN
...
RETURN rec; -- normal flow of the function
EXCEPTION WHEN OTHERS THEN
RAISE NOTICE 'Unable to add %', rec.user_id;
END;
$$;
您也不应该只执行 raise notice
,这意味着原始异常不会显示给最终用户。调用者也不知道异常发生的任何线索。如果您重新提出您处理的异常会更好:
....
RETURN rec; -- normal flow of the function
EXCEPTION WHEN OTHERS THEN
RAISE NOTICE 'Unable to add %', rec.user_id;
RAISE; -- signal this error to the caller
END;
$$;
我正在尝试创建一个已修改用户的列表,然后在交易结束时我想处理该列表。以下是我尝试执行此操作的方法:
CREATE TABLE "user"(
user_id bigserial NOT NULL,
username varchar(255) NOT NULL,
CONSTRAINT pk_5 PRIMARY KEY (user_id)
);
CREATE FUNCTION enlist_user ()
RETURNS trigger
LANGUAGE plpgsql
AS $$
DECLARE
rec record;
BEGIN
IF TG_OP = 'INSERT' OR TG_OP = 'UPDATE' THEN
rec := NEW;
ELSE
rec := OLD;
END IF;
CREATE TEMPORARY TABLE IF NOT EXISTS user_list (
user_id bigint NOT NULL,
CONSTRAINT user_queue_pk PRIMARY KEY (user_id)
);
INSERT INTO user_list
VALUES (rec.user_id);
EXCEPTION WHEN OTHERS THEN
RAISE NOTICE 'Unable to add %', rec.user_id;
RETURN rec;
END;
$$;
CREATE TRIGGER user_modified
AFTER INSERT OR DELETE OR UPDATE
ON "user"
FOR EACH ROW
EXECUTE PROCEDURE enlist_user();
INSERT INTO "user" VALUES (default, 'qwe');
但是运行上面的代码导致以下错误:
ERROR: control reached end of trigger procedure without RETURN
CONTEXT: PL/pgSQL function enlist_user()
这是怎么回事?为什么 RETURN rec
不起作用?
您的缩进具有误导性。 exception
部分在逻辑上与第一个 begin
:
CREATE FUNCTION enlist_user ()
RETURNS trigger
LANGUAGE plpgsql
AS $$
DECLARE
rec record;
BEGIN
...
EXCEPTION WHEN OTHERS THEN
RAISE NOTICE 'Unable to add %', rec.user_id;
RETURN rec; -- << only reached if an exception is thrown.
END;
$$;
所以 RETURN
是异常块的一部分,因此只有在 发生异常时才会达到 。你真正想要的是:
CREATE FUNCTION enlist_user ()
RETURNS trigger
LANGUAGE plpgsql
AS $$
DECLARE
rec record;
BEGIN
...
RETURN rec; -- normal flow of the function
EXCEPTION WHEN OTHERS THEN
RAISE NOTICE 'Unable to add %', rec.user_id;
END;
$$;
您也不应该只执行 raise notice
,这意味着原始异常不会显示给最终用户。调用者也不知道异常发生的任何线索。如果您重新提出您处理的异常会更好:
....
RETURN rec; -- normal flow of the function
EXCEPTION WHEN OTHERS THEN
RAISE NOTICE 'Unable to add %', rec.user_id;
RAISE; -- signal this error to the caller
END;
$$;