2017-08-07 25 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()。請參閱:

這是一個相關的答案有很多的解釋: