2017-08-07 24 views
2

using关键字清理用户输入这是我创造我search_term在PL/pgSQL的

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; $$; 

返回ERROR:

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; $$; 

...哪些工作。我错过了什么吗?
我的目标是消毒我的用户输入。

+0

所以,问题是'$ 1' –

+0

什么是'SEARCH_TERM '?如果它是'column_a ='some_string''类似的东西,那么它将不能用于预处理语句,因为它们不能用于动态SQL。 –

+0

'search_term'是用户输入a.k.a.的一个任意字符串值。 – Spacemoose

回答

1

如果一些输入参数可以NULL,应该在这种情况下被忽略,你最好建立动态地根据用户输入你的整个陈述 - 而完全忽略相应的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; 

我添加默认值函数的参数,这样你就可以省略不调用应用PARAMS。像:

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

更多:

注意战略性地使用concat_ws()。请参阅:

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