콘텐츠로 이동

11. 저장 프로시저 처리 SQL문#

저장 프로시저 처리 SQL문#

저장 프로시저 또는 저장 함수 관련 내장 SQL문을 저장 프로시저 처리 SQL문이라고 한다.

응용 프로그램 안에서 저장 프로시저 또는 저장 함수를 생성하고 실행할 수 있다.

CREATE#

저장 프로시저 또는 저장 함수를 생성한다.

구문#

저장 프로시저#
EXEC SQL CREATE [ OR REPLACE ] PROCEDURE
<procedure_name> ( [ <parameter_declaration_list> ] ) ] 
AS | IS 
[ <declaration_section> ] 
BEGIN <statement> 
[ EXCEPTION <exception_handler> ] 
END 
[ <procedure_name> ] ; 
END-EXEC;
저장 함수#
EXEC SQL CREATE [ OR REPLACE ] FUNCTION 
<function_name> [ ( [ <parameter_declaration_list> ] ) ]
RETURN <data_type> 
AS | IS 
[ <declaration_section> ] 
BEGIN <statement> 
[ EXCEPTION <exception_handler> ] 
END 
[ <function_name> ] ; 
END-EXEC;

인자#

  • <procedure_name>: 저장 프로시저의 이름
  • <function_name>: 저장 함수의 이름
  • <parameter_declaration_list>: Stored Procedures Manual 참조
  • <declaration_section>: Stored Procedures Manual 참조
  • <statement>: Stored Procedures Manual 참조
  • <exception_handler>: Stored Procedures Manual 참조
  • <data_type>: Stored Procedures Manual 참조

예제#

아래는 저장 프로시저 또는 저장 함수를 생성하는 예를 보여준다.

[예제 1] 다음은 저장 프로시저를 생성하는 예제이다.

ONO 칼럼 값이 ORDER_PROC의 파라미터인 s_ono와 같은 레코드를 검색하여 0건이면 지정한 변수 값들을 이용하여 ORDERS 테이블에 새로운 레코드를 삽입하고, 1건이 검색되면 검색된 레코드의 PROCESSING칼럼 값을 'P'로 변경한다.

< 예제 프로그램 : psm1.sc >

EXEC SQL CREATE OR REPLACE PROCEDURE ORDER_PROC
(s_ono in bigint)
        AS
            p_order_date date;
            p_eno        integer;
            p_cno        bigint;
            p_gno        char(10);
            p_qty        integer;
        BEGIN
            SELECT ORDER_DATE, ENO, CNO, GNO, QTY 
            INTO p_order_date, p_eno, p_cno, p_gno, p_qty
            FROM ORDERS 
            WHERE ONO = s_ono;
        EXCEPTION
            WHEN NO_DATA_FOUND THEN
                p_order_date := SYSDATE;
                p_eno        := 13;
                p_cno        := BIGINT'7610011000001';
                p_gno        := 'E111100013';
                p_qty        := 4580;
                INSERT INTO ORDERS 
                        (ONO, ORDER_DATE, ENO, CNO, GNO, QTY) 
                VALUES 
                        (s_ono, p_order_date, p_eno, p_cno, p_gno, p_qty);
            WHEN OTHERS THEN
                UPDATE ORDERS 
                SET PROCESSING = 'P'
                WHERE ONO = s_ono;
        END;
    END-EXEC;

[예제 2] 다음은 저장 함수를 생성하는 예제이다.

ORDERS 테이블에 새로운 레코드를 삽입하고, ORDERS 테이블의 전체 레코드 건수를 검색하여 그 건수를 결과로 반환한다.

< 예제 프로그램 : psm2.sc >

EXEC SQL CREATE OR REPLACE FUNCTION ORDER_FUNC(
            s_ono in bigint, s_order_date in date, 
            s_eno in integer, s_cno in char(13), 
            s_gno in char(10), s_qty in integer)
        RETURN INTEGER
        AS
            p_cnt integer;
        BEGIN
            INSERT INTO ORDERS 
(ONO, ORDER_DATE, ENO, CNO, GNO, QTY) 
VALUES 
(s_ono, s_order_date, s_eno, s_cno, s_gno, s_qty);
            SELECT COUNT(*) INTO p_cnt FROM ORDERS;
            RETURN p_cnt;
        END;
    END-EXEC;

ALTER#

저장 프로시저 또는 저장 함수를 재 컴파일 한다.

구문#

저장 프로시저#
EXEC SQL ALTER PROCEDURE <procedure_name> COMPILE; 
저장 함수#
EXEC SQL ALTER FUNCTION <function_name> COMPILE; 

인자#

  • <procedure_name>: 저장 프로시저의 이름

  • <function_name>: 저장 함수의 이름

설명#

저장 프로시저나 저장 함수를 재컴파일하여 유효한 상태로 만들어준다.

예제#

저장 프로시저 또는 저장 함수를 재컴파일 하는 예를 보여준다.

[예제 1] 다음은 ORDER_PROD 저장 프로시저를 재컴파일하는 예를 보여준다

EXEC SQL ALTER PROCEDURE ORDER_PROC COMPILE;

[예제 2] 다음은 ORDER_FUNC 저장 함수를 재컴파일하는 예를 보여준다.

EXEC SQL ALTER FUNCTION ORDER_FUNC COMPILE;

DROP#

저장 프로시저 또는 저장 함수를 삭제한다.

구문#

저장 프로시저#
EXEC SQL DROP PROCEDURE <procedure_name>; 
저장 함수#
EXEC SQL DROP FUNCTION <function_name>; 

인자#

  • <procedure_name>: 저장 프로시저의 이름

  • <function_name>: 저장 함수의 이름

예제#

저장 프로시저 또는 저장 함수를 삭제하는 예를 보여준다.

[예제 1] 다음은 ORDER_FUNC 저장 함수를 삭제하는 예를 보여준다.

< 예제 프로그램 : psm1.sc >

EXEC SQL DROP PROCEDURE ORDER_PROC;

[예제 2] 다음은 ORDER_FUNC 저장 함수를 삭제하는 예를 보여준다.

< 예제 프로그램 : psm2.sc >

EXEC SQL DROP FUNCTION ORDER_FUNC;

EXECUTE#

저장 프로시저 또는 저장 함수를 실행한다.

구문#

저장 프로시저#
EXEC SQL EXECUTE BEGIN 
<procedure_name>
[ ( [ <:host_var> [ IN | OUT | IN OUT ] [ , … ] ] ) ];
END;
END-EXEC;
저장 함수#
EXEC SQL EXECUTE BEGIN 
<:host_var> := <function_name> 
[ ( [ <:host_var> [ IN | OUT | IN OUT ] [ , … ] ] ) ];
END;
END-EXEC;

인자#

  • <procedure_name>: 저장 프로시저의 이름

  • <function_name>: 저장 함수의 이름

  • <:host_var>
    저장 프로시저 또는 함수 실행 시 필요한 IN, OUT 또는 IN/OUT 파라미터 (즉, 입력 또는 출력 호스트 변수 사용 가능) 저장 함수의 결과 값을 저장하기 위한 출력 호스트 변수

예제#

저장 프로시저 또는 저장 함수를 실행하는 예를 보여준다.

[예제 1] 다음은 저장 프로시저 ORDER_PROC를 실행하는 예를 보여준다.

< 예제 프로그램 : psm1.sc >

EXEC SQL BEGIN DECLARE SECTION;
long long s_ono;
EXEC SQL END DECLARE SECTION;

s_ono = 111111;

EXEC SQL EXECUTE 
BEGIN
    ORDER_PROC(:s_ono in);
END;
END-EXEC;

[예제 2] 다음은 저장 함수 ORDER_FUNC를 실행하는 예를 보여준다.

< 예제 프로그램 : psm2.sc >

EXEC SQL BEGIN DECLARE SECTION;
long long s_ono;
char      s_order_date[19+1];
int        s_eno;
char      s_cno[13+1];
char      s_gno[10+1];
int        s_qty;
int        s_cnt;
EXEC SQL END DECLARE SECTION;

s_ono = 200000001;
s_eno = 20;
s_qty = 2300;
strcpy(s_order_date, "19-May-03");
strcpy(s_cno, "7111111431202");
strcpy(s_gno, "C111100001");

EXEC SQL EXECUTE 
BEGIN
    :s_cnt := ORDER_FUNC(:s_ono in, :s_order_date in, 
                             :s_eno in, :s_cno in, :s_gno in, :s_qty in);
END;
END-EXEC;

ANONYMOUS BLOCK#

저장 프로시저를 생성하지 않고 바로 실행할 수 있는 SQL문이다.

EXEC SQL EXECUTE 
<<LABEL_NAME_OPTION>>
[DECLARE]
[ <declaration_section> ] 
BEGIN 
<statement> 
[ EXCEPTION <exception_handler> ] 
END 
[ <label_name> ] ; 
END-EXEC;

예제#

anonymous block을 사용하는 예제를 보여준다.

< 예제 프로그램 : anon.sc >

/* declare host variables */
EXEC SQL BEGIN DECLARE SECTION;
char usr[64];
char pwd[64];
char conn_opt[1024];

long long s_ono;
EXEC SQL END DECLARE SECTION;

s_ono = 999999;
/* execute anonymous block */
EXEC SQL EXECUTE
    <<LABEL1>>
    DECLARE
        p_order_date date;
        p_eno        integer;
        p_cno        bigint;
        p_gno        char(10);
        p_qty        integer;
    BEGIN
        SELECT ORDER_DATE, ENO, CNO, GNO, QTY
        INTO p_order_date, p_eno, p_cno, p_gno, p_qty
        FROM ORDERS
        WHERE ONO = :s_ono;
    EXCEPTION
        WHEN NO_DATA_FOUND THEN
            p_order_date := SYSDATE;
            p_eno        := 13;
            p_cno        := BIGINT'7610011000001';
            p_gno        := 'E111100013';
            p_qty        := 4580;
            INSERT INTO ORDERS (ONO, ORDER_DATE, ENO, CNO, GNO, QTY)
                   VALUES (:s_ono, p_order_date, p_eno, p_cno, p_gno, p_qty);
        WHEN OTHERS THEN
            UPDATE ORDERS
            SET ORDER_DATE = p_order_date,
                ENO        = p_eno,
                CNO        = p_cno,
                GNO        = p_gno,
                QTY        = p_qty
            WHERE ONO = :s_ono;
    END;
END-EXEC;

EXECUTE 문에서 배열 호스트 변수 사용#

EXECUTE 문으로 저장 프로시저를 실행할 때 배열 호스트 변수를 사용할 수 있다. 이는 하나의 EXECUTE 문으로 여러 개의 EXECUTE 문을 실행하는 효과를 주어 저장 프로시저의 실행 성능을 높일 수 있다.

EXECUTE 문에서 배열 호스트 변수를 사용하는 방법은 저장 프로시저 인자의 데이터 타입이 배열인지 아닌지에 따라 다르다.

저장 프로시저 인자의 데이터 타입이 배열이 아닐 때#

먼저, 저장 프로시저 인자의 데이터 타입이 배열이 아닐 때 EXECUTE 문에서 사용할 수 있는 배열 호스트 변수의 데이터형과 제한 사항에 대한 설명이다.

배열 호스트 변수로 사용할 수 있는 데이터형#

  • 숫자형 타입의 배열
  • 문자형 타입의 배열
  • 구성 요소가 배열인 구조체

제한 사항#

  • 입력 인자(IN)에서만 배열 호스트 변수를 사용할 수 있다.

  • 출력 인자(OUT) 또는 입출력 공용 인자(IN/OUT)에는 배열 호스트 변수를 사용할 수 없다.

    EXEC SQL BEGIN DECLARE SECTION;
    int var1[10];
    int var2[10];
    int var3[10];
    EXEC SQL END DECLARE SECTION;
    
    EXEC SQL EXECUTE BEGIN 
    PROC1(:var1 in, :var2 out, :var3 in out);  // 에러 발생. OUT 인자에 배열 호스트 변수를 사용한 예
    END;
    END-EXEC;
    
  • 저장 함수의 반환 값을 배열 호스트 변수에 저장할 수 없다.

    EXEC SQL BEGIN DECLARE SECTION;
    int var1[10];
    int var2[10];
    int var3[10];
    EXEC SQL END DECLARE SECTION;
    
    EXEC SQL EXECUTE BEGIN 
    :var1 = FUNC1(:var2 in, :var3 in); // 에러 발생. 배열 호스트 변수에 저장 함수의 반환 값을 저장한 예
    END;
    END-EXEC;
    
  • 배열 호스트 변수와 배열이 아닌 호스트 변수를 함께 사용할 수 없다.

    EXEC SQL BEGIN DECLARE SECTION;
    int var1;
    int var2;
    int var3[10];
    EXEC SQL END DECLARE SECTION;
    
    EXEC SQL EXECUTE BEGIN 
        PROC1(:var1 in, :var2 in, :var3 in); // 에러 발생. 배열 호스트 변수와 배열이 아닌 호스트 변수를     함께 사용한 예
    END;
    END-EXEC;
    
  • 위의 마지막 2 가지 제한 사항에 의해 저장 함수를 실행하는 EXECUTE 문에 배열 호스트 변수를 사용할 수 없다.

예제#

저장 프로시저의 입력 인자에 배열 호스트 변수를 사용하여 EXECUTE 문을 수행하는 예제이다.

예제 프로그램 : arrays2.sc

EXEC SQL BEGIN DECLARE SECTION;
char a_gno[3][10+1];
char a_gname[3][20+1];
EXEC SQL END DECLARE SECTION;

strcpy(a_gno[0], "G111100001");
strcpy(a_gno[1], "G111100002");
strcpy(a_gno[2], "G111100003");
strcpy(a_gname[0], "AG-100");
strcpy(a_gname[1], "AG-200");
strcpy(a_gname[2], "AG-300");

EXEC SQL EXECUTE
BEGIN
    GOODS_PROC(:a_gno in, :a_gname in);
END;
END-EXEC;

저장 프로시저 인자의 데이터 타입이 배열일 때#

다음은 인자의 데이터 타입을 배열로 선언한 저장 프로시저를 EXECUTE 문에서 실행할 때, 배열 호스트 변수로 사용할 수 있는 데이터형과 제한 사항에 대한 설명이다.

인자의 데이터 타입을 배열로 선언한 저장 프로시저는 아래와 같은 경우를 말한다.

CREATE OR REPLACE PACKAGE PSM_PKG
AS
TYPE PSM_SCOL IS TABLE OF SMALLINT INDEX BY INTEGER;
TYPE PSM_ICOL IS TABLE OF INTEGER  INDEX BY INTEGER;
TYPE PSM_LCOL IS TABLE OF BIGINT   INDEX BY INTEGER;
TYPE PSM_RCOL IS TABLE OF REAL     INDEX BY INTEGER;
TYPE PSM_DCOL IS TABLE OF DOUBLE   INDEX BY INTEGER;
END;
/

CREATE OR REPLACE PROCEDURE PSM3_1(scol in PSM_PKG.PSM_SCOL,
                                   icol in PSM_PKG.PSM_ICOL,
                                   lcol in PSM_PKG.PSM_LCOL,
                                   rcol in PSM_PKG.PSM_RCOL,
                                   dcol in PSM_PKG.PSM_DCOL)
AS
i integer;
BEGIN
    EXECUTE IMMEDIATE 'TRUNCATE TABLE PSM_TABLE';
    i := scol.first();
    LOOP
        IF i IS null
            THEN
            exit;
        ELSE
            INSERT INTO PSM_TABLE (SCOL, ICOL, LCOL, RCOL, DCOL)
            VALUES (scol(i), icol(i), lcol(i), rcol(i), dcol(i));
            i := scol.next(i);
        END IF;
    END LOOP;
END;
/

배열 호스트 변수로 사용할 수 있는 데이터형#

C 데이터형 SQL 데이터형
short SQL_SMALLINT
int SQL_INTEGER
long SQL_BIGINT
long long SQL_BIGINT
float SQL_REAL
double SQL_DOUBLE

제한 사항#

  • 윈도우즈와 32비트 리눅스 환경에서 BIGINT 배열의 인자를 사용하는 저장프로시저의 경우, 응용프로그램에서 배열 호스트 변수의 데이터 타입은 long이 아닌 long long을 사용해야 한다. 왜냐하면, long의 경우 윈도우즈와 32비트 리눅스 환경에서는 4바이트이기 때문이다.

  • C 데이터 타입과 SQL 데이터 타입이 서로 다른 경우, 에러가 발생하거나 잘못된 형변환이 이루어져 원하지 않는 동작이 발생할 수 있다.

    CREATE OR REPLACE PACKAGE pkg1
    AS
    TYPE type1 IS TABLE OF SMALLINT INDEX BY INTEGER;
    END;
    /
    
    // 저장 프로시저 출력 인자의 데이터 타입이 SQL_SMALLINT
    CREATE OR REPLACE PROCEDURE proc1( a OUT pkg1.type1 ) RETURN INTEGER
    AS
    BEGIN
    SELECT * BULK COLLECT INTO a FROM t1 ORDER BY c1;
    END;
    /
    
    EXEC SQL BEGIN DECLARE SECTION;
    char usr[10];                  
    char pwd[10];                  
    char conn_opt[1024];           
    double array1[array_size];                
    EXEC SQL END DECLARE SECTION;  
    
    // EXECUTE 문에서 사용한 배열 호스트 변수는 double 형
    EXEC SQL EXECUTE                        
    BEGIN                                   
        proc1(:array1 out);
    END;                                    
    END-EXEC;     
    
    // 결과
    Error : [-331900] The apre type and psm array type do not match.
    
  • 호스트 변수가 구조체이면 EXECUTE 문에서 배열 호스트 변수로 사용할 수 없다.

    typedef struct argx { float c1; float c2; } argx;
    
    EXEC SQL BEGIN DECLARE SECTION;
    argx args2[10];
    EXEC SQL END DECLARE SECTION;  
    
    // EXECUTE 문에서 구조체인 배열 호스트 변수를 사용할 수 없다.
    EXEC SQL EXECUTE     
    BEGIN 
        proc1(:args2);
    END; 
    END-EXEC;
    
  • 호스트 변수가 2차원 배열이면 EXECUTE 문에서 배열 호스트 변수로 사용할 수 없다.

    EXEC SQL BEGIN DECLARE SECTION;
    float args2[10][10];
    EXEC SQL END DECLARE SECTION; 
    
    // EXECUTE 문에서 2차열 배열인 배열 호스트 변수를 사용할 수 없다.
    EXEC SQL EXECUTE     
    BEGIN 
        proc1(:args2);
    END; 
    END-EXEC;
    

예제#

아래 예제를 위한 스키마이다.

schema.sql

CREATE OR REPLACE PACKAGE PSM_PKG
AS
TYPE PSM_SCOL IS TABLE OF SMALLINT INDEX BY INTEGER;
TYPE PSM_ICOL IS TABLE OF INTEGER  INDEX BY INTEGER;
TYPE PSM_LCOL IS TABLE OF BIGINT   INDEX BY INTEGER;
TYPE PSM_RCOL IS TABLE OF REAL     INDEX BY INTEGER;
TYPE PSM_DCOL IS TABLE OF DOUBLE   INDEX BY INTEGER;
END;
/

CREATE OR REPLACE PROCEDURE PSM3_1(scol in PSM_PKG.PSM_SCOL,
                                   icol in PSM_PKG.PSM_ICOL,
                                   lcol in PSM_PKG.PSM_LCOL,
                                   rcol in PSM_PKG.PSM_RCOL,
                                   dcol in PSM_PKG.PSM_DCOL)
AS
i integer;
BEGIN
    EXECUTE IMMEDIATE 'TRUNCATE TABLE PSM_TABLE';
    i := scol.first();
    LOOP
        IF i IS null
            THEN
            exit;
        ELSE
            INSERT INTO PSM_TABLE (SCOL, ICOL, LCOL, RCOL, DCOL)
            VALUES (scol(i), icol(i), lcol(i), rcol(i), dcol(i));
            i := scol.next(i);
        END IF;
    END LOOP;
END;
/

CREATE OR REPLACE PROCEDURE PSM4(scol out PSM_PKG.PSM_SCOL)
AS
BEGIN
    scol(1) := 1;
    scol(2) := 2;
    scol(3) := null;
    scol(4) := 3;
    scol(5) := 4;
END;
/

예제 프로그램 : psm3.sc

저장 프로시저 인자의 데이터 타입이 배열일 때, 배열 호스트 변수를 사용하여 EXECUTE 문을 수행하는 일반적인 예제이다.

/* declare host variables */
EXEC SQL BEGIN DECLARE SECTION;
char usr[10];
char pwd[10];
char conn_opt[1024];
short    sCol[ARRAY_SIZE];
int      iCol[ARRAY_SIZE];
long     lCol[ARRAY_SIZE];
float    fCol[ARRAY_SIZE];
double   dCol[ARRAY_SIZE];
EXEC SQL END DECLARE SECTION;

for (i = 0; i < ARRAY_SIZE; i++ )
{
    sCol[i] = i + 1;
    iCol[i] = i + 10;
    lCol[i] = i + 100;
    fCol[i] = i + 1.1;
    dCol[i] = i + 1.01;
}
/* execute procedure */
EXEC SQL EXECUTE
BEGIN
    PSM3_1(:sCol in,
           :iCol in,
           :lCol in,
           :fCol in,
           :dCol in);
END;
END-EXEC;

예제 프로그램 : psm4.sc

저장 프로시저 출력 인자가 널을 가진 배열일 때, 널을 확인하는 예제이다.

/* declare host variables */
EXEC SQL BEGIN DECLARE SECTION;
char usr[10];
char pwd[10];
char conn_opt[1024];
short    sCol[ARRAY_SIZE];
EXEC SQL END DECLARE SECTION;

for (i = 0; i < ARRAY_SIZE; i++ )
{
    sCol[i] = 0;
}
/* execute procedure */
EXEC SQL EXECUTE
BEGIN
    PSM4(:sCol out);
END;
END-EXEC;

if( SQLCODE == (int)-331898)
{
    printf("sCol \n");
    for(i=0; i < ARRAY_SIZE; i++)
    {
        if( APRE_SHORT_IS_NULL(sCol[i]) == true )
        {
            printf("NULL\n");
        }
        else
        {
            printf("%d\n", sCol[i]);
        }
    }
}

예제 프로그램#

psm1.sc#

$ALTIBASE_HOME/sample/APRE/psm1.sc 참고

실행 결과#
$ is -f schema/schema.sql
$ make psm1
$ ./psm1
<SQL/PSM 1>
------------------------------------------------------
[Create Procedure]                                                
------------------------------------------------------
Success create procedure

------------------------------------------------------
[Execute Procedure]                                               
------------------------------------------------------
Success execute procedure

------------------------------------------------------
[Drop Procedure]                                                  
------------------------------------------------------
Success drop procedure

psm2.sc#

$ALTIBASE_HOME/sample/APRE/psm2.sc 참고

실행 결과#
$ is -f schema/schema.sql
$ make psm2
$ ./psm2
<SQL/PSM 2>
------------------------------------------------------
[Create Function]                                                 
------------------------------------------------------
Success create function

------------------------------------------------------
[Execute Function]                                                
------------------------------------------------------
31 rows selected

------------------------------------------------------
[Drop Function]                                                   
------------------------------------------------------
Success drop function

psm3.sc#

$ALTIBASE_HOME/sample/APRE/psm3.sc 참고

실행 결과#
$ is -f schema/schema.sql
$ make psm3
$ ./psm3
<SQL/PSM 3>
------------------------------------------------------------------
[Execute Procedure]
------------------------------------------------------------------
Success execute procedure PSM3_1

------------------------------------------------------------------
[Execute Procedure]
------------------------------------------------------------------
Success execute procedure PSM3_2

sCol        iCol        lCol        fCol        dCol 
1           10          100         1.100000    1.010000
2           11          101         2.100000    2.010000
3           12          102         3.100000    3.010000
4           13          103         4.100000    4.010000
5           14          104         5.100000    5.010000

psm4.sc#

$ALTIBASE_HOME/sample/APRE/psm4.sc 참고

실행 결과#
$ is -f schema/schema.sql
$ make psm4
$./psm4
<SQL/PSM 4>
------------------------------------------------------------------
[Execute Procedure]
------------------------------------------------------------------
Error : [-331898] The fetched result contains a NULL value. or Fetch column value is NULL.

sCol 
1
2
NULL
3
4