2017-06-29 3 views
1

(ロールのリストとデータベースのリストを指定して)クエリを作成しようとしています。databaseschematable私はhas_XXX_privilege()機能を使用しようとしているが、出力が厄介な感じ...PostgreSQL - 各オブジェクトタイプの指定されたロールに対して有効な権限を取得する

は3つの役割、例えば、(app_rwcapp_rwapp_r)及びI「は、単一のDB test_db考える

(で開始します)このような出力を得たい場合は

これまでのところ、これは私が得たものであり、それは冗長である以外、それは一種の作品

role, obj_type, obj_name, has_permissions, missing_premissions app_rwc, DATABASE, test_db, CREATE+CONNECT+TEMPORARY", NULL app_rw, DATABASE, test_db, CONNECT+TEMPORARY, CREATE app_r, DATABASE, test_db, CONNECT+TEMPORARY, CREATE app_rwc, SCHEMA, audit, CREATE+USAGE, NULL app_rwc, SCHEMA, shared, CREATE+USAGE, NULL app_rw, SCHEMA, audit, USAGE, CREATE app_rw, SCHEMA, shared, USAGE, CREATE app_r, SCHEMA, audit, USAGE, CREATE app_r, SCHEMA, audit, USAGE, CREATE app_rwc, TABLE, audit.trail, SELECT+INSERT+UPDATE+DELETE+REFERENCES+TRIGGERS, TRUNCATE etc etc

... 誰もがより良いアプローチがある場合はお知らせください - 感謝を。

WITH 
databases AS (
    SELECT * FROM (VALUES ('app_prod')) AS t(database_name) 
), 
roles AS (
    SELECT * FROM (VALUES ('app_rwc'), ('app_rw'), ('app_r')) AS t(role_name) 
), 
db_permissions AS (
    SELECT * FROM (VALUES ('CREATE'), ('CONNECT'), ('TEMPORARY')) AS t(permission_name) 
), 
schemas AS (
    SELECT 
    schema_name 
    FROM 
    information_schema.schemata 
    WHERE 
     catalog_name IN (SELECT database_name FROM databases) 
    AND schema_owner IN (SELECT role_name FROM roles) 
), 
schema_permissions AS (
    SELECT * FROM (VALUES ('CREATE'), ('USAGE')) AS t(permission_name) 
), 
tables AS (
    SELECT table_schema, table_name 
    FROM information_schema.tables 
    WHERE 
     table_catalog IN (SELECT database_name FROM databases) 
    AND table_schema IN (SELECT schema_name FROM schemas) 
    AND table_type IN ('BASE TABLE') -- , 'VIEW' 
), 
table_permissions AS (
    SELECT * FROM (VALUES ('SELECT'), ('INSERT'), ('UPDATE'), ('DELETE'), ('TRUNCATE'), ('REFERENCES'), ('TRIGGER')) AS t(permission_name) 
) 
-- ---------------------------------------------------------------------------- 
SELECT 
    'DATABASE'           AS obj_type 
    , databases.database_name        AS obj_name 
    , roles.role_name 
    , db_permissions.permission_name 
    , has_database_privilege(roles.role_name, databases.database_name, db_permissions.permission_name) AS has_permission 
FROM 
    databases 
    CROSS JOIN roles 
    CROSS JOIN db_permissions 
-- ---------------------------------------------------------------------------- 
UNION ALL 
-- ---------------------------------------------------------------------------- 
SELECT 
    'SCHEMA'           AS obj_type 
    , schemas.schema_name        AS obj_name 
    , roles.role_name 
    , schema_permissions.permission_name 
    , has_schema_privilege(roles.role_name, schemas.schema_name, schema_permissions.permission_name) AS has_permission 
FROM 
    schemas 
    CROSS JOIN roles 
    CROSS JOIN schema_permissions 
-- ---------------------------------------------------------------------------- 
UNION ALL 
-- ---------------------------------------------------------------------------- 
SELECT 
    'TABLE'           AS obj_type 
    , tables.table_schema || '.' || tables.table_name AS obj_name 
    , roles.role_name 
    , table_permissions.permission_name 
    , has_table_privilege(roles.role_name, (tables.table_schema || '.' || tables.table_name),table_permissions.permission_name) AS has_permission 
FROM 
    tables 
    CROSS JOIN roles 
    CROSS JOIN table_permissions 

UPDATE#1 - ここでは、拡張されたクエリは、集約して(!おかげで先端のため@filipremする)それでもかなり大きい(種類、配列、および機能はありません)が、それは、私はそれが何をしたいん行う。

WITH 
databases AS (
    SELECT unnest('{app_prod}'::text[]) AS dbname 
), 
roles AS (
    SELECT unnest('{app_rwc,app_rw,app_r}'::text[]) AS rname 
), 
permissions AS (
    SELECT 'DATABASE' AS ptype, unnest('{CREATE,CONNECT,TEMPORARY}'::text[])         AS pname 
    UNION ALL 
    SELECT 'SCHEMA' AS ptype, unnest('{CREATE,USAGE}'::text[])            AS pname 
    UNION ALL 
    SELECT 'TABLE' AS ptype, unnest('{SELECT,INSERT,UPDATE,DELETE,TRUNCATE,REFERENCES,TRIGGER}'::text[]) AS pname 
    UNION ALL 
    SELECT 'SEQUENCE' AS ptype, unnest('{USAGE,SELECT,UPDATE}'::text[])          AS pname 
    UNION ALL 
    SELECT 'TYPE'  AS ptype, unnest('{USAGE}'::text[])              AS pname 
    UNION ALL 
    SELECT 'FUNCTION' AS ptype, unnest('{EXECUTE}'::text[])             AS pname  
), 
schemas AS (
    SELECT schema_name AS sname 
    FROM information_schema.schemata 
    WHERE catalog_name IN (SELECT dbname FROM databases)    -- show schemas that exist in specified DB 
    AND schema_owner IN (SELECT rname FROM roles)      -- show schemas that are owned by specified roles 
    OR schema_name IN ('public') -- always include these 
    --OR schema_name IN ('public', 'information_schema', 'pg_catalog') 
), 
tables AS (
    SELECT table_schema AS tschema, table_name AS tname 
    FROM information_schema.tables 
    WHERE table_catalog IN (SELECT dbname FROM databases) 
    AND table_schema IN (SELECT sname FROM schemas) 
    AND table_type IN ('BASE TABLE') -- , 'VIEW' 
), 
sequences AS (
    SELECT schemaname AS seqschema, sequencename AS seqname 
    FROM pg_sequences 
    WHERE schemaname IN (SELECT sname FROM schemas) 
), 
types AS (
    SELECT nspname AS typeschema, typname AS typename, CASE typtype WHEN 'c' THEN 'composite' WHEN 'd' THEN 'domain' WHEN 'e' THEN 'enum' WHEN 'r' THEN 'range' ELSE 'other' END AS typekind 
    FROM pg_type INNER JOIN pg_namespace ON pg_type.typnamespace = pg_namespace.oid 
    WHERE nspname IN (SELECT sname FROM schemas) 
    AND typtype NOT IN ('b','p')      -- exclude base and pseudo types 
    AND typname NOT IN (SELECT seqname FROM sequences) -- exclude sequences 
), 
functions AS (
    SELECT nspname AS fnschema, proname AS fnname, pg_proc.oid AS fnoid, pg_get_function_arguments(pg_proc.oid) AS fnargs 
    FROM pg_proc INNER JOIN pg_namespace ON pg_proc.pronamespace = pg_namespace.oid 
    WHERE nspname IN (SELECT sname FROM schemas) 
), 
final AS (
SELECT 
    permissions.ptype 
    , databases.dbname               AS obj_name 
    , roles.rname 
    , permissions.pname 
    , has_database_privilege(roles.rname, databases.dbname, permissions.pname) AS has_permission 
FROM 
    databases 
    CROSS JOIN roles 
    CROSS JOIN permissions 
WHERE 
    permissions.ptype = 'DATABASE' 
UNION ALL -- ---------------------------------------------------------------------------------------------------------- 
SELECT 
    permissions.ptype 
    , schemas.sname               AS obj_name 
    , roles.rname 
    , permissions.pname 
    , has_schema_privilege(roles.rname, schemas.sname, permissions.pname) AS has_permission 
FROM 
    schemas 
    CROSS JOIN roles 
    CROSS JOIN permissions 
WHERE 
    permissions.ptype = 'SCHEMA' 
UNION ALL -- ---------------------------------------------------------------------------------------------------------- 
SELECT 
    permissions.ptype 
    , tables.tschema || '.' || tables.tname              AS obj_name 
    , roles.rname 
    , permissions.pname 
    , has_table_privilege(roles.rname, (tables.tschema || '.' || tables.tname), permissions.pname) AS has_permission 
FROM 
    tables 
    CROSS JOIN roles 
    CROSS JOIN permissions 
WHERE 
    permissions.ptype = 'TABLE' 
UNION ALL -- ---------------------------------------------------------------------------------------------------------- 
SELECT 
    permissions.ptype 
    , sequences.seqschema || '.' || sequences.seqname               AS obj_name 
    , roles.rname 
    , permissions.pname 
    , has_sequence_privilege(roles.rname, (sequences.seqschema || '.' || sequences.seqname), permissions.pname) AS has_permission 
FROM 
    sequences 
    CROSS JOIN roles 
    CROSS JOIN permissions 
WHERE 
    permissions.ptype = 'SEQUENCE' 
UNION ALL -- ---------------------------------------------------------------------------------------------------------- 
SELECT 
    permissions.ptype || ' - ' || types.typekind 
    , types.typeschema || '.' || types.typename              AS obj_name 
    , roles.rname 
    , permissions.pname 
    , has_type_privilege(roles.rname, (types.typeschema || '.' || types.typename), permissions.pname) AS has_permission 
FROM 
    types 
    CROSS JOIN roles 
    CROSS JOIN permissions 
WHERE 
    permissions.ptype = 'TYPE' 
UNION ALL -- ---------------------------------------------------------------------------------------------------------- 
SELECT 
    permissions.ptype 
    , functions.fnschema || '.' || functions.fnname || '(' || fnargs || ')' AS obj_name 
    , roles.rname 
    , permissions.pname 
    , has_function_privilege(roles.rname, functions.fnoid, permissions.pname) AS has_permission 
FROM 
    functions 
    CROSS JOIN roles 
    CROSS JOIN permissions 
WHERE 
    permissions.ptype = 'FUNCTION'     
) 
-- ==================================================================================================================== 
SELECT 
    rname                 AS role_name 
, ptype                 AS object_type 
, obj_name                AS object_name 
, string_agg(DISTINCT CASE WHEN  has_permission THEN pname END, ',') AS granted_permissions 
, string_agg(DISTINCT CASE WHEN NOT has_permission THEN pname END, ',') AS missing_premissions 
FROM 
    final 
GROUP BY 1, 2, 3 
ORDER BY 1, 2, 3 

答えて

0

あなたのクエリは良いです、あなたはちょうどいくつかの集計を追加する必要があります。これは始まりです:

select obj_type, obj_name, role_name, 
array_agg(distinct case when has_permission then permission_name end), 
array_agg(distinct case when not has_permission then permission_name end) 
from (/* your query */) AS q1 
group by 1,2,3 
order by 1,2,3 
+0

ありがとうございました!私はあなたのアイデアを使ってクエリを拡張して質問を更新しました( 'string_agg'を使って配列内の' NULL'sを避けるためにいくつかの変更が加えられました)。 – zam6ak

関連する問題