¿Hay algún medio para establecer el propietario de todos los objetos en una base de datos PostgreSQL al mismo tiempo?

13

/programming/1348126/modify-owner-on-all-tables-simuallyly-in-postgresql describe algunas maneras ingeniosas de cambiar la tabla y otros objetos a un usuario específico, y funciona de manera excelente, sin embargo, todos los Las sugerencias parecen ignorar las funciones que creé.

¿Hay una manera bastante fácil de restablecer el propietario de TODOS los objetos en la base de datos, incluidas las funciones? Hacerlo a mano es muy indeseable.

Jeremy Holovacs
fuente

Respuestas:

22

Solo debe manipular los catálogos del sistema directamente, si sabe exactamente lo que está haciendo. Puede tener efectos secundarios inesperados. O puede dañar la base de datos (o todo el clúster de la base de datos) sin posibilidad de reparación.

La respuesta de Jeremy , aunque básicamente hace el truco, no es aconsejable para el público en general. Cambia incondicionalmente todas las funciones en un esquema. ¿Está seguro de que no hay funciones del sistema afectadas o funciones instaladas por un módulo adicional?
Tampoco tendría sentido cambiar el propietario de las funciones que ya pertenecen al propietario designado.

Primero, verifique si REASSIGN OWNEDpodría funcionar para usted:

cambiar la propiedad de los objetos de la base de datos propiedad de un rol de base de datos

Tiene que enumerar todos los roles que se desautorizarán explícitamente. Pero también reasigna funciones .

Para asignar todas las funciones (y ningún otro objeto) en un esquema dado a un nuevo propietario (opcionalmente, independientemente del propietario anterior):

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_%'

Esto genera los comandos canónicos de SQLALTER FUNCTION ... para cambiar todas las funciones (en el esquema especificado). Puede inspeccionar los comandos antes de ejecutarlos, uno por uno o todos a la vez:

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

Incluí algunas WHEREcláusulas comentadas que quizás quieras usar para filtrar los resultados.

La conversión a regprocedureproduce un nombre de función válido con parámetros, entre comillas dobles cuando sea necesario, esquema - calificado cuando sea necesario para la corriente search_path.

La función agregada string_agg () requiere PostgreSQL 9.0 o posterior. En versiones anteriores, sustituya con array_agg()y array_to_string().

Usted podría poner todo esto en una DOdeclaración o una función como se demuestra en esta respuesta relacionada:

En Postgres 9.5 o posterior, puede simplificar la consulta utilizando nuevos tipos de identificadores de objetos regnamespaceyregrole :

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

Utilizo esta función para alterar el propietario de tablas, funciones, tipos, etc. Puede cambiar la consulta de los cursores para adaptarla a sus necesidades.

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;

Luego simplemente ejecuto (si desea la salida de depuración, simplemente configure el segundo parámetro en verdadero):

SELECT fn_setowner('demo', false);
DROP FUNCTION fn_setowner(varchar(30), boolean);
JorSol
fuente
Tenga en cuenta que pg_proc.proisaggse sustituye en pg 11. Las notas de la versión decir: Reemplazar tabla de sistema pg_proc's proisaggy proiswindowcon prokind(Peter Eisentraut) `
Erwin Brandstetter
0

Esto debería funcionar 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
-1

Puede usar el comando REASSIGN OWNED

Simplemente inicie sesión en la base de datos con superusuario y ejecute a continuación

REASSIGN OWNED BY [old_user] TO [new_user];

Esto cambia todos los objetos, es decir, tablas, secuencia, función, etc., propiedad de old_role a la nueva función. No tiene que pensar qué tipo de objetos tiene el usuario, todos se cambiarán. Esto cambia los objetos solo si desea cambiar la propiedad de esa base de datos en sí misma, solo useALTER DATABASE name OWNER TO new_owner

Este es el mejor método ya que habrá n número de tablas, secuencia en lugar de bucles y secuencias de comandos bash

Ashiq Ahamed
fuente
2
Esto se menciona en la respuesta con más votos a favor desde hace 3 años. También sus limitaciones.
dezso
-7

Bueno, no encontré un proceso de un solo paso, pero esto se encarga de todos los objetos que puedo ver en mi base de datos:

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
fuente
55
Sin embargo, es una buena pregunta (+1) - -1 para su respuesta - No quisiera que nadie más piense que está bien actualizar directamente las tablas del sistema como esta sin estar muy seguro de que saben lo que están haciendo.
Jack dice que intente topanswers.xyz
1
Está solicitando pruebas de que no romperá algo, y mi argumento en contra es que si está rechazando algo, debe incluir una explicación de qué se romperá y cómo / por qué. Si no puede, entonces la respuesta no es incorrecta, engañosa, inútil o inútil, que son los criterios para un voto negativo. Las relaciones en las tablas de metadatos no fueron difíciles de resolver en este caso, después de un poco de examen, y como dije, funciona a la perfección. La carga de la prueba debe estar en el votante; Espero que tenga dificultades para encontrar lo que esta respuesta romperá.
Jeremy Holovacs
1
Me tomaré la libertad de citar literalmente a @Erwin: "Solo debe manipular los catálogos del sistema directamente, si sabe exactamente lo que está haciendo. Puede tener efectos secundarios inesperados. O puede corromper la base de datos (o todo el grupo de bases de datos) sin posibilidad de reparación". Erwin sabe lo que hace (y yo también). Consulte nuestra reputación y respuestas anteriores en la etiqueta postgres aquí y en SO. Mi voto negativo es una expresión de mi opinión y no ofrezco ninguna prueba porque los documentos son evidencia suficiente para mí (otros pueden decidir por sí mismos).
Jack dice que intente topanswers.xyz
66
¿Qué hay de malo en usar el método de Erwin? El hecho de que haya utilizado el método sin problemas (aparentes) no me da confianza y tampoco debería hacerlo: alguien podría decir igualmente que he usado RAID0 durante años sin problemas.
Jack dice que intente topanswers.xyz