準備する
数式は次のようになります。
d*b+(l*4+r)+(i/d)+s
変数を$n
表記法に置き換えて、plpgsqlで直接値に置き換えられるようにしますEXECUTE
(以下を参照)。
$1*$5+($3*4+$2)+($6/$1)+$4
(人間の目のために)オリジナルの数式を追加で保存するか、次のような式でこのフォームを動的に生成できます。
SELECT regexp_replace(regexp_replace(regexp_replace(
regexp_replace(regexp_replace(regexp_replace(
'd*b+(l*4+r)+(i/d)+s'
, '\md\M', '$1', 'g')
, '\mr\M', '$2', 'g')
, '\ml\M', '$3', 'g')
, '\ms\M', '$4', 'g')
, '\mb\M', '$5', 'g')
, '\mi\M', '$6', 'g');
確かに、あなたの翻訳は健全です。正規表現の説明:
\ m ..単語の先頭で
のみ一致します\ M .. 単語の末尾でのみ一致します
4番目のパラメータ'g'
..グローバルに置換
コア機能
CREATE OR REPLACE FUNCTION f_calc(
d int -- days worked that month
,r int -- new nodes accuired
,l int -- loyalty score
,s numeric -- subagent commission
,b numeric -- base rate
,i numeric -- revenue gained
,formula text
,OUT result numeric
) RETURNS numeric AS
$func$
BEGIN
EXECUTE 'SELECT '|| formula
INTO result
USING $1, $2, $3, $4, $5, $6;
END
$func$ LANGUAGE plpgsql SECURITY DEFINER IMMUTABLE;
コール:
SELECT f_calc(1, 2, 3, 4.1, 5.2, 6.3, '$1*$5+($3*4+$2)+($6/$1)+$4');
戻り値:
29.6000000000000000
主なポイント
この関数は、6つの値のパラメーターとformula text
7番目のパラメーターを取ります。数式を最後に置くので、の$1 .. $6
代わりに使用できます$2 .. $7
。読みやすさのためだけに。
私は適切だと思った値にデータ型を割り当てました。適切なタイプを割り当てるか(基本的な健全性チェックを実装するため)、またはすべてをすべてにしますnumeric
。
USING
句を使用して動的実行の値を渡します。これにより、キャストのやり取りが回避され、すべてがシンプル、安全、高速になります。
OUT
パラメータを使用しているのは、それがよりエレガントで、より短くて明確な構文になるためです。ファイナルRETURN
は必要ありません。OUTパラメータの値が自動的に返されます。
@Chrisによるセキュリティに関する講義と、マニュアルの「SECURITY DEFINER関数の安全な記述」の章を検討してください。私の設計では、注入の単一のポイントは式自体です。
一部のパラメーターのデフォルトを使用して、呼び出しをさらに単純化できます。