콘텐츠로 이동

9. 응용프로그램 작성#

이 장에서는 Altibase를 활용하는 응용 프로그램 작성법에 관하여 간략하게 설명하도록 한다.

응용 프로그램 작성 방법#

Altibase CLI, JDBC, ODBC, APRE C/C++ Precompiler 등을 사용하여 Altibase 응용 프로그램을 개발하는 것은 범용 데이터베이스 운용 환경에서의 응용 프로그램 작성법과 크게 다르지 않다.

본 장에서는 Altibase 응용 프로그램 작성법에 관하여 간략하게 설명하도록 한다.

응용 프로그램 작성의 자세한 내용은 CLI User's Manual, ODBC User's Manual, Precompiler User's Manual, 및 API User's Manual을 참조한다.


Altibase CLI를 활용한 프로그램#

이 절은 Altibase CLI를 이용하여 클라이언트 응용 프로그램를 작성하는 방법을 설명한다. Altibase CLI는 Altibase를 클라이언트-서버 구조로 운영하는 상황에서 사용할 수 있는 API이다. 자세한 내용은 CLI User's Manual을 참조한다.

헤더 파일과 라이브러리#

Altibase CLI를 이용하여 프로그램을 작성하기 위해서는 Altibase의 설치 홈 디렉토리의 서브 디렉토리인 include와 lib에 있는 헤더 파일과 라이브러리 파일이 필요하다.

$ALTIBASE_HOME/include/sqlcli.h
$ALTIBASE_HOME/lib/libodbccli.a

Makefile#

작성된 Altibase CLI 소스를 컴파일하기 위한 Makefile에는 다음과 같은 내용이 포함되어야 한다.

include $(ALTIBASE_HOME)/install/altibase_env.mk

이 파일 안에는 컴파일시 필요로 하는 라이브러리 경로와 라이브러리들을 링크시키기 위한 옵션들이 정의되어 있으며 오브젝트 파일을 만드는 규칙을 제공한다. $ALTIBASE_HOME/sample/SQLCLI 내의 Makefile을 참조한다.

예문#

include $(ALTIBASE_HOME)/install/altibase_env.mk

SRCS=
OBJS=$(SRCS:.cpp=.$(OBJEXT))

BINS=demo_ex1

all: $(BINS)

demo_ex1: demo_ex1.$(OBJEXT)
    $(LD) $(LFLAGS) $(LDOUT)demo_ex1$(BINEXT) demo_ex1.$(OBJEXT) $(LIBOPT)odbccli$(LIBAFT) $(LIBS)

멀티 쓰레드 프로그램#

멀티 쓰레드 프로그램을 작성할 때 다음과 같은 사항을 주의해야 한다.

  • 각 쓰레드 별로 환경 핸들, 연결 핸들을 각각 할당해야 한다.

프로그램 작성#

Altibase CLI를 이용하여 작성하는 프로그램에서 Altibase 서버에 접속하고 종료하는 방법을 간략하게 설명하도록 한다.

Altibase CLI 프로그램의 예#

/* test.cpp */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <unistd.h>
#include <sqlcli.h>

void sbigint_bigint(int cnt);  
void slong_integer(int cnt);
void char_char(int cnt);
void char_number(int cnt);
void double_double(int cnt);
void prepare();
void execute();
void usage();
long logMsec(const char *astr);
void conn(char *port, char *conntype);

#define MSG_LEN 1024  

SQLHENV   env;  // Environment를 할당 받을 handle
SQLHDBC   con;  // Connection을 할당 받을 handle
SQLHSTMT  hstmt;  // Statement를 할당 받을 handle
SQLHSTMT  bstmt;  // Statement를 할당 받을 handle
int          errNo;
short        msgLength;
char         errMsg[MSG_LEN];
SQLRETURN rc;

/* Main프로그램 - 인자 개수가 5보다 적을 경우 사용법(usage) 출력 */
int main(int ac, char **av)  
{
    if (ac < 5) 
    {
        usage();
    }

    conn(av[2], av[3]);

    switch(atoi(av[1]))
    {
    case 1:
        logMsec(" BIGINT - START TIME : ");
        sbigint_bigint(atoi(av[4]));
        logMsec(" BIGINT - END TIME : ");
        break;
    case 2:
        logMsec(" INTEGER - START TIME : ");
        slong_integer(atoi(av[4]));
        logMsec(" INTEGER - END TIME : ");
        break;
    case 3:
        logMsec(" CHAR - START TIME : ");
        char_char(atoi(av[4]));
        logMsec(" CHAR - END TIME : ");
        break;
    case 4:
        logMsec(" NUMBER - START TIME : ");
        char_number(atoi(av[4]));
        logMsec(" NUMBER - END TIME : ");
        break;
    case 5:
        logMsec(" DOUBLE - START TIME : ");
        double_double(atoi(av[4]));
        logMsec(" DOUBLE - END TIME : ");
        break;
    }
}

/* 프로그램의 사용법을 출력 */
void usage()
{
    printf("Usage: ./test <program_no> <port_no> <conntype> <cnt>\n");
    printf("\tprogram_no : 1  => \t SBIGINT-BIGINT\n");
    printf("\tprogram_no : 2  => \t SLONG-INTEGER\n");
    printf("\tprogram_no : 3  => \t CHAR-CHAR\n");
    printf("\tprogram_no : 4  => \t CHAR-NUMERIC\n");
    printf("\tprogram_no : 5  => \t DOUBLE-DOUBLE\n");
    exit(1);
}

/* 프로그램 시작시간 및 종료시간 체크 */
long logMsec(const char *astr)
{
    struct timeval  tv;
    struct tm       *ctm;

    gettimeofday(&tv,NULL);
    ctm = localtime(&(tv.tv_sec));

    fprintf(stderr, "%s [%.02d:%.02d:%.02d]\n", astr, ctm->tm_hour, 
ctm->tm_min, ctm->tm_sec);

    return tv.tv_usec;
}

/* Altibase 접속 구문 */
void conn(char *port, char *conntype)
{
    char connStr[200];
    char query[200];

    if (SQL_ERROR == SQLAllocEnv(&env))
    {
        fprintf(stderr, "SQLAllocEnv error!!\n"); 
//Environment를 위한 메모리를 할당.
        return;
    }

    if (SQL_ERROR == SQLAllocConnect(env, &con)) 
// connection을 위한 메모리를 할당
    {
        fprintf(stderr, "SQLAllocConnect error!!\n");
        SQLFreeEnv(env);
        return;
    }

    sprintf((char*)connStr, "DSN=127.0.0.1;PORT_NO=%s;UID=SYS;PWD=MANAGER;CONNTYPE=%s", port, conntype);

/* Connection 생성 */
    if (SQL_ERROR == SQLDriverConnect(con, NULL, (char*)connStr,
SQL_NTS, NULL, 0, NULL, SQL_DRIVER_NOPROMPT))
    {
        if (SQL_SUCCESS == SQLError(env, con, NULL, NULL, &errNo, (char*)errMsg, MSG_LEN, &msgLength)) 
        {
            fprintf(stderr, " rCM_-%d : %s\n", errNo, errMsg);
        }
        SQLFreeConnect(con);  
        SQLFreeEnv(env);
        return;
    }
/* 각 SQL문을 실행 시 자동으로 반영하지 않는다 */
    SQLSetConnectAttr(con, SQL_ATTR_AUTOCOMMIT, 
(void*)SQL_AUTOCOMMIT_OFF, 0);
    if (rc == SQL_ERROR)              
    {                                 
        if (SQL_SUCCESS == SQLError(env, con, NULL, NULL, &errNo, (char*)errMsg, MSG_LEN, &msgLength))
        {
            fprintf(stderr, "[%d : %s]\n", errNo, errMsg);
        }
    }

    hstmt = bstmt = SQL_NULL_HSTMT;  

    SQLAllocStmt(con, &hstmt);
    SQLAllocStmt(con, &bstmt);

/* DDL문을 직접 수행하며 오류발생시 메시지를 지정서식에 따라 파일로 출력 */
    strcpy(query, "drop table t1");   
    rc = SQLExecDirect(hstmt, (char*)query, SQL_NTS);  
    if (rc == SQL_ERROR)
    {
        if (SQL_SUCCESS == SQLError(env, con, hstmt, NULL, &errNo, (char*)errMsg, MSG_LEN, &msgLength))
        {
            fprintf(stderr, "[%d : %s]\n", errNo, errMsg); 
}
    }

/* DDL문을 직접 수행하며 오류발생시 메시지를 지정서식에 따라 파일로 출력 */
    strcpy(query, "create table t1(i1 number(6))");
    rc = SQLExecDirect(hstmt, (char*)query, SQL_NTS);
    if (rc == SQL_ERROR)
    {
        if (SQL_SUCCESS == SQLError(env, con, hstmt, NULL, &errNo, (char*)errMsg, MSG_LEN, &msgLength))
        {
            fprintf(stderr, "[%d : %s]\n", errNo, errMsg); 
}
    }
}

/* 실행할 SQL문을 준비 */
void prepare()   
{
    char query[100];

    strcpy(query, "insert into t1 values(?)");

    rc = SQLPrepare(bstmt, (char*)query, SQL_NTS);
    if (rc == SQL_ERROR)              
    {                                 
        if (SQL_SUCCESS == SQLError(env, con, bstmt, NULL, &errNo, (char*)errMsg, MSG_LEN, &msgLength))
        {
            fprintf(stderr, "[%d : %s]\n", errNo, errMsg);
        }
    }
}

/* 준비된 SQL문장을 실행 */
void execute()  
{
    rc = SQLExecute(bstmt);
    if (rc == SQL_ERROR)              
    {                                 
        if (SQL_SUCCESS == SQLError(env, con, bstmt, NULL, &errNo, (char*)errMsg, MSG_LEN, &msgLength))
        {
            fprintf(stderr, "[%d : %s]\n", errNo, errMsg);
        }
    }
}

void sbigint_bigint(int cnt)
{
    int i;
    long long i1;
    char tmp[100];
    int len = SQL_NTS;

    prepare();

/* SQL문장에 매개변수(parameter)를 연결시킴 */
    SQLBindParameter(bstmt, 1, SQL_PARAM_INPUT, SQL_C_SBIGINT, 
SQL_BIGINT, 0, 0, (void*)&i1, 0, &len);

    for(i=0; i<cnt; i++)
    {
        sprintf(tmp, "%d", i);
        i1 = atol(tmp);
        execute();
    }

/* 트랜잭션을 COMMIT 처리 */
    rc = SQLTransact(NULL, con, SQL_COMMIT); 
}

void slong_integer(int cnt)
{
    int i;
    int i1;
    char tmp[100];
    int len = SQL_NTS;

    prepare();

/* SQL문장에 매개변수(parameter)를 연결시킴 */
    SQLBindParameter(bstmt, 1, SQL_PARAM_INPUT, SQL_C_SLONG, 
SQL_INTEGER, 0, 0, (void*)&i1, 0, &len);

    for(i=0; i<cnt; i++)
    {
        sprintf(tmp, "%d", i);
        i1 = atoi(tmp);
        execute();
    }

/* 트랜잭션을 COMMIT 처리 */
    SQLTransact(NULL, con, SQL_COMMIT);
}

void char_char(int cnt)
{
    int  i;
    char i1[100];
    char tmp[100];
    int len = SQL_NTS;

    prepare();

/* SQL문장에 매개변수(parameter)를 연결시킴 */
    SQLBindParameter(bstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, 
SQL_CHAR, sizeof(i1)-1, 0, (void*)i1, sizeof(i1), &len);

    for(i=0; i<cnt; i++)
    {
        sprintf(tmp, "%d", i);
        strcpy(i1, tmp);
        execute();
    }

/* 트랜잭션을 COMMIT 처리 */
    SQLTransact(NULL, con, SQL_COMMIT);
}

void char_number(int cnt)
{
    int  i;
    char i1[100];
    char tmp[100];
    int len = SQL_NTS;

    prepare();

    SQLBindParameter(bstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, 
SQL_NUMERIC, sizeof(i1)-1, 0, (void*)i1, sizeof(i1), 
&len);

    for(i=0; i<cnt; i++)
    {
        sprintf(tmp, "%d", i);
        strcpy(i1, tmp);
        execute();
    }

/* 트랜잭션을 COMMIT 처리 */
    SQLTransact(NULL, con, SQL_COMMIT);
}

void double_double(int cnt)
{
    int  i;
    double i1;
    char tmp[100];
    int len = SQL_NTS;

    prepare();

    SQLBindParameter(bstmt, 1, SQL_PARAM_INPUT, SQL_C_DOUBLE, 
SQL_DOUBLE, 0, 0, (void*)&i1, 0, &len);

    for(i=0; i<cnt; i++)
    {
        sprintf(tmp, "%d", i);
        i1 = atof(tmp);
        execute();
    }

/* 트랜잭션을 COMMIT 처리 */
    SQLTransact(NULL, con, SQL_COMMIT);
}

실행결과#

$ make test
$ ./test 3 20300 1 100

BIGINT - START TIME :  [16:43:48]
BIGINT - END TIME :  [16:43:49]


JDBC를 활용한 프로그램#

Altibase의 JDBC 드라이버를 이용하여 클라이언트를 작성하는 방법이다. 자세한 내용은 JDBC User's Manual을 참조한다.

JDBC 드라이버#

Altibase는 기본적으로 $ALTIBASE_HOME/lib 디렉토리 안에 Altibase.jar 파일을 JDBC 드라이버로 제공한다.

Altibase 서버와 연결을 설정하기 위해, 먼저 드라이버를 로드하고, URL과의 연결을 시도한다. Altibase JDBC 드라이버에서 지원하는 URL 형식은 다음과 같다.

jdbc:Altibase://hostname:portnum/databasename

JDBC 드라이버를 로드할 때에는 프로그램 내에서 다음과 같은 코드로 JDBC 드라이버를 등록하여 사용한다.

Class.forName("Altibase.jdbc.driver.AltibaseDriver")

Altibase의 URL을 제공하고, URL과 연결을 시도하기 위한 일반적인 방법으로 다음과 같다. (데이터베이스에 로그인 하기 위한 id가 "SYS"이고, 패스워드가 "MANAGER"인 경우)

 String url = "jdbc:Altibase://127.0.0.1:20300/mydb";
 Connection con = DriverManager.getConnection(url, "SYS", "MANAGER");

CLASSPATH#

JDBC 응용 프로그램의 수행을 위해 Altibase.jar파일이 CLASSPATH에 포함되어야 한다.

$ export CLASSPATH=$ALTIBASE_HOME/lib/Altibase.jar:$CLASSPATH

프로그램 작성#

JDBC를 이용하여 작성하는 프로그램에서 Altibase 서버에 접속하고 종료하는 방법은 대략 다음과 같다.

JDBC 프로그램의 예#

/* SimpleSQL.java */
import java.util.Properties;
import java.sql.*;

class SimpleSQL
{
    public static void main(String args[]) {

        Properties        sProps   = new Properties();
        Connection        sCon     = null;
        Statement         sStmt    = null;
        PreparedStatement sPreStmt = null;
        ResultSet         sRS;

        if ( args.length == 0 )
        {
            System.err.println("Usage : java class_name port_no");
           System.exit(-1);
        }

        String sPort     = args[0];
        String sURL      = "jdbc:Altibase://127.0.0.1:" + sPort + "/mydb";
        String sUser     = "SYS";
        String sPassword = "MANAGER";

        sProps.put( "user",     sUser);
        sProps.put( "password", sPassword);

        /* Altibase JDBC 드라이버 등록 */
        try
        {
            Class.forName("Altibase.jdbc.driver.AltibaseDriver");
        }
        catch ( Exception e )
        {
            System.out.println("Can't register Altibase Driver");
            System.out.println( "ERROR MESSAGE : " + e.getMessage() );
            System.exit(-1);
        }

        /* 접속하고 Statment를 할당 */
        try
        {
            sCon = DriverManager.getConnection( sURL, sProps );
            sStmt = sCon.createStatement();
        }
        catch ( Exception e )
        {
            System.out.println( "ERROR MESSAGE : " + e.getMessage() );
            e.printStackTrace();
        }

        /* 쿼리수행 */
        try
        {
            sStmt.execute( "DROP TABLE TEST_EMP_TBL" );
        }
        catch ( SQLException e )
        {
        }

        try
        {
           sStmt.execute( "CREATE TABLE TEST_EMP_TBL " +
                           "( EMP_FIRST VARCHAR(20), " +
                           "EMP_LAST VARCHAR(20), " +
                           "EMP_NO INTEGER )" );

            sPreStmt = sCon.prepareStatement( "INSERT INTO TEST_EMP_TBL " +
                                              "VALUES( ?, ?, ? )" );

            sPreStmt.setString( 1, "Susan" );
            sPreStmt.setString( 2, "Davenport" );
            sPreStmt.setInt(    3, 2 );
            sPreStmt.execute();

            sPreStmt.setString( 1, "Ken" );
            sPreStmt.setString( 2, "Kobain" );
            sPreStmt.setInt(    3, 3 );
            sPreStmt.execute();

            sPreStmt.setString( 1, "Aaron" );
            sPreStmt.setString( 2, "Foster" );
            sPreStmt.setInt(    3, 4 );
            sPreStmt.execute();

            sPreStmt.setString( 1, "Farhad" );
            sPreStmt.setString( 2, "Ghorbani" );
            sPreStmt.setInt(    3, 5 );
            sPreStmt.execute();

            sPreStmt.setString( 1, "Ryu" );
            sPreStmt.setString( 2, "Momoi" );
            sPreStmt.setInt(    3, 6 );
            sPreStmt.execute();

            sRS = sStmt.executeQuery( "SELECT EMP_FIRST, EMP_LAST," +
                                      " EMP_NO FROM TEST_EMP_TBL " );

            /* 결과를 받아 화면에 출력 */
            while( sRS.next() )
            {
                System.out.println( "  EmpName : " + sRS.getString(1) +
                                   " " + sRS.getString(2) );
                System.out.println( "  EmpNO   : " + sRS.getInt(3) );
            }

            /* 연결 해제 */
            sStmt.close();
            sPreStmt.close();
            sCon.close();
        }
        catch ( SQLException e )
        {
            System.out.println( "ERROR CODE    : " + e.getErrorCode() );
            System.out.println( "ERROR MESSAGE : " + e.getMessage() );
            e.printStackTrace();
        }
    }
}

실행결과#

$ javac SimpleSQL.java      
$ java SimpleSQL 20300
  EmpName : Susan Davenport
  EmpNO   : 2
  EmpName : Ken Kobain
  EmpNO   : 3
  EmpName : Aaron Foster
  EmpNO   : 4
  EmpName : Farhad Ghorbani
  EmpNO   : 5
  EmpName : Ryu Momoi
  EmpNO   : 6


C/C++ Precompiler를 활용한 프로그램#

C/C++ Precompiler는 내장 SQL문이 포함된 소스 프로그램을 입력으로 받아, 내장 SQL문들을 실행 시간 라이브러리 호출로 변환하여, 호스트 언어로 컴파일될 수 있는 수정된 소스 프로그램을 생성한다. 자세한 내용은 Precompiler User's Manual을 참조한다.

환경 설정#

C/C++ Precompiler로 전처리된 결과 파일을 컴파일 및 링크하기 위해서 필요한 환경 설정은 다음과 같다.

헤더파일#

전처리된 소스파일을 컴파일하는데 필요한 헤더파일은 ulpLibInterface.h 이며, $ALTIBASE_HOME/include 디렉토리에 있다.

전처리된 응용 프로그램을 컴파일하기 위해서 아래의 옵션을 사용하라:

-I$ALTIBASE_HOME/include

라이브러리#

필요한 라이브리는 libapre.a와 libodbccli.a이며, $ALTIBASE_HOME/lib 디렉토리에 있다.

전처리된 응용 프로그램을 링크하기 위해서 아래의 옵션을 사용하라:

-L$ALTIBASE_HOME/lib -lapre -lodbccli -lpthread

전처리 실행#

C/C++ Precompiler는 내장 SQL문을 포함하는 C 또는 C++로 작성된 프로그램을 전처리하여 변환된 C 또는 C++ 프로그램을 생성한다. 입력 파일은 .sc 확장자를 가지는 C 또는 C++로 작성된 프로그램이며, 출력 파일은 .c 또는 .cpp를 확장자를 가진다. 출력 파일의 확장자는 사용자가 지정할 수 있으며 기본적으로 .c이다.

실행 옵션#

다음은 apre의 도움말 출력 결과이다. apre에 사용할 수 있는 다양한 전처리 옵션을 보여준다.

$ apre -h
=====================================================================
APRE (Altibase Precompiler) C/C++ Precompiler HELP Screen
=====================================================================
Usage  :  apre [<options>] <filename>

-h               : Display this help information.
-t <c|cpp>       : Specify the file extension for the output file.
                   c   - File extension is '.c' (default)
                   cpp - File extension is '.cpp'
-o <output_path> : Specify the directory path for the output file.
                   (default : current directory)
-mt              : When precompiling a multithreaded application,
                   this option must be specified.
-I<include_path> : Specify the directory paths for files included using APRE C/C++.
                   (default : current directory)
-parse <none|partial|full>
                 : Control which non-SQL code is parsed.
-D<define_name>  : Use to define a preprocessor symbol.
-v               : Output the version of APRE.
-n               : Specify when CHAR variables are not null-padded.
-unsafe_null     : Specify to suppress errors when NULL values are fetched
                   and indicator variables are not used.
-align           : Specify when using alignment in AIX.
-spill <values>  : Specify the register allocation spill area size.
-keyword         : Display all reserved keywords.
-debug <macro|symbol>
                 : Use for debugging.
                   macro   - Display macro table.
                   symbol  - Display symbol table.
-nchar_var <variable_name_list>
                 : Process the specified variables using
                   the Altibase national character set.
-nchar_utf16     : Set client nchar encoding to UTF-16.
-lines           : Add #line directives to the generated code.
-silent          : No display Copyright

======================================================================

멀티 쓰레드 프로그램#

C/C++ Precompiler는 멀티 쓰레드 프로그램을 지원한다. 멀티 쓰레드 프로그래밍시 내장 SQL문 사용 방법 및 주의 사항에 대해 알아보기로 한다.

  • 전처리 시 멀티 쓰레드 프로그램의 판단 근거를 전처리기에게 옵션(-mt)으로 제공하여야 한다.

  • 각 쓰레드마다 각각의 연결(connection)이 있어야 한다. 즉, 여러 쓰레드가 하나의 연결을 공유할 수 없다.

  • 연결 이름을 가지지 않는 connection(즉, default connection)은 한 프로그램 내에 하나만 허용된다.

  • 내장 SQL문에서도 사용할 연결 이름을 명시하여야 한다.

프로그램 작성#

Precompiler 응용 프로그램의 예#

/******************************************************************
 * SAMPLE : DELETE
 *          1. Using scalar host variables
 *          2. Reference  : array host variables - arrays1.sc
 ******************************************************************/

int main()
{
    /* 호스트 변수 선언 */
    EXEC SQL BEGIN DECLARE SECTION;
    char usr[10];
    char pwd[10];
    char conn_opt[1024];

    /* 스칼라형 */
    int      s_eno;
    short    s_dno;
    EXEC SQL END DECLARE SECTION;

    printf("<DELETE>\n");

    /* 이름, 비밀번호, 옵션 설정 */
    /* set username */
    strcpy(usr, "SYS");
    /* set password */
    strcpy(pwd, "MANAGER");
    /* set various options */
    strcpy(conn_opt, "Server=127.0.0.1"); /* Port=20300 */

    /* Altibase 서버에 접속 */
    EXEC SQL CONNECT :usr IDENTIFIED BY :pwd USING :conn_opt;
    /* check sqlca.sqlcode */
    if (sqlca.sqlcode != SQL_SUCCESS)
    {
        printf("Error : [%d] %s\n\n", SQLCODE, sqlca.sqlerrm.sqlerrmc);
        exit(1);
    }

    /* 스칼라 호스트 변수 사용 */
    s_eno = 5;
    s_dno = 1000;

    EXEC SQL DELETE FROM EMPLOYEES
                    WHERE ENO > :s_eno AND DNO > :s_dno AND EMP_JOB LIKE 'P%';

    printf("------------------------------------------------------------------\n");
    printf("[Scalar Host Variables]\n");
    printf("------------------------------------------------------------------\n");

    /* sqlca.sqlcode 검사 */
    if (sqlca.sqlcode == SQL_SUCCESS)
    {
        /* sqlca.sqlerrd[2] holds the rows-processed(deleted) count */
        printf("%d rows deleted\n\n", sqlca.sqlerrd[2]);
    }
    else
    {
        printf("Error : [%d] %s\n\n", SQLCODE, sqlca.sqlerrm.sqlerrmc);
    }

    /* 접속 해제 */
    EXEC SQL DISCONNECT;
    /* check sqlca.sqlcode */
    if (sqlca.sqlcode != SQL_SUCCESS)
    {
        printf("Error : [%d] %s\n\n", SQLCODE, sqlca.sqlerrm.sqlerrmc);
    }
}

실행결과#

$ make delete

$ ./delete
<DELETE>
------------------------------------------------------------------
[Scalar Host Variables]
------------------------------------------------------------------
3 rows deleted