如何在 Postgres 中以只读用户访问 information_schema 外键约束?
How to access information_schema foreign key constraints with read-only user in Postgres?
简介
我一直在开发一个向导来为没有任何 programming/SQL 背景的用户创建复杂的数据库 Postgres 查询。由于存储在 information_schema 中的视图中的外键约束,用户可以 select 任意数量的 table 并且该工具将找到正确的连接设置(因此,用户没有添加 ON table_a.field_1 = table_b.field_2
).
在开发过程中,我一直在使用管理数据库用户,现在想将其更改为只读用户以使其更安全。但是,这个只读用户似乎不能访问外键约束。
现状
当多个 table 被 select 编辑时,该工具会尝试获取各个 table 之间的连接,以便了解如何加入它们。在此过程中,将执行以下查询:
SELECT
tc.constraint_name,
tc.table_name,
kcu.column_name,
ccu.table_name AS foreign_table_name,
ccu.column_name AS foreign_column_name
FROM information_schema.table_constraints AS tc
JOIN information_schema.key_column_usage AS kcu
ON tc.constraint_name = kcu.constraint_name
JOIN information_schema.constraint_column_usage AS ccu
ON ccu.constraint_name = tc.constraint_name
WHERE constraint_type = 'FOREIGN KEY'
AND ccu.table_name = 'TableB'
AND tc.table_name IN ('TableA');
(注意:最后一个WHERE
子句使用IN
因为可以有多个基数table可用。表A是基数table 并且每个成功的 connected/joined table 将可用于其他连接,例如第三个 table 可以使用 AND ccu.table_name = 'TableC' AND tc.table_name IN ('TableA', 'TableB');
等等。)
当使用 admin db 用户(具有 GRANT、SELECT、INSERT、UPDATE、DELETE、TRUNCATE 等最常见的权限...)执行查询时,结果如下所示:
constraint_name | table_name | column_name | foreign_table_name | foreign_column_name
----------------+------------+-------------+--------------------+---------------------
constraint1 | TableA | field_1 | TableB | field_2
(1 row)
但是当只读数据库用户运行该查询时,它 returns:
constraint_name | table_name | column_name | foreign_table_name | foreign_column_name
----------------+------------+-------------+--------------------+---------------------
(0 rows)
由于存在但未 returned 的外键约束条目,连接不能正确地写为 SQL 并且用户生成的查询(通过使用向导)失败。
我试过的
当然,首先,我认为只读用户 (ro_user) 可能没有权限访问 table 和数据库 information_schema
中的视图。所以我运行
GRANT SELECT ON ALL TABLES IN SCHEMA information_schema TO ro_user;
作为管理员,但无济于事。更深入地研究文档,我发现 information_schema
中的所有 table 和视图在 postgres 中默认情况下都可用并可供任何用户访问。所以 g运行 赋予 select 特权甚至不应该改变任何东西。
为了确认一下,我也运行
GRANT REFERENCES ON ALL TABLES IN SCHEMA actual_database TO ro_user;
当然,这也没有改变任何东西,因为 REFERENCES
只需要 创建 新外键,我只需要阅读它们。
接下来,我想,可能是工具中的sql由于某些信息不可用而失败,所以我分别通过运行:
查询了三个视图
SELECT * FROM information_schema.table_constraints AS tc WHERE constraint_type = 'FOREIGN KEY';
SELECT * FROM information_schema.key_column_usage AS kcu;
SELECT * FROM information_schema.constraint_column_usage AS ccu;
果然,最后一个不会 return ro_user:
的任何一行
psql=> SELECT * FROM information_schema.constraint_column_usage AS ccu;
table_catalog | table_schema | table_name | column_name | constraint_catalog | constraint_schema | constraint_name
---------------+--------------+------------+-------------+--------------------+-------------------+-----------------
(0 rows)
而管理员用户得到了很多结果。所以,它归结为一种观点 information_schema.constraint_column_usage
。
当我在一个小时的时间里输入这个问题,回忆和总结我在过去几天尝试过的所有想法时,我终于找到了原因。
The view constraint_column_usage identifies all columns in the current database that are used by some constraint. Only those columns are shown that are contained in a table owned by a currently enabled role.
来自documentation via this SO answer
通过这个我找到了解决方案
SELECT
conrelid::regclass AS table_from,
conname,
pg_get_constraintdef(c.oid) AS cdef
FROM pg_constraint c
JOIN pg_namespace n
ON n.oid = c.connamespace
WHERE contype IN ('f')
AND n.nspname = 'public'
AND pg_get_constraintdef(c.oid) LIKE '%"TableB"%'
AND conrelid::regclass::text IN ('"TableA"')
ORDER BY conrelid::regclass::text, contype DESC;
它不会输出与旧查询相同的格式,但它包含相同的信息并且 - 最重要的是 - 可用于 ro_user。
简介
我一直在开发一个向导来为没有任何 programming/SQL 背景的用户创建复杂的数据库 Postgres 查询。由于存储在 information_schema 中的视图中的外键约束,用户可以 select 任意数量的 table 并且该工具将找到正确的连接设置(因此,用户没有添加 ON table_a.field_1 = table_b.field_2
).
在开发过程中,我一直在使用管理数据库用户,现在想将其更改为只读用户以使其更安全。但是,这个只读用户似乎不能访问外键约束。
现状
当多个 table 被 select 编辑时,该工具会尝试获取各个 table 之间的连接,以便了解如何加入它们。在此过程中,将执行以下查询:
SELECT
tc.constraint_name,
tc.table_name,
kcu.column_name,
ccu.table_name AS foreign_table_name,
ccu.column_name AS foreign_column_name
FROM information_schema.table_constraints AS tc
JOIN information_schema.key_column_usage AS kcu
ON tc.constraint_name = kcu.constraint_name
JOIN information_schema.constraint_column_usage AS ccu
ON ccu.constraint_name = tc.constraint_name
WHERE constraint_type = 'FOREIGN KEY'
AND ccu.table_name = 'TableB'
AND tc.table_name IN ('TableA');
(注意:最后一个WHERE
子句使用IN
因为可以有多个基数table可用。表A是基数table 并且每个成功的 connected/joined table 将可用于其他连接,例如第三个 table 可以使用 AND ccu.table_name = 'TableC' AND tc.table_name IN ('TableA', 'TableB');
等等。)
当使用 admin db 用户(具有 GRANT、SELECT、INSERT、UPDATE、DELETE、TRUNCATE 等最常见的权限...)执行查询时,结果如下所示:
constraint_name | table_name | column_name | foreign_table_name | foreign_column_name
----------------+------------+-------------+--------------------+---------------------
constraint1 | TableA | field_1 | TableB | field_2
(1 row)
但是当只读数据库用户运行该查询时,它 returns:
constraint_name | table_name | column_name | foreign_table_name | foreign_column_name
----------------+------------+-------------+--------------------+---------------------
(0 rows)
由于存在但未 returned 的外键约束条目,连接不能正确地写为 SQL 并且用户生成的查询(通过使用向导)失败。
我试过的
当然,首先,我认为只读用户 (ro_user) 可能没有权限访问 table 和数据库 information_schema
中的视图。所以我运行
GRANT SELECT ON ALL TABLES IN SCHEMA information_schema TO ro_user;
作为管理员,但无济于事。更深入地研究文档,我发现 information_schema
中的所有 table 和视图在 postgres 中默认情况下都可用并可供任何用户访问。所以 g运行 赋予 select 特权甚至不应该改变任何东西。
为了确认一下,我也运行
GRANT REFERENCES ON ALL TABLES IN SCHEMA actual_database TO ro_user;
当然,这也没有改变任何东西,因为 REFERENCES
只需要 创建 新外键,我只需要阅读它们。
接下来,我想,可能是工具中的sql由于某些信息不可用而失败,所以我分别通过运行:
查询了三个视图SELECT * FROM information_schema.table_constraints AS tc WHERE constraint_type = 'FOREIGN KEY';
SELECT * FROM information_schema.key_column_usage AS kcu;
SELECT * FROM information_schema.constraint_column_usage AS ccu;
果然,最后一个不会 return ro_user:
的任何一行psql=> SELECT * FROM information_schema.constraint_column_usage AS ccu;
table_catalog | table_schema | table_name | column_name | constraint_catalog | constraint_schema | constraint_name
---------------+--------------+------------+-------------+--------------------+-------------------+-----------------
(0 rows)
而管理员用户得到了很多结果。所以,它归结为一种观点 information_schema.constraint_column_usage
。
当我在一个小时的时间里输入这个问题,回忆和总结我在过去几天尝试过的所有想法时,我终于找到了原因。
The view constraint_column_usage identifies all columns in the current database that are used by some constraint. Only those columns are shown that are contained in a table owned by a currently enabled role.
来自documentation via this SO answer
通过这个我找到了解决方案
SELECT
conrelid::regclass AS table_from,
conname,
pg_get_constraintdef(c.oid) AS cdef
FROM pg_constraint c
JOIN pg_namespace n
ON n.oid = c.connamespace
WHERE contype IN ('f')
AND n.nspname = 'public'
AND pg_get_constraintdef(c.oid) LIKE '%"TableB"%'
AND conrelid::regclass::text IN ('"TableA"')
ORDER BY conrelid::regclass::text, contype DESC;
它不会输出与旧查询相同的格式,但它包含相同的信息并且 - 最重要的是 - 可用于 ro_user。