簡體   English   中英

如何將呈現的持久性/esqueleto 查詢傳遞給另一個查詢?

[英]How do I pass a rendered persistent/esqueleto query to another query?

我想使用 Persistent/Esqueleto 來實現計數估計。

本文推薦的一種方法是像這樣定義 function

CREATE FUNCTION count_estimate(query text) RETURNS integer AS $$
DECLARE
  rec   record;
  rows  integer;
BEGIN
  FOR rec IN EXECUTE 'EXPLAIN ' || query LOOP
    rows := substring(rec."QUERY PLAN" FROM ' rows=([[:digit:]]+)');
    EXIT WHEN rows IS NOT NULL;
  END LOOP;
  RETURN rows;
END;
$$ LANGUAGE plpgsql VOLATILE STRICT;

然后像這樣使用它

SELECT count_estimate('SELECT * FROM companies WHERE status = ''Active''');

為了使用count_estimate function,我需要(我認為?)呈現 Peristent/Equeleto 生成的查詢,但是當我嘗試使用renderQuerySelect呈現查詢時,我得到了這樣的結果

SELECT "companies"."id", "companies"."name", "companies"."status"
FROM "companies"
WHERE "companies"."status" IN (?)
; [PersistText "Active"]

這當然不能塞進count_estimate中,因為它會在? 占位符。 我也不能天真地替換? 使用"Active" ,因為它會在第一個雙引號上出現語法錯誤。

如何以我的count_estimate function 將接受的方式呈現查詢?

我試過這樣的東西,但它在運行時失敗

getEstimate :: (Text, [PersistValue]) -> DB [Single Int]
getEstimate (query, params) = rawSql [st|
  SELECT count_estimate('#{query}');
  |] params

我設法弄清楚(大部分)。

這是查詢和PersistValue參數中的單引號 escaping 的問題。 我目前正在這樣做,但需要重新添加 escaping 否則我認為它會創建 SQL 注入漏洞。 我可能還需要以某種特定方式處理其他PersistValue構造函數,但我還沒有遇到問題。

import qualified Data.Text as T
import qualified Database.Persist as P

getEstimate :: (Text, [PersistValue]) -> DB (Maybe Int)
getEstimate (query, params) = fmap unSingle . listToMaybe <$> rawSql [st|
  SELECT count_estimate('#{T.replace "'" "''" query}');
  |] (map replace' params)
  where literal a = PersistLiteral_ P.Unescaped ("''" <> a <> "''")
        replace' = \case
          PersistText t -> literal $ encodeUtf8 t
          PersistDay  d -> literal $ encodeUtf8 $ pack $ showGregorian d
          a             -> a

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM