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

问题描述

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

下面的触发器文档提供了一个将触发器附加到员工表更新的示例。

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 = $1 and employee_no = $2)
  UPDATE employees
  SET department = $3
  WHERE employee_no = $2;
  COMMIT;
END;
$$;

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

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

解决方法

这里没有什么是 yugabyte 独有的,所以这都是 postgres。这也意味着您可以使用 postgres 文档。

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

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

所以要回答您的问题:是的,这是可能的,这是一个stackoverflow答案,它提供了安排所请求功能的方法:How to use variable settings in trigger functions? (使用会话设置表中设置的自定义变量)

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

一般来说,这样做的方法是通过创建应用程序必须使用的过程(API)来操作数据,以便需要比表级函数(如触发器)可以看到的更多信息的任何规则都可以在那里处理。

这样数据库对象就可以拥有它们所有的数据范围规则(主键/外键、检查约束、非空),但不需要除表本身之外的任何东西来进行数据和数据库管理。

,

添加到 Frits 的答案:

一般来说,这样做的方法是创建应用程序必须使用的过程(API)来操作数据......

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

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

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

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

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...