Existe-t-il un moyen de définir le propriétaire de tous les objets dans une base de données PostgreSQL en même temps?

13

/programming/1348126/modify-owner-on-all-tables-simultaneous-in-postgresql décrit quelques façons astucieuses de changer la table et d'autres objets à un utilisateur spécifique, et cela fonctionne à merveille, cependant tous les les suggestions semblent ignorer les fonctions que j'ai créées.

Existe-t-il un moyen assez simple de réinitialiser le propriétaire de TOUS les objets de la base de données, y compris les fonctions? Le faire à la main est hautement indésirable.

Jeremy Holovacs
la source

Réponses:

22

Vous ne devez jamais manipuler directement les catalogues système que si vous savez exactement ce que vous faites. Cela peut avoir des effets secondaires inattendus. Ou vous pouvez corrompre la base de données (ou l'ensemble du cluster de base de données) au-delà de toute réparation.

La réponse de Jeremy , tout en faisant l'essentiel, est pas recommandée au grand public. Il modifie inconditionnellement toutes les fonctions d'un schéma. Êtes-vous sûr qu'aucune fonction système n'est affectée ou aucune fonction installée par un module supplémentaire?
Il serait également inutile de changer le propriétaire des fonctions qui appartiennent déjà au propriétaire désigné.

Vérifiez d'abord si REASSIGN OWNED pourrait fonctionner pour vous:

modifier la propriété des objets de base de données appartenant à un rôle de base de données

Vous devez répertorier tous les rôles à désavouer explicitement. Mais ça réaffecte également des fonctions .

Pour affecter toutes les fonctions (et aucun autre objet) d'un schéma donné à un nouveau propriétaire (éventuellement indépendamment du propriétaire précédent):

SELECT string_agg('ALTER FUNCTION ' || oid::regprocedure || ' OWNER TO foo;', E'\n') AS ddl
FROM   pg_catalog.pg_proc p
JOIN   pg_catalog.pg_namespace n ON n.oid = p.pronamespace
WHERE  n.nspname = 'public';
-- AND p.relowner <> (SELECT oid FROM pg_roles WHERE rolname = 'foo')
-- AND p.proname ~~ 'f_%'

Cela génère les commandes SQL canoniquesALTER FUNCTION ... pour modifier toutes les fonctions (dans le schéma spécifié). Vous pouvez inspecter les commandes avant de les exécuter - une par une ou toutes à la fois:

ALTER FUNCTION public.bar(text, text) OWNER TO foo;
ALTER FUNCTION public.foo(x integer) OWNER TO foo;
...

J'ai inclus quelques WHEREclauses commentées que vous voudrez peut-être utiliser pour filtrer les résultats.

Le transtypage en regprocedureproduit un nom de fonction valide avec des paramètres, entre guillemets si nécessaire, schéma - qualifié si nécessaire pour le courant search_path.

La fonction d'agrégation string_agg () nécessite PostgreSQL 9.0 ou version ultérieure. Dans l'ancienne version, remplacez par array_agg()et array_to_string().

Vous pouvez mettre tout cela dans une DOinstruction ou une fonction comme démontré dans cette réponse connexe:

Dans Postgres 9.5 ou version ultérieure, vous pouvez simplifier la requête à l'aide de nouveaux types d'identifiant d'objet regnamespaceetregrole :

SELECT string_agg('ALTER FUNCTION '|| oid::regprocedure || ' OWNER TO foo;', E'\n') AS ddl
FROM   pg_catalog.pg_proc
WHERE  pronamespace = 'public'::regnamespace;
-- AND relowner <> 'foo'::regrole
-- AND proname ~~ 'f_%'
Erwin Brandstetter
la source
1

J'utilise cette fonction pour modifier le propriétaire des tables, fonctions, types, etc. Vous pouvez modifier la requête des curseurs pour l'adapter à vos besoins.

CREATE OR REPLACE FUNCTION fn_setowner(varchar(50), boolean) RETURNS void AS
$BODY$
DECLARE
p_owner ALIAS FOR $1;
p_debug ALIAS FOR $2;
v_i integer := 0;
v_sql text;

--  CURSORS
-- SCHEMA
pesquemas CURSOR FOR
    SELECT quote_ident(schema_name) as nombre_esquema from information_schema.schemata WHERE schema_name NOT LIKE 'pg_%'
    and schema_name NOT IN ('information_schema') ORDER BY 1 ASC;

-- TABLE
ptablas CURSOR FOR
    SELECT quote_ident(table_schema) || '.' || quote_ident(table_name) as nombre_tabla, * FROM information_schema.tables
    WHERE table_schema NOT IN ('pg_catalog', 'information_schema')
    AND table_type <> 'FOREIGN TABLE' ORDER BY 1 ASC;

-- FUNCTION
pfunciones CURSOR FOR
    SELECT quote_ident(b.nspname) || '.' || quote_ident(a.proname) || '(' || pg_catalog.oidvectortypes(a.proargtypes) || ')' as nombre_function 
    FROM pg_proc a  INNER JOIN pg_namespace b on a.pronamespace = b.oid 
    WHERE b.nspname NOT IN ('pg_catalog', 'information_schema') AND proisagg = 'f'
    AND a.proname not like 'fsym_%' AND a.proname not like 'dblink%' ORDER BY 1 ASC;

-- SEQUENCE
psecuencias CURSOR FOR
    SELECT quote_ident(sequence_schema) || '.' || quote_ident(sequence_name) as nombre_secuencia FROM information_schema.sequences
    WHERE sequence_schema NOT IN ('pg_catalog', 'information_schema') ORDER BY 1 ASC;

-- TYPE
ptipos CURSOR FOR
    SELECT quote_ident(n.nspname) || '.' || quote_ident(t.typname) as nombre_tipo
    FROM pg_type t
    LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace 
    WHERE (t.typrelid = 0 OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid)) 
    AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem AND el.typarray = t.oid)
    AND n.nspname NOT IN ('pg_catalog', 'information_schema') ORDER BY 1 ASC;


BEGIN
--  CHECK LOGIN
    IF NOT EXISTS (SELECT 1 FROM pg_user WHERE usename = p_owner) THEN                     
        RAISE EXCEPTION 'Login role not exists --> %', p_owner
            USING HINT = 'Please specify correct login and try again.';
    END IF;

    v_i = 0;
    if (p_debug) THEN
    RAISE NOTICE '--########## CHANGE SCHEMA OWNER ##########--';
    END IF;
    FOR resquema IN pesquemas LOOP
        v_sql = 'ALTER SCHEMA ' || resquema.nombre_esquema || ' OWNER TO ' || quote_ident(p_owner) || ';';
        if (p_debug) THEN RAISE NOTICE '%', v_sql; END IF;
        EXECUTE v_sql;
        v_i = v_i + 1;
    END LOOP;
    if (p_debug) THEN
    RAISE NOTICE '--@@@@@@ SCHEMAS WITH OWNER % TOTAL = % @@@@@@--', p_owner, CAST(v_i AS VARCHAR);
    END IF;

    v_i = 0;
    if (p_debug) THEN
    RAISE NOTICE '--########## CHANGE TABLE OWNER ##########--';
    END IF;
    FOR rtables IN  ptablas LOOP
        v_sql = 'ALTER TABLE ' || rtables.nombre_tabla || ' OWNER TO ' || quote_ident(p_owner) || ';';
        if (p_debug) THEN RAISE NOTICE '%', v_sql; END IF;
        EXECUTE v_sql;
        v_i = v_i + 1;
    END LOOP;
    if (p_debug) THEN
    RAISE NOTICE '--@@@@@@ TABLES WITH OWNER % TOTAL = % @@@@@@--', p_owner, CAST(v_i AS VARCHAR);
    END IF;

    v_i = 0;
    if (p_debug) THEN
    RAISE NOTICE '--########## CHANGE FUNCTION OWNER ##########--';
    END IF;
    FOR rfunction IN  pfunciones LOOP
        v_sql = 'ALTER FUNCTION ' || rfunction.nombre_function || ' OWNER TO ' || quote_ident(p_owner) || ';';
        if (p_debug) THEN RAISE NOTICE '%', v_sql; END IF;
        EXECUTE v_sql;
        v_i = v_i + 1;
    END LOOP;
    if (p_debug) THEN
    RAISE NOTICE '--@@@@@@ FUNCTIONS WITH OWNER % TOTAL = % @@@@@@--', p_owner, CAST(v_i AS VARCHAR);
    END IF;

    v_i = 0;
    if (p_debug) THEN
    RAISE NOTICE '--########## CHANGE SEQUENCE OWNER ########## --';
    END IF;
    FOR rsecuencias IN  psecuencias LOOP
        v_sql = 'ALTER TABLE ' || rsecuencias.nombre_secuencia || ' OWNER TO ' || quote_ident(p_owner) || ';';             
        if (p_debug) THEN RAISE NOTICE '%', v_sql; END IF;
        EXECUTE v_sql;
        v_i = v_i + 1;
    END LOOP;
    if (p_debug) THEN
    RAISE NOTICE '--@@@@@@ SEQUENCES WITH OWNER % TOTAL = % @@@@@@--', p_owner, CAST(v_i AS VARCHAR);
    END IF;

    v_i = 0;
    if (p_debug) THEN
    RAISE NOTICE '--########## CHANGE TYPE OWNER ##########--';
    END IF;
    FOR rtipos IN  ptipos LOOP                
        v_sql = 'ALTER TYPE ' || rtipos.nombre_tipo || ' OWNER TO ' || quote_ident(p_owner) || ';';                
        if (p_debug) THEN RAISE NOTICE '%', v_sql; END IF;
        EXECUTE v_sql;
        v_i = v_i + 1;
    END LOOP;
    if (p_debug) THEN
    RAISE NOTICE '--@@@@@@  TYPES WITH OWNER % TOTAL = % @@@@@@--', p_owner, CAST(v_i AS VARCHAR);
    END IF;

END;
$BODY$
  LANGUAGE 'plpgsql' VOLATILE
  COST 100;

Ensuite, je viens d'exécuter (si vous voulez une sortie de débogage, définissez simplement le deuxième paramètre sur true):

SELECT fn_setowner('demo', false);
DROP FUNCTION fn_setowner(varchar(30), boolean);
JorSol
la source
Notez que pg_proc.proisaggest remplacé en pg 11. Les notes de version dit: Remplacer le tableau du système pg_procde proisagget proiswindowavec prokind(Peter Eisentraut) `
Erwin Brandstetter
0

Cela devrait fonctionner pour les fonctions:

IFS=$'\n'
for fnc in `psql -qAt -c "SELECT  '\"' || p.proname||'\"' || '(' || pg_catalog.pg_get_function_identity_arguments(p.oid) || ')' FROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_proc p ON p.pronamespace = n.oid WHERE n.nspname = 'public';" YOUR_DB`
do
  psql -c "alter function $fnc owner to NEW_OWNER" YOUR_DB
done
Anton Smolkov
la source
-1

Vous pouvez utiliser la commande REASSIGN OWNED

Connectez-vous simplement à la base de données avec le superutilisateur et exécutez ci-dessous

REASSIGN OWNED BY [old_user] TO [new_user];

Cela change tous les objets, c'est-à-dire les tables, séquences, fonctions, etc. appartenant à old_role au nouveau rôle. Vous n'avez pas à penser au type d'objets dont dispose l'utilisateur, ils seront tous modifiés. Cela ne change les objets que si vous voulez changer la propriété de cette base de donnéesALTER DATABASE name OWNER TO new_owner

C'est la meilleure méthode car il n'y aura pas de nombre de tables, la séquence va plutôt pour les boucles et les scripts bash

Ashiq Ahamed
la source
2
Ceci est mentionné dans la réponse avec le plus de votes depuis 3 ans. Aussi ses limites.
dezso
-7

Eh bien, je n'ai pas trouvé de processus en une seule étape, mais cela prend en charge tous les objets que je peux voir dans ma base de données:

update pg_class 
SET relowner = (SELECT oid FROM pg_roles WHERE rolname = 'foo')
where relnamespace = (select oid 
                      from pg_namespace 
                      where nspname = 'public' 
                      limit 1);

update pg_proc 
set proowner = (select oid from pg_roles where rolname = 'foo')
where pronamespace = (select oid 
                      from pg_namespace 
                      where nspname = 'public' 
                      limit 1);
Jeremy Holovacs
la source
5
C'est une bonne question (+1) - -1 pour votre réponse - je ne voudrais pas que quelqu'un d'autre pense qu'il est correct de mettre à jour directement les tables système comme ceci sans être très sûr qu'ils savent ce qu'ils font.
Jack dit d'essayer topanswers.xyz
1
Vous demandez la preuve que cela ne cassera pas quelque chose, et mon contre-argument est que si vous votez pour quelque chose, vous devez inclure une explication de ce qu'il cassera et comment / pourquoi. Si vous ne pouvez pas, alors la réponse n'est pas fausse, trompeuse, inutile ou inutile, qui sont les critères pour un downvote. Les relations dans les tableaux de métadonnées n'étaient pas difficiles à comprendre dans ce cas, après un peu d'examen, et comme je l'ai dit, cela fonctionne à merveille. La charge de la preuve devrait incomber à l'électeur descendant; J'espère que vous aurez du mal à trouver ce que cette réponse cassera.
Jeremy Holovacs
1
Je prendrai la liberté de citer @Erwin textuellement: "Vous ne devez jamais manipuler des catalogues système directement que si vous savez exactement ce que vous faites. Cela peut avoir des effets secondaires inattendus. Ou vous pouvez corrompre la base de données (ou l'ensemble du cluster de base de données). au-delà de la réparation". Erwin connaît son affaire (et moi aussi). Vérifiez notre réputation et nos réponses passées sur la balise postgres ici et sur SO. Mon downvote est une expression de mon opinion et je n'offre aucune preuve car les documents sont assez de preuves pour moi (d'autres peuvent décider par eux-mêmes).
Jack dit d'essayer topanswers.xyz
6
qu'est-ce qui ne va pas avec la méthode d'Erwin? Le fait que vous ayez utilisé la méthode sans problème (apparent) ne me donne aucune confiance et ne devrait pas non plus: quelqu'un pourrait également dire que j'utilise RAID0 depuis des années sans problème.
Jack dit d'essayer topanswers.xyz