执行存储过程

如果您对存储过程有 EXECUTE 权限,则可以使用指定存储过程及其 IN 实参的 CALL 语句来执行存储过程。

语法

CALL stored_procedure_name();

例如,存储过程 raiseXY() 定义为:

=> CREATE PROCEDURE raiseXY(IN x INT, y VARCHAR) LANGUAGE PLvSQL AS $$
BEGIN
    RAISE NOTICE 'x = %', x;
    RAISE NOTICE 'y = %', y;
    -- some processing statements
END;
$$;

CALL raiseXY(3, 'some string');
NOTICE 2005:  x = 3
NOTICE 2005:  y = some string

有关 RAISE NOTICE 的详细信息,请参阅错误和诊断

您可以使用 DO 执行匿名(未命名)过程。这不需要权限:

=> DO $$
BEGIN
    RAISE NOTICE '% ran an anonymous procedure', current_user();
END;
$$;

NOTICE 2005:  Bob ran an anonymous procedure

限制运行时

可以使用会话参数 RUNTIMECAP 来设置过程的最大运行时。

此示例将会话期间所有存储过程的运行时设置为一秒,并使用无限循环运行匿名过程。Vertica 在过程运行超过一秒后终止过程:

=> SET SESSION RUNTIMECAP '1 SECOND';

=> DO $$
BEGIN
    LOOP
    END LOOP;
END;
$$;

ERROR 0:  Query exceeded maximum runtime
HINT:  Change the maximum runtime using SET SESSION RUNTIMECAP

执行安全性和权限

默认情况下,存储过程以调用者的权限执行,因此,调用者必须对存储过程访问的编录对象具有必要的权限。您可以通过指定 SECURITY 选项的 DEFINER,来允许调用者使用定义者的权限、默认角色用户参数、和用户属性 (RESOURCE_POOL、MEMORY_CAP_KB、TEMP_SPACE_CAP_KB、RUNTIMECAP)。

例如,以下过程将一个值插入表 s1.t1。如果定义者具有所需的权限(对于架构,为 USAGE;对于表,为 INSERT),则此要求不适用于调用者。

=> CREATE PROCEDURE insert_into_s1_t1(IN x int, IN y int)
LANGUAGE PLvSQL
SECURITY DEFINER AS $$
BEGIN
    PERFORM INSERT INTO s1.t1 VALUES(x,y);
END;
$$;

使用 SECURITY DEFINER 的过程以该用户身份有效地执行过程,因此,对数据库的更改似乎是由过程的定义者(而不是其调用者)执行的。

示例

在此示例中,此表:

records(i INT, updated_date TIMESTAMP DEFAULT sysdate, updated_by VARCHAR(128) DEFAULT current_user())

包含以下内容:

=> SELECT * FROM records;
 i |        updated_date        | updated_by
---+----------------------------+------------
 1 | 2021-08-27 15:54:05.709044 | Bob
 2 | 2021-08-27 15:54:07.051154 | Bob
 3 | 2021-08-27 15:54:08.301704 | Bob
(3 rows)

Bob 创建一个过程来更新表,然后使用 SECURITY DEFINER 选项并将过程上的 EXECUTE 授予 Alice。Alice 现在可以使用该过程来更新表,而无需任何额外权限:

=> GRANT EXECUTE ON PROCEDURE update_records(int,int) to Alice;
GRANT PRIVILEGE

=> \c - Alice
You are now connected as user "Alice".

=> CALL update_records(99,1);
 update_records
---------------
             0
(1 row)

由于对 update_records() 的调用以 Bob 身份有效地运行过程,所以 Bob(而不是 Alice)被列为表的更新者:

=> SELECT * FROM records;
 i  |        updated_date        | updated_by
----+----------------------------+------------
 99 | 2021-08-27 15:55:42.936404 | Bob
  2 | 2021-08-27 15:54:07.051154 | Bob
  3 | 2021-08-27 15:54:08.301704 | Bob
(3 rows)