수식을 테이블에 저장하고 함수에서 수식을 사용하십시오.


10

PostgreSQL 9.1 데이터베이스가 있는데 그중 일부는 에이전트 커미션을 처리합니다. 각 에이전트는 커미션을받는 정도에 따라 계산 방식이 다릅니다. 각 요원이 받아야하는 커미션 금액을 생성하는 기능이 있지만 요원 수가 늘어남에 따라 사용할 수 없게되었습니다. 매우 긴 사례 진술과 반복 코드를 수행해야하므로 내 기능이 매우 커졌습니다.

모든 수식에는 상수 변수가 있습니다.

그 달에 일한 날
r .. 새 노드가 발생했습니다
충성도 점수
s .. 서브 에이전트 커미션
b .. 기본 요율
i .. 수익 증대

공식은 다음과 같습니다.

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

각 상담원은 HR 부서와 지불 공식을 협상합니다. 에이전트 테이블에 수식을 저장 한 다음 테이블에서 수식을 가져 와서 값으로 변환하고 금액을 계산하는 작은 함수처럼 사용할 수 있습니까?

답변:


6

준비

수식은 다음과 같습니다.

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 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에는 기능을 실행할 수있는 두 가지 보안 모드가 있습니다. SECURITY INVOKER가 기본값입니다. SECURITY DEFINER는 * nix의 SETUID 비트와 같은 "함수 소유자의 보안 컨텍스트로 실행"을 의미합니다. 함수 보안 정의자를 만들려면 함수 선언 ( CREATE FUNCTION foo(text) returns text IMMUTABLE LANGUAGE SQL SECURITY DEFINER AS $$...) 에서이를 지정 하거나 다음을 수행 할 수 있습니다.ALTER FUNCTION foo(text) SECURITY DEFINER
Chris Travers

아, 그것은 특정 PG 리노입니다. 알았어 대답에 백틱을 사용해야 함 ;-)
jcolebrand

@ChrisTravers 나는 수식을 평가하기 위해 일부 샘플 코드를 기대했습니다. 즉 a+b, 테이블의 텍스트 유형 열에 저장 된 다음 foo(a int, b int,formula text)수식이 a + b가되면 함수가 있습니다. 어떻게 함수가 실제로 a + b 대신 가능한 모든 수식에 대해 매우 긴 사례 진술을하고 모든 세그먼트에서 코드를 반복해야합니까?
indago

1
@indago, 보안 문제로 인해 이것을 두 개의 계층으로 나누고 싶다고 생각합니다. 첫 번째는 보간 레이어입니다. PostgreSQL에서 정규식을 사용하여이를 수행 할 수 있습니다. 하위 레벨에서는 기본적으로 jailed SQL 함수에서이를 실행합니다. 이 작업을 수행하려면 보안에 매우주의를 기울여야하며 반환 값에도주의를 기울여야합니다. 더 많이 알지 못하면 samople 코드로 많은 것을하기가 어렵지만 대답을 수정합니다.
Chris Travers

2

공식을 저장하고 실행하는 것의 대안 ( Chris가 언급했듯이 보안 문제가 있음 ) formula_steps기본적으로 변수와 연산자 및 실행 순서를 포함 하는 별도의 테이블 이 있습니다. 이것은 조금 더 많은 작업이지만 더 안전합니다. 테이블은 다음과 같습니다.

formula_steps
-------------
  formula_step_id
  formula_id (FK, 에이전트 테이블에서 참조)
  input_1
  input_2
  operator (연산자 기호를 직접 저장하지 않으려는 경우 허용 된 연산자 테이블의 ID 일 수도 있음)
  순서

또 다른 옵션은 일부 타사 라이브러리 / 도구를 사용하여 수학 표현식을 평가하는 것입니다. 이로 인해 데이터베이스가 SQL 주입에 덜 취약 해지지 만 가능한 보안 문제를 외부 도구로 옮겨갔습니다 (여전히 안전 할 수도 있음).


마지막 옵션은 수학 표현식을 평가하는 프로 시저를 작성 (또는 다운로드)하는 것입니다. 이 문제에 대한 알려진 알고리즘이 있으므로 온라인에서 정보를 찾기가 어렵지 않습니다.


1
세 번째 옵션은 +1입니다. 모든 잠재적 인 입력이 알려진 경우 각 입력을 하드 코딩하여 선택한 후 필요한 경우 텍스트로 저장된 공식으로 입력 한 다음 라이브러리 루틴을 사용하여 산술을 평가하십시오. SQL 주입 위험이 제거되었습니다.
Joel Brown
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.