Zmodyfikuj WŁAŚCICIELA na wszystkich stołach jednocześnie w PostgreSQL

409

Jak zmodyfikować właściciela wszystkich tabel w bazie danych PostgreSQL?

Próbowałem, ALTER TABLE * OWNER TO new_ownerale nie obsługuje składni gwiazdki.

Kai
źródło

Odpowiedzi:

459

Zobacz REASSIGN OWNEDpolecenie

Uwaga: Jak wspomina @trygvis w odpowiedzi poniżej , REASSIGN OWNEDpolecenie jest dostępne od wersji co najmniej 8.2 i jest znacznie łatwiejszą metodą.


Ponieważ zmieniasz własność wszystkich tabel, prawdopodobnie chcesz też widoków i sekwencji. Oto co zrobiłem:

Stoły:

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

Sekwencje:

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

Wyświetlenia:

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

Prawdopodobnie możesz to trochę przesuszyć , ponieważ instrukcje alter są identyczne dla wszystkich trzech.


Alex Soto
źródło
10
+1 dzięki Alex. Stworzyłem mały skrypt bash oparty na twojej odpowiedzi, dostępny na gist.github.com/2482969
gingerlime
10
Zobacz ostatnią odpowiedź @trygvis. Najprostsza jak dotąd odpowiedź:REASSIGN OWNED BY old_role [, ...] TO new_role
David
64
REASSIGN OWNED BY nie działa dla obiektów należących do postgres.
BrunoJCM,
19
Ponadto REASSIGN OWNED faktycznie wpływa na własność wszystkich baz danych należących do starej roli (patrz: postgresql.org/docs/9.3/static/sql-reassign-owned.html ). Jeśli więc chcesz zmienić własność tylko jednej bazy danych, strzeż się!
kitsune
3
Na podstawie skryptu @gingerlime, bspkrs (nie mógł znaleźć swojego imienia) stworzył taki, który również zmienia funkcje: https://gist.github.com/bspkrs/b997ed7f1eb1268f3403
elysch
537

Możesz użyć REASSIGN OWNEDpolecenia.

Streszczenie:

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

Spowoduje to zmianę wszystkich obiektów należących old_roledo nowej roli. Nie musisz myśleć o tym, jakie obiekty ma użytkownik, wszystkie zostaną zmienione. Pamiętaj, że dotyczy to tylko obiektów w jednej bazie danych. Nie zmienia to również właściciela samej bazy danych.

Jest dostępny w wersji co najmniej 8.2. Ich dokumentacja online sięga tak daleko wstecz.

Trygve Laugstøl
źródło
ERROR: unexpected classid 3079. Myślę, że obecnie nie działa, jeśli są jakieś rozszerzenia.
Steve Jorgensen,
40
Wydaje się, że to nie działa w przypadku postgresów użytkowników, mimo że jestem podłączony do bazy danych, którą utworzyłem (tj. Nie jest to systemowa baza danych), mówi to: BŁĄD: nie można ponownie przypisać własności obiektów należących do roli postgres, ponieważ są one wymagane przez bazę danych system
wtorek
13
Jak donosi @thnee, REASSIGN wpływa na wszystkie obiekty w bazie danych i nie rozróżnia obiektów zdefiniowanych przez użytkownika od obiektów systemowych, więc nie działa dla postgres, jeśli jakieś rozszerzenie ma własne tabele. Nadal wolę (+1) tę opcję ze względu na elegancję, mimo że niewiele mi to pomogło (moja baza danych była wcześniej własnością postgres).
Pavel V.
6
Żeby było jasne, to polecenie działa TYLKO w bazie danych, z którą jesteś aktualnie połączony. Jeśli old_role posiada obiekty w wielu bazach danych, powinieneś połączyć i uruchomić to polecenie w każdej z tych baz danych
mavroprovato,
11
nie działa to na postgres hostowanych przez AWS RDS. Pojawia się błąd „odmowa ponownego przypisania uprawnień” i ten link sugeruje dlaczego: „Wydaje się, że jedynym sposobem na„ ponowne przypisanie własności ”jest superużytkownik (co jest sprzeczne z dokumentacją), co jest niedostępne w RDS. ” postgresql-archive.org/…
typoerrpr
196

To: http://archives.postgresql.org/pgsql-bugs/2007-10/msg00234.php jest również dobrym i szybkim rozwiązaniem, które działa na wielu schematach w jednej bazie danych:

Stoły

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;

Sekwencje

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;

Wyświetlenia

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;

Widoki zmaterializowane

Na podstawie tej odpowiedzi

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

Generuje to wszystkie wymagane instrukcje ALTER TABLE/ ALTER SEQUENCE/ ALTER VIEW, kopiuje je i wkleja z powrotem do plsql, aby je uruchomić.

Sprawdź swoją pracę w psql, wykonując:

\dt *.*
\ds *.*
\dv *.*
rkj
źródło
Świetne rozwiązanie. Moim jedynym problemem było to, że wyeksportowałem skrypty, a następnie wykonałem wyeksportowane skrypty. Jestem SQL Server Guru, ale nie jestem pewien, jaki skrót ma zostać wykonany. Kliknąłem polecenie wykonania zapytania i uruchomiłem pgScript. Co robiłem źle?
Tyrone Moodley,
1
Wolałem to, ponieważ działa z poziomu plsql po zalogowaniu - skrypty poziomu uniksowego (obecnie ulubiona odpowiedź) wymagają wpisania „-U postgres” i hasła w moim środowisku.
Oszołomiony
2
Wolę tę odpowiedź, ponieważ (1) można to zrobić w psql lub pgAdmin (2), pozwala łatwo zobaczyć obiekty, które zmienisz. Użyłem również stackoverflow.com/questions/22803096/... , który jest podobny, ale dotyczy funkcji.
AlannaRose
wspaniała logika.
Emipro Technologies Pvt. Sp. z o.o.
42

Jeśli chcesz to zrobić w jednej instrukcji SQL, musisz zdefiniować funkcję exec (), jak wspomniano w 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$;

Następnie możesz wykonać to zapytanie, zmieni ono właściciela tabel, sekwencji i widoków:

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 to nowa nazwa nowego właściciela postgresql.

W większości przypadków musisz być superużytkownikiem, aby to wykonać. Można tego uniknąć, zmieniając właściciela z własnego użytkownika na grupę ról, do której należysz.

Dzięki RhodiumToad na #postgresql za pomoc w tym.

Johan Dahlin
źródło
2
Jest to o wiele bardziej przydatne, ponieważ zmienia własność całego schematu, w tym funkcji, indeksów, sekwencji itp. Dziękuję!
liviucmg
Nie zmienia właścicieli schematów. Jak zmienić także właścicieli schematów?
Andrus
@Andrus ZMIEŃ bazę danych $ DB WŁAŚCICIEL DO $ WŁAŚCICIEL;
Johan Dahlin
modyfikuj zmiany bazy danych cały właściciel bazy danych. Zapytałem, jak zmienić właścicieli schematów.
Andrus
ALTER SCHEMA fred WŁAŚCICIELEM do betty;
Eric Aldinger
21

Niedawno musiałem zmienić własność wszystkich obiektów w bazie danych. Chociaż tabele, widoki, wyzwalacze i sekwencje zostały nieco zmienione, powyższe podejście nie powiodło się dla funkcji, ponieważ podpis jest częścią nazwy funkcji. To prawda, że ​​mam doświadczenie w MySQL i nie znam się na Postgresie.

Jednak pg_dump pozwala na zrzucenie tylko schematu, a zawiera on ALTER xxx WŁAŚCICIEL DO rrr; oświadczenia, których potrzebujesz. Oto moja odrobina magii powłoki na ten temat

pg_dump -s YOUR_DB | grep -i 'owner to' | sed -e 's/OWNER TO .*;/OWNER TO NEW_OWNER;/i' | psqL YOUR_DB
magiconair
źródło
Nie jestem pewien, dlaczego używasz greppolecenia. Sam jestem nowy w Linuksie, ale z mojego rozumienia wydaje się, że sedjest w porządku, zwłaszcza, że ​​i tak określasz dopasowanie bez rozróżniania wielkości liter.
Bobort
19

bardzo proste, spróbuj ...

 select 'ALTER TABLE ' || table_name || ' OWNER TO myuser;' from information_schema.tables where table_schema = 'public';
mwendamseke
źródło
4
Możesz dodać notatkę, że odpowiednie ciągi muszą zostać skopiowane i wykonane. Nie, że to nie jest oczywiste: p
Nightscape
Obejmuje to usunięcie wszystkich cudzysłowów wokół instrukcji alter. W tym przypadku pomaga kursor lub zamień.
knownasilya
19

jest bardzo proste

  1. su - postgres
  2. psql
  3. PONOWNIE PRZEKŁADAJ SIĘ PRZEZ [old_user] DO [new_user];
  4. \ c [twoja baza danych]
  5. PONOWNIE PRZEKŁADAJ SIĘ PRZEZ [old_user] DO [new_user];

gotowy.

durenzo
źródło
1
To pewnie robi to, co querent chciał. Zdecydowanie najłatwiejszy.
Geof Sawaya,
1
Spóźniłeś się na przyjęcie tylko 4 lata; przewiń w górę: stackoverflow.com/a/13535184/1772379
Ben Johnson
16

Podoba mi się ten, ponieważ modyfikuje on tabele , widoki , sekwencje i funkcje właściciela określonego schematu za jednym razem (w jednej instrukcji SQL), bez tworzenia funkcji i można go używać bezpośrednio w PgAdmin III i psql :

(Testowane w 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$$;

Na podstawie odpowiedzi udzielonych przez @rkj, @AlannaRose, @SharoonThomas, @ user3560574 i tę odpowiedź przez @a_horse_with_no_name

Wielkie dzięki.


Jeszcze lepiej: zmień także właściciela bazy danych i schematu .

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
źródło
NIESAMOWITY! Dlaczego postgres tego nie dodaje Nie wiem!
pip
Dwa pytania: 1) Wygląda na to, że pierwsza i trzecia linia „ALTER TABLE” to duplikaty. Czy jest to celowe (np. Czy musisz zrobić dwa przejścia nad tabelami, aby zmienić własność?). 2) Stwierdzamy, że information_schema.sequencesjest pusty, mimo że SELECT c.* FROM pg_class c WHERE c.relkind = 'S';wyświetla sekwencje. Dlaczego mogą się nie zgadzać?
GuyPaddock,
Czy drugie ALTERpytanie nie powinno być ALTER SEQUENCE?
GuyPaddock,
12

Musiałem zmienić własność tabel, widoków i sekwencji i stwierdziłem, że świetne rozwiązanie opublikowane przez @rjk działa dobrze - pomimo jednego szczegółu: jeśli nazwy obiektów mają różne litery (np. „TableName”), to nie powiedzie się z „ nie znaleziono błędu.
Aby to obejść, zawiń nazwy obiektów następującymi znakami „”:

Stoły

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;

Sekwencje

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;

Wyświetlenia

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;
Sędzia
źródło
10

Możesz spróbować wykonać następujące czynności w 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$$;
użytkownik3560574
źródło
6

W PostgreSQL nie ma takiego polecenia. Ale możesz obejść to przy użyciu metody, którą opisałem jakiś czas temu dla GRANT.


źródło
Dziękuję bardzo fajny artykuł. Zachowam to jako odniesienie w przyszłości. Korzystając z pgAdmin, utworzyłem kopię zapasową bazy danych, upuszczając / usuwając bazę danych, tymczasowo przyznając new_owner niezbędne uprawnienia, a następnie ponownie tworząc i przywracając DB jako new_owner, z opcją „no owner” zaznaczoną w oknie przywracania. To dało wyniki, których szukałem z właścicielem new_owner jako właścicielem wszystkiego.
Kai
Postgres 9.3 wprowadził komendę REASSIGN OWNED. postgresql.org/docs/9.3/sql-reassign-owned.html
Georg Zimmer
3

Na podstawie odpowiedzi elysch , oto rozwiązanie dla wielu schematów:

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
źródło
2

Odpowiedź @Alex Soto jest prawidłowa, a treść przesłana przez @Yoav Aner również działa, pod warunkiem, że nie ma żadnych znaków specjalnych w nazwach tabel / widoków (które są legalne w postgresie).

Musisz uciec od nich, aby pracować, a ja przesłałem do tego listę: https://gist.github.com/2911117

Sharoon Thomas
źródło
2
pg_dump as insert statements 
pg_dump -d -O database filename
-d ( data as inserts ) -O ( capital O is no owner )

Następnie przenieś plik kopii zapasowej z powrotem do PostgreSQL, używając:

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

Ponieważ nie ma w nim właściciela, wszystkie utworzone tabele, schematy itp. Są tworzone w ramach określonego użytkownika logowania.

Przeczytałem, że może to być również dobre podejście do migracji między wersjami PostgreSQL.

atwsKris
źródło
2

Stworzyłem do tego wygodny skrypt; pg_change_db_owner.sh . Ten skrypt zmienia własność wszystkich tabel, widoków, sekwencji i funkcji w schemacie bazy danych, a także właściciela samego schematu.

Pamiętaj, że jeśli chcesz tylko zmienić własność wszystkich obiektów w określonej bazie danych, należących do określonej roli bazy danych, możesz po prostu użyć polecenia REASSIGN OWNEDzamiast tego.

Jakub Jirutka
źródło
1

Począwszy od PostgreSQL 9.0, możesz określić, GRANT [priv name] ON ALL [object type] IN SCHEMAgdzie [priv name]jest typowy SELECT, INSERT, UPDATE, DELETE, etci [object type]może być jednym z:

  • TABLES
  • SEQUENCES
  • FUNCTIONS

Dokumenty PostgreSQL GRANTi REVOKEprzejdź do bardziej szczegółowych informacji na ten temat. W niektórych sytuacjach nadal wymagane jest stosowanie sztuczek obejmujących katalogi systemowe ( pg_catalog.pg_*), ale nie jest to tak powszechne. Często wykonuję następujące czynności:

  1. BEGIN transakcja modyfikacji prywatny
  2. Zmień właściciela DATABASESna „rolę DBA”
  3. Zmień właściciela SCHEMASna „rolę DBA”
  4. REVOKE ALLprivs na wszystko TABLES, SEQUENCESa FUNCTIONSze wszystkich ról
  5. GRANT SELECT, INSERT, UPDATE, DELETE na odpowiednich / odpowiednich tabelach do odpowiednich ról
  6. COMMIT transakcja DCL.
Sean
źródło
1

Zaakceptowane rozwiązanie nie dba o własność funkcji po rozwiązaniu dba o wszystko (podczas przeglądu zauważyłem, że jest podobny do @magiconair powyżej)

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
źródło
1

Poniższy prostszy skrypt powłoki zadziałał dla mnie.

#!/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

Gdzie wpisz 1 $ - nazwa użytkownika (baza danych) 2 $ = istniejący schemat 3 USD = nowy schemat.

sramay
źródło
1

To samo, co podejście @ AlexSoto do funkcji:

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
źródło
0

Docker: modyfikuj właściciela wszystkich tabel i sekwencji

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
źródło