私はこのようにします:
CREATE OR REPLACE FUNCTION list(
_category varchar(100)
, _limit int
, _offset int
, _order_by varchar(100)
, _order_asc_desc text = 'ASC') -- last param with default value
RETURNS TABLE(id int, name varchar, clientname varchar, totalcount bigint)
LANGUAGE plpgsql AS
$func$
DECLARE
_empty text := '';
BEGIN
-- Assert valid _order_asc_desc
IF upper(_order_asc_desc) IN ('ASC', 'DESC', 'ASCENDING', 'DESCENDING') THEN
-- proceed
ELSE
RAISE EXCEPTION 'Unexpected value for parameter _order_asc_desc.
Allowed: ASC, DESC, ASCENDING, DESCENDING. Default: ASC';
END IF;
RETURN QUERY EXECUTE format(
'SELECT id, name, clientname, count(*) OVER() AS full_count
FROM design_list
WHERE ($1 = $2 OR category ILIKE $1)
ORDER BY %I %s
LIMIT %s
OFFSET %s'
, _order_by, _order_asc_desc, _limit, _offset)
USING _category, _empty;
END
$func$;
コア機能:format()
クエリ文字列を安全かつエレガントに連結します。関連:
ASC
/ DESC
(またはASCENDING
/DESCENDING
)は固定キーワードです。手動チェックを追加しました(IF ...
)そして後で単純な%s
と連結します 。それは1つです 正当な入力を主張する方法。便宜上、予期しない入力に対するエラーメッセージとパラメータのデフォルトを追加したため、関数のデフォルトはASC
になります。 呼び出しで最後のパラメーターが省略された場合。関連:
Pavelの有効なアドレスコメント
、_limit
を連結します および_offset
直接なので、クエリはすでにこれらのパラメータで計画されています。
_limit
および_offset
integer
です パラメータなので、プレーンな%s
を使用できます SQLインジェクションの危険なし。連結する前に、妥当な値(負の値と高すぎる値を除く)を表明することをお勧めします...
-
一貫した命名規則を使用します。すべてのパラメーターと変数の前にアンダースコア
_
を付けました 、一部だけではありません 。 -
EXECUTE
内でテーブル修飾を使用しない 、関係するテーブルは1つだけであり、EXECUTE
個別のスコープがあります。 -
明確にするために、いくつかのパラメーターの名前を変更しました。
_order_by
_sort_by
の代わりに;_order_asc_desc
_order
の代わりに 。