티스토리 뷰

프로프레임의 DBIO는 DML문만 생성 가능하다. 
CREATE, DROP, TRUNCATE, ANALYZE 등의 DDL문은 DBIO로 생성이 불가능하다.
그렇다면 DDL문을 프로프레임에서 사용하기 위해서는 어떻게 해야될까?
방법은 두가지가 있다.

  1. DBA에게 function으로 해당 DDL문을 만들어달라고 하여 그 function을 호출하는 select DBIO를 만든 후
    해당 DBIO를 사용하는 비즈모듈을 만들어서 제공한다. 이 방법의 문제점은 oracle function이 DDL문을 지원하지 않는다는 점이다. 이 경우 function을 만들때 dynamicSQL을 사용하여 DDL을 excute 하도록 만들면 된다.

DDL문을 function으로 만들수 없음
create or replace function f
  return int as
  update_count int;
begin
  
  create table t2 ( x int );
  
  return update_count;
end;
/

Errors: check compiler log

sho err

LINE/COL ERROR
-------- -----------------------------------------------------------------
6/3      PLS-00103: Encountered the symbol "CREATE" when expecting one of the following:
코드 출처: https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:9535950100346777407

DynamicSQL로 직접 DDL을 execute 
create or replace function f
  return int as
  update_count int;
begin
  
  execute immediate 'create table t2 ( x int )';
  
  return update_count;
end;
/
sho err

var v number;
exec :v := f;
desc t2

Name Null?    Type       
---- -------- ----------
X    NOT NULL NUMBER(38)
코드 출처: https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:9535950100346777407

하지만 function으로 테이블을 생성하고 변경하고 삭제하는등의 DDL문을 만드는것은 일반적으로 좋은 방법이 아니다. 부득이하게 사용해야 하는경우 function으로 만들었을때 혹시나 logic 변경시 해당 function을 사용하는 dbio와 비즈모듈만 컴파일 하면되므로 동적반영이 가능하다는 장점이 있다.



  1. DBA에게 해당 DDL문을 사용하는 procedure를 만들어달라하여 그 procedure를 호출하는 Pro*C를 작성하여 API를 제공한다.

Pro*C를 처음부터 직접 작성할 필요는 없고
프로프레임에서 제공하는 pfmOracleUtil.pc 에 위 로직만 추가하고 make_common_proframe 파일에 path 추가, 컴파일, dlupdate 하여 반영하면 된다.
static 반영이기 때문에 반영 후 tmax를 재기동 해줘야한다.


TRUNCATE 작업을 수행하는 procedure (SYS.TB_TRUNCATE)를 호출한다고 가정하자. 다음과 같은 방법으로 procedure를 호출한다.

long pfmCallProc_truncate(char *tname) {
    pdb_param_t param;
 
    EXEC SQL CALL
        SYS.TB_TRUNCATE(:tname);
 
    if(DB_CHK_FAIL) {
        memset(&param, 0x00, sizeof(param));
        _pfmDbioLogSqlError(&param, __FILE__, __LINE__);
        return RC_ERR;
    }
 
    return RC_NRM;
}

 혹은 직접 Pro*C 내에서 직접 procedure를 작성해서 호출하는 방법도 있다.

long pfmCallProc_truncate(char *tname)
{
        pdb_param_t param;
        EXEC SQL BEGIN DECLARE SECTION;
        varchar statement[1000+1];
        EXEC SQL END DECLARE SECTION;

        statement.len = (unsigned short)sprintf((char *)statement.arr, "TRUNCATE TABLE %s", tname);

        EXEC SQL
                EXECUTE IMMEDIATE :statement;

        if(DB_CHK_FAIL)
        {
                memset(&param, 0x00, sizeof(param));
                _pfmDbioLogSqlError(&param, __FILE__, __LINE__);
                return RC_ERR;
        }

        return RC_NRM;
}

하지만 후자의 방법은 치명적인 단점이 있다.
전자처럼 SYS계정으로 만든 procedure를 호출하는것이 아니라 직접 procedure를 만들어 호출하기 때문에
runtime에서 물고 올라가는 프로프레임 DB 계정에 있는 테이블들에게만 해당 api가 작동하고
프로프레임 계정과 업무계정 DB가 따로 분리되어 있는경우 업무테이블들에 대해서는 권한이 없어서 해당 api가 작동하지 않는다.

TRUNCATE 같은 DDL문의 경우 테이블별로 권한과 synonym을 지정할 수 없다. 
프로프레임 계정이 업무계정 DB 테이블에 대해 DDL문을 수행하려면 any 권한을 가져야 하는데
이는 금감원 감사시 감점요인으로 대부분의 사이트에서 허용하지 않는다.
이를 우회하기 위한 방법으로 DBA가 sys계정으로 필요한 DDL문을 procedure를 만들어주고
해당 procedure에 대한 execute 권한을 프로프레임 계정에게 부여하는 것으로 과도한 권한 부여 문제를 피할 수 있다.

댓글