【问题标题】:Is there a way to pass a variable as an argument to a trigger function in YugabyteDB?有没有办法将变量作为参数传递给 YugabyteDB 中的触发函数?
【发布时间】:2021-04-07 07:56:10
【问题描述】:

[免责声明:这个问题是由我们的一位 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-db


    【解决方案1】:

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

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

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

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

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

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

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

    【讨论】:

      【解决方案2】:

      添加到 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$;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-09-27
        • 1970-01-01
        • 2020-06-24
        • 1970-01-01
        • 2022-01-03
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多