postgresql 无法更新具有行级安全性的表的行

6tdlim6h  于 2022-11-04  发布在  PostgreSQL
关注(0)|答案(1)|浏览(168)

我尝试使用行级安全策略更新表中的行,但不断收到错误new row violates row-level security policy for table "my_table"
以下是我设置RLS策略的方法:

alter table my_table enable row level security;
alter table my_table force row level security;

create policy select_policy on my_table for select to public using (deleted is false);
create policy insert_policy on my_table for insert to public with check (true);
create policy delete_policy on my_table for delete to public using (true);
create policy update_policy on my_table for update to public using (true) with check (true);

我尝试运行的查询是:

update my_table set deleted = true where id = 1;

我需要以这种方式对my_table中的行执行“软删除”--通过切换deleted标志。
我在这里做错了什么?我如何使这样的查询工作?

更新1

重现步骤:

create table if not exists my_table (
    "name" varchar(40),
    deleted boolean default false
);

insert into my_table (name) values ('John'), ('Alice'), ('Bob');

alter table my_table enable row level security;
alter table my_table force row level security;

drop policy if exists my_table_select_policy on my_table;
drop policy if exists my_table_insert_policy on my_table;
drop policy if exists my_table_delete_policy on my_table;
drop policy if exists my_table_update_policy on my_table;

create policy my_table_select_policy on my_table for select to public using (deleted is false);
create policy my_table_insert_policy on my_table for insert to public with check (true);
create policy my_table_delete_policy on my_table for delete to public using (true);
create policy my_table_update_policy on my_table for update to public using (true);

update my_table set deleted = true where name = 'John'; -- throws error

下面的屏幕截图显示了current_user的权限:

我当前用户的权限是grant all on schema public to my_user;

kr98yfug

kr98yfug1#

Postgres将my_table_select_policy应用于更新的行(删除= false)。原因我不知道。
作为一种解决方法,我建议在my_table_select_policy仍返回true的情况下构建一个宽限期:

  • 代替delete,具有deleted_at列,并在删除时在其中存储当前时间戳(即删除发生时的时间戳)
  • 在SELECT策略中,检查deleted_at是否为NULL,或者deleted_at和now之间的时间是否小于1秒
USING (
        my_table.deleted_at IS NULL
        OR
        ABS(EXTRACT(EPOCH FROM (now() - my_table.deleted_at))) < 1
  )

相关问题