Есть ли способ установить владельца всех объектов в базе данных PostgreSQL одновременно?

13

/programming/1348126/modify-owner-on-all-tables-simrallelually-in-postgresql описывает некоторые изящные способы изменения таблицы и других объектов для конкретного пользователя, и это работает плавно, однако все предложения, кажется, игнорируют функции, которые я создал.

Есть ли достаточно простой способ сбросить владельца ВСЕХ объектов в базе данных, включая функции? Делать это вручную крайне нежелательно.

Джереми Головач
источник

Ответы:

22

Вы должны когда-либо манипулировать системными каталогами напрямую, только если точно знаете, что делаете. Это может иметь неожиданные побочные эффекты. Или вы можете повредить базу данных (или весь кластер базы данных) без возможности восстановления.

Ответ Джереми , хотя и делает свое дело, не рекомендуется для широкой публики. Это безоговорочно меняет все функции в схеме. Вы уверены, что не затронуты системные функции или функции, установленные дополнительным модулем?
Также было бы бессмысленно менять владельца функций, которые уже принадлежат назначенному владельцу.

Во-первых, проверьте, 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_%'

Это генерирует канонические команды 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;

Затем я просто выполняю (если вы хотите отладочный вывод, просто установите для второго параметра значение true):

SELECT fn_setowner('demo', false);
DROP FUNCTION fn_setowner(varchar(30), boolean);
JorSol
источник
Обратите внимание , что pg_proc.proisaggзаменяется на стр 11. Примечания к выпуску сказать: Заменить системную таблицу pg_proc«s proisaggи proiswindowс prokind(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 года. Также его ограничения.
Дезсо
-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
Вы запрашиваете доказательство того, что это не сломает что-то, и мой контраргумент состоит в том, что если вы отрицаете что-то, вы должны включить объяснение того, что это сломает и как / почему. Если вы не можете, тогда ответ не является неправильным, вводящим в заблуждение, бесполезным или бесполезным, что является критерием для отрицательного ответа. Отношения в таблицах метаданных было не сложно выяснить в этом случае, после небольшого изучения, и, как я уже сказал, это работает плавно. Бремя доказывания должно быть на downvoter; Я ожидаю, что у вас будут трудности с поиском того, что сломает этот ответ.
Джереми Холовач
1
Я позволю себе процитировать @Erwin дословно: «Вы должны когда-либо манипулировать системными каталогами напрямую, только если вы точно знаете, что делаете. Это может иметь неожиданные побочные эффекты. Или вы можете повредить базу данных (или весь кластер базы данных). неподлежащий ремонту". Эрвин знает свое дело (и я тоже). Проверьте нашу репутацию и прошлые ответы по тегу postgres здесь и на SO. Мое отрицание является выражением моего мнения, и я не предлагаю никаких доказательств, потому что документы являются достаточным доказательством для меня (другие могут решить для себя).
Джек говорит, попробуйте topanswers.xyz
6
что не так с использованием метода Эрвина? Тот факт, что вы использовали метод без (очевидной) проблемы, не дает мне уверенности и не должен: кто-то может сказать, что я годами использовал RAID0 без проблем.
Джек говорит, попробуйте topanswers.xyz