2010-07-15 26 views
5

Tôi viết tập lệnh PSQL và sử dụng các biến (cho cú pháp dòng lệnh psql --variable key = value).Có cú pháp thoát cho biến psql bên trong các hàm PostgreSQL không?

Công trình này hoàn hảo cho phạm vi cấp cao nhất như chọn * từ: khóa, nhưng tôi tạo chức năng với tập lệnh và cần giá trị biến bên trong chúng.

Vì vậy, cú pháp như

create function foo() returns void as 
$$ 
declare 
begin 
    grant select on my_table to group :user; 
end; 
$$ 
language plpgsql; 

thất bại tại : hướng dẫn.

Theo như tôi hiểu các biến psql là một tính năng thay thế macro đơn giản, nhưng nó không xử lý các đối tượng chức năng. Có cú pháp thoát nào cho các trường hợp như vậy không? Xung quanh : người dùng với $$ hoạt động liên quan đến thay thế, nhưng psql không thành công tại $$.

Có cách nào khác để thực hiện điều này ngoài việc xử lý macro độc lập (sed, awk, v.v ...) không?

+0

Bạn có thể có hàm foo tham số và sử dụng thông số đó không? – Fosco

Trả lời

7

PSQL SET biến không được nội suy bên trong các chuỗi được trích dẫn bằng đô la. Tôi không biết điều này cho chắc chắn, nhưng tôi nghĩ rằng không có lối thoát hoặc thủ thuật khác để bật SET nội suy biến trong đó.

Người ta có thể nghĩ rằng bạn có thể nêm một số không giới hạn :user giữa hai khoảng cách PL-pgSQL được trích dẫn bằng đô la để có được hiệu quả mong muốn. Nhưng điều này dường như không làm việc ... Tôi nghĩ rằng cú pháp đòi hỏi một chuỗi duy nhất và không phải là một biểu thức nối chuỗi. Có thể bị nhầm lẫn về điều đó.

Dù sao, điều đó cũng không quan trọng. Có một cách tiếp cận khác (như Pasco đã lưu ý): viết thủ tục lưu sẵn để chấp nhận một đối số PL/pgSQL. Đây là những gì sẽ như thế.

CREATE OR REPLACE FUNCTION foo("user" TEXT) RETURNS void AS 
$$ 
BEGIN 
     EXECUTE 'GRANT SELECT ON my_table TO GROUP ' || quote_ident(user); 
END;  
$$ LANGUAGE plpgsql; 

Ghi chú về chức năng này:

  1. EXECUTE tạo ra một thích hợp GRANT trên mỗi lời gọi sử dụng trên lập luận quy trình của chúng tôi. Phần hướng dẫn sử dụng PG có tên "Executing Dynamic Commands" giải thích chi tiết EXECUTE.
  2. Việc khai báo đối số thủ tục user phải được trích dẫn kép. Dấu ngoặc kép buộc nó được hiểu là một định danh.

Khi bạn xác định hàm như thế này, bạn có thể gọi nó bằng biến PSQL nội suy. Đây là một phác thảo.

  1. Chạy psql --variable user="'whoever'" --file=myscript.sql. Dấu nháy đơn được yêu cầu xung quanh tên người dùng!
  2. Trong myscript.sql, hãy xác định hàm như trên.
  3. Trong myscript.sql, hãy đặt select foo(:user);. Đây là nơi chúng ta dựa vào những dấu nháy đơn mà chúng ta đặt trong giá trị của user.

Mặc dù điều này có vẻ hiệu quả nhưng nó lại gây ấn tượng mạnh với tôi.Tôi nghĩ rằng các biến số SET được dành cho cấu hình thời gian chạy. Mang dữ liệu xung quanh trong SET có vẻ lạ.

Chỉnh sửa: đây là lý do cụ thể để không sử dụng sử dụng biến số SET. Từ manpage: "Những bài tập này được thực hiện trong giai đoạn khởi động rất sớm, vì vậy các biến dành riêng cho mục đích nội bộ có thể bị ghi đè sau." Nếu Postgres quyết định sử dụng biến có tên là user (hoặc bất kỳ thứ gì bạn chọn), nó có thể ghi đè đối số tập lệnh của bạn bằng một thứ mà bạn không bao giờ có ý định. Trong thực tế, psql đã mất USER cho chính nó - điều này chỉ hoạt động vì SET phân biệt chữ hoa chữ thường. Điều này gần như đã phá vỡ mọi thứ ngay từ đầu!

+1

bạn nên sử dụng EXECUTE 'GRANT SELECT ON my_table TO GROUP' || quote_ident (người dùng); Tôi tin. – rfusca

+0

@rfusca vâng, không thể làm tổn hại đến việc khử trùng nó! –

4

Bạn có thể sử dụng phương pháp Dan LaRocque mô tả để làm cho công việc hack'ishly (không phải gõ cửa Dan) - nhưng psql không thực sự là bạn của bạn để thực hiện loại công việc này (giả sử loại công việc này là kịch bản) và không phải những thứ một lần). Nếu bạn đã có một chức năng, viết lại nó để có một tham số như sau:

create function foo(v_user text) returns void as 
$$ 
begin 
    execute 'grant select on my_table to group '||quote_ident(v_user); 
end; 
$$ 
language plpgsql; 

(quote_ident() làm cho nó, do đó bạn không cần phải đảm bảo hai dấu ngoặc kép, nó xử lý tất cả những gì.)

Nhưng sau đó sử dụng ngôn ngữ kịch bản thực như Perl, Python, Ruby, v.v. có trình điều khiển Postgres để gọi hàm của bạn bằng tham số.

Psql có vị trí của nó, tôi chỉ không chắc chắn rằng đây là nó.

+0

Tôi đồng ý rằng bằng cách sử dụng psql 'SET' như thế này có lẽ là một mối nguy hiểm bảo trì. Tôi đã chia sẻ những hiểu lầm của bạn khi tôi viết câu trả lời của tôi. Có một đoạn nhỏ ở cuối cho một lý do cụ thể * tại sao * nó nguy hiểm. –

+0

@Dan LaRocque: Vâng, đó là lý do tại sao tôi không cảm thấy cần phải nhắc lại điều đó và tại sao tôi thậm chí còn upvoted câu trả lời của bạn. :) – rfusca

Các vấn đề liên quan