【问题标题】:Count rows in all schemas (with permission granted) in all tables计算所有表中所有模式中的行数(已授予权限)
【发布时间】:2019-03-07 17:55:28
【问题描述】:

我正在尝试计算数据库中所有表中的行数。由于我想得到的答案必须区分不同的模式,因此我还考虑了特定表所在的模式。

这个answer 很有帮助,但事实证明我没有访问数据库中所有模式的权限。

我知道我可以通过执行以下查询来检查我对特定表或架构的权限:

select count(*) from (
SELECT grantee, privilege_type 
FROM information_schema.role_table_grants 
WHERE table_name='data' and privilege_type = 'SELECT') as foo

并检查输出是否等于或大于一。

我现在的代码如下:

CREATE or replace function rowcount_all(schema_name text default 'public')
  RETURNS table(table_name_var text, cnt bigint) as
$$
declare
 table_name_var text;
begin
  for table_name_var in SELECT c.relname FROM pg_class c
    JOIN pg_namespace s ON (c.relnamespace=s.oid)
    WHERE c.relkind = 'r' AND s.nspname=schema_name
  loop
    if (
    select count(*) from (
    SELECT grantee, privilege_type 
    FROM information_schema.role_table_grants 
    WHERE table_name=table_name_var and privilege_type = 'SELECT') as foo
  ) >= 1 then 
    RETURN QUERY EXECUTE format('select cast(%L as text),count(*) from %I.%I',
       table_name_var, schema_name, table_name_var);
    end if;
  END loop;
end
$$ language plpgsql;

在执行以下查询时

WITH rc(schema_name,tbl) AS (
  select s.n,rowcount_all(s.n) from (values ('schema1'),
    ('schema2'), ('schema3'), ('schema4')) as s(n)
)
SELECT schema_name,(tbl).* FROM rc;

我收到一个错误,ERROR: permission denied for relation table1 其中table1 在我无权访问的架构中。我认为我在 IF 语句中的逻辑不会过滤掉我无权访问的表。

【问题讨论】:

    标签: postgresql count schema database-table


    【解决方案1】:

    information_schema 是数据库元数据的 SQL 标准表示,如果您尝试构建可移植的东西,它很有用,但如果您只是尝试管理 Postgres 服务器,则通常有点笨拙。

    检查权限的最简单方法是使用privilege check functions。我相信这只会返回您能够查询的表:

    select oid::regclass::text
    from pg_class
    where relkind = 'r'
      and relnamespace = schema_name::regnamespace
      and has_schema_privilege(relnamespace, 'USAGE')
      and has_any_column_privilege(oid, 'SELECT')
    

    请注意,您的情况是has_any_column_privilege() 有用的少数情况之一(与更明显的has_table_privilege() 相比),因为您不需要select count(*) 的全表权限,只需访问其中一个列(但不重要)。

    另请注意,oid::regclass::text 将返回一个已被引用和模式限定的表名(如有必要),因此您的format() 调用可以使用简单的%s 而不是%I.%I

    如果您可以使用近似且稍微过时的记录计数,则可以通过查询上次 VACUUM 运行的统计信息来完全绕过权限检查(并为自己节省大量表扫描) :

    select
      oid::regclass::text,
      reltuples
    from pg_class
    where relkind = 'r'
      and relnamespace = schema_name::regnamespace
    

    【讨论】:

    • @balkon16:更新了我的答案以涵盖我忽略的边缘情况,以及您可能会发现有用的替代方法
    猜你喜欢
    • 2012-07-06
    • 1970-01-01
    • 1970-01-01
    • 2021-06-20
    • 1970-01-01
    • 2020-12-25
    • 2014-08-16
    • 2020-11-22
    • 2014-02-04
    相关资源
    最近更新 更多