行级安全性生效时未获得 "Detail" 部分唯一约束错误
Not getting "Detail" section of unique constraint error when row level security in effect
TL;DR:在 Postgres 10.6 上,当行级别安全性生效时 - 我没有收到唯一约束违规错误的 "DETAIL" 部分,即使该角色可以 see/insert 所有行.
我有 2 个角色:admin
(表的所有者)和 app_role
行级别安全性生效。
重现方法如下:
--using the admin role
create table parents(
parent_id int primary key,
parent_name text unique
);
create table childs(
child_id int primary key,
child_name text,
parent_id int references parents (parent_id),
constraint childs_uq unique (parent_id, child_name)
);
insert into parents values(1,'aaa');
insert into childs values(1,'bbb',1);
insert into childs values(2,'bbb',1);
--SQL Error [23505]: ERROR: duplicate key value violates unique constraint "childs_uq"
-- Detail: Key (parent_id, child_name)=(1, bbb) already exists.
注意 "Detail: Key (parent_id, child_name)=(1, bbb) already exists."
app_role
角色获得了以下授权和 RLS 政策:
GRANT SELECT, UPDATE, INSERT, DELETE ON parents TO app_role;
GRANT SELECT, UPDATE, INSERT, DELETE ON childs TO app_role;
CREATE POLICY parents_select
ON parents
AS permissive
FOR SELECT
TO app_role
USING (true);
alter table parents enable row level security;
CREATE POLICY childs_select
ON childs
AS permissive
FOR SELECT
TO app_role
USING (true);
CREATE POLICY childs_insert
ON childs
AS permissive
FOR INSERT
TO app_role
WITH CHECK (true);
alter table childs enable row level security;
现在解决问题:
--using `app_role`
insert into childs values(3,'ccc',1); -- works
insert into childs values(2,'bbb',1);
--SQL Error [23505]: ERROR: duplicate key value violates unique constraint "childs_uq"
错误不包含 "Detail" 部分。
这是一个错误吗?预期行为(希望看到文档参考)?
这是按设计实现的,并记录在 src/backend/access/index/genam.c
函数的注释中 BuildIndexValueDescription
:
char *
BuildIndexValueDescription(Relation indexRelation,
Datum *values, bool *isnull)
{
[...]
/*
* Check permissions- if the user does not have access to view all of the
* key columns then return NULL to avoid leaking data.
*
* First check if RLS is enabled for the relation. If so, return NULL to
* avoid leaking data.
*
* Next we need to check table-level SELECT access and then, if there is
* no access there, check column-level permissions.
*/
[...]
/* RLS check- if RLS is enabled then we don't return anything. */
if (check_enable_rls(indrelid, InvalidOid, true) == RLS_ENABLED)
return NULL;
显示细节的问题很明显:
如果您知道您的条目与哪个键冲突,您可能会获得一些您看不到的有关数据库中行的信息。
这在主键冲突的情况下似乎没有必要,因为您知道冲突的值是什么,即使您没有收到详细消息,但情况与 - 比如说 - 排除约束不同.似乎没有人关心区分。
还有 可以 检查您是否可以看到冲突的行并且您 可以 得到前者的详细消息案例,但似乎没有人打扰。
TL;DR:在 Postgres 10.6 上,当行级别安全性生效时 - 我没有收到唯一约束违规错误的 "DETAIL" 部分,即使该角色可以 see/insert 所有行.
我有 2 个角色:admin
(表的所有者)和 app_role
行级别安全性生效。
重现方法如下:
--using the admin role
create table parents(
parent_id int primary key,
parent_name text unique
);
create table childs(
child_id int primary key,
child_name text,
parent_id int references parents (parent_id),
constraint childs_uq unique (parent_id, child_name)
);
insert into parents values(1,'aaa');
insert into childs values(1,'bbb',1);
insert into childs values(2,'bbb',1);
--SQL Error [23505]: ERROR: duplicate key value violates unique constraint "childs_uq"
-- Detail: Key (parent_id, child_name)=(1, bbb) already exists.
注意 "Detail: Key (parent_id, child_name)=(1, bbb) already exists."
app_role
角色获得了以下授权和 RLS 政策:
GRANT SELECT, UPDATE, INSERT, DELETE ON parents TO app_role;
GRANT SELECT, UPDATE, INSERT, DELETE ON childs TO app_role;
CREATE POLICY parents_select
ON parents
AS permissive
FOR SELECT
TO app_role
USING (true);
alter table parents enable row level security;
CREATE POLICY childs_select
ON childs
AS permissive
FOR SELECT
TO app_role
USING (true);
CREATE POLICY childs_insert
ON childs
AS permissive
FOR INSERT
TO app_role
WITH CHECK (true);
alter table childs enable row level security;
现在解决问题:
--using `app_role`
insert into childs values(3,'ccc',1); -- works
insert into childs values(2,'bbb',1);
--SQL Error [23505]: ERROR: duplicate key value violates unique constraint "childs_uq"
错误不包含 "Detail" 部分。
这是一个错误吗?预期行为(希望看到文档参考)?
这是按设计实现的,并记录在 src/backend/access/index/genam.c
函数的注释中 BuildIndexValueDescription
:
char *
BuildIndexValueDescription(Relation indexRelation,
Datum *values, bool *isnull)
{
[...]
/*
* Check permissions- if the user does not have access to view all of the
* key columns then return NULL to avoid leaking data.
*
* First check if RLS is enabled for the relation. If so, return NULL to
* avoid leaking data.
*
* Next we need to check table-level SELECT access and then, if there is
* no access there, check column-level permissions.
*/
[...]
/* RLS check- if RLS is enabled then we don't return anything. */
if (check_enable_rls(indrelid, InvalidOid, true) == RLS_ENABLED)
return NULL;
显示细节的问题很明显:
如果您知道您的条目与哪个键冲突,您可能会获得一些您看不到的有关数据库中行的信息。
这在主键冲突的情况下似乎没有必要,因为您知道冲突的值是什么,即使您没有收到详细消息,但情况与 - 比如说 - 排除约束不同.似乎没有人关心区分。
还有 可以 检查您是否可以看到冲突的行并且您 可以 得到前者的详细消息案例,但似乎没有人打扰。