PostgreSQL 데이터베이스에있는 모든 객체의 소유자를 동시에 설정하는 수단이 있습니까?


13

/programming/1348126/modify-owner-on-all-tables-simultaneously-in-postgresql 은 테이블 및 기타 객체를 특정 사용자로 변경하는 멋진 방법을 설명하지만 수영으로 작동합니다. 제안은 내가 만든 기능을 무시하는 것 같습니다.

함수를 포함하여 데이터베이스의 모든 객체 소유자를 재설정하는 매우 쉬운 방법이 있습니까? 손으로하는 것은 매우 바람직하지 않습니다.

답변:


22

정확히 무엇을하고 있는지 알고 있다면 시스템 카탈로그를 직접 조작 해야합니다 . 예기치 않은 부작용이있을 수 있습니다. 또는 복구 할 수없는 데이터베이스 (또는 전체 데이터베이스 클러스터)를 손상시킬 수 있습니다.

Jeremy의 대답 은 기본적으로 트릭을 수행 하지만 일반 대중 에게는 권장되지 않습니다 . 무조건 스키마의 모든 함수를 변경합니다. 영향을받는 시스템 기능이 없거나 추가 모듈에 의해 설치된 기능이 확실하지 않습니까?
지정된 소유자에 이미 속한 함수의 소유자를 변경하는 것도 의미가 없습니다.

먼저, 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 ... 을 생성하여 지정된 스키마에서 모든 기능 을 변경 합니다 . 명령을 실행하기 전에 한 번에 하나씩 또는 모두 하나씩 검사 할 수 있습니다.

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 이상에서는 다음 같은 새로운 객체 식별자 유형을regnamespaceregrole 사용하여 쿼리를 단순화 할 수 있습니다 .

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;

그런 다음 방금 실행합니다 (디버깅 출력을 원하면 두 번째 매개 변수를 true로 설정하십시오).

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

참고 pg_proc.proisagg페이지 (11)의 교체는 릴리스 정보는 말한다 : 시스템 테이블 교체 pg_procproisaggproiswindow함께 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 명령을 사용할 수 있습니다

수퍼 유저로 데이터베이스에 로그인하고 아래에서 실행하십시오.

REASSIGN OWNED BY [old_user] TO [new_user];

그러면 old_role이 소유 한 테이블, 시퀀스, 함수 등의 모든 개체가 새 역할로 변경됩니다. 사용자가 어떤 종류의 객체를 가지고 있는지 생각할 필요가 없으며 모두 변경됩니다. 이것은 데이터베이스 자체의 소유권을 변경하려는 경우에만 객체를 변경합니다.ALTER DATABASE name OWNER TO new_owner

이것은 루프와 bash 스크립트를 처리하는 대신 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
당신은 그것이 무언가를 깨뜨리지 않을 것이라는 증거를 요구하고 있으며, 내 반박 론은 만약 당신이 무언가를 내리는 것이라면 그것이 무엇이 깨질 것인지 그리고 어떻게 / 왜 그런지에 대한 설명을 포함시켜야한다는 것입니다. 당신이 할 수 없다면, 답은 틀리거나, 오도하거나, 유용하지 않거나, 도움이되지 않는데, 이것은 공감대에 대한 기준입니다. 메타 데이터 테이블의 관계는이 경우 약간의 조사를 통해 파악하기가 어렵지 않았으며 내가 말했듯이 수영으로 작동합니다. 증거의 부담은 하락세에 있어야한다. 이 답변이 깨지는 것을 찾는 데 어려움이 있기를 바랍니다.
Jeremy Holovacs

1
@Erwin을 그대로 인용하면 자유로울 것입니다. "무엇을하고 있는지 정확히 알고 있다면 시스템 카탈로그를 직접 조작해야합니다. 예상치 못한 부작용이있을 수 있습니다. 또는 데이터베이스 (또는 전체 데이터베이스 클러스터)를 손상시킬 수 있습니다. 수리 할 수 ​​없을 정도의". 어윈은 자신의 것을 알고 있습니다. postgres 태그 및 여기에서 우리의 명성과 과거 답변을 확인하십시오. 내 downvote는 내 의견의 표현이며 문서가 나에게 충분한 증거이기 때문에 증거를 제공하지 않습니다 (다른 사람들이 스스로 결정할 수 있음).
잭 topanswers.xyz 시도라고


6
Erwin의 방법을 사용하여 무엇이 문제입니까? 당신이 (명백한) 문제없이 방법을 사용했다는 사실은 나에게 자신감을주지 않으며 그렇게해서는 안됩니다.
잭 topanswers.xyz 시도라고
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.