PostgreSQL:如何从函数内部设置search_path?

时间:2014-01-21 13:28:18

标签: sql postgresql

我需要在查询之前设置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),但它没有用。

谢谢!

2 个答案:

答案 0 :(得分:3)

Generic' ish solution

我使用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;

基于OP的原始代码

的测试

由于我们事先并不知道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';