有没有办法将变量作为参数传递给 YugabyteDB 中的触发器函数?

Is there a way to pass a variable as an argument to a trigger function in YugabyteDB?

[免责声明:这个问题是由我们的 YugabyteDB 用户之一在我们的 yugabyte 上提出的。com/slack 频道]

下面的触发器文档给出了将触发器附加到员工更新的示例 table。

https://docs.yugabyte.com/latest/explore/ysql-language-features/triggers/

假设您有一个程序,只允许经理调动员工,前提是该员工是经理的直接下属,类似于以下内容:

#transfer_employee(manager_no, employee_no, department)
CREATE OR REPLACE PROCEDURE transfer_employee(integer, integer, text)
LANGUAGE plpgsql
AS $$
BEGIN
  -- IF employee reports to mgr, allow mgr to transfer person
  IF EXISTS (SELECT employee_no FROM mgr_table where mgr_id =  and employee_no = )
  UPDATE employees
  SET department = 
  WHERE employee_no = ;
  COMMIT;
END;
$$;

YugabyteDB 中有没有办法让触发器获得访问权限,或者将存储过程的状态变量传递给触发器,以便您可以登录 table 变量,例如 manager_id 谁进行了更改,而不仅仅是新部门或旧部门(例如,这是一个仅存在于存储过程上下文中的变量)?

如果可能的话,我不清楚这个例子中的语法。

我在这里看不到任何 yugabyte 独有的东西,所以这都是 postgres。这也意味着您可以使用 postgres 文档。

postgres 文档声明触发器函数必须在没有参数的情况下声明。 (https://www.postgresql.org/docs/11/plpgsql-trigger.html) 换句话说:变量不能作为参数传递给触发器函数。

由于触发器的主体是一个函数,因此可能性是无限的。但我强烈建议考虑确保数据和逻辑的配置方式不会使其不明显。

因此,为您的问题提供一个答案:是的,这是可能的,这是一个 Whosebug 答案,它提供了安排所请求功能的方法: (使用会话设置中设置的自定义变量 table)

请不要在这里停止阅读。通过这样做,使触发功能起作用的唯一方法是根据触发器的需要手动制作会话状态。这使得一般情况下处理数据真的很难(如果不是:不可能)。尤其是如果这种类型的触发器被添加到更多的地方。

一般来说,实现此目的的方法是创建应用程序必须使用的过程(API)以操纵数据,因此任何需要比 [=28= 需要更多信息的规则] level function like a trigger 可以看到,可以在那里处理。

这样数据库对象就可以拥有它们所有的数据范围规则(primary/foreign 键,检查约束,非空),但不需要任何超出 table 本身的数据和数据库管理。

添加到 Frits 的回答中:

In general the way to do this is by creating procedures that an application must use (an API) in order to manipulate the data… 

是——100%同意。更上一层楼,问题变成了“如何在 PostgreSQL 中建模会话状态”。在 Oracle 数据库中,通常的范例是使用包状态(无论如何只能通过 setter 过程和 getter 函数可见)。遗憾的是,在 PostgreSQL(没有包)中没有简单的方法可以做到这一点。唯一的选择是 tables 或 Frits 提到的堆栈交换片描述的内容。

表格有问题:性能;定期将您的行与其他会话的行区分开来 table;没有全局临时 table 和 PG 这样的东西,因此会话临时 table 需要以某种方式在会话开始时创建 sla。

以下是我如何构建用于多个服务器调用的秒表。麻烦。但它确实有效。

create procedure admin.start_stopwatch()
language plpgsql
as $body$
declare
 -- Make a memo of the current wall-clock time.
 start_time constant text not null := clock_timestamp()::text;
begin
 execute 'set stopwatch.start_time to '''||start_time||'''';
end;
$body$;

create function admin.stopwatch_reading()
 returns text
 -- It's critical to use "volatile". Else wrong results.
 volatile
language plpgsql
as $body$
declare
 -- Read the starting wall-clock time from the memo.
 start_time constant timestamptz not null := current_setting('stopwatch.start_time');

 -- Read the current wall-clock time.
 curr_time constant timestamptz not null := clock_timestamp();
 diff constant interval not null := curr_time - start_time;
begin
 return ...
end;
$body$;