Giải pháp chung
Tôi đã tạo một hàm sql thuần túy bằng cách sử dụng set_config ().
Giải pháp này hỗ trợ thiết lập nhiều lược đồ trong một chuỗi được phân tách bằng dấu phẩy. Theo mặc định, thay đổi áp dụng cho phiên hiện tại. Đặt thông số "is_local" thành true sẽ làm cho thay đổi chỉ áp dụng cho giao dịch hiện tại, xem http://www.postgresql.org/docs/9.4/static/functions-admin.html để biết thêm chi tiết.
CREATE OR REPLACE FUNCTION public.set_search_path(path TEXT, is_local BOOLEAN DEFAULT false) RETURNS TEXT AS $$
SELECT set_config('search_path', regexp_replace(path, '[^\w ,]', '', 'g'), is_local);
$$ LANGUAGE sql;
Vì chúng tôi không chạy bất kỳ sql động nào nên ít có khả năng bị tiêm sql hơn. Chỉ để chắc chắn rằng tôi đã thêm một số cách làm sạch văn bản bằng cách xóa tất cả các ký tự ngoại trừ chữ và số, dấu cách và dấu phẩy. Thoát / trích dẫn chuỗi không phải là tầm thường, nhưng tôi không phải là một chuyên gia, vì vậy .. =)
Hãy nhớ rằng sẽ không có phản hồi nếu bạn đặt một đường dẫn không đúng định dạng.
Đây là một số mã mẫu để thử nghiệm:
DROP SCHEMA IF EXISTS testschema CASCADE;
CREATE SCHEMA testschema;
CREATE TABLE testschema.mytable ( id INTEGER );
SELECT set_search_path('testschema, public');
SHOW search_path;
INSERT INTO mytable VALUES(123);
SELECT * FROM mytable;
Một bài kiểm tra dựa trên mã gốc của OP
Vì chúng ta không biết trước lược đồ cho mytable, chúng ta cần sử dụng dynamic sql. Tôi đã nhúng set_config-oneliner vào hàm get_section () - thay vì sử dụng hàm chung chung.
Lưu ý: Tôi đã phải đặt is_local =false trong set_config () để điều này hoạt động. Điều đó có nghĩa là đường dẫn đã sửa đổi vẫn còn sau khi chạy hàm. Tôi không chắc tại sao.
DROP SCHEMA IF EXISTS testschema CASCADE;
CREATE SCHEMA testschema;
SET search_path TO public;
CREATE TABLE testschema.mytable ( id INTEGER, name varchar, type varchar );
INSERT INTO testschema.mytable VALUES (123,'name', 'some-type');
INSERT INTO testschema.mytable VALUES (567,'name2', 'beer');
CREATE OR REPLACE FUNCTION get_sections(schema_name TEXT) RETURNS
TABLE(id integer, name varchar, type varchar) AS $$
BEGIN
PERFORM set_config('search_path', regexp_replace(schema_name||', public', '[^\w ,]', '', 'g'), true);
EXECUTE 'SELECT id, name, type FROM mytable';
END;
$$ LANGUAGE plpgsql;
SET search_path TO public;
SELECT * FROM get_sections('testschema');
SHOW search_path; -- Unfortunately this has modified the search_path for the whole session.