我正在使用AWS Aurora Postgres 14(14.5)并设置了此表(在Rust中的Diesel的帮助下)->
create table contacts (
email TEXT NOT NULL,
user_id TEXT NOT NULL,
contact_data JSONB,
user_groups TEXT[],
tenant_groups TEXT[],
tags TEXT[],
PRIMARY KEY (email, user_id)
);
政策->
ALTER TABLE contacts FORCE ROW LEVEL SECURITY;
CREATE POLICY select_contacts_policy ON contacts
FOR SELECT
USING (user_id = current_setting('myapp.user_id'));
ALTER TABLE contacts ENABLE ROW LEVEL SECURITY;
CREATE POLICY insert_contacts_policy ON contacts
FOR INSERT
WITH CHECK (true);
ALTER TABLE contacts ENABLE ROW LEVEL SECURITY;
在向这个表插入新数据时,我首先设置一个名为user_id
(一个字符串)的会话参数(使用Diesel的sql_query函数)->
sql_query(format!("SET SESSION myapp.user_id = '{user_id}';")).execute(pg_conn)?;
然后我插入使用柴油->
diesel::insert_into(contacts::table)
.values(&contacts) # a custom struct
.on_conflict((contacts::email, contacts::user_id))
.do_update()
.set(&contacts)
.execute(pg_conn)?;
在此查询之后,user_id
将恢复为默认的->
sql_query("SET SESSION myapp.user_id = -1;").execute(pg_conn)?;
diesel函数调用将转换为SQL查询(从postgres日志中获取)->
INSERT INTO "contacts" ("email", "user_id", "contact_data", "user_groups", "tenant_groups", "tags") VALUES ($1, $2, $3, $4, $5, $6) ON CONFLICT ("email", "user_id") DO UPDATE SET "email" = $7, "user_id" = $8, "contact_data" = $9, "user_groups" = $10, "tenant_groups" = $11, "tags" = $12
在运行这个查询时,当出现冲突并触发更新分支->时,我会得到这个错误消息new row violates row-level security policy (USING expression) for table "contacts"
我有一个有点类似(没有多个用户,但相同的模式)postgres安装(v 14. 8)在我的本地,这是能够upsert没有任何问题。
其他信息->
处理此任务的用户是另一个名为backend
的用户
访问权限-> Snapshot of access privileges for the contacts table
我尝试运行EXPLAIN ANALYZE
查询并记录它以查看错误发生的位置,但该查询在完成之前导致了策略冲突。如果我在没有ANALYZE
标志的情况下运行,它只会打印查询计划(但我想知道在哪里以及是什么导致了冲突)。
1条答案
按热度按时间xxb16uws1#
这里的问题是
ON CONFLICT ... DO UPDATE
。普通的INSERT
或INSERT ... ON CONFLICT DO NOTHING
将成功。您只能更新可以看到的行,即具有
FOR SELECT
策略的行,如the documentation所述:[...]需要
SELECT
权限的查询(如UPDATE
)也将仅看到SELECT
策略允许的那些记录。因此,在这里给您带来麻烦的是
FOR SELECT
策略和(缺失的)FOR UPDATE
策略。这有点令人惊讶,因为有人可能会认为只有在INSERT
期间发生冲突时才应该得到该错误。但是,要确定是否存在冲突,您需要能够从表中SELECT
。如果没有冲突,添加FOR SELECT
策略将使语句成功。如果存在冲突,则需要额外的FOR UPDATE
策略。您必须添加允许插入角色无条件更新的策略,并选择: