Modifier OWNER sur toutes les tables simultanément dans PostgreSQL

412

Comment modifier le propriétaire de toutes les tables d'une base de données PostgreSQL?

J'ai essayé ALTER TABLE * OWNER TO new_ownermais il ne prend pas en charge la syntaxe astérisque.

Kai
la source

Réponses:

461

Voir la REASSIGN OWNEDcommande

Remarque: Comme @trygvis le mentionne dans la réponse ci - dessous , la REASSIGN OWNEDcommande est disponible depuis au moins la version 8.2 et est une méthode beaucoup plus simple.


Étant donné que vous modifiez la propriété de toutes les tables, vous souhaiterez probablement également des vues et des séquences. Voici ce que j'ai fait:

Les tables:

for tbl in `psql -qAt -c "select tablename from pg_tables where schemaname = 'public';" YOUR_DB` ; do  psql -c "alter table \"$tbl\" owner to NEW_OWNER" YOUR_DB ; done

Séquences:

for tbl in `psql -qAt -c "select sequence_name from information_schema.sequences where sequence_schema = 'public';" YOUR_DB` ; do  psql -c "alter sequence \"$tbl\" owner to NEW_OWNER" YOUR_DB ; done

Vues:

for tbl in `psql -qAt -c "select table_name from information_schema.views where table_schema = 'public';" YOUR_DB` ; do  psql -c "alter view \"$tbl\" owner to NEW_OWNER" YOUR_DB ; done

Vous pourriez probablement sécher cela un peu, car les instructions alter sont identiques pour les trois.


Alex Soto
la source
10
+1 Merci Alex. J'ai créé un petit script bash basé sur votre réponse, disponible sur gist.github.com/2482969
gingerlime
10
Voir la réponse récente de @trygvis. Réponse la plus simple de loin:REASSIGN OWNED BY old_role [, ...] TO new_role
David
64
REASSIGN OWNED BY ne fonctionne pas pour les objets appartenant à postgres.
BrunoJCM
19
En outre, REASSIGN OWNED affecte en fait la propriété de toutes les bases de données appartenant à l'ancien rôle (Voir: postgresql.org/docs/9.3/static/sql-reassign-own.html ). Donc, si vous voulez seulement changer la propriété d'une seule base de données, méfiez-vous!
kitsune
3
Basé sur le script @gingerlime, bspkrs (n'a pas pu trouver son nom) en a créé une qui modifie également les fonctions: https://gist.github.com/bspkrs/b997ed7f1eb1268f3403
elysch
538

Vous pouvez utiliser la REASSIGN OWNEDcommande.

Synopsis:

REASSIGN OWNED BY old_role [, ...] TO new_role

Cela modifie tous les objets appartenant à old_role le nouveau rôle. Vous n'avez pas à penser au type d'objets que possède l'utilisateur, ils seront tous modifiés. Notez qu'il ne s'applique qu'aux objets à l'intérieur d'une seule base de données. Cela ne modifie pas non plus le propriétaire de la base de données elle-même.

Il est disponible depuis au moins 8.2. Leur documentation en ligne remonte à très loin.

Trygve Laugstøl
la source
ERROR: unexpected classid 3079. Je suppose que cela ne fonctionne pas actuellement s'il y a des extensions.
Steve Jorgensen
40
Cela ne semble pas fonctionner pour les postgres utilisateur, même si je suis connecté à une base de données que j'ai créée (c'est-à-dire pas une base de données système), il dit ceci: ERREUR: ne peut pas réaffecter la propriété des objets appartenant au rôle postgres car ils sont requis par la base de données système
thnee
13
Comme l'a indiqué @thnee, REASSIGN affecte tous les objets de la base de données et ne fait pas de distinction entre les objets définis par l'utilisateur et les objets système, donc cela ne fonctionne pas pour les postgres s'il existe une extension ayant leurs propres tables. Je préfère toujours (+1) cette option pour l'élégance, même si cela ne m'a pas beaucoup aidé (ma base de données appartenait auparavant à postgres).
Pavel V.
6
Juste pour être clair, cette commande fonctionne UNIQUEMENT dans la base de données à laquelle vous êtes actuellement connecté. Si le old_role possède des objets dans plusieurs bases de données, vous devez vous connecter et exécuter cette commande dans chacune de ces bases de données
mavroprovato
11
cela ne semble pas fonctionner sur les postgres hébergés via AWS RDS. Je reçois cette erreur "autorisation refusée de réaffecter des objets" et ce lien suggère pourquoi: "Il semblerait que la seule façon de" réaffecter la propriété "soit en tant que superutilisateur (ce qui est contredit par la documentation), qui n'est pas accessible dans RDS. ' postgresql-archive.org/…
typoerrpr
198

Ceci: http://archives.postgresql.org/pgsql-bugs/2007-10/msg00234.php est également une solution agréable et rapide, et fonctionne pour plusieurs schémas dans une base de données:

les tables

SELECT 'ALTER TABLE '|| schemaname || '.' || tablename ||' OWNER TO my_new_owner;'
FROM pg_tables WHERE NOT schemaname IN ('pg_catalog', 'information_schema')
ORDER BY schemaname, tablename;

Les séquences

SELECT 'ALTER SEQUENCE '|| sequence_schema || '.' || sequence_name ||' OWNER TO my_new_owner;'
FROM information_schema.sequences WHERE NOT sequence_schema IN ('pg_catalog', 'information_schema')
ORDER BY sequence_schema, sequence_name;

Vues

SELECT 'ALTER VIEW '|| table_schema || '.' || table_name ||' OWNER TO my_new_owner;'
FROM information_schema.views WHERE NOT table_schema IN ('pg_catalog', 'information_schema')
ORDER BY table_schema, table_name;

Vues matérialisées

Basé sur cette réponse

SELECT 'ALTER TABLE '|| oid::regclass::text ||' OWNER TO my_new_owner;'
FROM pg_class WHERE relkind = 'm'
ORDER BY oid;

Cela génère tous les ALTER TABLE/ ALTER SEQUENCE/ nécessairesALTER VIEW instructions , copiez-les et collez-les dans plsql pour les exécuter.

Vérifiez votre travail dans psql en faisant:

\dt *.*
\ds *.*
\dv *.*
rkj
la source
Excellente solution. Mon seul problème était que j'avais exporté les scripts puis exécuté les scripts exportés. Je suis SQL Server Guru mais je ne sais pas quel est le raccourci à exécuter. J'ai cliqué sur exécuter la requête et exécuter pgScript. Qu'est-ce que je faisais mal?
Tyrone Moodley
1
J'ai préféré cela car cela fonctionne depuis plsql une fois connecté - les scripts de niveau Unix (réponse actuellement préférée) nécessitent une entrée "-U postgres" et un mot de passe dans mon environnement.
Dazed
2
Je préfère cette réponse car (1) elle peut être faite en psql ou pgAdmin (2) elle vous permet facilement de voir les objets que vous allez modifier. J'ai également utilisé stackoverflow.com/questions/22803096/… , qui est similaire, mais pour les fonctions.
AlannaRose
splendide logique.
Emipro Technologies Pvt. Ltd.
42

Si vous voulez le faire dans une instruction sql, vous devez définir une fonction exec () comme mentionné dans http://wiki.postgresql.org/wiki/Dynamic_DDL

CREATE FUNCTION exec(text) returns text language plpgsql volatile
  AS $f$
    BEGIN
      EXECUTE $1;
      RETURN $1;
    END;
$f$;

Ensuite, vous pouvez exécuter cette requête, cela changera le propriétaire des tables, des séquences et des vues:

SELECT exec('ALTER TABLE ' || quote_ident(s.nspname) || '.' ||
            quote_ident(s.relname) || ' OWNER TO $NEWUSER')
  FROM (SELECT nspname, relname
          FROM pg_class c JOIN pg_namespace n ON (c.relnamespace = n.oid) 
         WHERE nspname NOT LIKE E'pg\\_%' AND 
               nspname <> 'information_schema' AND 
               relkind IN ('r','S','v') ORDER BY relkind = 'S') s;

$ NEWUSER est le nouveau nom postgresql du nouveau propriétaire.

Dans la plupart des cas, vous devez être superutilisateur pour exécuter cela. Vous pouvez éviter cela en changeant le propriétaire de votre propre utilisateur en un groupe de rôles dont vous êtes membre.

Merci à RhodiumToad sur #postgresql pour son aide.

Johan Dahlin
la source
2
Ceci est beaucoup plus utile car il change la propriété de tout le schéma, y ​​compris les fonctions, les index, les séquences, etc. Merci!
liviucmg
Il ne change pas les propriétaires de schéma. Comment changer également les propriétaires de schéma?
Andrus
@Andrus ALTER DATABASE $ DB OWNER TO $ OWNER;
Johan Dahlin
modifier la base de données change le propriétaire de la base de données entière. J'ai demandé comment changer de propriétaire de schéma.
Andrus
ALTER SCHEMA fred PROPRIÉTAIRE À betty;
Eric Aldinger
21

J'ai récemment dû changer la propriété de tous les objets d'une base de données. Bien que les tables, les vues, les déclencheurs et les séquences aient été quelque peu modifiés facilement, l'approche ci-dessus a échoué pour les fonctions car la signature fait partie du nom de la fonction. Certes, j'ai une formation MySQL et je ne connais pas très bien Postgres.

Cependant, pg_dump vous permet de vider uniquement le schéma et celui-ci contient le ALTER xxx OWNER TO yyy; déclarations dont vous avez besoin. Voici ma magie du shell sur le sujet

pg_dump -s YOUR_DB | grep -i 'owner to' | sed -e 's/OWNER TO .*;/OWNER TO NEW_OWNER;/i' | psqL YOUR_DB
magiconair
la source
Je ne sais pas pourquoi vous utilisez la grepcommande. Je suis moi-même nouveau sur Linux, mais d'après ce que je comprends, il semble que ce sedsoit très bien à utiliser, d'autant plus que vous spécifiez une correspondance insensible à la casse de toute façon.
Bobort
19

très simple, essayez-le ...

 select 'ALTER TABLE ' || table_name || ' OWNER TO myuser;' from information_schema.tables where table_schema = 'public';
mwendamseke
la source
4
Vous pouvez ajouter une note indiquant que les chaînes correspondantes doivent être copiées et exécutées. Ce n'est pas évident: p
Nightscape
Ce qui inclut la suppression de toutes les citations autour des instructions alter .. multi-curseurs ou replace aide dans ce cas.
knownasilya
19

est très simple

  1. su - postgres
  2. psql
  3. RÉASSIGNER APPARTENANT À [ancien_utilisateur] À [nouveau_utilisateur];
  4. \ c [votre base de données]
  5. RÉASSIGNER APPARTENANT À [ancien_utilisateur] À [nouveau_utilisateur];

terminé.

durenzo
la source
1
Cela fait probablement ce que le demandeur voulait. De loin le plus simple.
Geof Sawaya du
1
Vous avez seulement 4 ans de retard pour la fête; faites défiler vers le haut: stackoverflow.com/a/13535184/1772379
Ben Johnson
16

J'aime celui-ci car il modifie les tables , les vues , les séquences et les fonctions propriétaire d'un certain schéma en une seule fois (dans une instruction sql), sans créer de fonction et vous pouvez l'utiliser directement dans PgAdmin III et psql :

(Testé dans PostgreSql v9.2)

DO $$DECLARE r record;
DECLARE
    v_schema varchar := 'public';
    v_new_owner varchar := '<NEW_OWNER>';
BEGIN
    FOR r IN 
        select 'ALTER TABLE "' || table_schema || '"."' || table_name || '" OWNER TO ' || v_new_owner || ';' as a from information_schema.tables where table_schema = v_schema
        union all
        select 'ALTER TABLE "' || sequence_schema || '"."' || sequence_name || '" OWNER TO ' || v_new_owner || ';' as a from information_schema.sequences where sequence_schema = v_schema
        union all
        select 'ALTER TABLE "' || table_schema || '"."' || table_name || '" OWNER TO ' || v_new_owner || ';' as a from information_schema.views where table_schema = v_schema
        union all
        select 'ALTER FUNCTION "'||nsp.nspname||'"."'||p.proname||'"('||pg_get_function_identity_arguments(p.oid)||') OWNER TO ' || v_new_owner || ';' as a from pg_proc p join pg_namespace nsp ON p.pronamespace = nsp.oid where nsp.nspname = v_schema
    LOOP
        EXECUTE r.a;
    END LOOP;
END$$;

Sur la base des réponses fournies par @rkj, @AlannaRose, @SharoonThomas, @ user3560574 et cette réponse par @a_horse_with_no_name

Merci beaucoup.


Mieux encore: changez également le propriétaire de la base de données et du schéma .

DO $$DECLARE r record;
DECLARE
    v_schema varchar := 'public';
    v_new_owner varchar := 'admin_ctes';
BEGIN
    FOR r IN 
        select 'ALTER TABLE "' || table_schema || '"."' || table_name || '" OWNER TO ' || v_new_owner || ';' as a from information_schema.tables where table_schema = v_schema
        union all
        select 'ALTER TABLE "' || sequence_schema || '"."' || sequence_name || '" OWNER TO ' || v_new_owner || ';' as a from information_schema.sequences where sequence_schema = v_schema
        union all
        select 'ALTER TABLE "' || table_schema || '"."' || table_name || '" OWNER TO ' || v_new_owner || ';' as a from information_schema.views where table_schema = v_schema
        union all
        select 'ALTER FUNCTION "'||nsp.nspname||'"."'||p.proname||'"('||pg_get_function_identity_arguments(p.oid)||') OWNER TO ' || v_new_owner || ';' as a from pg_proc p join pg_namespace nsp ON p.pronamespace = nsp.oid where nsp.nspname = v_schema
        union all
        select 'ALTER SCHEMA "' || v_schema || '" OWNER TO ' || v_new_owner 
        union all
        select 'ALTER DATABASE "' || current_database() || '" OWNER TO ' || v_new_owner 
    LOOP
        EXECUTE r.a;
    END LOOP;
END$$;
elysch
la source
INCROYABLE! Pourquoi Postgres n'ajoute pas ça je ne sais pas!
pip
Deux questions: 1) Il semble que les première et troisième lignes "ALTER TABLE" soient des dupes. Est-ce intentionnel (par exemple, devez-vous faire deux passes sur les tables pour changer de propriétaire?). 2) Nous constatons qu'il information_schema.sequencesest vide, même s'il SELECT c.* FROM pg_class c WHERE c.relkind = 'S';répertorie les séquences. Pourquoi pourraient-ils ne pas correspondre?
GuyPaddock
De plus, la deuxième ALTERrequête ne devrait-elle pas être un ALTER SEQUENCE?
GuyPaddock
12

J'ai dû changer la propriété des tables, des vues et des séquences et j'ai trouvé que la grande solution publiée par @rjk fonctionnait bien - malgré un détail: si les noms d'objet sont de casse mixte (par exemple "TableName"), cela échouera avec un " Erreur non trouvée.
Pour contourner cela, enveloppez les noms des objets avec '"' comme ceci:

les tables

SELECT 'ALTER TABLE \"'|| schemaname || '.' || tablename ||'\" OWNER TO my_new_owner;'
FROM pg_tables WHERE NOT schemaname IN ('pg_catalog', 'information_schema')
ORDER BY schemaname, tablename;

Les séquences

SELECT 'ALTER SEQUENCE \"'|| sequence_schema || '.' || sequence_name ||'\" OWNER TO my_new_owner;'
FROM information_schema.sequences WHERE NOT sequence_schema IN ('pg_catalog', 'information_schema')
ORDER BY sequence_schema, sequence_name;

Vues

SELECT 'ALTER VIEW \"'|| table_schema || '.' || table_name ||'\" OWNER TO my_new_owner;'
FROM information_schema.views WHERE NOT table_schema IN ('pg_catalog', 'information_schema')
ORDER BY table_schema, table_name;
Juge
la source
10

Vous pouvez essayer ce qui suit dans PostgreSQL 9

DO $$DECLARE r record;
BEGIN
    FOR r IN SELECT tablename FROM pg_tables WHERE schemaname = 'public'
    LOOP
        EXECUTE 'alter table '|| r.tablename ||' owner to newowner;';
    END LOOP;
END$$;
user3560574
la source
6

Il n'y a pas une telle commande dans PostgreSQL. Mais vous pouvez contourner ce problème en utilisant la méthode que j'ai décrite il y a quelque temps pour les subventions.


la source
Merci, très bon article. Je garderai cela comme référence future. À l'aide de pgAdmin, j'ai fini par sauvegarder la base de données, supprimer / supprimer la base de données, accorder temporairement à new_owner les droits nécessaires, puis recréer et restaurer DB en tant que new_owner, avec l'option "no owner" cochée dans la fenêtre de restauration. Cela a produit les résultats que je cherchais avec new_owner comme propriétaire de tout.
Kai
Postgres 9.3 a introduit la commande REASSIGN OWNED. postgresql.org/docs/9.3/sql-reassign-OWN.html
Georg Zimmer
3

Sur la base de la réponse d'elysch , voici une solution pour plusieurs schémas:

DO $$
DECLARE 
  r record;
  i int;
  v_schema text[] := '{public,schema1,schema2,schema3}';
  v_new_owner varchar := 'my_new_owner';
BEGIN
    FOR r IN 
        select 'ALTER TABLE "' || table_schema || '"."' || table_name || '" OWNER TO ' || v_new_owner || ';' as a from information_schema.tables where table_schema = ANY (v_schema)
        union all
        select 'ALTER TABLE "' || sequence_schema || '"."' || sequence_name || '" OWNER TO ' || v_new_owner || ';' as a from information_schema.sequences where sequence_schema = ANY (v_schema)
        union all
        select 'ALTER TABLE "' || table_schema || '"."' || table_name || '" OWNER TO ' || v_new_owner || ';' as a from information_schema.views where table_schema = ANY (v_schema)
        union all
        select 'ALTER FUNCTION "'||nsp.nspname||'"."'||p.proname||'"('||pg_get_function_identity_arguments(p.oid)||') OWNER TO ' || v_new_owner || ';' as a from pg_proc p join pg_namespace nsp ON p.pronamespace = nsp.oid where nsp.nspname = ANY (v_schema)
        union all
        select 'ALTER DATABASE "' || current_database() || '" OWNER TO ' || v_new_owner 
    LOOP
        EXECUTE r.a;
    END LOOP;
    FOR i IN array_lower(v_schema,1) .. array_upper(v_schema,1)
    LOOP
        EXECUTE 'ALTER SCHEMA "' || v_schema[i] || '" OWNER TO ' || v_new_owner ;
    END LOOP;
END
$$;
JC Boggio
la source
2

La réponse de @Alex Soto est la bonne et l'essentiel téléchargé par @Yoav Aner fonctionne également à condition qu'il n'y ait pas de caractères spéciaux dans les noms de table / vue (qui sont légaux en postgres).

Vous devez leur échapper pour travailler et j'ai téléchargé un résumé pour cela: https://gist.github.com/2911117

Sharoon Thomas
la source
2
pg_dump as insert statements 
pg_dump -d -O database filename
-d ( data as inserts ) -O ( capital O is no owner )

Redirigez ensuite le fichier de sauvegarde vers PostgreSQL en utilisant:

psql -d database -U username -h hostname < filename

Comme aucun propriétaire n'est inclus, tous les tableaux, schémas, etc. créés sont créés sous l'utilisateur de connexion que vous spécifiez.

J'ai lu que cela pourrait également être une bonne approche pour la migration entre les versions de PostgreSQL.

atwsKris
la source
2

J'ai créé un script pratique pour cela; pg_change_db_owner.sh . Ce script change la propriété de toutes les tables, vues, séquences et fonctions dans un schéma de base de données et également le propriétaire du schéma lui-même.

Veuillez noter que si vous souhaitez simplement modifier la propriété de tous les objets, dans une base de données particulière, appartenant à un rôle de base de données particulier, vous pouvez simplement utiliser la commande à la REASSIGN OWNEDplace.

Jakub Jirutka
la source
1

À partir de PostgreSQL 9.0, vous avez la possibilité de savoir GRANT [priv name] ON ALL [object type] IN SCHEMA[priv name]est le standard SELECT, INSERT, UPDATE, DELETE, etcet vous [object type]pouvez être l'un des suivants:

  • TABLES
  • SEQUENCES
  • FUNCTIONS

Les documents de PostgreSQL sur GRANTet REVOKEaller plus en détail à ce sujet. Dans certaines situations, il est toujours nécessaire d'utiliser des astuces impliquant les catalogues système ( pg_catalog.pg_*), mais ce n'est pas aussi courant. Je fais souvent ce qui suit:

  1. BEGIN une transaction pour modifier les privs
  2. Changer la propriété de DATABASESen "rôle DBA"
  3. Changer la propriété de SCHEMASpour le "rôle DBA"
  4. REVOKE ALLprivs sur tous TABLES, SEQUENCESet FUNCTIONSde tous les rôles
  5. GRANT SELECT, INSERT, UPDATE, DELETE sur des tableaux pertinents / appropriés aux rôles appropriés
  6. COMMIT la transaction DCL.
Sean
la source
1

La solution acceptée ne prend pas en charge la propriété de la fonction. La solution suivante s'occupe de tout (en examinant, j'ai remarqué qu'elle est similaire à @magiconair ci-dessus)

echo "Database: ${DB_NAME}"
echo "Schema: ${SCHEMA}"
echo "User: ${NEW_OWNER}"

pg_dump -s -c -U postgres ${DB_NAME} | egrep "${SCHEMA}\..*OWNER TO"| sed -e "s/OWNER TO.*;$/OWNER TO ${NEW_OWNER};/" | psql -U postgres -d ${DB_NAME}
# do following as last step to allow recovery
psql -U postgres -d postgres -c "ALTER DATABASE ${DB_NAME} OWNER TO ${NEW_OWNER};"
jsh
la source
1

Le script shell plus simple suivant a fonctionné pour moi.

#!/bin/bash
for i in  `psql -U $1  -qt -c  "select tablename from pg_tables where schemaname='$2'"`
do
psql -U $1 -c  "alter table $2.$i set schema $3"
done

Où entrée $ 1 - nom d'utilisateur (base de données) $ 2 = schéma existant $ 3 = vers le nouveau schéma.

sramay
la source
1

Identique à l'approche de @ AlexSoto 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
0

Docker: Modifier le propriétaire de toutes les tables + séquences

export user="your_new_owner"
export dbname="your_db_name"

cat <<EOF | docker run -i --rm --link postgres:postgres postgres sh -c "psql -h \$POSTGRES_PORT_5432_TCP_ADDR -p \$POSTGRES_PORT_5432_TCP_PORT -U postgres -d $dbname" | grep ALTER | docker run -i --rm --link postgres:postgres postgres sh -c "psql -h \$POSTGRES_PORT_5432_TCP_ADDR -p \$POSTGRES_PORT_5432_TCP_PORT -U postgres -d $dbname"
SELECT 'ALTER TABLE '||schemaname||'.'||tablename||' OWNER TO $user;' FROM pg_tables WHERE schemaname = 'public';
SELECT 'ALTER SEQUENCE '||relname||' OWNER TO $user;' FROM pg_class WHERE relkind = 'S';
EOF
Vojtech Vitek
la source