Dynamic SQL


Dynamic SQL, 동적 SQL은 상황에 따라 가변적으로 사용되는 SQL을 의미한다.

Dynamic SQL의 기본적 개념 및 사용법을 다루도록 하겠다.

 

Dynamic SQL?

대부분의 데이타베이스 응용프로그램은 특정한 일을 한다. 예를 들면, 단순한 것으로 사용자의 사번을 묻고, EMP나 DEPT 테이블 등을 갱신하는 것이 있다.

이런 경우, 컴파일 하기 전에 UPDATE 문을 구성하는 것들을 알고 있게 된다.

즉, 어떤 테이블이 변화되어야 할 것인지, 각 테이블과 컬럼에 정의된 제한점, 각 컬럼의 데이타 타입 등이 이에 해당한다.

그러나, 어떤 응용프로그램들은 실행 시 SQL문의 변화를 수용해야만 한다.

예를 들어 일반적 목적의 리포트 writer는 처리해야 할 다양한 리포트에 따라 SELECT 문을 서로 다르게 구축한다.

이 경우, 실행 이전에 문장의 구성을 알 수는 없다. 이런 문장들은 실행 상에 있어서 변화될 것이다. 이는 Dynamic SQL 문장으로 불린다.

정적인 SQL 문과는 달리, Dynamic SQL 문장은 source program에 추가되지는 않는다. 대신, 문자열 입력으로 프로그램에 저장되거나, 프로그램에 의해 구축된다.

이것은 상호작용적으로 입력되거나 file로 부터 읽혀진다.

Dynamic SQL의 장단점

동적으로 정의된 SQL 문장을 받아들이고 처리하는 호스트 프로그램은 평범한 embedded SQL 프로그램보다 변동이 심하다. 동적 SQL문장은 SQL에 대해 전혀 모르는 사용자로 부터 입력을 받아들여 구축된다.

예를 들면, 당신의 프로그램은 사용자에게 SELECT, UPDATE,DELETE 문 등의 WHERE 절에 시용될 검색 조건을 요구할 수 있다. 보다 복잡한 프로그램은 사용자에게 SQL 연산들, 테이블과 뷰 이름들, 컬럼명들 등이 나열된 메뉴로 부터 골라내기를 허용할 수도 있다. 따라서 동적 SQL은 매우 융통성있는 응용프로그램을 사용할 수 있게 한다.

그러나, 어떤 동적 쿼리는 특수한 데이타 구조를 사용하거나, 실행시간에 처리하게 하는 복잡한 코딩을 요구하기도 한다. 여러분이 동적 SQL의 개념과 기법을 완전히 숙지하지 않는다면, 추가적 처리 시간을 알지 못하는 동안, 코딩이 어렵다는 것을 느낄 수 있다.

언제 Dynamic SQL을 사용하는가

실제적으로는 정적 SQL이 거의 모든 프로그래밍 요구사항을 만족시킬 것이다. 동적 SQL은 오직 완전한 유연성이 필요할 때만 쓰도록 하라. 다음에 나오는 항목 중 하나라도 컴파일하기 이전에 분명히 알 수 없다면 동적 SQL을 사용할 것을 권한다.

  • SQL 문의 문구. (사용될 모든 명령, 절 등등)
  • 호스트 변수의 갯수. (동적으로 변할 수 있는가)
  • 호스트 변수의 데이타 타입.
  • 데이타베이스 객체(컬럼, 인덱스, 시퀀스, 테이블, 사용자이름, 뷰)를 참조하는 것.

    Dynamic SQL문의 요구사항

    동적 SQL의 문자열은 적절한 SQL 문을 포함하고 있어야 하며, EXEC SQL이나 문장 종료 기호, 또는 이하에 나오는 embedded SQL 명령을 포함해서는 안된다.

  • CLOSE
  • DECLARE
  • DESCRIBE
  • EXECUTE
  • FETCH
  • INCLUDE
  • OPEN
  • PREPARE
  • WHENEVER

거의 대부분의 경우, 문자열은 dummy 호스트 변수들을 가질 수 있다. 그것들은 SQL문에서 실제로 사용되는 호스트 변수에 대해 자리를 잡는다. Dummy 호스트 변수들은 그저 자리를 잡는 것(placeholder)이므로, 그것들을 선언하지 않고 아무렇게나 이름을 붙여도 된다. Oracle은 아래에 나오는 두 문장에 대해 차이를 두지 않는다. :m과 :j는 호스트 변수들의 자리를 잡아두는 역할만 하는 것이다.

‘DELETE FROM EMP WHERE MGR = :mgr_number AND JOB = :job_title’

‘DELETE FROM EMP WHERE MGR = :m AND JOB = :j’

Dynamic SQL 문은 어떻게 처리되는가

전형적으로, 응용프로그램은 사용자에게 SQL 문장과 그 문장에서 사용된 호스트 변수의 값을 묻는다. 그러고 나면, Oracle은 SQL 문장을 parse한다. 즉, SQL 문장이 문장 규칙을 따르는지, 적절한 데이타베이스 객체를 참조하는지 등을 검사한다. Parsing은 또한 데이타베이스 접근 권한 검사, 필요한 자원 예약, 최적의 접근 경로 찾기 등을 포함한다.

다음으로, Oracle은 호스트 변수와 SQL 문장을 bind한다. 즉, 호스트 변수의 주소를 얻어내어 그 값을 읽거나 쓰게 되는 것이다.

그 다음은 SQL 문장을 execute한다. 테이블에서 행을 삭제하는 따위의 SQL문 요청을 실행한다.

SQL 문장은 호스트 변수의 새로운 값을 사용하여 반복적으로 실행될 수 있다.

Dynamic SQL 사용 기법

여기서는 동적 SQL 문장들을 정의하는 데에 사용될 수 있는 네가지 기법 중 기법 1과 기법2를 소개한다. 각 기법은 능력과 제한을 간략히 소개하고, 적절한 기법을 사용하기 위한 가이드라인을 제시한다. 다음 장에는 각 기법의 사용(기법1,2)과 sample 프로그램(기법2)이 나와 있다. 기법3과 4에 대해서는 각자 공부하기를 바란다.

네 가지 기법들은 전체적인 것으로 증가한다. 즉, 기법2는 기법1을 포함하며, 기법3은 기법1과 2를 포함하는 등이다. 그러나 각 기법들은 특정 종류의 SQL 문장을 다루는 데에 매우 유용하다. 이하 표에 그 기법과 종류가 나와 있다.

기법

SQL 문장의 종류

1

호스트 변수가 없고, 질의가 없는 것

2

입력 호스트 변수의 갯수를 알고, 질의가 없는 것

3

select-list item과 입력 호스트 변수의 갯수를 알고, 질의가 있는 것

4

select-list item 또는 입력 호스트 변수의 갯수가 정해져 있지 않고, 질의가 있는 것
  • 참고: select-list item은 컬럼명과 표현을 포함한다. (예: SAL*1.10, MAX(SAL))

    기법 1

    이 기법은 프로그램으로 하여금 동적 SQL문을 받아들이거나 구축하고, EXECUTE IMMEDIATE 명령을 사용하여 즉각 실행하는 방법이다. SQL 문장은 SELECT 문 같은 질의가 아니어야 하며, 입력 호스트 변수에 대해 placeholder를 가져서도 안된다. 이하의 호스트 문자열은 이 조건을 만족한다.

    ‘DELETE FROM EMP WHERE DEPTNO = 20’

    ‘GRANT SELECT ON EMP TO scott’ (scott 사용자에게 SELECT 권한 부여)

    기법1은 실행될 때 마다 SQL 문이 parse 된다.

    기법 2

    이 기법은 프로그램으로 하여금 동적 SQL 문을 받아들이거나 구축하고, PREPARE와 EXECUTE 명령을 사용하여 처리한다. SQL 문장은 질의가 아니어야 한다. 입력 호스트 변수에 대한placeholder의 개수와 데이타 타입은 컴파일 이전에 알 수 있어야 한다. 예를 들어 다음 호스트 문자열은 이 조건을 충족한다.

    ‘INSERT INTO EMP (ENAME, JOB) VALUES (:emp_name, :job_title)’

    ‘DELETE FROM EMP WHERE EMPNO = :emp_number’

    기법2로써, SQL 문장은 오직 한번 parse되지만, 호스트 변수의 값에 따라 여러번 실행될 수 있다. CREATE와 GRANT 등의 SQL 데이타 정의 문장은 PREPARE되었을 때 실행된다.

    기법3

    이 기법은 프로그램으로 하여금 동적 질의를 구축하거나 수용하게 하고, DECLARE, OPEN, FETCH, CLOSE 등의 cursor 명령과 함께 PREPARE문을 사용함으로써 그 질의를 처리한다. Select-list의 항목 수, 입력 호스트 변수에 대한 placeholder의 개수와 데이타 타입은 precompile 시기에 알 수 있어야 한다. 예를 들면 다음의 호스트 문자열은 이러한 조건을 충족한다.

    ‘SELECT DEPTNO, MIN(SAL), MAX(SAL) FROM EMP GROUP BY DEPTNO’

    ‘SELECT ENAME, EMPNO FROM EMP WHERE DEPTNO = :dept_number’

    기법4

    이 기법은 프로그램으로 하여금 동적 질의를 구축하거나 수용하고 나서, descriptor를 사용하여 처리한다. Select list의 항목 수, 입력 호스트 변수에 대한 placeholder의 개수와 데이타 타입은 run time 이전까지 모를 수도 있다. 예를 들어 다음의 호스트 문자열은 이러한 조건에 맞는다.

    ‘INSERT INTO EMP (<unknown>) VALUES (<unknown>)’

    ‘SELECT <unknown> FROM EMP WHERE DEPTNO = 20’

    기법 4는 몇개인지 알 수 없는 select-list의 항목 수와 입력 호스트 변수를 포함한 동적 SQL문을 위해 요구된다.

    가이드라인

    네 가지 모든 기법들에 있어서 동적 SQL문은 문자열로 저장되어야 하며, 그것은 호스트 변수이거나 ”로 싸인 문자들이다. SQL 문을 문자열로 저장할 때 EXEC SQL 키워드와 ‘;’를 제거한다.

    기법 2와 3에 있어서, 입력 호스트 변수에 대한 placeholder의 개수와 데이타 타입은 precompile 시에 알려져야 한다.

    열거된 각 기법은 1에서 4로 갈수록 점점 적은 제한을 주지만, 코딩하기엔 더 어려어진다. 될 수 있는한 가장 단순한 기법을 사용도록 하라. 그러나, 기법 1을 사용하여 동적SQL 문이 반복적으로 실행된다면, 각 실행에 대해 reparse됨을 방지하기 위해서 기법 2를 사용하라.

    기법 4는 최고의 유연성을 갖지만, 복잡한 코딩과 동적 SQL 개념의 완벽한 이해를 요구한다. 일반적으로, 기법1,2,3을 모두 사용하지 못할 경우 사용한다. 다음 그림은 적절한 기법을 선택하는 데 도움을 줄 것이다.


    공통 에러 피하기

     

  • Command line option = V6 / DBMS = V6_CHAR 일 경우…

다른 SQL 문에 대해 배열을 재사용할 때 초기화를 시켜주는 것은 매우 중요하다. 항상 SQL 문장을 저장하기 이전에 호스트 문자열을 초기화 또는 재초기화하는 것을 규칙화하여야 한다. 호스트 문자열을 null로 끝나게 하지 않아야 한다. Oracle은 null 종결값을 end-of-string sentinel로 인식하지 못한다. 대신 그것을 SQL 문의 일부로 다룬다.

 

  • Command line option = V7 일 경우…

PREPARE 또는 EXECUTE IMMEDIATE 명령을 실행하기 이전에 문자열이 null로 끝나는지를 확인해야 한다.

DBMS에 무관하게, VARCHAR 변수를 동적 SQL 문장을 저장하는 데에 사용한다면, PREPARE 또는 EXECUTE IMMEDIATE 명령을 실행하기 이전에 VARCHAR의 길이가 제대로 설정되었는지 확인해야 한다.

기법1의 사용

가장 단순한 동적 SQL 문장의 결과는 ‘성공’ 또는 ‘실패’로 나타나며, 호스트 변수를 사용하지 않는다. 몇 가지 예를 들어본다.

‘DELETE FROM table_name WHERE column_name = constant’

‘CREATE TABLE table_name …’

‘DROP INDEX index_name’

‘UPDATE table_name SET column_name = constant’

‘GRANT SELECT ON table_name TO username’

‘REVOKE RESOURCE FROM username’ (사용자로부터 전체 권한 취소)

기법 1은 parse하고 EXECUTE IMMEDIATE 명령을 사용하여 SQL문을 즉각 실행한다. 명령 다음으로 질의가 아닌, 실행될 SQL문이 담긴 호스트 변수나 literal 등의 문자열이 따른다.

EXECUTE IMMEDIATE 문의 문법 규칙은 다음과 같다.

EXECUTE SQL EXECUTE IMMEDIATE { :host_string | string_literal };

다음에 나오는 예에서 호스트 변수 sql_stmt는 사용자로부터 입력된 SQL 문을 저장하는 데에 사용된다.

char sql_stmt[132];

. . .

for ( ; 😉

{

    printf(“Enter SQL statements: “);

    gets(sql_stmt);

    if (*sql_stmt == ‘\0’)

        break;

    /* sql_stmt는 이제 SQL 문장을 갖게 된다. */

    EXEC SQL EXECUTE IMMEDIATE :sql_stmt;

}

또한 아래 예처럼 문자열을 직접 사용할 수도 있다.

EXEC SQL EXECUTE IMMEDIATE ‘REVOKE RESOURCE FROM MILLER’;

EXECUTE IMMEDIATE는 매 실행 이전에 입력 SQL문을 parse 시키므로, 기법 1은 오직 한번 실행되는 문장에 대해 최고의 효과를 갖는다. DDL이 주로 이 영역에 속한다.

Sample Program

다음에 나오는 프로그램은 테이블을 생성, 행 삽입, 삽입 commit, 테이블 삭제 등의 내용으로 기법1을 사용한 것이다.

#include <stdio.h>

#include <string.h>

#include <oraca.h>

EXEC ORACLE OPTION (ORACA = YES)

/* RELEASE_CURSOR=YES 옵션을 설정함으로써 embedded SQL이 실행되고

* 나면 그들과 결합되어 있던 자원을 해제할 수 있게 된다.

*/

EXEC ORACLE OPTION (RELEASE_CURSOR = YES)

void sql_error();

main();

{

    char     *username = “SCOTT”;

    char    *password = “TIGER”;

    char    *sqlstmt1;

    char    sqlstmt2[10];

    VARCHAR    sqlstmt3[80];

    EXEC SQL WHENEVER SQLERROR DO sql_error(“Oracle error:”);

    oraca.orastxtf = ORASTFERR;

    EXEC SQL CONNECT :username IDENTIFIED BY :password;

    puts(“\nConnected to ORACLE.\n”);

/* 테이블을 생성하는 문자열을 실행한다. 사실 이것은 실행 시간에 SQL 문장을

* 결정하는 것이 아니므로 동적이지 못하다.

*/

    puts(“CREATE TABLE dyn1 (col1 VARCHAR2(4))”);

    EXEC SQL EXECUTE IMMEDIATE

        “CREATE TABLE dyn1 (col1 VARCHAR2(4))”;

/* 행을 삽입하는 문자열을 실행한다. 배열의 사용되지 않는 나머지 부분은 공백으로

* 채우고, 문자열은 null로 끝나지 않아야 한다.

*/

    strncpy(sqlstmt2, “COMMIT “, 10);

    printf(“%.10s\n”, sqlstmt2);

    EXEC SQL EXECUTE IMMEDIATE :sqlstmt2;


/* 테이블을 drop하기 위해 VARCHAR를 실행하라. ‘.len’ 필드값을 ‘.arr’ 필드의

* 길이로 설정한다.

*/

    strcpy(sqlstmt3.arr, “DROP TABLE DYN1”);

    sqlstmt3.len = strlen(sqlstmt3.arr);

    puts((char *) sqlstmt3.arr);

    EXEC SQL EXECUTE IMMEDIATE :sqlstmt3;

/* 미결정된 변화를 commit하고 Oracle 접속을 끊는다. */

    EXEC SQL EXECUTE IMMEDIATE :sqlstmt3;

    puts(“\nHave a good day!\n”);


    return 0;

}


void sql_error()

{

/* 이 프로그램은 oracle error handler로서, 에러 메시지, 현재 SQL문장, error의

* 위치 등 진단 문구를 출력한다.

*/

    printf(“%s\n”, msg);

    printf(“\n%.*s\n”, sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc);

    printf(“in \”%.*s. . .\”\n”, oraca.orastxt.orastxt1, oraca.oraca.orastxt.orastxtc);

    printf(“on line %d of %.*s.\n\n”,

        oraca.oraslnr, orasfnm.orasfnml,

        oraca.orasfnm.orasfnmc);

/* 이 루틴내에서 무한 루프를 돌다가 또 다른 에러를 유발하는 것을 방지하기 위해

* ORACLE error checking을 무력하게 한다. */

    EXEC SL WHENEVER SQLERROR CONTINUE;

/* 미결정된 변화를 rollback시키고 Oracle 접속을 끊는다. */

    EXEC SQL ROLLBACK RELEASE;

    exit(1);

}

기법2의 사용

기법1이 1스텝이면, 기법2는 2스텝이다. 질의 형태가 아닐 수도 있는 동적 SQL 문장은 먼저 PREPARE(명명되고 parse됨)되고 나서 EXECUTE된다.

기법2에서는 SQL 문장이 입력 호스트 변수와 indicator 변수에 대해 placeholder를 가질 수 있다. 일단 SQL 문을 PREPARE하고 나면, 호스트 변수의 여러 값들을 사용하여 반복적으로 EXECUTE 시킨다. 게다가, COMMIT이나 ROLLBACK 이후 SQL문을 다시 PREPARE할 필요가 없다. (log off하고 reconnect 하지 않는 한)

PREPARE 문의 문법은 다음과 같다.

EXEC SQL PREPARE statement_name

    FROM { :host_string | string_literal };

PREPARE는 SQL 문을 parse해주고 이름을 준다.

statement_name은 precompiler에 의해 사용되는 식별자로서, 호스트 변수나 프로그램 변수가 아니고, 선언부(Declare Section) 내에 선언되어서는 안된다. 그것은 단지 실행시키고 싶은 PREPARE된 문장을 의미할 뿐이다.

EXECUTE문의 문법은 다음과 같다.

EXEC SQL EXECUTE statement_name [USING host_variable_list];

host_variable_list는 다음 문법을 따른다.

:host_variable1[:indicator1] [, host_variable2 [:indicator2], …]

EXECUTE는 각각의 입력 호스트 변수를 가지고 parse된 SQL 문장을 실행시킨다. 다음에 나오는 예에서 입력 SQL 문장은 placeholder n을 가지고 있다.

. . .

int emp_number INTEGER;

char delete_stmt[120], search_cond[40];

. . .

strcpy(delete_stmt, “DELETE FROM EMP WHERE EMPNO = :n AND “);

printf(“Complete the following statement’s search condition–\n”);

printf(“%s\n”, delete_stmt);

gets(search_cond);

strcat(delete_stmt, search_cond);

EXEC SQL PREPARE sql_stmt FROM :delete_stmt;

for( ; 😉

{

printf(“Enter employee number: “);

    gets(temp);

    emp_number = atoi(temp);

    if (emp_number == 0)

        break;

    EXEC SQL EXECUTE sql_stmt USING :emp_number;

}

기법2에서는 precompile 시에 입력 호스트 변수의 데이타 타입을 알고 있어야 한다. 위 예에서 emp_number는 int로 선언되었다. 이는 float, char로 선언될 수도 있다. Oracle은 이런 모든 데이타 타입을 내부의 Oracle NUMBER 타입으로 전환할 수 있다.

USING 절

SQL 문이 EXECUTE 될 때, USING절에 있는 입력 호스트 변수들은 PREPARE 동적 SQL 문에 있는 placeholder와 대치된다.

각 PREPARE 동적 SQL문의 placeholder는 USING절의 서로 다른 호스트 변수와 대응되어야 한다. 그래서, 만약 같은 placeholder가 PREPARE문에 여러번 나타난다면, USING 절에서도 호스트 변수가 대응되어 나타나야 한다.

Placeholder의 이름은 호스트 변수의 이름과 대등할 필요가 없다. 하지만, PREPARE 동적 SQL문의 placeholder의 순서와 USING절의 호스트 변수의 순서는 대등하여야 한다.

만약, USING절의 호스트 변수 중 하나가 배열이라면, 모두 배열이어야 한다.

Null 값인지 명확히 하기 위해서, USING절의 호스트 변수와 indicator 변수를 결합할 수 있다.

Sample Program

여기 있는 프로그램은 동적 SQL 기법 2를 사용하여 EMP 테이블에 두개의 행을 삽입하고 삭제한다. 파일 sample7.pc, demo 디렉토리, on-line으로 사용 가능하다.

/*

* sample 7.pc : Dynamic SQL Method 2

.*/

#include <stdio.h>

#include <string.h>

#define USERNAME “SCOTT”

#define PASSWORD “TIGER”

/* ORACLE이 에러 코드, 경고 플래그, 진단 문구 등의 실행시간 상태 정보를 만들어

* 주기 위해 필요한 SQL Communication Area를 Include 해준다.

*/

#include <sqlca.h>

/* ORACLE이 추가적인 실행시간 상태 정보를 만들어 주기 위해 필요한 ORACLE

* Communication Area를 include 한다.

*/

#include <oraca.h>

/* ORACA=YES 옵션은 ORACA의 사용을 가능하게 하기 위해서 필요하다. */

EXEC ORACLE OPTION (ORACA = YES);

char        *username = USENAME;

char        *password = PASSWORD;

VARCHAR    sqlstmt[80];

int        empno = 1234;

int        deptno1 = 97;

int        deptno2 = 99;

/* SQL runtime error를 처리한다. */

void sql_error();

main()

{

/* embedded SQL을 처리하는 도중 에러가 발생하면 sql_error()을 호출한다. */

EXEC SQL WHENEVER SQLERROR DO sql_error(“Oracle error”);

/* Error가 발생하면 ORACA에 있는 현재의 SQL문장을 저장한다. */

    oraca.orastxtf = ORASTFERR;

/* Oracle에 접속한다. */

    EXEC SQL CONNECT :username IDENTIFIED BY :password;

    puts(“\nConnected to Oracle.\n”);

/* SQL문을 VARCHAR sqlstmt에 할당한다. 배열과 길이 부분은 제대로 설정되어야

* 한다. 문장에 두개의 호스트 변수 placeholder인 v1, v2가 있음을 주시하라. 실제

* 입력 호스트 변수는 EXECUTE 시에 제공되어야 한다.

*/

    strcpy(sqlstmt.arr,

        “INSERT INTO EMP (EMPNO, DEPTNO) VALUES (:v1, :v2)”);

    sqlstmt.len = strlen(sqlstmt.arr);

/* SQL문과 현재의 입력 호스트 변수 값을 표시한다. */

    puts((char *) sqlstmt.arr);

    printf(”    v1 = %d, v2 = %d\n”, empno, deptno1);

/* PREPARE문은 문장 이름과 SQL문이 들어있는 문자열을 결합시킨다. 문장

* 이름은 SQL 식별자이며, 호스트 변수가 아니다. 따라서 선언부에 나타나지 않는다.

* 하나의 문장 이름은 서로 다른 문자열 변수를 사용하면, 한번 이상 PREPARE될 수

* 있다.

*/

    EXEC SQL PREPARE S FROM :sqlstmt;

/* EXECUTE문은 PREPARE문에서 사용된 placeholder의 위치에 맞게 입력 호스트

* 변수를 대치하여 실행시킨다. Placeholder가 여러 개라면 USING 절에서도 그에

* 맞는 호스트 변수가 대응되어 있어야 한다. 문장이 placeholder를 가지고 있지

* 않다면 USING절은 필요없게 된다.

* 한 개의 PREPARE문은 USING절의 입력 호스트 변수를 바꿔 사용함으로써

* 여러번 실행될 수 있다.

*/

    EXEC SQL EXECUTE S USING :empno, :deptno1;

/* empno를 증가시키고 새 입력 호스트 변수를 표시한다. */

    empno++;

    printf(”    v1 = %d, v2 = %d\n”, empno, deptno2);

/* 새로운 empno와 다른 입력 호스트 변수 deptno2를 집어넣고 S를 재실행한다.

* 다시 PREPARE를 사용하는 것은 불필요하다.

*/

    EXEC SQL S USING :empno, :deptno2;

/* sqlstmt에 새 값을 할당한다. */

    strcpy(sqlstmt.arr,

        “DELETE FROM EMP WHERE DEPTNO = :v1 OR DEPTNO = :v2”);

    sqlstmt.len = strlen(sqlstmt.arr);

/* 새 SQL문과 현재의 입력 호스트 변수 값을 표시한다. */

    puts((char *) sqlstmt.arr);

    printf(”    v1 = %d, v2 = %d\n”, deptno1, deptno2);

/* 새로운 sqlstmt로 부터 S를 재PREPARE한다. */

    EXEC SQL PEPARE S FROM :sqlstmt;

/* 이전에 삽입된 두 행을 삭제하기 위해 S를 실행한다. */

    EXEC SQL EXECUTE S USING :deptno1, :deptno2;

/* 미결정된 변화를 commit시키고 Oracle 접속을 끊는다. */

    EXECUTE SQL COMMIT RELEASE;

    puts(“\nHave a good day!\n”);

    exit(0);

}

void sql_error(char* msg)

{

    /* 6.5.1 Sample Program 의 내용을 참조. */

}



Comments

comments

haisins

오라클 DBA 박용석 입니다. haisins@gmail.com 으로 문의 주세요.

댓글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다