Modifique PROPIETARIO en todas las tablas simultáneamente en PostgreSQL

412

¿Cómo modifico el propietario de todas las tablas en una base de datos PostgreSQL?

Lo intenté ALTER TABLE * OWNER TO new_ownerpero no admite la sintaxis de asterisco.

Kai
fuente

Respuestas:

461

Ver REASSIGN OWNEDcomando

Nota: Como @trygvis menciona en la respuesta a continuación , el REASSIGN OWNEDcomando está disponible desde al menos la versión 8.2, y es un método mucho más fácil.


Como está cambiando la propiedad de todas las tablas, es probable que también desee vistas y secuencias. Esto es lo que hice:

Mesas:

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

Secuencias:

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

Puntos de vista:

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

Probablemente podría SECAR eso un poco ya que las declaraciones alter son idénticas para los tres.


Alex Soto
fuente
10
+1 Gracias Alex. He creado un pequeño script bash basado en su respuesta, disponible en gist.github.com/2482969
gingerlime
10
Ver la respuesta reciente de @trygvis. Respuesta más sencilla, con mucho:REASSIGN OWNED BY old_role [, ...] TO new_role
David
64
REASSIGN OWNED BY no funciona para objetos propiedad de postgres.
BrunoJCM 01 de
19
Además, REASSIGN OWNED en realidad afecta la propiedad de todas las bases de datos propiedad de la función anterior (ver: postgresql.org/docs/9.3/static/sql-reassign-owned.html ). Entonces, si solo desea cambiar la propiedad de una sola base de datos, ¡tenga cuidado!
kitsune
3
Basado en el script @gingerlime, bspkrs (no pudo encontrar su nombre) creó uno que también cambia las funciones: https://gist.github.com/bspkrs/b997ed7f1eb1268f3403
elysch
538

Puedes usar el REASSIGN OWNEDcomando.

Sinopsis:

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

Esto cambia todos los objetos que pertenecen old_roleal nuevo rol. No tiene que pensar qué tipo de objetos tiene el usuario, todos se cambiarán. Tenga en cuenta que solo se aplica a objetos dentro de una única base de datos. Tampoco altera al propietario de la base de datos.

Está disponible de nuevo al menos a 8.2. Su documentación en línea solo va tan atrás.

Trygve Laugstøl
fuente
ERROR: unexpected classid 3079. Supongo que actualmente no funciona si hay extensiones.
Steve Jorgensen
40
Esto no parece funcionar para los usuarios de postgres, aunque estoy conectado a una base de datos que he creado (es decir, no a una base de datos del sistema), dice esto: ERROR: no puede reasignar la propiedad de los objetos que son propiedad de postgres de roles porque son requeridos por la base de datos system
thnee
13
Como informó @thnee, REASSIGN afecta a todos los objetos en la base de datos y no discrimina entre objetos definidos por el usuario y del sistema, por lo que no funciona para postgres si hay alguna extensión que tenga sus propias tablas. Aún así, prefiero (+1) esta opción por elegancia, aunque no me ayudó mucho (mi base de datos era propiedad de postgres).
Pavel V.
66
Para que quede claro, este comando funciona SOLO en la base de datos a la que está conectado actualmente. Si old_role posee objetos en varias bases de datos, debe conectarse y ejecutar este comando en cada una de esas bases de datos
mavroprovato
11
Esto no parece funcionar en postgres alojados a través de AWS RDS. Recibo este error "permiso denegado para reasignar objetos" y este enlace sugiere por qué: "Parece que la única forma de 'reasignar propiedad' es como un superusuario (que está contradicho por la documentación), que no es accesible en RDS. postgresql-archive.org/…
typoerrpr
198

Esto: http://archives.postgresql.org/pgsql-bugs/2007-10/msg00234.php también es una solución agradable y rápida, y funciona para múltiples esquemas en una base de datos:

Mesas

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;

Secuencias

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;

Puntos de vista

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;

Vistas materializadas

Basado en esta respuesta

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

Esto genera todas las declaraciones / ALTER TABLE/ requeridas , cópielas y péguelas nuevamente en plsql para ejecutarlas.ALTER SEQUENCEALTER VIEW

Verifique su trabajo en psql haciendo:

\dt *.*
\ds *.*
\dv *.*
rkj
fuente
Gran solución Mi único problema fue que exporté los scripts y luego ejecuté los scripts exportados. Soy SQL Server Guru pero no estoy seguro de cuál es el acceso directo para ejecutar. Hice clic en ejecutar consulta y ejecutar pgScript. ¿Qué estaba haciendo mal?
Tyrone Moodley
1
Preferí esto, ya que funciona desde plsql una vez que inicié sesión: los scripts de nivel Unix (respuesta favorita actualmente) requieren una entrada de "-U postgres" y contraseña en mi entorno.
Aturdido el
2
Prefiero esta respuesta porque (1) se puede hacer en psql o pgAdmin (2) le permite ver fácilmente los objetos que alterará. También utilicé stackoverflow.com/questions/22803096/… , que es similar, pero para funciones.
AlannaRose
espléndida lógica
Emipro Technologies Pvt. Ltd.
42

Si desea hacerlo en una instrucción sql, debe definir una función exec () como se menciona en 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$;

Luego puede ejecutar esta consulta, cambiará el propietario de las tablas, secuencias y vistas:

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 es el nuevo nombre postgresql del nuevo propietario.

En la mayoría de los casos, debe ser un superusuario para ejecutar esto. Puede evitar eso cambiando el propietario de su propio usuario a un grupo de roles del que sea miembro.

Gracias a RhodiumToad en #postgresql por ayudar con esto.

Johan Dahlin
fuente
2
Esto es mucho más útil ya que cambia la propiedad de todo el esquema, incluidas funciones, índices, secuencias, etc. ¡Gracias!
liviucmg
No cambia los propietarios del esquema. ¿Cómo cambiar los propietarios del esquema también?
Andrus
@Andrus ALTER DATABASE $ DB PROPIETARIO A $ PROPIETARIO;
Johan Dahlin
alter database cambia el propietario de la base de datos completa. Pregunté cómo cambiar los propietarios del esquema.
Andrus
ALTERAR EL ESQUEMA fred PROPIETARIO A Betty;
Eric Aldinger
21

Recientemente tuve que cambiar la propiedad de todos los objetos en una base de datos. Aunque las tablas, las vistas, los desencadenantes y las secuencias se cambiaron fácilmente, el enfoque anterior falló para las funciones, ya que la firma es parte del nombre de la función. Por supuesto, tengo experiencia en MySQL y no estoy tan familiarizado con Postgres.

Sin embargo, pg_dump le permite volcar solo el esquema y este contiene ALTER xxx OWNER TO yyy; declaraciones que necesitas. Aquí está mi poco de magia de concha sobre el tema

pg_dump -s YOUR_DB | grep -i 'owner to' | sed -e 's/OWNER TO .*;/OWNER TO NEW_OWNER;/i' | psqL YOUR_DB
magiconair
fuente
No estoy seguro de por qué estás usando el grepcomando. Soy nuevo en Linux, pero, según tengo entendido, parece que sedestá bien usarlo, especialmente porque de todos modos estás especificando una coincidencia entre mayúsculas y minúsculas.
Bobort
19

muy simple, pruébalo ...

 select 'ALTER TABLE ' || table_name || ' OWNER TO myuser;' from information_schema.tables where table_schema = 'public';
mwendamseke
fuente
44
Puede agregar una nota de que las cadenas correspondientes deben copiarse y ejecutarse. No es que no sea obvio: p
Nightscape
Lo que incluye la eliminación de todas las comillas alrededor de las declaraciones de alteración ... varios cursores o reemplazar ayuda en este caso.
conocidoasilya
19

es muy simple

  1. su - postgres
  2. psql
  3. REASIGNAR PROPIETARIO DE [old_user] TO [new_user];
  4. \ c [su base de datos]
  5. REASIGNAR PROPIETARIO DE [old_user] TO [new_user];

hecho.

durenzo
fuente
1
Esto probablemente hace lo que el consultante quería. De lejos, el más fácil.
Geof Sawaya
1
Llegas solo 4 años tarde a la fiesta; desplazarse hacia arriba: stackoverflow.com/a/13535184/1772379
Ben Johnson
16

Me gusta este, ya que modifica las tablas , vistas , secuencias y funciones del propietario de un determinado esquema de una vez (en una instrucción sql), sin crear una función y puede usarlo directamente en PgAdmin III y psql :

(Probado en 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$$;

Basado en las respuestas proporcionadas por @rkj, @AlannaRose, @SharoonThomas, @ user3560574 y esta respuesta por @a_horse_with_no_name

Muchas gracias.


Mejor aún: también cambie la base de datos y el propietario del 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
fuente
¡ASOMBROSO! ¿Por qué Postgres no agrega esto? ¡No lo sé!
pip
Dos preguntas: 1) Parece que las líneas primera y tercera "ALTER TABLE" son engañosas. ¿Es intencional? 2) Estamos descubriendo que information_schema.sequencesestá vacío a pesar de que SELECT c.* FROM pg_class c WHERE c.relkind = 'S';enumera secuencias. ¿Por qué podrían no coincidir?
GuyPaddock
Además, ¿no debería ser la segunda ALTERconsulta un ALTER SEQUENCE?
GuyPaddock
12

Tuve que cambiar la propiedad de tablas, vistas y secuencias y descubrí que la excelente solución publicada por @rjk funciona bien, a pesar de un detalle: si los nombres de los objetos son de mayúsculas y minúsculas (por ejemplo, "TableName"), esto fallará con un " error no encontrado.
Para evitar esto, envuelva los nombres de los objetos con '"' así:

Mesas

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;

Secuencias

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;

Puntos de vista

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;
Juez
fuente
10

Puede probar lo siguiente en 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$$;
usuario3560574
fuente
6

No existe dicho comando en PostgreSQL. Pero puede solucionarlo utilizando el método que describí hace algún tiempo para GRANT.


fuente
Gracias, muy buen artículo. Mantendré esto como referencia futura. Usando pgAdmin, terminé haciendo una copia de seguridad de la base de datos, descartando / eliminando la base de datos, otorgando temporalmente a new_owner los derechos necesarios y luego volviendo a crear y restaurando la base de datos como new_owner, con la opción "sin propietario" marcada en la ventana de restauración. Esto produjo los resultados que estaba buscando con new_owner como propietario de todo.
Kai
Postgres 9.3 introdujo el comando REASSIGN OWNED. postgresql.org/docs/9.3/sql-reassign-owned.html
Georg Zimmer
3

Basado en la respuesta de elysch , aquí hay una solución para múltiples 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
fuente
2

La respuesta de @Alex Soto es la correcta y la esencia cargada por @Yoav Aner también funciona siempre que no haya caracteres especiales en los nombres de tabla / vista (que son legales en postgres).

Necesitas escapar de ellos para trabajar y he subido una esencia para eso: https://gist.github.com/2911117

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

Luego canalice el archivo de copia de seguridad nuevamente a PostgreSQL usando:

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

Como no se incluye ningún propietario, todas las tablas, esquemas, etc. creados se crean con el usuario de inicio de sesión que especifique.

He leído que esto también podría ser un buen enfoque para migrar entre versiones de PostgreSQL.

atwsKris
fuente
2

He creado un script conveniente para eso; pg_change_db_owner.sh . Este script cambia la propiedad de todas las tablas, vistas, secuencias y funciones en un esquema de base de datos y también propietario del esquema en sí.

Tenga en cuenta que si solo desea cambiar la propiedad de todos los objetos, en una base de datos particular, propiedad de un rol de base de datos particular, simplemente puede usar el comando en su REASSIGN OWNEDlugar.

Jakub Jirutka
fuente
1

A partir de PostgreSQL 9.0, tiene la capacidad de GRANT [priv name] ON ALL [object type] IN SCHEMAdónde [priv name]es lo típico SELECT, INSERT, UPDATE, DELETE, etcy [object type]puede ser uno de:

  • TABLES
  • SEQUENCES
  • FUNCTIONS

Los documentos de PostgreSQL se activan GRANTy REVOKEentran en más detalles sobre esto. En algunas situaciones, todavía es necesario usar trucos que involucren los catálogos del sistema ( pg_catalog.pg_*), pero no es tan común. Con frecuencia hago lo siguiente:

  1. BEGIN una transacción para modificar los privs
  2. Cambiar la propiedad de DATABASESa un "rol de DBA"
  3. Cambiar la propiedad del SCHEMAS"rol DBA"
  4. REVOKE ALLPrivs en todos TABLES, SEQUENCESy FUNCTIONSde todos los roles
  5. GRANT SELECT, INSERT, UPDATE, DELETE en tablas relevantes / apropiadas para los roles apropiados
  6. COMMIT La transacción DCL.
Sean
fuente
1

La solución aceptada no se ocupa de la propiedad de la función. La siguiente solución se encarga de todo (mientras revisaba me di cuenta de que es similar a @magiconair arriba)

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

El siguiente script de shell más simple funcionó para mí.

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

Donde ingrese $ 1 - nombre de usuario (base de datos) $ 2 = esquema existente $ 3 = al nuevo esquema.

sramay
fuente
1

Igual que el enfoque de @ AlexSoto para las funciones:

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

Docker: Modificar propietario de todas las tablas + secuencias

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
fuente