我想使用SET
记录会话/事务中的用户id,这样我以后就可以使用current_setting
在触发器函数中访问它。基本上,我尝试使用very similar ticket posted previously中的选项n2,不同之处在于我使用的是PG 10.1。
我尝试了3种方法来设置变量:
SET local myvars.user_id = 4
,从而在事务中本地设置它;SET myvars.user_id = 4
,从而将其设置在会话中;SELECT set_config('myvars.user_id', '4', false)
(取决于最后一个参数)将是前两个选项的快捷方式。
它们都不能在触发器中使用,当通过current_setting
获取变量时,触发器接收NULL
。下面是我设计的一个脚本来排除故障(可以很容易地与postgres docker映像一起使用):
database=$POSTGRES_DB
user=$POSTGRES_USER
[ -z "$user" ] && user="postgres"
psql -v ON_ERROR_STOP=1 --username "$user" $database <<-EOSQL
DROP TRIGGER IF EXISTS add_transition1 ON houses;
CREATE TABLE IF NOT EXISTS houses (
id SERIAL NOT NULL,
name VARCHAR(80),
created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now(),
PRIMARY KEY(id)
);
CREATE TABLE IF NOT EXISTS transitions1 (
id SERIAL NOT NULL,
house_id INTEGER,
user_id INTEGER,
created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now(),
PRIMARY KEY(id),
FOREIGN KEY(house_id) REFERENCES houses (id) ON DELETE CASCADE
);
CREATE OR REPLACE FUNCTION add_transition1() RETURNS TRIGGER AS \$\$
DECLARE
user_id integer;
BEGIN
user_id := current_setting('myvars.user_id')::integer || NULL;
INSERT INTO transitions1 (user_id, house_id) VALUES (user_id, NEW.id);
RETURN NULL;
END;
\$\$ LANGUAGE plpgsql;
CREATE TRIGGER add_transition1 AFTER INSERT OR UPDATE ON houses FOR EACH ROW EXECUTE PROCEDURE add_transition1();
BEGIN;
%1% SELECT current_setting('myvars.user_id');
%2% SELECT set_config('myvars.user_id', '55', false);
%3% SELECT current_setting('myvars.user_id');
INSERT INTO houses (name) VALUES ('HOUSE PARTY') RETURNING houses.id;
SELECT * from houses;
SELECT * from transitions1;
COMMIT;
DROP TRIGGER IF EXISTS add_transition1 ON houses;
DROP FUNCTION IF EXISTS add_transition1;
DROP TABLE transitions1;
DROP TABLE houses;
EOSQL
我得出的结论是,该函数是在不同的事务和不同的(?)会话中触发的。这是否是可以配置的,以便所有事件都在同一个上下文中发生?
3条答案
按热度按时间4xrmg8kj1#
正确处理 * customized option * 的所有可能情况:
1.尚未设置选项
所有对它的引用都会引发异常,包括
current_setting()
,除非使用第二个参数 *missing_ok
* 调用。手册:如果没有名为 *
setting_name
* 的设定,则current_setting
会掷回错误,除非提供了 *missing_ok
*,而且是true
。1.选项设置为有效的整数文本
1.选项设置为无效的整数文字
1.选项重置(可分解为特殊情况 3.)
例如,如果使用
SET LOCAL
或set_config('myvars.user_id3', '55', true)
设置自定义选项,则在事务结束时重置选项值。它仍然 * 存在 *,可以被引用,但它现在返回空字符串(''
)-不能转换为integer
。除了演示中的明显错误之外,您还需要为所有4种情况做好准备。
备注:
_user_id
.text
。我们将在稍后对无效输入进行分类后进行强制转换。一个包含
EXCEPTION
子句的块比一个没有EXCEPTION
子句的块的进入和退出开销要大得多。因此,如果没有必要,不要使用EXCEPTION
。_user_id ~ '^\d+$'
。对于任何无效的输入,我都重置为NULL。根据您的需要进行调整。WARNING
,以方便您进行调试。3.
和4.
的情况仅在自定义选项为字符串文字(类型text
)时出现,无法自动强制有效的数据类型。相关:
除此之外,根据您的具体需求,可能还有更优雅的解决方案来解决您试图在没有定制选项的情况下执行的操作。
lf5gs5x22#
不清楚为什么要将
NULL
连接到user_id
,但这显然是问题的原因。请删除它:请注意,
总是给出
NULL
。4urapxun3#
当值不存在时,您可以捕获异常--下面是我为使其正常工作所做的更改: