我需要在查询之前设置search_path。新的搜索路径应基于函数参数。我怎么能这样做?现在我有:
CREATE FUNCTION get_sections(integer) RETURNS
table(id integer, name varchar, type varchar) as $$
SET search_path to $1, public;
select id, name, type from sections;
$$ language 'sql';
但它根本不接受1美元。我也尝试过quote_ident($ 1),但它没有用。
谢谢!
答案 0 :(得分:3)
我使用set_config()创建了一个纯sql函数。
此解决方案支持在逗号分隔的字符串中设置多个模式。默认情况下 此更改适用于当前会话。设置" is_local"参数为true使更改仅适用于当前事务,有关详细信息,请参阅http://www.postgresql.org/docs/9.4/static/functions-admin.html。
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;
由于我们没有运行任何动态sql,因此应该减少sql注入的机会。只是为了确保通过删除除字母数字,空格和逗号之外的所有字符,我添加了一些天真的文本消毒。转义/引用字符串并非易事,但我不是专家,所以.. =)
请记住,如果设置格式错误的路径,则没有反馈。
以下是一些测试示例代码:
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;
由于我们事先并不知道mytable的架构,因此我们需要使用动态sql。我将set_config-oneliner嵌入到get_sections() - 函数中,而不是使用泛型' ish函数。
注意:我必须在set_config()中设置is_local = false才能生效。这意味着在运行函数后,修改后的路径仍然存在。我不确定为什么。
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.
答案 1 :(得分:0)
下面的代码将起作用
CREATE FUNCTION get_sections(num integer) RETURNS
table(id integer, name varchar, type varchar) as $$
EXECUTE FORMAT('SET search_path to %L::INTEGER, public;'num);
select id, name, type from sections;
$$ language 'sql';