Apakah ada cara untuk mengatur pemilik semua objek dalam database PostgreSQL secara bersamaan?

13

/programming/1348126/modify-owner-on-all-tables-simurrentously-in-postgresql menjelaskan beberapa cara bagus untuk mengubah tabel dan objek lain ke pengguna tertentu, dan itu berfungsi dengan baik, namun semua itu berfungsi dengan baik. saran tampaknya mengabaikan fungsi yang saya buat.

Apakah ada cara yang cukup mudah untuk mengatur ulang pemilik SEMUA objek dalam database, termasuk fungsinya? Melakukannya dengan tangan sangat tidak diinginkan.

Jeremy Holovacs
sumber

Jawaban:

22

Anda hanya boleh memanipulasi katalog sistem secara langsung, jika Anda tahu persis apa yang Anda lakukan. Ini mungkin memiliki efek samping yang tidak terduga. Atau Anda dapat merusak database (atau seluruh kluster basis data) yang tidak dapat diperbaiki.

Jawaban Jeremy , sementara pada dasarnya melakukan trik, tidak disarankan untuk masyarakat umum. Itu tanpa syarat mengubah semua fungsi dalam skema. Apakah Anda yakin tidak ada fungsi sistem yang terpengaruh atau fungsi yang dipasang oleh modul tambahan?
Juga tidak ada gunanya mengubah pemilik fungsi yang sudah menjadi milik pemilik yang ditunjuk.

Pertama, periksa apakah REASSIGN OWNEDbisa bekerja untuk Anda:

mengubah kepemilikan objek database yang dimiliki oleh peran basis data

Anda harus mencantumkan semua peran yang akan dihapus secara eksplisit. Tetapi juga menugaskan kembali fungsi .

Untuk menetapkan semua fungsi (dan tidak ada objek lain) dalam skema yang diberikan kepada pemilik baru (opsional terlepas dari pemilik sebelumnya):

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

Ini menghasilkan perintah SQL kanonikALTER FUNCTION ... untuk mengubah semua fungsi (dalam skema yang ditentukan). Anda dapat memeriksa perintah sebelum menjalankannya - satu per satu atau sekaligus:

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

Saya menyertakan beberapa WHEREklausa komentar yang mungkin ingin Anda gunakan untuk memfilter hasilnya.

Para pemain untuk regproceduremenghasilkan nama fungsi yang valid dengan parameter, dikutip ganda jika diperlukan, skema - terkualifikasi jika perlu untuk saat ini search_path.

Fungsi agregat string_agg () membutuhkan PostgreSQL 9.0 atau yang lebih baru. Dalam versi yang lebih lama, gantikan dengan array_agg()dan array_to_string().

Anda bisa memasukkan semua ini ke dalam DOpernyataan atau fungsi seperti diperlihatkan dalam jawaban terkait ini:

Di Postgres 9.5 atau yang lebih baru, Anda bisa menyederhanakan kueri menggunakan tipe pengenal objekregnamespaceregrole baru dan :

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

Saya menggunakan fungsi ini untuk mengubah pemilik tabel, fungsi, tipe, dll. Anda dapat mengubah kueri kursor untuk menyesuaikannya dengan kebutuhan Anda.

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;

Maka saya hanya menjalankan (jika Anda ingin debugging output cukup atur parameter kedua menjadi true):

SELECT fn_setowner('demo', false);
DROP FUNCTION fn_setowner(varchar(30), boolean);
JorSol
sumber
Perhatikan bahwa pg_proc.proisaggdiganti di pg 11. Catatan rilis mengatakan: Ganti sistem table pg_proc's proisaggdan proiswindowdengan prokind(Peter Eisentraut) `
Erwin Brandstetter
0

Ini harus berfungsi untuk fungsi:

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

Anda dapat menggunakan perintah REASSIGN OWNED

Cukup masuk ke database dengan superuser dan jalankan di bawah ini

REASSIGN OWNED BY [old_user] TO [new_user];

Ini mengubah semua objek yaitu tabel, urutan, fungsi dll yang dimiliki oleh old_role ke peran baru. Anda tidak perlu memikirkan objek seperti apa yang dimiliki pengguna, semuanya akan diubah. Ini mengubah objek hanya jika Anda ingin mengubah kepemilikan dari database itu sendiri hanya menggunakanALTER DATABASE name OWNER TO new_owner

Ini adalah metode terbaik karena akan ada n jumlah tabel, urutan agak terjadi untuk loop dan skrip bash

Ashiq Ahamed
sumber
2
Ini disebutkan dalam jawaban dengan suara terbanyak sejak 3 tahun. Juga keterbatasannya.
dezso
-7

Yah, saya tidak menemukan proses satu langkah, tapi ini menangani semua objek yang bisa saya lihat di database saya:

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
sumber
5
Ini pertanyaan yang bagus (+1) - -1 untuk jawaban Anda - Saya tidak ingin orang lain berpikir bahwa boleh langsung memperbarui tabel sistem seperti ini tanpa sangat yakin mereka tahu apa yang mereka lakukan.
Jack bilang coba topanswers.xyz
1
Anda meminta bukti bahwa itu tidak akan merusak sesuatu, dan argumen saya adalah bahwa jika Anda menurunkan sesuatu, Anda harus memasukkan penjelasan tentang apa yang akan rusak dan bagaimana / mengapa. Jika Anda tidak bisa, maka jawabannya tidak salah, menyesatkan, tidak berguna, atau tidak membantu, yang merupakan kriteria untuk downvote. Hubungan dalam tabel metadata tidak sulit untuk dipecahkan dalam kasus ini, setelah sedikit pemeriksaan, dan seperti yang saya katakan, itu bekerja dengan baik. Beban pembuktian harus ada pada orang yang kalah; Saya harap Anda akan kesulitan menemukan jawaban yang akan dipecahkan.
Jeremy Holovacs
1
Saya akan dengan bebas mengutip @Erwin kata demi kata: "Anda hanya boleh memanipulasi katalog sistem secara langsung, jika Anda tahu persis apa yang Anda lakukan. Mungkin ada efek samping yang tidak diharapkan. Atau Anda dapat merusak database (atau seluruh kluster basis data) tidak dapat diperbaiki ". Erwin tahu barang-barangnya (dan saya juga). Periksa reputasi kami dan jawaban masa lalu pada tag postgres di sini dan di SO. Downvote saya adalah ekspresi pendapat saya dan saya tidak memberikan bukti karena dokumen adalah bukti yang cukup untuk saya (orang lain dapat memutuskan sendiri).
Jack bilang coba topanswers.xyz
6
apa yang salah dengan menggunakan metode Erwin? Fakta bahwa Anda telah menggunakan metode ini tanpa masalah (jelas) membuat saya tidak percaya diri dan tidak seharusnya begitu: seseorang mungkin juga mengatakan saya telah menggunakan RAID0 selama bertahun-tahun tanpa masalah.
Jack bilang coba topanswers.xyz