执行存储过程
如果您对存储过程有 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 的过程以该用户身份有效地执行过程,因此,对数据库的更改似乎是由过程的定义者(而不是其调用者)执行的。
当心
对 SECURITY DEFINER 使用不当会导致混淆代理问题,并在您的系统中引入 SQL 注入等漏洞。示例
在此示例中,此表:
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)