Existe um meio de definir o proprietário de todos os objetos em um banco de dados PostgreSQL ao mesmo tempo?

13

/programming/1348126/modify-owner-on-all-tables-simultaneous-in-postgresql descreve algumas maneiras bacanas de alterar a tabela e outros objetos para um usuário específico, e funciona de maneira limpa, no entanto, todas as sugestões parecem ignorar as funções que eu criei.

Existe uma maneira bastante fácil de redefinir o proprietário de TODOS os objetos no banco de dados, incluindo as funções? Fazer isso manualmente é altamente indesejável.

Jeremy Holovacs
fonte

Respostas:

22

Você só deve manipular os catálogos do sistema diretamente, se souber exatamente o que está fazendo. Pode ter efeitos colaterais inesperados. Ou você pode corromper o banco de dados (ou todo o cluster de bancos de dados) além do reparo.

A resposta de Jeremy , embora basicamente faça o truque, não é aconselhável para o público em geral. Altera incondicionalmente todas as funções em um esquema. Você tem certeza de que não há funções do sistema afetadas ou funções instaladas por um módulo adicional?
Também não faria sentido alterar o proprietário das funções que já pertencem ao proprietário designado.

Primeiro, verifique se REASSIGN OWNEDpoderia funcionar para você:

alterar a propriedade dos objetos de banco de dados pertencentes a uma função de banco de dados

Você precisa listar todas as funções a serem rejeitadas explicitamente. Mas também reatribui funções .

Para atribuir todas as funções (e nenhum outro objeto) em um determinado esquema a um novo proprietário (opcionalmente independentemente do proprietário 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_%'

Isso gera os comandos SQL canônicosALTER FUNCTION ... para alterar todas as funções (no esquema especificado). Você pode inspecionar os comandos antes de executá-los - um por um ou todos de uma vez:

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

Incluí algumas WHEREcláusulas comentadas que você pode usar para filtrar os resultados.

O elenco para regprocedure produz um nome de função válido com parâmetros, aspas duplas quando necessário, esquema - qualificado quando necessário para a corrente search_path.

A função agregada string_agg () requer o PostgreSQL 9.0 ou posterior. Na versão anterior, substitua porarray_agg() e array_to_string().

Você pode colocar tudo isso em umDO declaração ou função, como demonstrado nesta resposta relacionada:

No Postgres 9.5 ou posterior, você pode simplificar a consulta usando novos tipos de identificador de objeto regnamespaceeregrole :

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

Uso essa função para alterar o proprietário de tabelas, funções, tipos etc. Você pode alterar a consulta dos cursores para adaptá-la às suas necessidades.

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;

Então eu apenas executo (se você quiser uma saída de depuração, basta definir o segundo parâmetro como true):

SELECT fn_setowner('demo', false);
DROP FUNCTION fn_setowner(varchar(30), boolean);
JorSol
fonte
Note-se que pg_proc.proisaggé substituído na pg 11. As notas de lançamento dizem: substituir a tabela de sistema pg_proc's proisagge proiswindowcom prokind(Peter Eisentraut) `
Erwin Brandstetter
0

Isso deve funcionar 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
-1

Você pode usar o comando REASSIGN OWNED

Basta fazer login no banco de dados com superusuário e executar abaixo

REASSIGN OWNED BY [old_user] TO [new_user];

Isso altera todos os objetos, isto é, tabelas, sequência, função etc, pertencentes a old_role, para a nova função. Você não precisa pensar em que tipo de objetos o usuário possui, todos eles serão alterados. Isso altera os objetos apenas se você quiser alterar a propriedade desse banco de dados, basta usarALTER DATABASE name OWNER TO new_owner

Este é o melhor método, pois haverá n número de tabelas, sequência em vez de loops e scripts bash

Ashiq Ahamed
fonte
2
Isso é mencionado na resposta com mais votos positivos desde 3 anos. Também suas limitações.
Dez27
-7

Bem, não encontrei um processo de uma etapa, mas isso cuida de todos os objetos que posso ver no meu banco de dados:

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
fonte
5
É uma pergunta boa (+1) - -1 pela sua resposta embora - Eu não quero que ninguém mais pensa que é ok para atualizar diretamente as tabelas do sistema como este sem ser muito certeza que eles sabem o que estão fazendo.
Jack diz que tente topanswers.xyz
1
Você está pedindo uma prova de que isso não quebrará algo, e meu contra-argumento é que, se você estiver votando contra algo, deve incluir uma explicação sobre o que ele quebrará e como / por que. Se você não puder, a resposta não é errada, enganosa, inútil ou inútil, que são os critérios para um voto negativo. As relações nas tabelas de metadados não foram difíceis de descobrir nesse caso, após um pouco de exame e, como eu disse, funciona muito bem. O ônus da prova deve recair sobre o downvoter; Espero que você tenha dificuldades em encontrar o que essa resposta vai quebrar.
Jeremy Holovacs
1
Tomei a liberdade de citar @ Err literalmente: "Você só deve manipular catálogos de sistema diretamente, se souber exatamente o que está fazendo. Pode ter efeitos colaterais inesperados. Ou pode corromper o banco de dados (ou todo o cluster) além do reparo ". Erwin conhece suas coisas (e eu também). Verifique nossa reputação e respostas anteriores na tag postgres aqui e no SO. Meu voto negativo é uma expressão da minha opinião e não ofereço prova porque os documentos são evidência suficiente para mim (outros podem decidir por si mesmos).
Jack diz que tente topanswers.xyz
6
o que há de errado em usar o método de Erwin? O fato de você ter usado o método sem problema (aparente) não me dá confiança e nem deveria: alguém poderia dizer igualmente que eu usei o RAID0 por anos sem problemas.
Jack diz que tente topanswers.xyz 20/08/14