Gibt es eine Möglichkeit, den Eigentümer aller Objekte in einer PostgreSQL-Datenbank gleichzeitig festzulegen?


13

/programming/1348126/modify-owner-on-all-tables-simultaneous-inpostgresql beschreibt einige raffinierte Möglichkeiten, um Tabellen und andere Objekte für einen bestimmten Benutzer zu ändern, und es funktioniert problemlos, jedoch mit allen Vorschläge scheinen die von mir erstellten Funktionen zu ignorieren.

Gibt es eine relativ einfache Möglichkeit, den Eigentümer ALLER Objekte in der Datenbank einschließlich der Funktionen zurückzusetzen? Es ist höchst unerwünscht, es von Hand zu tun.

Antworten:


21

Sie sollten Systemkataloge nur dann direkt bearbeiten , wenn Sie genau wissen, was Sie tun. Es kann unerwartete Nebenwirkungen haben. Oder Sie können die Datenbank (oder den gesamten Datenbankcluster) irreparabel beschädigen.

Während Jeremys Antwort im Grunde genommen den Trick macht, ist sie für die breite Öffentlichkeit nicht ratsam . Es ändert bedingungslos alle Funktionen in einem Schema. Sind Sie sicher, dass keine Systemfunktionen betroffen sind oder Funktionen von einem Zusatzmodul installiert wurden?
Es wäre auch sinnlos, den Eigentümer von Funktionen zu ändern, die bereits dem designierten Eigentümer gehören.

Überprüfen Sie zunächst, ob REASSIGN OWNEDes für Sie funktioniert:

den Besitz von Datenbankobjekten ändern, die einer Datenbankrolle gehören

Sie müssen alle Rollen auflisten, die explizit abgelehnt werden sollen. Es weist aber auch Funktionen neu zu .

So weisen Sie einem neuen Eigentümer alle Funktionen (und keine anderen Objekte) in einem bestimmten Schema zu (optional unabhängig vom vorherigen Eigentümer):

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

Dadurch werden die kanonischen SQL-BefehleALTER FUNCTION ... zum Ändern aller Funktionen (im angegebenen Schema) generiert . Sie können die Befehle überprüfen, bevor Sie sie ausführen - einzeln oder alle gleichzeitig:

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

Ich habe einige kommentierte WHEREKlauseln eingefügt, die Sie möglicherweise zum Filtern der Ergebnisse verwenden möchten.

Die Umwandlung in regprocedureerzeugt einen gültigen Funktionsnamen mit Parametern, gegebenenfalls in doppelten Anführungszeichen, einem Schema, das für den aktuellen Bedarf qualifiziert ist search_path.

Die Aggregatfunktion string_agg () erfordert PostgreSQL 9.0 oder höher. In der älteren Version durch array_agg()und ersetzen array_to_string().

Sie könnten dies alles in eine DOAnweisung oder eine Funktion einfügen, wie in dieser verwandten Antwort gezeigt:

In Postgres 9.5 oder höher können Sie die Abfrage mit neuen Objektidentifikationstypenregnamespaceregrole vereinfachen und :

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

Ich benutze diese Funktion, um den Eigentümer von Tabellen, Funktionen, Typen usw. zu ändern. Sie können die Abfrage der Cursor ändern, um sie an Ihre Bedürfnisse anzupassen.

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;

Dann führe ich einfach aus (wenn du die Ausgabe debuggen willst, setze einfach den zweiten Parameter auf true):

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

Beachten Sie, dass pg_proc.proisaggin pg 11 ersetzt Die Release Notes sagen: Ersetzen Systemtabellepg_proc ‚s proisaggund proiswindowmit prokind(Peter Eisentraut)`
Erwin Brandstetter

0

Dies sollte für folgende Funktionen funktionieren:

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

Sie können den Befehl REASSIGN OWNED verwenden

Melden Sie sich einfach mit dem Superuser in der Datenbank an und führen Sie die folgenden Schritte aus

REASSIGN OWNED BY [old_user] TO [new_user];

Dies ändert alle Objekte, dh Tabellen, Sequenzen, Funktionen usw., die old_role gehören, in die neue Rolle. Sie müssen nicht darüber nachdenken, welche Art von Objekten der Benutzer hat, sie werden alle geändert. Dies ändert die Objekte nur, wenn Sie den Eigentümer dieser Datenbank selbst ändern möchtenALTER DATABASE name OWNER TO new_owner

Dies ist die beste Methode, da es nicht so viele Tabellen gibt, da die Reihenfolge eher für Schleifen und Bash-Skripte gilt


2
Dies wird in der Antwort mit den meisten positiven Stimmen seit 3 ​​Jahren erwähnt. Auch seine Grenzen.
Dezso

-7

Nun, ich habe keinen einstufigen Prozess gefunden, aber dieser kümmert sich um alle Objekte, die ich in meiner Datenbank sehen kann:

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
Es ist eine gute Frage (+1) - -1 für Ihre Antwort - ich möchte nicht, dass jemand anderes denkt, dass es in Ordnung ist, Systemtabellen wie diese direkt zu aktualisieren, ohne sehr sicher zu sein, dass sie wissen, was sie tun.
Jack sagt, versuchen Sie topanswers.xyz

1
Sie fordern den Beweis, dass etwas nicht kaputt geht, und mein Gegenargument lautet, dass Sie, wenn Sie etwas ablehnen, eine Erklärung hinzufügen sollten, was kaputt geht und wie / warum. Wenn Sie dies nicht können, ist die Antwort nicht falsch, irreführend, unbrauchbar oder nicht hilfreich. Dies sind die Kriterien für eine Ablehnung. Die Beziehungen in den Metadatentabellen waren in diesem Fall nach einigem Hinsehen nicht schwer herauszufinden, und wie ich bereits sagte, funktioniert dies problemlos. Die Beweislast sollte beim Downvoter liegen; Ich gehe davon aus, dass Sie Schwierigkeiten haben werden, herauszufinden, was diese Antwort bewirken wird.
Jeremy Holovacs

1
Ich werde es mir erlauben, @Erwin wörtlich zu zitieren: "Sie sollten Systemkataloge nur dann direkt manipulieren, wenn Sie genau wissen, was Sie tun. Es kann unerwartete Nebenwirkungen haben. Oder Sie können die Datenbank (oder den gesamten Datenbankcluster) beschädigen. nicht mehr zu reparieren". Erwin kennt sich aus (und ich auch). Überprüfen Sie unseren Ruf und frühere Antworten auf dem Postgres-Tag hier und auf SO. Meine Ablehnung ist ein Ausdruck meiner Meinung und ich biete keine Beweise an, weil die Dokumente für mich genug Beweise sind (andere können selbst entscheiden).
Jack sagt, versuchen Sie topanswers.xyz


6
Was ist los mit Erwins Methode? Die Tatsache, dass Sie die Methode ohne (offensichtliche) Probleme verwendet haben, gibt mir kein Vertrauen und sollte es auch nicht: Jemand könnte auch sagen, dass ich RAID0 jahrelang ohne Probleme verwendet habe.
Jack sagt, versuchen Sie topanswers.xyz
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.