Чи є засіб одночасно встановити власника всіх об'єктів у базі даних PostgreSQL?


13

/programming/1348126/modify-owner-on-all-tables-sim istovreme-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;

Тоді я просто виконую (якщо ви хочете налагоджувати вихід просто встановіть другий параметр на істинне):

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

Зверніть увагу , що 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
Ви просите доказ того, що це щось не зламає, і мій контраргумент полягає в тому, що якщо ви щось скасовуєте, ви повинні включити пояснення, що воно порушиться і як / чому. Якщо ви не можете, то відповідь не є помилковою, оманливою, невикористовуваною чи не корисною, що є критеріями для участі в програмі. Взаємовідносини в таблицях метаданих було важко розібратися в цьому випадку за допомогою невеликої перевірки, і, як я вже сказав, це працює добре. Тягар доказування повинен лежати на потоці; Я очікую, що у вас виникнуть труднощі з пошуку того, що ця відповідь порушить.
Джеремі Головач

1
Я візьму на себе сміливо цитувати @Erwin дослівно: "Вам слід коли-небудь безпосередньо маніпулювати системними каталогами, якщо ви точно знаєте, що ви робите. Це може мати несподівані побічні ефекти. Або ви можете пошкодити базу даних (або весь кластер баз даних) поза ремонтом ". Ервін знає свої речі (так само і я). Перевірте нашу репутацію та минулі відповіді на тезі postgres тут та на ТАК. Мій голос є вираженням моєї думки, і я не пропоную жодних доказів, оскільки документи є для мене достатньою доказою (інші можуть вирішити самі).
Джек каже, спробуйте topanswers.xyz


6
що не в застосуванні методу Ервіна? Той факт, що ви використовували метод без (очевидного) питання, не дає мені впевненості, і це також не повинно: хтось може однаково сказати, що я використовував RAID0 роками без проблем.
Джек каже, спробуйте topanswers.xyz
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.