选项包括:
当您打开连接时,CREATE TEMPORARY TABLE current_app_user(username text); INSERT INTO current_app_user(username) VALUES ('the_user');
. 然后在您的触发器中,SELECT username FROM current_app_user
获取当前用户名,可能作为子查询。
在为自定义 GUCpostgresql.conf
创建条目时,例如. 每当您创建连接时运行. 然后在触发器中,使用函数获取值。实际上,您正在滥用 GUC 机制来提供会话变量。阅读适合您的服务器版本的文档,因为自定义 GUC 在 9.2 中发生了更改。my_app.username = 'unknown';
SET my_app.username = 'the_user';
current_setting('my_app.username')
调整您的应用程序,使其具有适用于每个应用程序用户的数据库角色。SET ROLE
在工作之前给那个用户。这不仅可以让您使用内置的类current_user
变量函数SELECT current_user;
,还可以让您在数据库中强制执行安全性。看到这个问题。您可以直接以用户身份登录,而不是使用SET ROLE
,但这往往会使连接池变得困难。
在这三种情况下,您都在使用连接池,当您将连接返回到池时必须小心DISCARD ALL;
。(虽然它没有记录为这样做,DISCARD ALL
但确实如此RESET ROLE
)。
演示的常见设置:
CREATE TABLE tg_demo(blah text);
INSERT INTO tg_demo(blah) VALUES ('spam'),('eggs');
-- Placeholder; will be replaced by demo functions
CREATE OR REPLACE FUNCTION get_app_user() RETURNS text AS $$
SELECT 'unknown';
$$ LANGUAGE sql;
CREATE OR REPLACE FUNCTION tg_demo_trigger() RETURNS trigger AS $$
BEGIN
RAISE NOTICE 'Current user is: %',get_app_user();
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER tg_demo_tg
AFTER INSERT OR UPDATE OR DELETE ON tg_demo
FOR EACH ROW EXECUTE PROCEDURE tg_demo_trigger();
使用 GUC:
- 在 的
CUSTOMIZED OPTIONS
部分中postgresql.conf
,添加一行,如myapp.username = 'unknown_user'
。在 9.2 之前的 PostgreSQL 版本上,您还必须设置custom_variable_classes = 'myapp'
.
- 重新启动 PostgreSQL。您现在将能够
SHOW myapp.username
获得价值unknown_user
。
现在您可以SET myapp.username = 'the_user';
在建立连接时使用,或者如果您希望它是事务本地的,则可以在事务SET LOCAL myapp.username = 'the_user';
之后使用,这对于池连接很方便。BEGIN
get_app_user
函数定义:
CREATE OR REPLACE FUNCTION get_app_user() RETURNS text AS $$
SELECT current_setting('myapp.username');
$$ LANGUAGE sql;
SET LOCAL
使用交易本地当前用户名的演示:
regress=> BEGIN;
BEGIN
regress=> SET LOCAL myapp.username = 'test_user';
SET
regress=> INSERT INTO tg_demo(blah) VALUES ('42');
NOTICE: Current user is: test_user
INSERT 0 1
regress=> COMMIT;
COMMIT
regress=> SHOW myapp.username;
myapp.username
----------------
unknown_user
(1 row)
如果您使用SET
而不是SET LOCAL
设置,则不会在提交/回滚时恢复,因此它在整个会话中是持久的。它仍然被重置DISCARD ALL
:
regress=> SET myapp.username = 'test';
SET
regress=> SHOW myapp.username;
myapp.username
----------------
test
(1 row)
regress=> DISCARD ALL;
DISCARD ALL
regress=> SHOW myapp.username;
myapp.username
----------------
unknown_user
(1 row)
另外,请注意,您不能使用SET
或SET LOCAL
与服务器端绑定参数一起使用。如果要使用绑定参数(“准备好的语句”),请考虑使用函数形式set_config(...)
。查看系统管理功能
使用临时表
这种方法需要使用一个触发器(或最好由触发器调用的辅助函数),它试图从每个会话应该具有的临时表中读取一个值。如果找不到临时表,则提供默认值。这可能有点慢。仔细测试。
get_app_user()
定义:
CREATE OR REPLACE FUNCTION get_app_user() RETURNS text AS $$
DECLARE
cur_user text;
BEGIN
BEGIN
cur_user := (SELECT username FROM current_app_user);
EXCEPTION WHEN undefined_table THEN
cur_user := 'unknown_user';
END;
RETURN cur_user;
END;
$$ LANGUAGE plpgsql VOLATILE;
演示:
regress=> CREATE TEMPORARY TABLE current_app_user(username text);
CREATE TABLE
regress=> INSERT INTO current_app_user(username) VALUES ('testuser');
INSERT 0 1
regress=> INSERT INTO tg_demo(blah) VALUES ('42');
NOTICE: Current user is: testuser
INSERT 0 1
regress=> DISCARD ALL;
DISCARD ALL
regress=> INSERT INTO tg_demo(blah) VALUES ('42');
NOTICE: Current user is: unknown_user
INSERT 0 1
安全会话变量
还有一个向 PostgreSQL 添加“安全会话变量”的提议。这些有点像包变量。从 PostgreSQL 12 开始,该功能尚未包含在内,但如果您需要,请留意并在黑客名单上发言。
高级:您自己的共享内存区域扩展
对于高级用途,您甚至可以拥有自己的 C 扩展注册共享内存区域,并使用 C 函数调用在 DSA 段中读取/写入值在后端之间进行通信。有关详细信息,请参阅 PostgreSQL 编程示例。您将需要 C 知识、时间和耐心。