Có một phương tiện để thiết lập chủ sở hữu của tất cả các đối tượng trong cơ sở dữ liệu PostgreSQL cùng một lúc không?


13

/programming/1348126/modify-owner-on-all-tables-simallelly-in-postgresql mô tả một số cách tiện lợi để thay đổi bảng và các đối tượng khác cho một người dùng cụ thể, tuy nhiên tất cả đều hoạt động tốt đề xuất dường như bỏ qua các chức năng tôi tạo ra.

Có một cách khá dễ dàng để thiết lập lại chủ sở hữu của TẤT CẢ các đối tượng trong cơ sở dữ liệu, bao gồm các chức năng? Làm điều đó bằng tay là rất không mong muốn.

Câu trả lời:


21

Bạn chỉ nên thao tác trực tiếp danh mục hệ thống , nếu bạn biết chính xác những gì bạn đang làm. Nó có thể có tác dụng phụ không mong muốn. Hoặc bạn có thể làm hỏng cơ sở dữ liệu (hoặc toàn bộ cụm cơ sở dữ liệu) sau khi sửa chữa.

Câu trả lời của Jeremy , trong khi về cơ bản thực hiện mánh khóe, không được khuyến khích cho công chúng. Nó thay đổi vô điều kiện tất cả các chức năng trong một lược đồ. Bạn có chắc chắn không có chức năng hệ thống nào bị ảnh hưởng hoặc các chức năng được cài đặt bởi một mô-đun bổ sung không?
Việc thay đổi chủ sở hữu các chức năng đã thuộc về chủ sở hữu được chỉ định cũng là vô nghĩa.

Trước tiên, hãy kiểm tra nếu REASSIGN OWNEDcó thể làm việc cho bạn:

thay đổi quyền sở hữu đối tượng cơ sở dữ liệu thuộc sở hữu của vai trò cơ sở dữ liệu

Bạn phải liệt kê tất cả các vai trò để bị từ chối rõ ràng. Nhưng nó cũng gán lại chức năng .

Để gán tất cả các hàm (và không có đối tượng nào khác) trong một lược đồ đã cho cho chủ sở hữu mới (tùy chọn bất kể chủ sở hữu trước đó):

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

Điều này tạo ra các lệnh SQL chuẩnALTER FUNCTION ... để thay đổi tất cả các hàm (trong lược đồ đã chỉ định). Bạn có thể kiểm tra các lệnh trước khi thực hiện chúng - từng cái một hoặc tất cả cùng một lúc:

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

Tôi bao gồm một số WHEREmệnh đề nhận xét mà bạn có thể muốn sử dụng để lọc kết quả.

Các diễn viên để regproceduretạo ra một tên hàm hợp lệ với các tham số, trích dẫn kép khi cần thiết, lược đồ - đủ điều kiện khi cần thiết cho hiện tại search_path.

Hàm tổng hợp string_agg () yêu cầu PostgreSQL 9.0 trở lên. Trong phiên bản cũ thay thế bằng array_agg()array_to_string().

Bạn có thể đặt tất cả những điều này vào một DOtuyên bố hoặc một chức năng như thể hiện trong câu trả lời liên quan này:

Trong Postgres 9.5 trở lên, bạn có thể đơn giản hóa truy vấn bằng cách sử dụng các loại định danh đối tượngregnamespaceregrole mới :

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

Tôi sử dụng chức năng này để thay đổi chủ sở hữu của các bảng, hàm, loại, v.v. Bạn có thể thay đổi truy vấn của các con trỏ để điều chỉnh nó theo nhu cầu của bạn.

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;

Sau đó, tôi chỉ thực hiện (nếu bạn muốn gỡ lỗi đầu ra, chỉ cần đặt tham số thứ hai thành true):

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

Lưu ý pg_proc.proisaggđược thay thế trong pg 11. Ghi chú phát hành cho biết: Thay thế bảng hệ thốngpg_proc 's proisaggproiswindowvới prokind(Peter Eisentraut) `
Erwin Brandstetter

0

Điều này sẽ làm việc cho các chức năng:

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

Bạn có thể sử dụng lệnh REASSIGN OWNED

Chỉ cần đăng nhập vào cơ sở dữ liệu bằng superuser và thực hiện bên dưới

REASSIGN OWNED BY [old_user] TO [new_user];

Điều này thay đổi tất cả các đối tượng, ví dụ như bảng, trình tự, hàm, vv do old_role sở hữu sang vai trò mới. Bạn không cần phải suy nghĩ về loại đối tượng mà người dùng có, tất cả chúng sẽ được thay đổi. Điều này chỉ thay đổi các đối tượng nếu bạn muốn thay đổi quyền sở hữu cơ sở dữ liệu đó.ALTER DATABASE name OWNER TO new_owner

Đây là phương pháp tốt nhất vì sẽ có n số bảng, trình tự thay vì các vòng lặp và tập lệnh bash


2
Điều này được đề cập trong câu trả lời với hầu hết các upvote kể từ 3 năm. Ngoài ra những hạn chế của nó.
dezso

-7

Chà, tôi đã không tìm thấy quy trình một bước, nhưng điều này quan tâm đến tất cả các đối tượng tôi có thể thấy trong cơ sở dữ liệu của mình:

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
Đó là một câu hỏi hay (1) - -1 cho câu trả lời của bạn mặc dù - Tôi không muốn bất cứ ai khác để nghĩ rằng đó là ok để trực tiếp cập nhật bảng hệ thống như thế này mà không bị rất chắc chắn rằng họ biết những gì họ đang làm.
Jack nói hãy thử topanswers.xyz

1
Bạn đang yêu cầu bằng chứng rằng nó sẽ không phá vỡ thứ gì đó, và phản biện của tôi là nếu bạn đang hạ thấp thứ gì đó, bạn nên bao gồm một lời giải thích về những gì nó sẽ phá vỡ và làm thế nào / tại sao. Nếu bạn không thể, thì câu trả lời không sai, gây hiểu lầm, không đáng tin cậy hoặc không có ích, đó là những tiêu chí cho một downvote. Các mối quan hệ trong các bảng siêu dữ liệu không khó để tìm ra trong trường hợp này, sau khi kiểm tra một chút, và như tôi đã nói, nó hoạt động một cách bơi lội. Gánh nặng của bằng chứng nên ở trên downvoter; Tôi hy vọng bạn sẽ gặp khó khăn trong việc tìm ra câu trả lời này sẽ phá vỡ.
Jeremy Holovacs

1
Tôi sẽ tự do trích dẫn nguyên văn @Erwin: "Bạn chỉ nên thao tác trực tiếp danh mục hệ thống, nếu bạn biết chính xác những gì bạn đang làm. Nó có thể có tác dụng phụ không mong muốn. Hoặc bạn có thể làm hỏng cơ sở dữ liệu (hoặc toàn bộ cụm cơ sở dữ liệu) ngoài sửa chữa ". Erwin biết công cụ của mình (và tôi cũng vậy). Kiểm tra danh tiếng và câu trả lời trước đây của chúng tôi trên thẻ postgres tại đây và trên SO. Downvote của tôi là một biểu hiện ý kiến ​​của tôi và tôi không đưa ra bằng chứng nào vì các tài liệu là đủ bằng chứng cho tôi (những người khác có thể tự quyết định).
Jack nói hãy thử topanswers.xyz


6
Có gì sai khi sử dụng phương pháp của Erwin? Thực tế là bạn đã sử dụng phương thức mà không có vấn đề (rõ ràng) khiến tôi không tự tin và cũng không nên: ai đó có thể nói rằng tôi đã sử dụng RAID0 trong nhiều năm mà không gặp vấn đề gì.
Jack nói hãy thử topanswers.xyz
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.