选项包括:
当你打开一个连接时,CREATE TEMPORARY TABLE current_app_user(username text); INSERT INTO current_app_user(username) VALUES ('the_user');
.然后在触发器中输入SELECT username FROM current_app_user
以获取当前用户名,可能作为子查询.
在postgresql.conf
中,为custom GUC创建一个条目,比如my_app.username = 'unknown';
.无论何时创建连接run SET my_app.username = 'the_user';
.然后在触发器中,使用current_setting('my_app.username')
function获取值.实际上,您正在滥用GUC机制来提供会话变量.Read the documentation appropriate to your server version, as custom GUCs changed in 9.2
调整应用程序,使其具有每个应用程序用户的数据库角色.SET ROLE
在工作前发送给该用户.这不仅让您可以使用内置的current_user
变量函数来设置SELECT current_user;
,还可以设置enforce security in the database.见this question.您可以直接以用户身份登录,而不是使用SET ROLE
,但这往往会使连接池变得困难.
在这三种情况下,您都是连接池,当您将连接返回到连接池时,必须小心设置为DISCARD ALL;
.(Though it is not documented as doing soDISCARD 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:
- 在
postgresql.conf
的CUSTOMIZED OPTIONS
部分,添加一行,如myapp.username = 'unknown_user'
.在9.2以上的PostgreSQL版本上,还必须设置custom_variable_classes = 'myapp'
.
- 重新启动PostgreSQL.现在,您将能够获得
SHOW myapp.username
并获得unknown_user
的值.
现在,您可以在建立连接时使用SET myapp.username = 'the_user';
,或者如果希望事务是事务本地的,则在BEGIN
ning事务后使用SET LOCAL myapp.username = 'the_user';
,这对于池连接来说很方便.
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(...)
.见system adminstration functions
使用临时桌子
这种方法需要使用一个触发器(或者触发器调用的助手函数,最好是这样),它试图从每个会话应该具有的临时表中读取一个值.如果找不到临时表,则会提供默认值.这个数字可能是somewhat slow.仔细测试.
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扩展注册共享内存区域,并使用读取/写入DSA段中值的C函数调用在后端之间进行通信.有关详细信息,请参见PostgreSQL编程示例.你需要知识、时间和耐心.