किसी तालिका में सूत्र को संग्रहीत करें और फ़ंक्शन में सूत्र का उपयोग करें


10

मेरे पास एक PostgreSQL 9.1 डेटाबेस है जहां इसका हिस्सा एजेंट कमीशन संभालता है। प्रत्येक एजेंट के पास गणना का अपना सूत्र होता है कि उन्हें कितना कमीशन मिलता है। मेरे पास प्रत्येक एजेंट को कमीशन की राशि उत्पन्न करने के लिए एक फ़ंक्शन है, लेकिन एजेंटों की संख्या बढ़ने के साथ इसका उपयोग करना असंभव है। एम ने कुछ बेहद लंबे केस स्टेटमेंट और रिपीटिंग कोड को करने के लिए मजबूर किया, जिससे मेरा काम बहुत बड़ा हो गया।

सभी फ़ार्मुलों में निरंतर चर होते हैं:

d .. उस महीने काम किया
r .. नया नोड अर्जित किया गया
l .. वफादारी स्कोर
s .. उपशमन आयोग
b .. आधार दर
i .. राजस्व प्राप्त हुआ

सूत्र कुछ इस तरह हो सकता है:

d*b+(l*4+r)+(i/d)+s

प्रत्येक एजेंट एचआर विभाग के साथ भुगतान सूत्र पर बातचीत करता है। तो क्या मैं एजेंट तालिका में सूत्र को संग्रहीत कर सकता हूं, फिर एक छोटे से फ़ंक्शन की तरह हो सकता है जो सिर्फ तालिका से सूत्र प्राप्त करता है और इसे मूल्यों के साथ अनुवाद करता है और राशि की गणना करता है?

जवाबों:


6

तैयार

आपके सूत्र इस तरह दिखते हैं:

d*b+(l*4+r)+(i/d)+s

मैं चर को $nसंकेतन से बदलूंगा ताकि उन्हें सीधे प्लस्पग्ल में मानों से बदला जा सके 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');

बस सुनिश्चित करें, आप अनुवाद ध्वनि है। Regexp अभिव्यक्तियों के लिए कुछ स्पष्टीकरण :

\ 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 text7 वें के रूप में लेता है । मैंने सूत्र को अंतिम रूप दिया, इसलिए हम $1 .. $6इसके बजाय उपयोग कर सकते हैं $2 .. $7। सिर्फ पठनीयता के लिए।
    मैंने मूल्यों के लिए डेटा प्रकार असाइन किए हैं जैसा कि मैंने फिट देखा। उचित प्रकार असाइन करें (बुनियादी स्वच्छता जांच को लागू करने के लिए) या बस उन सभी को बनाएं numeric:

  • USINGक्लॉज के साथ गतिशील निष्पादन के लिए मानों को पास करें । यह आगे और पीछे कास्टिंग से बचा जाता है और सब कुछ सरल, सुरक्षित और तेज बनाता है।

  • मैं एक OUTपैरामीटर का उपयोग करता हूं क्योंकि यह अधिक सुरुचिपूर्ण है और छोटे स्पष्ट वाक्यविन्यास के लिए बनाता है। एक अंतिम RETURNजरूरत नहीं है, OUT पैरामीटर (मानों) का मान स्वचालित रूप से वापस आ जाता है।

  • मैनुअल में @Chris और अध्याय "लेखन सुरक्षा DEFINER फ़ंक्शंस" द्वारा सुरक्षा पर व्याख्यान पर विचार करें । मेरे डिजाइन में, इंजेक्शन का एकल बिंदु सूत्र ही है।

  • आप कॉल को और सरल बनाने के लिए कुछ मापदंडों के लिए चूक का उपयोग कर सकते हैं ।


5

कृपया सुरक्षा संबंधी बातों को ध्यान से पढ़ें। अनिवार्य रूप से आप अपने कार्यों में मनमाने ढंग से SQL इंजेक्षन करने की कोशिश कर रहे हैं। नतीजतन आपको अत्यधिक प्रतिबंधित अनुमतियों वाले उपयोगकर्ता के तहत यह रन करना होगा।

  1. एक उपयोगकर्ता बनाएं और उसमें से सभी अनुमतियां रद्द करें। ऐसा करने के लिए उसी db में सार्वजनिक करने की अनुमति न दें।

  2. अभिव्यक्ति का मूल्यांकन करने के लिए एक फ़ंक्शन बनाएं, इसे बनाएं security definerऔर मालिक को उस प्रतिबंधित उपयोगकर्ता को बदल दें।

  3. अभिव्यक्ति को बढ़ाएं और फिर इसे आपके द्वारा बनाए गए eval () फ़ंक्शन में पास करें। यदि आप की जरूरत है, तो आप एक और समारोह में यह कर सकते हैं

फिर से ध्यान दें, इसके गंभीर सुरक्षा निहितार्थ हैं।

संपादित करें: संक्षिप्त नमूना कोड (यदि आप डॉक्स का पालन करते हैं तो आपको वहां जाना चाहिए):

CREATE OR REPLACE FUNCTION eval_numeric(text) returns numeric language plpgsql security definer immutable as
$$
declare retval numeric;
begin

execute $e$ SELECT ($1)::numeric$e$ into retval;
return retval;
end;
$$;

ALTER FUNCTION eval_numeric OWNER TO jailed_user;

CREATE OR REPLACE FUNCTION foo(expression text, a numeric, b numeric) returns numeric language sql immutable as $$
select eval(regexp_replace(regexp_replace($1, 'a', $2, 'g'), 'b', '$3', 'g'));
$$; -- can be security invoker, but eval needs to be jailed.

"इसे सुरक्षा सुनिश्चित करें" वास्तव में भ्रामक है, क्या आप समझा सकते हैं?
jcolebrand

1
PostgreSQL में दो सुरक्षा मोड हैं जो एक फ़ंक्शन के रूप में चल सकते हैं। सुरक्षा चालान डिफ़ॉल्ट है। सुरक्षा DEFINER का अर्थ है "फ़ंक्शन के मालिक के सुरक्षा संदर्भ के साथ चलना" "Six पर SETUID बिट की तरह।" फ़ंक्शन सुरक्षा को निश्चित करने के लिए आप इसे फ़ंक्शन डिक्लेरेशन ( CREATE FUNCTION foo(text) returns text IMMUTABLE LANGUAGE SQL SECURITY DEFINER AS $$...) में निर्दिष्ट कर सकते हैं या आप कर सकते हैंALTER FUNCTION foo(text) SECURITY DEFINER
क्रिस ट्रैवर्स

ओह, तो यह विशिष्ट पीजी लिनो है। पकड़ लिया। चाहिये उत्तर में ;-) बैकटिक इस्तेमाल किया
jcolebrand

@ क्रिसट्रावर्स मैं कुछ नमूना कोड की उम्मीद कर रहा था कि सूत्र का मूल्यांकन करने के लिए a+bएक तालिका में एक पाठ प्रकार के कॉलम में संग्रहीत किया जाता है, तो मेरे पास एक फ़ंक्शन है foo(a int, b int,formula text)यदि यह सूत्र प्राप्त होता है + b तो मैं कैसे बना सकता हूं कि फ़ंक्शन वास्तव में a + b के बजाय a मुझे सभी संभावित फ़ार्मुलों के लिए बहुत लंबा केस स्टेटमेंट देने और सभी सेगमेंट में कोड दोहराने की आवश्यकता है?
इण्डागो

1
@indago, मुझे लगता है कि सुरक्षा चिंताओं के कारण आप इसे दो परतों में तोड़ना चाहते हैं। पहला एक प्रक्षेप परत है। आप ऐसा करने के लिए PostgreSQL में regexes का उपयोग कर सकते हैं। निचले स्तर में, आप मूल रूप से एक जेल SQL फ़ंक्शन में इसे चला रहे हैं। यदि आप ऐसा करने जा रहे हैं, तो आपको वास्तव में सुरक्षा पर बहुत ध्यान देने की आवश्यकता है, और आपको मूल्यों को वापस करने के लिए भी ध्यान देना होगा। बहुत अधिक जानने के बिना, समोपल कोड के साथ बहुत कुछ करना मुश्किल है, लेकिन जवाब में संशोधन करेगा।
क्रिस ट्रैवर्स

2

बस फॉर्मूला को स्टोर करने और फिर इसे निष्पादित करने का एक विकल्प (जिसे क्रिस ने उल्लेख किया है, सुरक्षा समस्याएं हैं ) एक अलग तालिका formula_stepsहोगी जिसे मूल रूप से चर और ऑपरेटर शामिल होंगे और जिस क्रम में वे निष्पादित किए जाते हैं। यह थोड़ा और काम होगा, लेकिन अधिक सुरक्षित होगा। तालिका इस तरह दिख सकती है:

formula_steps
-------------
  formula_step_id
  सूत्र_आईडी (एफके, एजेंट तालिका द्वारा संदर्भित)
  INPUT_1
  INPUT_2
  ऑपरेटर (अनुमति प्राप्त ऑपरेटरों की तालिका के लिए एक आईडी भी हो सकती है, यदि आप ऑपरेटर प्रतीकों को सीधे स्टोर नहीं करना चाहते हैं)
  अनुक्रम

एक और विकल्प गणितीय अभिव्यक्तियों के मूल्यांकन के लिए कुछ तृतीय-पक्ष पुस्तकालय / उपकरण का उपयोग करना होगा। यह आपके डेटाबेस को SQL इंजेक्शन के लिए कम संवेदनशील बना देगा, लेकिन अब आपने अपने बाहरी टूल (जो अभी भी बहुत सुरक्षित हो सकता है) को सुरक्षा समस्याओं को स्थानांतरित कर दिया है।


अंतिम विकल्प एक प्रक्रिया लिखना (या डाउनलोड करना) होगा जो गणितीय अभिव्यक्तियों का मूल्यांकन करता है। इस समस्या के लिए ज्ञात एल्गोरिदम हैं, इसलिए ऑनलाइन जानकारी प्राप्त करना कठिन नहीं होना चाहिए।


1
तीसरे विकल्प के लिए +1। यदि सभी संभावित इनपुट ज्ञात हैं, तो हार्ड कोड प्रत्येक इनपुट का चयन करता है और उन्हें पाठ के रूप में संग्रहीत सूत्र में (और यदि आवश्यक हो) स्थानापन्न करता है, तो अंकगणित का मूल्यांकन करने के लिए एक पुस्तकालय दिनचर्या का उपयोग करें। एसक्यूएल इंजेक्शन जोखिम को खत्म कर दिया।
जोएल ब्राउन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.