postgresql INSERT语句返回策略冲突(USING表达式)

oxiaedzo  于 2023-06-22  发布在  PostgreSQL
关注(0)|答案(1)|浏览(276)

我正在使用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标志的情况下运行,它只会打印查询计划(但我想知道在哪里以及是什么导致了冲突)。

xxb16uws

xxb16uws1#

这里的问题是ON CONFLICT ... DO UPDATE。普通的INSERTINSERT ... ON CONFLICT DO NOTHING将成功。
您只能更新可以看到的行,即具有FOR SELECT策略的行,如the documentation所述:
[...]需要SELECT权限的查询(如UPDATE)也将仅看到SELECT策略允许的那些记录。
因此,在这里给您带来麻烦的是FOR SELECT策略和(缺失的)FOR UPDATE策略。这有点令人惊讶,因为有人可能会认为只有在INSERT期间发生冲突时才应该得到该错误。但是,要确定是否存在冲突,您需要能够从表中SELECT。如果没有冲突,添加FOR SELECT策略将使语句成功。如果存在冲突,则需要额外的FOR UPDATE策略。
您必须添加允许插入角色无条件更新的策略,并选择:

CREATE POLICY inserter_may_select ON contacts FOR SELECT TO inserter
   USING (TRUE);
CREATE POLICY inserter_may_update ON contacts FOR UPDATE TO inserter
   USING (TRUE);

相关问题