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;
$$;