PostgreSQLデータベース内のすべてのオブジェクトの所有者を同時に設定する方法はありますか?


13

/programming/1348126/modify-owner-on-all-tables-simultaneously-in-postgresqlは、テーブルやその他のオブジェクトを特定のユーザーに変更するいくつかの気の利いた方法を説明します。提案は、私が作成した関数を無視するようです。

関数を含む、データベース内のすべてのオブジェクトの所有者をリセットするかなり簡単な方法はありますか?手作業で行うことは非常に望ましくありません。

回答:


21

実行していることを正確に把握している場合にのみ、システムカタログを直接操作する必要があります。予期しない副作用が生じる可能性があります。または、修復できないほどデータベース(またはデータベースクラスター全体)を破損する可能性があります。

ジェレミーの答えは、基本的にトリックをやっていますが、一般の人にはお勧めできません。スキーマ内のすべての関数を無条件に変更します。影響を受けるシステム機能や追加モジュールによってインストールされた機能はありませんか?
また、指定された所有者に既に属している関数の所有者を変更しても意味がありません。

まず、REASSIGN OWNEDあなたのために働くことができるかどうかを確認してください:

データベースロールが所有するデータベースオブジェクトの所有権を変更する

明示的に否認されるすべてのロールをリストする必要があります。ただし、機能の再割り当ても行います

特定のスキーマ内のすべての機能(および他のオブジェクトではない)を新しい所有者に割り当てるには(オプションで以前の所有者に関係なく):

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

これにより、(指定されたスキーマ内の)すべての関数を変更する標準的なSQLコマンドがALTER FUNCTION ...生成されます。コマンドを実行する前に、1つずつ、または一度に検査できます。

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;

次に、実行します(デバッグ出力が必要な場合は、2番目のパラメーターをtrueに設定するだけです)。

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

pg_proc.proisaggPG 11に交換されるリリースノートには:回答システムテーブルを取り付けpg_procさんproisaggproiswindowprokindしました。(Peter 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コマンドを使用できます

スーパーユーザーでデータベースにログインし、以下を実行するだけです

REASSIGN OWNED BY [old_user] TO [new_user];

これにより、old_roleが所有するテーブル、シーケンス、関数などのすべてのオブジェクトが新しいロールに変更されます。ユーザーがどのような種類のオブジェクトを持っているかを考える必要はありません。それらはすべて変更されます。これは、そのデータベース自体の所有権を変更したい場合にのみオブジェクトを変更しますALTER DATABASE name OWNER TO new_owner

n個のテーブル、ループではなくシーケンス、bashスクリプトがあるため、これが最良の方法です。


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
あなたはそれが何かを壊さないという証拠を求めています、そして私の反論は、あなたが何かをダウン投票しているなら、あなたはそれが何を壊すのか、どのように/なぜの説明を含めるべきだということです。それができない場合、答えは間違っている、誤解を招く、役に立たない、または役に立たないものではありません。これらは、ダウン投票の基準です。メタデータテーブル内の関係は、少し調べてみると、この場合は理解するのが難しくありませんでした。立証責任はダウンボターにあるべきです。この答えが何を破るのかを見つけるのが難しいと思います。
ジェレミーホロヴァックス

1
@Erwinを逐語的に引用する自由を取ります:「何をしているのかを正確に知っている場合にのみ、システムカタログを直接操作する必要があります。予期しない副作用が発生する可能性があります。修理不能"。アーウィンは自分のことを知っています(私もそうです)。こことSOでpostgresタグの評判と過去の回答を確認してください。私のダウン票は私の意見の表明であり、ドキュメントは私にとって十分な証拠であるため、証拠を提供しません(他の人が自分で決めることができます)。
ジャックはtopanswers.xyz


6
Erwinのメソッドを使用することの何が問題になっていますか?(明らかな)問題のない方法を使用したという事実は、私に自信を与えず、またそうすべきではありません。
ジャックはtopanswers.xyzを試す14
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.