콘텐츠로 이동

부록 B. Pro*C에서 APRE로 변환#

이 부록은 오라클의 Pro*C(C++)로 작성된 응용 프로그램을 Altibase C/C++ Precompiler 응용 프로그램으로 전환할 때 참조한다.

데이터 타입 비교#

오라클에서 사용되는 데이터 타입과 여기에 대응되는 Altibase의 데이터 타입의 종류를 설명한다.

ODBC SQL data type 오라클 Altibase 비 고
SQL_CHAR CHAR CHAR 1-32000 length
SQL_TIMESTAMP DATE DATE
SQL_LONGVARCHAR LONG BLOB 2147483647 바이트까지 가능
SQL_INTEGER INT INTEGER
SQL_FLOAT NUMBER NUMBER
SQL_DECIMAL NUMBER(P) NUMBER(P) 1-38
SQL_DECIMAL NUMBER(P,S) NUMBER(P,S) precision : 1-38 scale : -84 - 126
SQL_BINARY RAW HSS_BYTES 1-32000
SQL_VARCHAR VARCHAR VARCHAR max 32000 bytes
SQL_VARCHAR VARCHAR2 VARCHAR max 32000 bytes

내장 함수 비교#

오라클과 마찬가지로 Altibase 역시 숫자함수, 날짜함수, 문자열함수, 데이터 타입 변환함수 및 기타 내장함수(Built-in function)를 제공한다. 오라클에 대응하는 Altibase의 데이터 타입 변환 함수와 내장 함수를 설명한다.

오라클에서 사용되는 함수의 이름, 용도, 사용법이 유사하다.

Altibase에서 지원하는 함수의 종류는 다음과 같다.

  • 숫자 함수:
    ABS, ACOS, ASIN, ATAN, ATAN2, CEIL, COS, COSH, EXP, FLOOR, ISNUMERIC, LN, LOG, MOD, POWER, RANDOM, ROUND, SIGN, SIN, SINH, SQRT, TAN, TANH, TRUNC, BITTAND, BITOR, BITXOR, BITNOT
  • 그룹 함수:
    AVG, COUNT, GROUP_CONCAT, LISTAGG, MAX, MIN, PERCENTILE_CONT, PERCENTILE_DISC, STATS_ONE_WAY_ANOVA, STDDEV, STDDEV_POP, STDDEV_SAMP, SUM, VARIANCE, VAR_POP, VAR_SAMP
  • 문자열 함수:
    ASCII, CHAR_LENGTH, CHOSUNG, CHR, CONCAT, DIGITS, INITCAP, INSTR, INSTRB, POSITION, LOWER, LPAD, LTRIM, NCHR, OCTET_LENGTH, PKCS7PAD16, PKCS7UNPAD16, RANDOM_STRING, REGEXP_COUNT, REGEXP_INSTR, REGEXP_SUBSTR, REPLACE2, REVERSE_STR, RPAD, RTRIM, SIZEOF, SUBSTR, TRANSLATE, TRIM, UPPER, REPLICATE, REVERSE_STR, STUFF, UPPER
  • 날짜 함수:
    ADD_MONTHS, CURRENT_DATE, CURRENT_TIMESTAMP, CONV_TIMEZONE, DATEADD, DATEDIFF, DATENAME, DB_TIMEZONE, EXTRACT, LAST_DAY, MONTHS_BETWEEN, ROUND, NEXT_DAY, SESSION_TIMEZONE, SYSDATE, SYSTIMESTAMP, TRUNC, UNIX_DATE, UNIX_TIMESTAMP
  • 데이터 타입 변환 함수:
    ASCIISTR, BIN_TO_NUM, CONVERT, DATE_TO_UNIX, HEX_ENCODE, HEX_DECODE, HEX_TO_NUM, OCT_TO_NUM, TO_BIN, TO_CHAR, TO_DATE, TO_HEX, TO_NCHAR, TO_NUMBER, TO_OCT, TO_RAW, UNISTR, UNIX_TO_DATE
  • 암호화 함수:
    AESDECRYPT, AESENCRYPT, DESENCRYPT, DESDECRYPT, TDESDECRYPT/TRIPLE_DESDECRYPT,TDESENCRYPT/TRIPLE_DESENCRYPT
  • 윈도우 함수:
    AVG, COUNT, LISTAGG, MAX, MIN, PERCENTILE_CONT, PERCENTILE_DISC, STDDEV, SUM, VARIANCE, GROUP_CONCAT, RANK, DENSE_RANK, ROW_NUMBER, LAG, LEAD, FIRST_VALUE, LAST_VALUE, NTH_VALUE
  • 기타 함수:
    BINARY_LENGTH, CASE2, CASE_WHEN, COALESCE, DECODE, DIGEST, DUMP, GREATEST, GROUPING, GROUPING_ID, HOST_NAME, LEAST, LNNVL, NULLIF, NVL, NVL2, RAW_SIZEOF, RAW_CONCAT, ROWNUM, NVL, NVL2, SENDMSG, SUBRAW, SYS_CONNECT_BY_PATH, USER_ID, USER_NAME, SESSION_ID

함수들에 대한 보다 자세한 설명은 SQL Reference을 참조한다.

데이터베이스 연결/해제#

오라클과 Altibase에 연결하고 해제하는 방법을 비교 설명한다.

데이터베이스 연결#

오라클과 Altibase의 default connection 문법은 동일하며 connection name을 부여하여 multi connection도 가능하다. 오라클과 마찬가지로 USING을 사용하여 연결 옵션을 설정할 수 있다.

Connect Statement#

  • 오라클

    EXEC SQL CONNECT {:user IDENTIFIED BY :oldpswd :usr_psw } 
    [[ AT { dbname | :host_variable }] USING :connect_string ];
    
  • Altibase

     EXEC SQL [AT {conn_name | :conn_name}] 
    CONNECT <:user> IDENTIFIED BY <:passwd>
     [USING <:conn_opt>[,<:conn_opt2>]];
    

Default Connection 연결 예제#

  • 오라클

    char *username = "SCOTT";
    char *password = "TIGER";
    char *connstr = "ORA817";
    EXEC SQL WHENEVER SQLERROR
    .
    .
    .
    EXEC SQL CONNECT :username IDENTIFIED BY :password 
    USING :connstr;
    
  • Altibase

    strcpy(username, "SYS");
    strcpy(password, "MANAGER");
    strcpy(connstr,"DSN=192.168.1.2;PORTNO=20310;CONNTYPE=3");
    EXEC SQL CONNECT :username IDENTIFIED BY :password 
    USING :connstr;
    
  • USING 절이 없을 경우 응용프로그램이 수행되는 시스템의 Altibase로 연결하게 된다.

Named Connection 연결 예제#

  • 오라클

    char *username = "SCOTT";
    char *password = "TIGER";
    char *connstr = "ORA817";
    EXEC SQL WHENEVER SQLERROR 
    .
    .
    .
    EXEC SQL CONNECT :username IDENTIFIED BY :password
    AT :db_name USING :connstr;
    
  • Altibase

    strcpy(user2, "ALTIBASE");
    strcpy(passwd2, "ALTIBASE");
    strcpy(conn_name, "CONN2");
    strcpy(connstr,"DSN=192.168.1.12;PORTNO=20310;CONNTYPE=1");
    EXEC SQL AT :conn_name CONNECT :user2 IDENTIFIED BY :passwd2
    USING :connstr;
    

데이터베이스 연결 해제#

오라클은 롤백을 실행하면서 연결 해제를 실행하는 하나의 문장(EXEC SQL ROLLBACK WORK RELEASE )은 지원한다.

Altibase도 이 문장을 지원한다.

Disconnect Statement#

  • 오라클

    EXEC SQL COMMIT WORK RELEASE;
    
    또는
    EXEC SQL ROLLBACK  WORK RELEASE;
    

  • Altibase

    EXEC SQL COMMIT WORK RELEASE;
    
    또는
    EXEC SQL ROLLBACK  WORK RELEASE;
    

호스트 변수#

오라클의 Pro*C와 Altibase의 Precompiler에서 사용되는 호스트 변수(Host Variables)를 비교하고 차이점을 설명한다.

호스트 변수 타입 비교#

오라클 Altibase 비 고
Database Column type Host Variable C type Database Column type Host Variable C type
CHAR char CHAR char/char[2] single character
VARCHAR2(X) VARCHAR(X) VARCHAR[X] VARCHAR VARCHAR n-byte variable-length character array
CHAR[X] char[x] CHAR[X] char[x] n-byte character array
NUMBER int NUMBER/ INTEGER int/ APRE _INT integer
NUMBER(P,S) short int long float double NUMBER(P,S) short int/APRE_INTEGER long float double small integer integer large integer float-point number double-precision floating-point number
DATE char[n] varchar[n] DATE char[n] varchar[n] n >= 20

호스트 변수 선언부#

선언부의 구문은 오라클과 Altibase가 같은 형식이다.

  • 오라클

    EXEC SQL BEGIN DECLARE SECTION;
    /* 호스트 변수 선언 */
    EXEC SQL END DECLARE SECTION;
    
  • Altibase

    EXEC SQL BEGIN DECLARE SECTION;
    /* 호스트 변수 선언 */
    EXEC SQL END DECLARE SECTION;
    

내장 SQL 문#

Altibase Precompiler와 오라클 Pro*C의 기본 SQL(SELECT, UPDATE, INSERT, DELETE)과 커서 처리 SQL 문, 동적 SQL 문을 비교 설명한다.

기본 DML 문#

Select, Insert, Update, Delete 모두 오라클과 Altibase에서의 사용 방법이 동일하다.

커서 처리 SQL 문#

기본적인 커서의 선언 방법은 오라클과 Altibase에서 동일하다. 다만, Altibase는 오라클처럼 커서 이름에 호스트 변수를 사용하는 방법을 지원하지 않는다.

커서 선언#

  • 오라클

    EXEC SQL DECLARE cur_emp CURSOR FOR 
    SELECT ename, job, sal 
    FROM emp;
    
  • Altibase

    EXEC SQL DECLARE cur_emp CURSOR FOR
    SELECT ename, job, sal 
    FROM emp;
    

커서의 Open 과 fetch#

커서의 open과 fetch는 오라클과 동일하다. 오라클과 Altibase 간의 에러 코드의 종류와 값이 다르므로 FETCH 문 안에서의 에러 처리 코드는 변경되어야 한다. 실행 시간 에러 처리를 위한 WHENEVER 문인 EXEC SQL WHENEVER NOT FOUND DO BREAK; 는 오라클과 동일한 사용법으로 지원한다.

  • 오라클

    EXEC SQL OPEN cur_emp;
    if(sqlca.sqlcode != SQL_OK ) {
    fprintf(stderr, "OPEN CSR ERROR%d\n",sqlca.sqlcode);
       close_db();
       exit(0);
    }
    for(;;)
    {
    EXEC SQL FETCH cur_emp 
     INTO :emp_name, :job_title, :salary;    
       switch(sqlca.sqlcode)
       {
            case 0:
                    printf("emp_name : %s\n", emp_name);
                    continue;
            case 1403:      /* Not Found Data */
                    break;
            default :
                    fprintf(stderr, "FETCH CSR ERROR %d",sqlca.sqlcode);
                    close_db();
                    exit(0);
       }
    }
    
  • Altibase

    EXEC SQL OPEN cur_emp;
    if(sqlca.sqlcode != SQL_SUCCESS ) {
        fprintf(stderr, "OPEN CSR ERROR %d\n",sqlca.sqlcode);
        close_db();
        exit(0);
    }
    for(;;)
    {
        EXEC SQL  FETCH  cur_emp INTO :emp_name, :job_title, :salary;    
        switch(sqlca.sqlcode)
        {
            case SQL_SUCCESS:
                    printf("emp_name : %s\n", emp_name);
                    continue;
            case SQL_NO_DATA:      /* Not Found Data */
                    break;
            default :
                    fprintf(stderr, "FETCH CSR ERROR %d",sqlca.sqlcode);
                    close_db();
                    exit(0);
        }
    }
    

커서 Close#

커서 close문은 오라클 Pro*C 와 Altibase Precompiler는 동일하다.

  • 오라클

    EXEC SQL CLOSE cur_emp;
    
  • Altibase

    EXEC SQL CLOSE cur_emp;
    

Dynamic SQL 문#

Altibase는 메소드 1, 메소드 2, 메소드 3, 메소드 4 형식을 지원한다.

오라클은 파라미터 마커(parameter marker)로서 ":v[1…n]"와 물음표("?")를 사용할 수 있다. Altibase는 물음표("?")만을 지원한다.

메소드 1#

  • 오라클

    char dynstmt1[80];    
    strcpy(dynstmt1, "DROP TABLE EMP" );
    EXEC SQL EXECUTE IMMEDIATE :dynstmt1;
    
  • Altibase

    EXEC SQL BEGIN DECLARE SECTION;
    char dynstmt1[80];
    EXEC SQL END DECLARE SECTION;    
    strcpy(dynstmt1, "DROP TABLE EMP" );
    EXEC SQL EXECUTE IMMEDIATE :dynstmt1;
    

메소드 2#

  • 오라클

    int emp_number;
    char delete_stmt[120];
    .
    .
    .
    strcpy(delete_stmt, "DELETE FROM EMP WHERE EMPNO = :v1");
    EXEC SQL PREPARE sql_stmt FROM :delete_stmt;
    emp_number = 10;
    EXEC SQL EXECUTE sql_stmt USING :emp_number;
    
  • Altibase

    EXEC SQL BEGIN DECLARE SECTION;
    int emp_number;
    char delete_stmt[120];
    EXEC SQL END DECLARE SECTION;
    .
    .
    .
    strcpy(delete_stmt, "DELETE FROM EMP WHERE EMPNO = ?");
    
    EXEC SQL PREPARE sql_stmt FROM :delete_stmt;
    emp_number = 10;
    
    EXEC SQL EXECUTE sql_stmt USING :emp_number;
    

메소드 3#

  • 오라클

    char sql_query[80];
    int  deptno = 10;
    char ename[10];
    strcpy(sql_query,"SELECT ename FROM emp WHERE deptno > :v1");
    EXEC SQL PREPARE S FROM : sql_query;
    EXEC SQL DECLARE C CURSOR FOR S;
    EXEC SQL OPEN C USING :deptno;
    for (;;)
    {
        EXEC SQL FETCH C INTO :ename;
        .
        .
        .
    }
    
  • Altibase

    EXEC SQL BEGIN DECLARE SECTION;
    char sql_query[80];
    int  deptno = 10;
    char ename[10];
    EXEC SQL END DECLARE SECTION;
    strcpy(sql_query,"SELECT ename FROM emp WHERE deptno > ? ");
    EXEC SQL PREPARE S FROM : sql_query;
    EXEC SQL DECLARE C CURSOR FOR S;
    EXEC SQL OPEN C USING :deptno;
    for (;;)
    {
        EXEC SQL FETCH C INTO :ename;
        .
        .
        .
    }
    

메소드 4#

  • 오라클

    #define MAX_COLUMN_SIZE 30
    
    char name[10];
    int number;
    
    short ind_number;
    
    char *sql_stmt = "INSERT INTO emp (empno, ename) VALUES(:e, :n);
    SQLDA *binda;
    .
    .
    .
    binda = SQLSQLDAAlloc(SQL_SINGLE_RCTX, MAX_COLUMN_SIZE, 10, 10);
    binda->N = MAX_COLUMN_SIZE;
    
    EXEC SQL PREPARE stmt FROM :sql_stmt;
    EXEC SQL DESCRIBE BIND VARIABLES FOR stmt INTO binda;
    binda->N = binda->F;
    
    binda->V[0] = (char*)&number;
    binda->L[0] = (long)sizeof(int);
    binda->T[0] = 3;
    binda->I[0] = &ind_number;
    
    binda->V[1] = (char*) name;
    binda->L[1] = (long) 10;
    binda->T[1] = 1;
    binda->I[1] = (short*)0;
    .
    .
    .
    number = 1024;
    strcpy(name, "ALLISON");
    ind_number = 0;
    
    EXECUTE stmt USING DESCRIPTOR binda;
    
  • Altibase

    #define MAX_COLUMN_SIZE 30
    
    EXEC SQL BEGIN DECLARE SECTION;
    char *sql_stmt = "INSERT INTO emp VALUES(?,?)";
    SQLDA *binda;
    EXEC SQL END DECLARE SECTION;
    
    int number;
    char name[10];
    
    short ind_name;
    
    binda = (SQLDA*) SQLSQLDAAlloc( MAX_COLUMN_SIZE );
    
    EXEC SQL PREPARE stmt FROM :sql_stmt;
    
    EXEC SQL DESCRIBE BIND VARIABLES FOR stmt INTO :binda;
    binda->N = binda->F;
    
    binda->V[0] = (char*)&number;
    binda->L[0] = sizeof(int);
    bidna->T[0] = SQLDA_TYPE_SINT;
    binda->I[0] = NULL;
    
    binda->V[1] = (char*)name;
    binda->L[1] = 10;
    binda->T[1] = SQLDA_TYPE_CHAR;
    binda->I[1] = (short*)&ind_name;
    
    number = 1024;
    strcpy(name, "ALLISON");
    ind_name = strlen(name);
    
    EXEC SQL EXECUTE stmt USING DESCRIPTOR :binda;
    

수행 결과 및 상태 코드#

오라클과 Altibase의 실행 시간 에러 처리를 위한 SQLSTATE, SQLCODE, SQLCA 값의 차이점을 비교한다.

SQLCA#

내장 SQL 문의 수행 결과를 저장하는 구조체이다. Altibase가 지원하는 구성 요소는 sqlcode, sqlerrm.sqlerrmc, sqlerrm.sqlerrml, sqlerrd[2]이며, 오라클의 SQLCA에만 존재하고 Altibase에서 지원하지 않는 sqlwarn 같은 구성 요소는 사용할 수 없다.

SQLCA의 선언#

  • 오라클

    EXEC SQL INCLUDE SQLCA;
    
    또는
    #include <sqlca.h>
    

  • Altibase
    별도의 선언 없이 사용할 수 있다.

sqlca.sqlcode 상태값#

  • 오라클

    Status Code Description
    0 Success
    >0 No rows returned
    <0 database, system, network , application error
  • Altibase

    Status Code Description
    SQL_SUCCESS Success
    SQL_SUCCESS_WITH_INFO
    SQL_NO_DATA No rows returned
    SQL_ERROR
    SQL_INVALID_HANDLE

sqlca.sqlerrm#

오라클과 Altibase에서 sqlerrmc, sqlerrml은 용도와 사용법이 동일하다.

sqlca.sqlerrd[2]#

  • 오라클
    INSERT, UPDATE, DELETE 또는 SELECT 연산에 의해 영향 받은 레코드 개수로 이 값은 누적된다.

  • Altibase
    INSERT, UPDATE 또는 DELETE 연산에 의해 영향 받은 레코드 개수로 누적되지 않는다.
    배열인 출력 호스트 변수를 사용하여 SELECT 문이나 FETCH 문 수행 시 반환되는 레코드 개수이다.

SQLSTATE#

SQLSTATE에는 상태 코드가 저장되며 이 상태 코드를 통해 에러와 예외 상황의 종류를 알 수 있다.

SQLSTATE의 선언과 사용#

  • 오라클
    SQLSTATE를 아래와 같이 선언하고, 전처리기의 명령행 옵션으로 MODE=ANSI를 명시해야 한다.

    char SQLSTATE[6];
    
  • Altibase

    별도의 선언 없이 사용할 수 있다.

SQLSTATE의 상태 코드#

오라클과 Altibase의 SQLSTATE 상태 코드는 그 의미와 코드값이 다르므로, 8장의 상태 코드 테이블과 ODBC 코드 테이블을 참조하여 변환해야 한다.

SQLCODE#

SQLCODE에는 내장 SQL 문 수행 후 에러 코드가 저장된다.

SQLCODE의 선언과 사용#

  • 오라클
    SQLCODE를 아래와 같이 선언하고, 전처리기의 명령행 옵션으로 MODE=ANSI를 명시해야 한다.

    long SQLCODE;
    
  • Altibase
    별도의 선언 없이 사용할 수 있다.
    Altibase에서의 SQLCODE의 자료형은 int 형이다.

SQLCODE의 상태코드값#

  • 오라클
    sqlca.sqlcode와 동일한 상태 코드 값이 저장된다.

  • Altibase

    상태 코드 설명
    0 내장 SQL 문을 성공적으로 수행한 경우. 즉, sqlca.sqlcode 값이 SQL_SUCCESS 인 경우
    1 내장 SQL 문을 수행하였으나 예외 상황이 발견된 경우. 즉, sqlca.sqlcode 값이 SQL_SUCCESS_WITH_INFO 인 경우
    100 SELECT 문이나 FETCH 문 수행 후 반환되는 레코드가 없는 경우. 즉, sqlca.sqlcode 값이 SQL_NO_DATA인 경우
    -1 내장 SQL 문 수행 시 에러가 발생하였지만 해당 에러코드가 없는 경우. 이 때의 sqlca.sqlcode 값은 SQL_ERROR 이다.
    -2 데이터베이스 서버와 연결하지 않고 내장 SQL 문을 수행한 경우. 즉, sqlca.sqlcode 값이 SQL_INVALID_HANDLE 인 경우
    • 위의 값 이외의 값이 SQLCODE에 설정되는 경우는 에러 메시지가 있는 경우로서 해당 SQL에서 에러가 발생한 경우이다.

기타 차이점#

Altibase와 오라클의 커밋 모드 변경 방법, 기본 커밋 모드, 커밋 방법의 차이점을 설명한다.

기본 커밋 모드#

오라클 Altibase
Non-Autocommit mode Autocommit mode

커밋 모드 변경#

  • 오라클

    EXEC SQL ALTER SESSION SET AUTOCOMMIT = TRUE
    
    또는
    EXEC SQL ALTER SESSION SET AUTOCOMMIT = FALSE
    

  • Altibase

    EXEC SQL AUTOCOMMIT ON
    
    또는
    EXEC SQL ALTER SESSION SET AUTOCOMMIT = TRUE
    
    또는
    EXEC SQL ALTER SESSION SET AUTOCOMMIT = FALSE
    

명시적 커밋#

  • 오라클

    EXEC SQL COMMIT;
    
    또는
    EXEC SQL COMMIT WORK;
    

  • Altibase

    EXEC SQL COMMIT;
    

예제 프로그램#

앞서 기술된 내용이 담긴 예제 프로그램이다.

오라클#

#include <stdio.h>
#include <stdlib.h>

EXEC SQL include sqlca.h;

EXEC SQL BEGIN DECLARE SECTION;
char    emp_name[21];
char    job_title[21];
int     salary;
int     emp_number;
EXEC SQL END DECLARE SECTION;

char uid[10] = "SCOTT";
char pwd[10] = "TIGER";

int main(void)
{
  int  dynamic_emp_number;
  char dynamic_stmt[120];

  EXEC SQL CONNECT :uid IDENTIFIED BY :pwd;
  if ( sqlca.sqlcode != 0 ) {
       fprintf(stderr, "DataBase Connect Error : [%d]!!!", sqlca.sqlcode);
       exit(-1);
  }

  /* INSERT */
  /* value setting */
  emp_number = 10;
  strcpy(emp_name,  "oracle1");
  strcpy(job_title, "oracle dba1");
  salary    = 10000;

  /* INSERT  DML */
  EXEC SQL INSERT INTO emp (empno, ename, job, sal) 
                  VALUES (:emp_number, :emp_name, :job_title, :salary);
  if ( sqlca.sqlcode != 0 ) {
       fprintf(stderr, "DataBase Connect Error : [%d]!!!", sqlca.sqlcode);
       exit(-1);
  }

  emp_number = 20;
  strcpy(emp_name,  "oracle2");
  strcpy(job_title, "oracle dba2");
  salary    = 10000;

  EXEC SQL INSERT INTO emp (empno, ename, job, sal) 
                  VALUES (:emp_number, :emp_name, :job_title, :salary);

  if ( sqlca.sqlcode != 0 ) {
       fprintf(stderr, "Insert Error : [%d]!!!", sqlca.sqlcode);
       exit(-1);
  }

  /* SELECT DML */
  emp_number = 10;
  EXEC SQL SELECT ename, job, sal INTO :emp_name, :job_title, :salary
           FROM emp
           WHERE empno = :emp_number;
  if ( sqlca.sqlcode != 0 ) {
       fprintf(stderr, "Select Error : [%d]!!!", sqlca.sqlcode);
       exit(-1);
  }
  printf(" SELECT result : ename=[%s], job=[%s], sal=[%d]\n", 
                            emp_name, job_title, salary);

  /* UPDATE DML */
  emp_number = 10;
  salary     = 2000;  
  EXEC SQL UPDATE emp SET sal = :salary WHERE empno = :emp_number;
  if ( sqlca.sqlcode != 0 ) {
       fprintf(stderr, "Update Error : [%d]!!!", sqlca.sqlcode);
       exit(-1);
  }

  /* Cursor  Create */
  EXEC SQL DECLARE cur_emp CURSOR FOR
                   SELECT ename, job, sal FROM   emp;

  /* Cursor Open */
  EXEC SQL  OPEN  cur_emp;
  if(sqlca.sqlcode != 0 ) {
       fprintf(stderr, "OPEN CSR ERROR %d\n",sqlca.sqlcode);
       exit(-1);
  }

  /* Fetch Cursor */ 
  for(;;)
  {
     EXEC SQL  FETCH  cur_emp INTO :emp_name, :job_title, :salary;

     switch(sqlca.sqlcode)
     {
        case 0:
                printf("Fetch Result : emp_name[%s], job[%s], sal=[%d]\n", 
                                        emp_name, job_title, salary );
                continue;
        case 1403:      /* Not Found Data */
                break;
        default :
                fprintf(stderr, "FETCH CSR ERROR %d",sqlca.sqlcode);
                exit(-1);
     }
     break;
   }

  /* Cursor Close */
  EXEC SQL CLOSE cur_emp; 

  /* Dynamic SQL */
  strcpy(dynamic_stmt, "DELETE FROM EMP WHERE EMPNO = :v1");
  EXEC SQL PREPARE sql_stmt FROM :dynamic_stmt;
  dynamic_emp_number = 10;
  EXEC SQL EXECUTE sql_stmt USING :dynamic_emp_number;

  /* Disconnect */
  EXEC SQL COMMIT WORK RELEASE;

  exit(0);
}

Altibase#

#include <stdio.h>
#include <stdlib.h>

EXEC SQL BEGIN DECLARE SECTION;
char    emp_name[21];
char    job_title[21];
int     salary;
int     emp_number;
char    uid[10];
char    pwd[10];
char    dynamic_stmt[120];
int     dynamic_emp_number;
EXEC SQL END DECLARE SECTION;

int main(void)
{
  strcpy(uid, "SYS" );
  strcpy(pwd, "MANAGER");

  EXEC SQL CONNECT :uid IDENTIFIED BY :pwd;
  if ( sqlca.sqlcode != SQL_SUCCESS ) {
       fprintf(stderr, "DataBase Connect Error : [%d]!!!", sqlca.sqlcode);
       exit(-1);
  }

  /* INSERT */
  /* value setting */
  emp_number = 10;
  strcpy(emp_name,  "altibase1");
  strcpy(job_title, "dba1");
  salary    = 10000;
  /* INSERT  DML */
  EXEC SQL INSERT INTO emp (empno, ename, job, sal) 
                  VALUES (:emp_number, :emp_name, :job_title, :salary);
  if ( sqlca.sqlcode != SQL_SUCCESS ) {
       fprintf(stderr, "DataBase Connect Error : [%d]!!!", sqlca.sqlcode);
       exit(-1);
  }

  emp_number = 20;
  strcpy(emp_name,  "altibase2");
  strcpy(job_title, "dba2");
  salary    = 20000;
  EXEC SQL INSERT INTO emp (empno, ename, job, sal) 
                  VALUES (:emp_number, :emp_name, :job_title, :salary);


  /* SELECT DML */
  emp_number = 10;
  EXEC SQL SELECT ename, job, sal INTO :emp_name, :job_title, :salary
           FROM emp
           WHERE empno = :emp_number;
  if ( sqlca.sqlcode != SQL_SUCCESS ) {
       fprintf(stderr, "Select Error : [%d]!!!", sqlca.sqlcode);
       exit(-1);
  }
  printf(" SELECT result : ename=[%s], job=[%s], sal=[%d]\n", 
                            emp_name, job_title, salary);

  /* UPDATE DML */
  emp_number = 10;
  salary     = 2000;  
  EXEC SQL UPDATE emp SET sal = :salary WHERE empno = :emp_number;
  if ( sqlca.sqlcode != SQL_SUCCESS ) {
       fprintf(stderr, "Update Error : [%d]!!!", sqlca.sqlcode);
       exit(-1);
  }

  /* Cursor  Create */
  EXEC SQL DECLARE cur_emp CURSOR FOR
                   SELECT ename, job, sal FROM   emp;

  /* Cursor Open */
  EXEC SQL  OPEN  cur_emp;
  if(sqlca.sqlcode != SQL_SUCCESS ) {
       fprintf(stderr, "OPEN CSR ERROR %d\n",sqlca.sqlcode);
       exit(-1);
  }

  /* Fetch Cursor */ 
  for(;;)
  {
     EXEC SQL  FETCH  cur_emp INTO :emp_name, :job_title, :salary;

     switch(sqlca.sqlcode)
     {
        case SQL_SUCCESS:
                printf("Fetch Result : emp_name[%s], job[%s], sal=[%d]\n", 
                                        emp_name, job_title, salary );
                continue;
        case SQL_NO_DATA:      /* Not Found Data */
                break;
        default :
                fprintf(stderr, "FETCH CSR ERROR %d %s\n",
                            sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
                exit(-1);
     }
     break;
   }

  /* Cursor Close */
  EXEC SQL CLOSE cur_emp;


  /* Dynamic SQL */
  strcpy(dynamic_stmt, "DELETE FROM EMP WHERE EMPNO = ?");

  EXEC SQL PREPARE sql_stmt FROM :dynamic_stmt;
  dynamic_emp_number = 10;

  EXEC SQL EXECUTE sql_stmt USING :dynamic_emp_number;


  /* Disconnect */
  EXEC SQL DISCONNECT;

exit(0);
}