มีวิธีการตั้งเจ้าของวัตถุทั้งหมดในฐานข้อมูล PostgreSQL ในเวลาเดียวกัน?


13

/programming/1348126/modify-owner-on-all-tables-simultaneously-in-postgresqlอธิบายวิธีที่ดีในการเปลี่ยนตารางและวัตถุอื่น ๆ ให้กับผู้ใช้ที่เฉพาะเจาะจงและใช้งานได้ทั้งหมด คำแนะนำดูเหมือนจะไม่สนใจฟังก์ชั่นที่ฉันสร้างขึ้น

มีวิธีที่ค่อนข้างง่ายในการรีเซ็ตเจ้าของวัตถุทั้งหมดในฐานข้อมูลรวมถึงฟังก์ชั่นหรือไม่? การทำด้วยมือเป็นสิ่งที่ไม่พึงปรารถนาอย่างมาก

คำตอบ:


22

คุณควรจัดการแคตตาล็อกระบบโดยตรงเท่านั้นหากคุณรู้ว่าคุณกำลังทำอะไรอยู่ มันอาจมีผลข้างเคียงที่ไม่คาดคิด หรือคุณอาจเสียหายฐานข้อมูล (หรือกลุ่มฐานข้อมูลทั้งหมด) เกินกว่าจะซ่อม

คำตอบของ Jeremyในขณะที่ทำเคล็ดลับไม่แนะนำให้สาธารณะชนทั่วไปทำ มันไม่มีการเปลี่ยนแปลงฟังก์ชั่นทั้งหมดในสคีมาโดยไม่มีเงื่อนไข คุณแน่ใจหรือว่าไม่มีฟังก์ชั่นของระบบที่ได้รับผลกระทบหรือฟังก์ชั่นที่ติดตั้งโดยโมดูลเพิ่มเติม?
มันจะไม่มีประโยชน์ที่จะเปลี่ยนเจ้าของฟังก์ชั่นที่เป็นเจ้าของแล้ว

ก่อนอื่นให้ตรวจสอบว่าREASSIGN OWNEDสามารถทำงานให้คุณได้หรือไม่:

เปลี่ยนความเป็นเจ้าของของวัตถุฐานข้อมูลที่เป็นเจ้าของโดยบทบาทฐานข้อมูล

คุณต้องแสดงบทบาททั้งหมดที่จะปฏิเสธอย่างชัดเจน แต่มันก็ยัง reassigns ฟังก์ชั่น

ในการกำหนดฟังก์ชั่นทั้งหมด (และไม่มีวัตถุอื่น) ในสคีมาที่กำหนดให้กับเจ้าของใหม่ (เป็นทางเลือกโดยไม่คำนึงถึงเจ้าของก่อนหน้า):

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

สิ่งนี้จะสร้างคำสั่ง canonical SQLALTER FUNCTION ...เพื่อเปลี่ยนฟังก์ชั่นทั้งหมด (ในสคีมาที่ระบุ) คุณสามารถตรวจสอบคำสั่งก่อนที่จะดำเนินการ - หนึ่งโดยหนึ่งหรือทั้งหมดในครั้งเดียว:

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

ฉันได้รวมWHEREข้อความที่มีความคิดเห็นบางส่วนที่คุณอาจต้องการใช้เพื่อกรองผลลัพธ์

หล่อการregprocedureผลิตชื่อฟังก์ชั่นที่ถูกต้องกับพารามิเตอร์สองครั้งที่ยกมาในกรณีที่จำเป็นคีมา - search_pathมีคุณสมบัติที่จำเป็นสำหรับปัจจุบัน

ฟังก์ชันการรวมstring_agg ()ต้องใช้ PostgreSQL 9.0 หรือใหม่กว่า ในแทนรุ่นเก่าด้วยและarray_agg()array_to_string()

คุณสามารถใส่ทั้งหมดนี้ลงในDOคำสั่งหรือฟังก์ชันที่แสดงในคำตอบที่เกี่ยวข้องนี้:

ใน Postgres 9.5หรือใหม่กว่าคุณสามารถทำให้การสืบค้นง่ายขึ้นโดยใช้ตัวระบุวัตถุชนิดใหม่regnamespaceและregrole :

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

ฉันใช้ฟังก์ชั่นนี้เพื่อเปลี่ยนเจ้าของตารางฟังก์ชั่นประเภท ฯลฯ คุณสามารถเปลี่ยนแบบสอบถามของเคอร์เซอร์เพื่อปรับให้เข้ากับความต้องการของคุณ

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;

จากนั้นฉันก็ดำเนินการ (ถ้าคุณต้องการ debugging output เพียงตั้งค่าพารามิเตอร์ที่สองเป็นจริง):

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

โปรดทราบว่าpg_proc.proisaggจะถูกแทนที่ใน PG 11. บันทึกประจำรุ่นกล่าวว่าแทนที่ตารางระบบpg_proc's proisaggและproiswindowด้วยprokind(ปีเตอร์ Eisentraut) `
เออร์วิน Brandstetter

0

สิ่งนี้ควรใช้กับฟังก์ชั่น:

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 ได้

เพียงเข้าสู่ฐานข้อมูลด้วย superuser และดำเนินการด้านล่าง

REASSIGN OWNED BY [old_user] TO [new_user];

สิ่งนี้จะเปลี่ยนวัตถุทั้งหมดเช่นตารางลำดับฟังก์ชัน ฯลฯ ซึ่งเป็นของ old_role เป็นบทบาทใหม่ คุณไม่ต้องคิดเกี่ยวกับวัตถุชนิดใดที่ผู้ใช้มีพวกเขาทั้งหมดจะถูกเปลี่ยน สิ่งนี้จะเปลี่ยนวัตถุก็ต่อเมื่อคุณต้องการเปลี่ยนความเป็นเจ้าของฐานข้อมูลนั้นเองก็แค่ใช้ALTER DATABASE name OWNER TO new_owner

นี่เป็นวิธีที่ดีที่สุดเนื่องจากมีจำนวน n ตารางเรียงลำดับค่อนข้างจะเป็นการวนซ้ำและสคริปต์ทุบตี


2
สิ่งนี้ถูกกล่าวถึงในคำตอบของผู้โหวตมากที่สุดตั้งแต่ 3 ปี ยังมีข้อ จำกัด
dezso

-7

ฉันไม่พบกระบวนการที่เป็นขั้นตอนเดียว แต่จะจัดการกับวัตถุทั้งหมดที่ฉันเห็นในฐานข้อมูลของฉัน:

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
มันเป็นคำถามที่ดี (+1) - -1 สำหรับคำตอบของคุณแม้ว่า - ฉันจะไม่ต้องการคนอื่นจะคิดว่ามันก็โอเคที่จะปรับปรุงโดยตรงตารางระบบเช่นนี้โดยไม่ต้องมากแน่ใจว่าพวกเขารู้ว่าสิ่งที่พวกเขากำลังทำ
แจ็คบอกว่าลอง topanswers.xyz

1
คุณกำลังขอหลักฐานว่ามันจะไม่ทำลายบางอย่างและการโต้เถียงของฉันคือถ้าคุณกำลัง downvoting บางสิ่งคุณควรรวมคำอธิบายของสิ่งที่จะทำลายและวิธีการ / ทำไม ถ้าคุณทำไม่ได้คำตอบนั้นไม่ผิดทำให้เข้าใจผิดไม่ได้ประโยชน์หรือไม่ช่วยเหลือซึ่งเป็นเกณฑ์สำหรับการลงคะแนนเสียง ความสัมพันธ์ในตารางเมตาดาต้านั้นไม่ยากที่จะเข้าใจในกรณีนี้จากการตรวจสอบเล็กน้อยและอย่างที่ฉันบอกว่ามันใช้งานได้ดี ภาระการพิสูจน์ควรอยู่ที่ผู้ลงคะแนนเสียง ฉันคาดว่าคุณจะมีปัญหาในการค้นหาสิ่งที่คำตอบนี้จะทำลาย
Jeremy Holovacs

1
ฉันจะใช้เสรีภาพในการอ้างอิง @Erwin verbatim: "คุณควรจัดการแคตตาล็อกระบบโดยตรงหากคุณรู้ว่าคุณกำลังทำอะไรอยู่อาจมีผลข้างเคียงที่ไม่คาดคิดหรือคุณอาจทำให้ฐานข้อมูลเสียหาย (หรือทั้งฐานข้อมูลคลัสเตอร์) เกินซ่อม " เออร์วินรู้สิ่งของของเขา (และฉันก็ทำเช่นนั้น) ตรวจสอบชื่อเสียงและคำตอบที่ผ่านมาของเราบนแท็ก postgres ที่นี่และบน SO downvote ของฉันคือการแสดงออกของความเห็นของฉันและฉันไม่ได้ให้ข้อพิสูจน์เพราะเอกสารเป็นหลักฐานเพียงพอสำหรับฉัน (คนอื่นสามารถตัดสินใจด้วยตนเอง)
แจ็คบอกว่าลอง topanswers.xyz


6
เกิดอะไรขึ้นกับการใช้วิธีการของเออร์วิน ความจริงที่ว่าคุณใช้วิธีที่ไม่มีปัญหา (ชัดเจน) ทำให้ฉันไม่มั่นใจและไม่ควร: บางคนอาจบอกว่าฉันใช้ RAID0 มาหลายปีโดยไม่มีปัญหา
แจ็คบอกว่าลอง topanswers.xyz
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.