Modifique OWNER em todas as tabelas simultaneamente no PostgreSQL

412

Como modifico o proprietário de todas as tabelas em um banco de dados PostgreSQL?

Eu tentei, ALTER TABLE * OWNER TO new_ownermas ele não suporta a sintaxe do asterisco.

Kai
fonte

Respostas:

461

Ver REASSIGN OWNEDcomando

Nota: Como @trygvis menciona na resposta abaixo , o REASSIGN OWNEDcomando está disponível desde pelo menos a versão 8.2 e é um método muito mais fácil.


Como você está alterando a propriedade de todas as tabelas, provavelmente também deseja visualizações e sequências. Aqui está o que eu fiz:

Tabelas:

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

Sequências:

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

Visualizações:

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

Você provavelmente poderia secar um pouco, pois as instruções alter são idênticas para os três.


Alex Soto
fonte
10
+1 Obrigado Alex. Eu criei um pequeno script bash com base em sua resposta, disponível em gist.github.com/2482969
gingerlime
10
Veja a resposta recente de @trygvis. Resposta mais simples, de longe:REASSIGN OWNED BY old_role [, ...] TO new_role
David
64
A nova atribuição de propriedade de não funciona para objetos pertencentes ao postgres.
BrunoJCM
19
Além disso, REASSIGN OWNED realmente afeta a propriedade de todos os bancos de dados pertencentes à função antiga (consulte: postgresql.org/docs/9.3/static/sql-reassign-owned.html ). Portanto, se você deseja alterar apenas a propriedade de um único banco de dados, tenha cuidado!
kitsune
3
Baseado em @gingerlime roteiro, bspkrs (não poderia encontrar o seu nome) criou um que também altera as funções: https://gist.github.com/bspkrs/b997ed7f1eb1268f3403
elysch
538

Você pode usar o REASSIGN OWNEDcomando

Sinopse:

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

Isso altera todos os objetos pertencentes a old_rolepara a nova função. Você não precisa pensar em que tipo de objetos o usuário possui, todos eles serão alterados. Observe que isso se aplica apenas a objetos dentro de um único banco de dados. Também não altera o proprietário do próprio banco de dados.

Está disponível de volta a pelo menos 8.2. Sua documentação on-line remonta apenas a esse ponto.

Trygve Laugstøl
fonte
ERROR: unexpected classid 3079. Acho que atualmente não funciona se houver extensões.
Steve Jorgensen
40
Isso parece não funcionar para os usuários do postgres, mesmo estando conectado a um banco de dados que criei (isto é, não um banco de dados do sistema), ele diz o seguinte: ERRO: não é possível reatribuir a propriedade dos objetos pertencentes aos papéis do postgres porque eles são solicitados pelo banco de dados sistema
thnee 8/03/2019
13
Como o @thnee relatou, o REASSIGN afeta todos os objetos no banco de dados e não discrimina entre objetos definidos pelo usuário e objetos do sistema, portanto, não funciona para o postgres se houver alguma extensão com suas próprias tabelas. Ainda prefiro (+1) esta opção por elegância, mesmo que não tenha me ajudado muito (meu banco de dados era de propriedade do postgres).
Pavel V.
6
Só para esclarecer, este comando funciona no banco de dados que você está conectado SOMENTE no momento. Se o OLD_ROLE possui objetos em vários bancos de dados, você deve conectar e executar este comando em cada um desses bancos de dados
mavroprovato
11
isso parece não funcionar no postgres hospedado pelo AWS RDS. Estou recebendo esse erro "permissão negada para reatribuir objetos" e este link sugere o motivo: "Parece que a única maneira de 'reatribuir propriedade' é como um superusuário (que é contradito pela documentação), que não está acessível no RDS. postgresql-archive.org/…
typoerrpr
198

Esta: http://archives.postgresql.org/pgsql-bugs/2007-10/msg00234.php também é uma solução agradável e rápida e funciona para vários esquemas em um banco de dados:

Tabelas

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;

Sequências

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;

Visualizações

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;

Visualizações materializadas

Com base nesta resposta

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

Isso gera todas as instruções / ALTER TABLE/ necessárias , copie-as e cole-as novamente no plsql para executá-las.ALTER SEQUENCEALTER VIEW

Verifique seu trabalho no psql fazendo:

\dt *.*
\ds *.*
\dv *.*
rkj
fonte
Ótima solução. Meu único problema foi que eu exportei os scripts e depois executei os scripts exportados. Eu sou o SQL Server Guru, mas não sei ao certo qual é o atalho a ser executado. Cliquei em executar consulta e executar pgScript. O que eu estava fazendo de errado?
Tyrone Moodley
1
Eu preferi isso, pois ele trabalha no plsql uma vez logado - os scripts no nível unix (atualmente a resposta favorita) exigem um "-U postgres" e uma entrada de senha no meu ambiente.
Apraz
2
Prefiro esta resposta porque (1) ela pode ser feita no psql ou no pgAdmin (2), e permite ver facilmente os objetos que você estará alterando. Eu também usei stackoverflow.com/questions/22803096/… , que é semelhante, mas para funções.
AlannaRose
lógica esplêndida.
Emipro Technologies Unip. Ltd.
42

Se você quiser fazer isso em uma instrução sql, precisará definir uma função exec () conforme mencionado em 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$;

Então você pode executar esta consulta, ela mudará o proprietário de tabelas, sequências e visualizações:

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 é o novo nome do novo proprietário do postgresql.

Na maioria das circunstâncias, você precisa ser superusuário para executar isso. Você pode evitar que, alterando o proprietário de seu próprio usuário para um grupo de funções do qual você seja membro.

Agradecemos ao RhodiumToad no #postgresql por ajudar com isso.

Johan Dahlin
fonte
2
Isso é muito mais útil, pois altera a propriedade de todo o esquema, incluindo funções, índices, sequências, etc. Obrigado!
liviucmg
Não altera os proprietários do esquema. Como alterar os proprietários do esquema também?
Andrus
@Andrus ALTER O PROPRIETÁRIO DE $ DB A $ OWNER;
Johan Dahlin
alterar banco de dados altera o proprietário inteiro do banco de dados. Perguntei como alterar os proprietários do esquema.
18720 Andrus
ALTER SCHEMA FRED PROPRIETÁRIO A Betty;
precisa saber é o seguinte
21

Recentemente, tive que alterar a propriedade de todos os objetos em um banco de dados. Embora tabelas, visualizações, gatilhos e seqüências tenham sido alterados com alguma facilidade, a abordagem acima falhou para as funções, pois a assinatura faz parte do nome da função. Concedido, eu tenho um histórico no MySQL e não estou familiarizado com o Postgres.

No entanto, pg_dump permite despejar apenas o esquema e isso contém o ALTER xxx OWNER TO yyy; declarações que você precisa. Aqui está o meu pouco de magia shell sobre o tema

pg_dump -s YOUR_DB | grep -i 'owner to' | sed -e 's/OWNER TO .*;/OWNER TO NEW_OWNER;/i' | psqL YOUR_DB
magiconair
fonte
Não sei por que você está usando o grepcomando Eu sou novo no Linux, mas, pelo que entendi, parece que sedé muito bom de usar, especialmente porque você está especificando uma correspondência que não diferencia maiúsculas de minúsculas.
Bobort 9/03
19

muito simples, experimente ...

 select 'ALTER TABLE ' || table_name || ' OWNER TO myuser;' from information_schema.tables where table_schema = 'public';
mwendamseke
fonte
4
Você pode adicionar uma nota de que as seqüências correspondentes devem ser copiadas e executadas. Não que não é óbvio: p
Nightscape
O que inclui a remoção de todas as aspas ao redor das instruções alter.
knownasilya
19

é muito simples

  1. su - postgres
  2. psql
  3. REASSINAR PROPRIEDADE POR [old_user] TO [new_user];
  4. \ c [seu banco de dados]
  5. REASSINAR PROPRIEDADE POR [old_user] TO [new_user];

feito.

durenzo
fonte
1
Isso provavelmente faz o que o consultor queria. De longe o mais fácil.
Geof Sawaya
1
Você está com apenas 4 anos de atraso na festa; Role para cima: stackoverflow.com/a/13535184/1772379
Ben Johnson
16

Eu gosto deste, pois modifica tabelas , visualizações , sequências e funções proprietárias de um determinado esquema de uma só vez (em uma instrução sql), sem criar uma função e você pode usá-lo diretamente no PgAdmin III e no psql :

(Testado no 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$$;

Com base nas respostas fornecidas por @rkj, @AlannaRose, @SharoonThomas, @ user3560574 e esta resposta por @a_horse_with_no_name

Muito obrigado.


Melhor ainda: altere também o proprietário do banco de dados e do esquema .

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
fonte
SURPREENDENTE! Por que o postgres não adiciona isso, eu não sei!
pip
Duas perguntas: 1) Parece que a primeira e a terceira linhas "ALTER TABLE" são burras. Isso é intencional (por exemplo, você precisa fazer duas passagens sobre as tabelas para mudar de propriedade?). 2) Descobrimos que ele information_schema.sequencesestá vazio, apesar de SELECT c.* FROM pg_class c WHERE c.relkind = 'S';listar sequências. Por que eles não combinam?
precisa saber é o seguinte
Além disso, a segunda ALTERconsulta não deveria ser uma ALTER SEQUENCE?
GuyPaddock
12

Eu tive que mudar a propriedade das tabelas, visualizações e seqüências e achei que a ótima solução postada por @rjk está funcionando bem - apesar de um detalhe: se os nomes dos objetos forem de letras maiúsculas e minúsculas (por exemplo, "TableName"), isso falhará com " erro não encontrado.
Para contornar isso, envolva os nomes dos objetos com '"' assim:

Tabelas

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;

Sequências

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;

Visualizações

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;
Juiz
fonte
10

Você pode tentar o seguinte no 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
fonte
6

Não existe esse comando no PostgreSQL. Mas você pode contornar isso usando o método que descrevi há algum tempo para GRANTs.


fonte
Obrigado, artigo muito bom. Vou manter isso como uma referência futura. Usando o pgAdmin, acabei fazendo backup do banco de dados, removendo / excluindo o banco de dados, concedendo temporariamente a new_owner os direitos necessários e, em seguida, recriando e restaurando o DB como new_owner, com a opção "no owner" marcada na janela de restauração. Isso produziu os resultados que eu estava procurando com new_owner como o proprietário de tudo.
Kai
O Postgres 9.3 introduziu o comando REASSIGN OWNED. postgresql.org/docs/9.3/sql-reassign-owned.html
Georg Zimmer
3

Com base na resposta de elysch , aqui está uma solução para vários esquemas:

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
fonte
2

A resposta de @Alex Soto é a correta e a essência enviada por @Yoav Aner também funciona, desde que não haja caracteres especiais nos nomes de tabela / exibição (que são legais no postgres).

Você precisa evitá-los para o trabalho e eu carreguei uma essência para isso: https://gist.github.com/2911117

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

Em seguida, envie o arquivo de backup novamente para o PostgreSQL usando:

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

Como não há proprietário incluído, todas as tabelas, esquemas etc. criados são criados no usuário de login especificado.

Eu li que isso poderia ser uma boa abordagem para a migração entre as versões do PostgreSQL também.

atwsKris
fonte
2

Eu criei um script conveniente para isso; pg_change_db_owner.sh . Esse script altera a propriedade de todas as tabelas, visualizações, sequências e funções em um esquema de banco de dados e também o proprietário do próprio esquema.

Observe que, se você quiser apenas alterar a propriedade de todos os objetos, em um banco de dados específico, pertencentes a uma função de banco de dados específica, basta usar o comando REASSIGN OWNED.

Jakub Jirutka
fonte
1

A partir do PostgreSQL 9.0, você tem a capacidade de GRANT [priv name] ON ALL [object type] IN SCHEMAonde [priv name]está o típico SELECT, INSERT, UPDATE, DELETE, etce [object type]pode ser um dos seguintes:

  • TABLES
  • SEQUENCES
  • FUNCTIONS

Os documentos do PostgreSQL estão disponíveis GRANTe REVOKEentram em mais detalhes sobre isso. Em algumas situações, ainda é necessário usar truques envolvendo os catálogos do sistema ( pg_catalog.pg_*), mas isso não é tão comum. Eu frequentemente faço o seguinte:

  1. BEGIN uma transação para modificar os privs
  2. Alterar a propriedade de DATABASESpara uma "função DBA"
  3. Alterar a propriedade de SCHEMASpara a "função DBA"
  4. REVOKE ALLprivs em todos TABLES, SEQUENCESe FUNCTIONSde todas as funções
  5. GRANT SELECT, INSERT, UPDATE, DELETE em tabelas relevantes / apropriadas para as funções apropriadas
  6. COMMIT a transação DCL.
Sean
fonte
1

A solução aceita não cuida da propriedade da função. A seguinte solução cuida de tudo (ao revisar, observei que é semelhante ao @magiconair acima)

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
fonte
1

O seguinte script shell mais simples funcionou para mim.

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

Onde entrada $ 1 - nome de usuário (banco de dados) $ 2 = esquema existente $ 3 = para o novo esquema.

sramay
fonte
1

Igual à abordagem de @ AlexSoto para funções:

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
fonte
0

Docker: modificar proprietário de todas as tabelas + seqüências

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
fonte