Bir PostgreSQL veritabanındaki tüm nesnelerin sahibini aynı anda ayarlamanın bir yolu var mı?


13

/programming/1348126/modify-owner-on-all-tables-simultaneously-in-postgresql , tabloyu ve diğer nesneleri belirli bir kullanıcıya değiştirmenin bazı şık yollarını açıklar ve her şey yüzerek çalışır, ancak tüm bunlar öneriler oluşturduğum işlevleri görmezden geliyor gibi görünüyor.

İşlevler de dahil olmak üzere veritabanındaki TÜM nesnelerin sahibini sıfırlamanın oldukça kolay bir yolu var mı? Elle yapmak son derece istenmeyen bir durumdur.

Yanıtlar:


22

Sistem kataloglarını yalnızca ne yaptığınızı tam olarak biliyorsanız doğrudan yönetmelisiniz. Beklenmedik yan etkileri olabilir. Veya veritabanını (veya tüm veritabanı kümesini) onarılamayacak şekilde bozabilirsiniz.

Jeremy'nin cevabı , temelde hile yaparken, halk için tavsiye edilmez . Şemadaki tüm işlevleri koşulsuz olarak değiştirir. Etkilenen herhangi bir sistem işlevi veya ek bir modül tarafından yüklenmiş işlevler olmadığından emin misiniz?
Ayrıca, önceden belirlenmiş sahibine ait olan işlevlerin sahibini değiştirmek de anlamsız olacaktır.

İlk olarak, REASSIGN OWNEDsizin için çalışıp çalışmadığını kontrol edin :

veritabanı rolüne ait veritabanı nesnelerinin sahipliğini değiştirme

Reddedilecek tüm rolleri açıkça listelemeniz gerekir. Ancak işlevleri yeniden atar .

Belirli bir şemadaki tüm işlevleri (ve başka bir nesneyi olmayan) yeni bir sahibe (isteğe bağlı olarak önceki sahibine bakılmaksızın) atamak için :

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

Bu, tüm işlevleri (belirtilen şemada) değiştirmek için standart SQL komutlarıALTER FUNCTION ... oluşturur . Komutları yürütmeden önce kontrol edebilirsiniz - birer birer veya hepsi aynı anda:

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

WHERESonuçları filtrelemek için kullanmak isteyebileceğiniz bazı yorumlu hükümler ekledim.

Döküm için regprocedure, gerektiğinde çift tırnaklı, geçerli olduğunda şema nitelemeli parametrelerle geçerli bir işlev adı üretir search_path.

Toplama fonksiyonu string_agg () PostgreSQL 9.0 veya üstünü gerektirir. Eski sürümde array_agg()ve ile değiştirilir array_to_string().

Sen olabilir bir içine tüm bu koymak DOdeyimi veya bu ilgili cevap gösterildiği gibi bir fonksiyonu:

Postgres 9.5 veya sonraki sürümlerinde, sorguyu yeni nesne tanımlayıcı türleriniregnamespaceregrole kullanarak basitleştirebilirsiniz ve :

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

Tablolar, işlevler, türler vb. Sahiplerini değiştirmek için bu işlevi kullanıyorum. İmleçlerin sorgusunu ihtiyaçlarınıza göre değiştirmek için değiştirebilirsiniz.

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;

Sonra ben sadece yürütmek (hata ayıklama çıktısı sadece ikinci parametre true olarak ayarlamak istiyorsanız):

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

Not pg_proc.proisaggpg 11'de değiştirilir sürüm notları ki: sistem tablo değiştirin pg_proc'ın proisaggve proiswindowile prokind(Peter Eisentraut) `
Erwin Brandstetter

0

Bu işlevler için çalışmalıdır:

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

REASSIGN OWNED komutunu kullanabilirsiniz

Sadece superuser ile veritabanına giriş yapın ve aşağıda çalıştırın

REASSIGN OWNED BY [old_user] TO [new_user];

Bu, old_role'a ait olan tüm nesneleri, yani tabloları, diziyi, işlevi vb. Yeni role değiştirir. Kullanıcının ne tür nesnelere sahip olduğunu düşünmenize gerek yok, hepsi değişecek. Bu, yalnızca veritabanının kendisinin sahipliğini değiştirmek istediğinizde nesneleri kullanır.ALTER DATABASE name OWNER TO new_owner

En iyi yöntem budur çünkü n sayıda tablo, döngüler ve bash betikleri için sıralar


2
Bu, 3 yıldan bu yana en çok oy alan cevapta belirtilmiştir. Ayrıca sınırlamaları.
dezso

-7

Tek adımlı bir süreç bulamadım, ancak bu veritabanımda görebildiğim tüm nesneleri halleder:

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
Bu iyi bir soru (1) var - -1 Cevabınız için olsa - Ben başkasının doğrudan olmadan bu gibi sistem tabloları güncellemek için ok olduğunu düşünüyorum isteyeyim çok emin onlar ne yaptıklarını biliyorum.
Jack diyor ki topanswers.xyz

1
Bunun bir şeyi kırmayacağına dair kanıt istiyorsunuz ve benim karşıt yönüm, bir şeyi küçümsüyorsanız, neyin kırılacağına ve nasıl / neden olduğuna dair bir açıklama eklemeniz gerektiğidir. Yapamıyorsanız, cevap yanlış, yanıltıcı, işe yaramaz veya yararsızdır, bu da bir aşağı oy için kriterdir. Meta veri tablolarındaki ilişkilerin bu durumda, biraz inceleme yapıldıktan sonra anlaşılması zor değildi ve dediğim gibi, yüzerek çalışıyor. İspat yükü downvoter'da olmalıdır; Bu cevabın ne kıracağını bulmakta zorluk çekeceğinizi umuyorum.
Jeremy Holovacs

1
@Erwin verbatim'den alıntı yapma özgürlüğünü alacağım: "Sadece tam olarak ne yaptığınızı biliyorsanız, sistem kataloglarını doğrudan manipüle etmelisiniz. Beklenmedik yan etkileri olabilir. Veya veritabanını (veya tüm veritabanı kümesini) bozabilirsiniz tamir edilemeyecek şekilde". Erwin eşyalarını biliyor (ben de biliyorum). Buradaki ve SO'daki postgres etiketindeki itibarımızı ve geçmiş yanıtlarımızı kontrol edin. Downvote'um fikrimin bir ifadesidir ve hiçbir kanıt sunmuyorum çünkü dokümanlar benim için yeterli kanıttır (diğerleri kendileri için karar verebilir).
Jack diyor ki topanswers.xyz


6
Erwin'in yöntemini kullanmanın nesi yanlış? Yöntemi (belirgin) sorun olmadan kullandığınız gerçeği bana güven vermiyor ve aynı şekilde olmamalı: birisi eşit olarak RAID0'ı yıllarca sorunsuz kullandığımı söyleyebilir.
Jack diyor ki topanswers.xyz
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.