gpt4 book ai didi

sql - 在 PL/pgSQL 中使用 USING 关键字清理用户输入

转载 作者:搜寻专家 更新时间:2023-10-30 19:50:22 25 4
gpt4 key购买 nike

这就是我创建 search_term 的方式:

    IF char_length(search_term) > 0 THEN
order_by := 'ts_rank_cd(textsearchable_index_col, to_tsquery(''' || search_term || ':*''))+GREATEST(0,(-1*EXTRACT(epoch FROM age(last_edited)/86400))+60)/60 DESC';
search_term := 'to_tsquery(''' || search_term || ':*'') @@ textsearchable_index_col';
ELSE
search_term := 'true';
END IF;

我在使用 PLPGSQL 函数时遇到了一些问题:

    RETURN QUERY EXECUTE '
SELECT
*
FROM
articles
WHERE
$1 AND
' || publication_date_query || ' AND
primary_category LIKE ''' || category_filter || ''' AND
' || tags_query || ' AND
' || districts_query || ' AND
' || capability_query || ' AND
' || push_notification_query || ' AND
' || distance_query || ' AND
' || revision_by || ' AND
' || publication_priority_query || ' AND
' || status_query || ' AND
is_template = ' || only_templates || ' AND
status <> ''DELETED''
ORDER BY ' || order_by || ' LIMIT 500'
USING search_term;
END; $$;

返回错误:

argument of AND must be type boolean, not type text at character 64

相对于:

        RETURN QUERY EXECUTE '
SELECT
*
FROM
articles
WHERE
' || search_term || ' AND
' || publication_date_query || ' AND
primary_category LIKE ''' || category_filter || ''' AND
' || tags_query || ' AND
' || districts_query || ' AND
' || capability_query || ' AND
' || push_notification_query || ' AND
' || distance_query || ' AND
' || revision_by || ' AND
' || publication_priority_query || ' AND
' || status_query || ' AND
is_template = ' || only_templates || ' AND
status <> ''DELETED''
ORDER BY ' || order_by || ' LIMIT 500';
END; $$;

... 有效。我错过了什么吗?
我的目标是净化我的用户输入。

最佳答案

如果您的某些输入参数可以是 NULLempty 并且在这种情况下应该被忽略,您最好根据用户输入动态构建整个语句 - 并省略各自WHERE/ORDER BY条款完整。

关键是在这个过程中正确、安全(优雅)地处理 NULL 和空字符串。对于初学者,search_term <> ''是比 char_length(search_term) > 0 更聪明的测试.见:

而且您需要对 PL/pgSQL 有深入的了解,否则您可能会不知所措。您的案例的示例代码:

CREATE OR REPLACE FUNCTION my_func(
_search_term text = NULL -- default value NULL to allow short call
, _publication_date_query date = NULL
-- , more parameters
)
RETURNS SETOF articles AS
$func$
DECLARE
sql text;
sql_order text; -- defaults to NULL

BEGIN
sql := concat_ws(' AND '
,'SELECT * FROM articles WHERE status <> ''DELETED''' -- first WHERE clause is immutable
, CASE WHEN _search_term <> '' THEN '$1 @@ textsearchable_index_col' END -- ELSE NULL is implicit
, CASE WHEN _publication_date_query <> '' THEN 'publication_date > $2' END -- or similar ...
-- , more more parameters
);

IF search_term <> '' THEN -- note use of $1!
sql_order := 'ORDER BY ts_rank_cd(textsearchable_index_col, $1) + GREATEST(0,(-1*EXTRACT(epoch FROM age(last_edited)/86400))+60)/60 DESC';
END IF;

RETURN QUERY EXECUTE concat_ws(' ', sql, sql_order, 'LIMIT 500')
USING to_tsquery(_search_term || ':*') -- $1 -- prepare ts_query once here!
, _publication_date_query -- $2 -- order of params must match!
-- , more parameters
;

END
$func$ LANGUAGE plpgsql;

我为函数参数添加了默认值,因此您可以省略在调用中不适用的参数。喜欢:

SELECT * FROM my_func(_publication_date_query => '2016-01-01');

更多:

注意 concat_ws() 的战略用途.见:

这是一个相关的答案,有很多解释:

关于sql - 在 PL/pgSQL 中使用 USING 关键字清理用户输入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45542789/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com