[英]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.