Esiste un modo per impostare contemporaneamente il proprietario di tutti gli oggetti in un database PostgreSQL?


13

/programming/1348126/modify-owner-on-all-tables-simultaneously-in-postgresql descrive alcuni modi ingegnosi per cambiare tabella e altri oggetti in un utente specifico, e funziona a meraviglia, tuttavia tutti i i suggerimenti sembrano ignorare le funzioni che ho creato.

Esiste un modo abbastanza semplice per ripristinare il proprietario di TUTTI gli oggetti nel database, comprese le funzioni? Farlo a mano è altamente indesiderabile.

Risposte:


22

Dovresti sempre manipolare direttamente i cataloghi di sistema , se sai esattamente cosa stai facendo. Potrebbe avere effetti collaterali imprevisti. In alternativa, è possibile corrompere il database (o l'intero cluster di database) irreparabilmente.

La risposta di Jeremy , mentre sostanzialmente fa il trucco, non è consigliabile per il grande pubblico. Cambia incondizionatamente tutte le funzioni in uno schema. Sei sicuro che non ci siano funzioni di sistema interessate o funzioni installate da un modulo aggiuntivo?
Sarebbe inoltre inutile cambiare il proprietario di funzioni che appartengono già al proprietario designato.

Innanzitutto, controlla se REASSIGN OWNEDpotrebbe funzionare per te:

modificare la proprietà degli oggetti del database di proprietà di un ruolo del database

Devi elencare tutti i ruoli per essere esplicitamente rinnegati. Ma riassegna anche le funzioni .

Per assegnare tutte le funzioni (e nessun altro oggetto) in un determinato schema a un nuovo proprietario (facoltativamente indipendentemente dal proprietario precedente):

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

Questo genera i comandi SQL canoniciALTER FUNCTION ... per modificare tutte le funzioni (nello schema specificato). È possibile controllare i comandi prima di eseguirli - uno per uno o tutti in una volta:

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

Ho incluso alcune WHEREclausole commentate che potresti voler utilizzare per filtrare i risultati.

Il cast regprocedureproduce un nome di funzione valido con parametri, tra virgolette doppie ove necessario, schema - qualificato dove necessario per la corrente search_path.

La funzione aggregata string_agg () richiede PostgreSQL 9.0 o successivo. Nella versione precedente sostituire con array_agg()e array_to_string().

Si potrebbe mettere tutto questo in una DOdichiarazione o di una funzione come dimostrato in questa risposta correlato:

In Postgres 9.5 o versioni successive, puoi semplificare la query usando nuovi tipi di identificatori di oggetti 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_%'

1

Uso questa funzione per modificare il proprietario di tabelle, funzioni, tipi, ecc. È possibile modificare la query dei cursori per adattarla alle proprie esigenze.

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;

Quindi eseguo solo (se vuoi l'output di debug, imposta semplicemente il secondo parametro su true):

SELECT fn_setowner('demo', false);
DROP FUNCTION fn_setowner(varchar(30), boolean);

Si noti che pg_proc.proisaggviene sostituito in pg 11. Le note di rilascio dire: Sostituire tabella di sistema pg_proc's proisagge proiswindowcon prokind(Peter Eisentraut) `
Erwin Brandstetter

0

Questo dovrebbe funzionare per le funzioni:

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

-1

È possibile utilizzare il comando REASSIGN OWNED

Accedi al database con superutente ed esegui di seguito

REASSIGN OWNED BY [old_user] TO [new_user];

Ciò cambia tutti gli oggetti, ad esempio tabelle, sequenza, funzione, ecc. Di proprietà di old_role nel nuovo ruolo. Non devi pensare al tipo di oggetti che l'utente ha, saranno tutti cambiati. Ciò modifica gli oggetti solo se si desidera modificare la proprietà di quel database stessoALTER DATABASE name OWNER TO new_owner

Questo è il metodo migliore in quanto non ci sarà n numero di tabelle, sequenza piuttosto che per loop e script bash


2
Questo è menzionato nella risposta con il maggior numero di voti da 3 anni. Anche i suoi limiti.
dezso,

-7

Bene, non ho trovato un processo in un solo passaggio, ma questo si occupa di tutti gli oggetti che posso vedere nel mio database:

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);

5
È una buona domanda (+1) - -1 per la tua risposta però - Non vorrei che nessun altro pensasse che fosse giusto aggiornare direttamente tabelle di sistema come questa senza essere molto sicuri di sapere cosa stanno facendo.
Jack dice di provare topanswers.xyz il

1
Stai chiedendo la prova che non si romperà qualcosa, e il mio controprogramma è che se stai effettuando il downgrade di qualcosa, dovresti includere una spiegazione di cosa si romperà e come / perché. Se non è possibile, la risposta non è sbagliata, fuorviante, inutile o inutile, che sono i criteri per un voto negativo. Le relazioni nelle tabelle dei metadati non sono state difficili da capire in questo caso, dopo un po 'di esame, e come ho detto, funziona a meraviglia. L'onere della prova dovrebbe essere a carico del downvoter; Mi aspetto che tu abbia difficoltà a trovare ciò che questa risposta romperà.
Jeremy Holovacs,

1
Mi prenderò la libertà di citare alla lettera @Erwin alla lettera: "Dovresti sempre manipolare direttamente i cataloghi di sistema, se sai esattamente cosa stai facendo. Potrebbe avere effetti collaterali inaspettati. Oppure puoi corrompere il database (o l'intero cluster di database) irreparabile". Erwin conosce le sue cose (e anche io). Controlla la nostra reputazione e le risposte passate sul tag postgres qui e su SO. Il mio downvote è un'espressione della mia opinione e non offro prove perché i documenti sono prove sufficienti per me (gli altri possono decidere da soli).
Jack dice di provare topanswers.xyz il


6
cosa c'è di sbagliato nell'usare il metodo di Erwin? Il fatto che tu abbia usato il metodo senza (apparente) problema non mi dà fiducia e nemmeno dovrebbe: qualcuno potrebbe anche dire che ho usato RAID0 per anni senza problemi.
Jack dice di provare topanswers.xyz il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.