在Postgres Trigger功能中进行例外调用之前执行操作

发布于 2025-02-08 14:09:49 字数 1158 浏览 1 评论 0 原文

Postgres 8.4这里。想象

CREATE FUNCTION emp_stamp() RETURNS trigger AS $emp_stamp$
BEGIN
    -- Check that empname and salary are given
    IF NEW.empname IS NULL THEN
        RAISE EXCEPTION 'empname cannot be null';
    END IF;
    IF NEW.salary IS NULL THEN
        RAISE EXCEPTION '% cannot have null salary', NEW.empname;
    END IF;

    -- Who works for us when she must pay for it?
    IF NEW.salary < 0 THEN
        RAISE EXCEPTION '% cannot have a negative salary', NEW.empname;
    END IF;

    -- Remember who changed the payroll when
    NEW.last_date := current_timestamp;
    NEW.last_user := current_user;
    RETURN NEW;
END;
$emp_stamp$ LANGUAGE plpgsql;

如果我们想执行诸如在自定义表中登录的事情,以下例外:

-- Check that empname and salary are given
IF NEW.empname IS NULL THEN
    INSERT INTO my_log_table ('User didn't supplied empname')
    RAISE EXCEPTION 'empname cannot be null';
END IF;

它不会起作用,因为我们在提高异常之前放置的任何内容 call the Rollback 提高异常意味着,即我们创建的My_log_table行只有 rish five exception 即可删除。

完成这样的事情的最佳方法是什么?也许会发现我们的自定义例外?

我需要关闭回滚 @触发器。

Postgres 8.4 here. Imagine this code snippet from Postgres doc:

CREATE FUNCTION emp_stamp() RETURNS trigger AS $emp_stamp$
BEGIN
    -- Check that empname and salary are given
    IF NEW.empname IS NULL THEN
        RAISE EXCEPTION 'empname cannot be null';
    END IF;
    IF NEW.salary IS NULL THEN
        RAISE EXCEPTION '% cannot have null salary', NEW.empname;
    END IF;

    -- Who works for us when she must pay for it?
    IF NEW.salary < 0 THEN
        RAISE EXCEPTION '% cannot have a negative salary', NEW.empname;
    END IF;

    -- Remember who changed the payroll when
    NEW.last_date := current_timestamp;
    NEW.last_user := current_user;
    RETURN NEW;
END;
$emp_stamp$ LANGUAGE plpgsql;

If we want to do something like logging in a custom table these exceptions:

-- Check that empname and salary are given
IF NEW.empname IS NULL THEN
    INSERT INTO my_log_table ('User didn't supplied empname')
    RAISE EXCEPTION 'empname cannot be null';
END IF;

It won't work because anything we put before a RAISE EXCEPTION call is undone by the rollback RAISE EXCEPTION implies, i.e. the my_log_table row we create will be deleted as soon as RAISE EXCEPTION is called.

What's is the best way to accomplish something like this? Maybe catching our custom exception?

Turning off rollback @ TRIGGER is not an option, I need it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

我喜欢麦丽素 2025-02-15 14:09:49

您可以 /捕获异常。

异常块中,您可以做任何其他事情,例如 insert 在另一个表中。之后,您可以重新调整异常以传播,但这会卷回整个事务,包括 insert 到日志表(除非将异常包装并捕获在外部功能中)。

可以

另外,您只需取消触发触发功能的行,而不是 提出异常。交易中的其他所有内容正常进行。

假设这是更新上的触发,并且您有另一个具有相同结构的表,以写入失败 insert s to:

CREATE OR REPLACE FUNCTION emp_stamp()
  RETURNS trigger
  LANGUAGE plpgsql AS
$func$
BEGIN
   -- Check that empname and salary are given
   IF NEW.empname IS NULL THEN
      RAISE EXCEPTION 'empname cannot be null';
   END IF;

-- IF ...

   RETURN NEW;    -- regular end

EXCEPTION WHEN others THEN  -- or be more specific
   INSERT INTO log_tbl VALUES (NEW.*); -- identical table structure
   RETURN NULL;   -- cancel row
END
$func$;

请注意, new 包含异常发生之前的行,包括同一功能中的先前成功语句。

扳机:

CREATE TRIGGER emp_stamp
BEFORE INSERT OR UPDATE ON tbl
FOR EACH ROW EXECUTE FUNCTION emp_stamp();

You can trap errors / catch exceptions.

In the EXCEPTION block you can do anything else, like INSERT into another table. Afterwards you could re-raise the exception to propagate out, but that would roll back the whole transaction including the INSERT to the log table (unless the exception is wrapped and caught in an outer function).

You could:

Alternatively, you can just cancel the row that triggered the trigger function and not raise an exception. Everything else in the transaction goes through normally.

Assuming this is a trigger ON UPDATE and you have another table with identical structure to write failed INSERTs to:

CREATE OR REPLACE FUNCTION emp_stamp()
  RETURNS trigger
  LANGUAGE plpgsql AS
$func$
BEGIN
   -- Check that empname and salary are given
   IF NEW.empname IS NULL THEN
      RAISE EXCEPTION 'empname cannot be null';
   END IF;

-- IF ...

   RETURN NEW;    -- regular end

EXCEPTION WHEN others THEN  -- or be more specific
   INSERT INTO log_tbl VALUES (NEW.*); -- identical table structure
   RETURN NULL;   -- cancel row
END
$func$;

Note that NEW contains the state of the row right before the exception occurred, including previous successful statements in the same function.

Trigger:

CREATE TRIGGER emp_stamp
BEFORE INSERT OR UPDATE ON tbl
FOR EACH ROW EXECUTE FUNCTION emp_stamp();
无声情话 2025-02-15 14:09:49

实际上,您有两个选择。

  1. 您可以通过使用一些级别的级别来登录PostgreSQL日志,请检查手动
  2. 记录应用程序上的错误,而不是在数据库事务中。例如,不应像这样的触发功能中检查负工资。否则应在插入起义上处理例外。

You have two options actually.

  1. You can log into the postgresql log by using some level on raise Check the manual
  2. Log the error on your application, not in Db transaction. For example, negative salary should not be checked in trigger function like this. Or the exception should be handled on the insert invocations.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文