- 개요
- Altibase 개발을 위한 기본 고려사항
- APRE 기본 사용방법
- APRE 예제 프로그램
- 자주 발생하는 오류 메세지
- Connection does not exist. (SQLCODE=–2)
- String data right truncated. (SQLCODE=1)
- Invalid size of data to bind to a host variable [ Column ID = <A%d>, Data Size = <B%d> , Declared Size of Host Variable = <C%d> ] (SQLCODE=-201144 or -266423)
- Calculation stack overflow (SQLCODE=-135187 or -659475)
- Value overflow or Numeric value out of range (SQLCODE=-135184 or -659472 or -331890)
- Conversion not applicable (SQLCODE=-135180 or -659468)
- Invalid length of the data type (SQLCODE=-135181 or -659469)
- Invalid literal (SQLCODE=-135185 or -659473)
- Invalid character value for cast specification (SQLCODE=-331893)
- Invalid cursor state. (SQLCODE=-331822) or Function sequence error (SQLCODE= -331796)
- The cursor must be opened for fetch (SQLCODE=-1) or The cursor does not exist (SQLCODE=-589857)
- Not enough insert values (SQLCODE=-200787)
- The tablespace does not have enough free space (SQLCODE=-69685 or -69923)
- Input literal is not long enough for date format. (SQLCODE=-135218)
- Literals in the input do not match format string. (SQLCODE=-135224)
- The transaction is already active. (SQLCODE=-266311 or -266312)
- The row already exists in a unique index. (SQLCODE=-69720)
- Unable to insert (or update) NULL into NOT NULL column. (SQLCODE=- 200790)
- Indicator variable required but not supplied. (SQLCODE=-331841 or -594101 or 594103)
- Client's query exceeded in the execution time limitation. (SQLCODE=-4164)
- Communication link failure. (SQLCODE=-331843 or -331855)
- 타 DBMS에서 변환 시 고려사항
개요
본 문서는 ALTIBASE Precompiler인 APRE*C/C++를 이용하여 DBMS 응용 프로그램을 개발하는 개발자를 위한 문서이다. 여기서는 ALTIBASE를 이용한 가장 적합한 개발방법 등을 소개하며 본 문서에 소개된 여러 섹션들을 참고하여 타 DBMS로부터의 소스 변환 작업에도 참고하도록 한다. 자세한 개발자 문서는 매뉴얼을 참고하도록 한다.
아래 문서들을 사전에 읽어 볼 것을 권장한다.
- 효율적인 ALTIBASE 이중화 구성 가이드
- ALTIBASE 이중화 제약사항 가이드
- APRE*C/C++ New Features & 업그레이드 가이드
- ALTIBASE APRE(SES)*C/C++ makefile
본 문서의 테스트 환경은 다음과 같다.
- ALTIBASE : Altibase 6 이상 버전
- OS : Linux ( 2.6.32-504.el6.x86_64 )
Altibase 개발을 위한 기본 고려사항
Altibase Precompiler를 통해 개발할 경우 사전에 고려할 사항을 설명한다. 이 부분에서는 성능, 쓰레드 및 지원되지 않는 사항을 먼저 언급함으로써 프로그램을 개발하는데 참고하도록 한다.
성능을 고려한 사항
개발자는 최소한 다음 2가지를 성능과 관련해 고려하도록 해야 한다.
매번 Prepare/Execute 또는 Direct-Execute방식의 최소화
수행 형태
단순 Insert 성능 (2.4GHz / 8EA)
매번 Prepare/Execute
0.0008.43sec (1건당 처리 시간)
1회 Prepare/매번 Execute
0.0005.55sec (1건당 처리 시간)
위의 성능 비교는 매우 단순한 Insert를 대상으로 한 성능임으로 실제로 적용 시점에서는 쿼리의 복잡도나 부하 및 장비마다 성능 개선 효과는 다를 수 있음을 전제해야 한다. 하지만, 매번 DBMS와 Prepare로 인한 통신 비용을 줄일 경우 어플리케이션 서버가 DBMS서버와 별도로 분리된 구조에서는 매우 큰 효과를 볼 수 있다. 즉, prepare 1번과 execute 1번의 통신 비용에서 1번의 prepare통신 비용을 줄이는 효과를 기대하는 것이다.
SQL문의 실행계획(PLAN) 확인
ALTIBASE는 다음 명령으로 실행계획을 확인할 수 있다."iSQL" 란 프롬프트는 Altibase가 제공하는 SQL문 실행 유틸리티에서 수행되는 것을 의미하며 이 유틸리티는 $ALTIBASE_HOME/bin/isql 로 제공된다. (이 외에도 윈도우 환경에서는 Altibase가 제공하는 웨어밸리사의 "Orange for Altibase" 및 Opensource "DBeaver"를 사용할 수 있다.)
위와 같은 명령을 수행한 후 질의 처리기에서 질의를 수행하게 되면 해당 질의의 실행계획이 표시된다.개발자는 최소한 테이블이 어떤 인덱스(INDEX)를 접근하게 되고 해당 인덱스에서 몇 번의 접근(ACCESS)을 통해 데이터를 가져오는지 확인하여 접근 횟수의 비용을 줄이는 형태로 SQL문을 튜닝 할 필요가 있다. Altibase의 메모리DB는 디스크I/O를 거의 하지 않기 때문에 풀스캔을 하더라도 일정 부분 빠른 성능을 낼 수 있으나 반대로 불필요하게 빈번한 메모리의 접근은 잦은 시스템 콜을 유발하여 상대적으로 CPU 부하를 일으키게 된다. 즉, CPU가 연산할 수 있는 공간인 캐쉬에 메모리의 공간을 적재하는 과정이 빈번하게 발생하는 만큼의 CPU비용을 감당해야 한다는 것이다. 따라서, 적절한 인덱스 스캔을 통해 이러한 비용을 줄이면 성능의 최대화 및 CPU 부하의 최소화라는 효과를 거둘 수 있음을 고려해야 한다.
쓰레드를 고려한 사항
Altibase는 연결 객체에 대해 쓰레드간 보호를 보장하지 않는다. 즉, 하나의 커넥션을 가지고 동시에 접근하여 질의를 수행하는 경우 알 수 없는 오류가 발생하게 된다. 따라서, 개별 쓰레드 별로 연결 객체를 가져가는 형태로 개발을 하거나 또는 하나의 연결을 다수의 쓰레드가 접근해야 한다면 반드시 사용자가 연결 객체에 대한 동시성 제어를 수행해야 한다. 이와 같은 동시성 제어를 하지 않을 경우 다음과 같은 오류들이 발생할 수 있다.
호스트 변수의 고려사항
Altibase의 호스트 변수 선언 시 char형 호스트 변수 크기를 지정할 때에는 반드시 null-padding을 고려한 "+1byte"를 추가해야 한다. Precompiler의 옵션에서는 "-n" 옵션을 통해 +1byte를 생략할 수 있으나 이 경우 사용자가 char형 호스트 변수에 대한 명확한 길이를 제어해야 한다
NULL 값이 리턴 되는 경우 발생하는 Indicator와 관련된 부분도 자주 발생하는 문제의 경우이다. 이 부분은 문서의 마지막 부분인 "자주 발생하는 오류 메시지" 에서 설명한다. Altibase의 모든 Precompiler를 통한 호스트 변수의 파라미터 마커는 "?"를 사용한다.
또한, 소스 내에서의 호스트 변수 앞에는 반드시 콜론(:)을 사용해야 한다.
에러 체크 확인
Altibase의 SQLCA객체는 별도의 선언 없이 사용이 가능하다. 개발자는 EXEC SQL 구문을 사용하는 모든 단계에서는 반드시 에러 체크를 수행하는 코드를 삽입할 것을 권고한다. Altibase의 경우 Cursor를 사용할 경우에 Cursor Prepare/Declare 단계에서 에러를 체크하지 않을 경우 Cursor Open 시점에 단순히 Cursor가 define 되지 않았다는 오류만 확인되기 때문에 실제 어떤 구문상의 오류 등을 알 수 없을 경우가 있음으로 일반적으로 누락하는 Cursor Prepare/Declare 단계에서도 에러 체크를 반드시 하도록 한다. Open 또는 Fetch단계에서 다음과 같은 오류가 발생할 수 있다.
Altibase가 에러 체크를 위해 제공하는 변수들은 다음과 같다. 에러 체크는 어떤 변수를 선택해도 상관 없으나 일반적으로 에러의 체크는 sqlca.sqlcode를 이용하고 상세한 오류의 확인을 위해 디버깅 로그를 출력할 때에는 SQLCODE를 출력하는 것을 권장한다.
분류 | 설명 |
---|---|
SQLCODE | ALTIBASE가 내부적으로 정의한 상세한 에러 코드 (ex. -69720) |
sqlca.sqlcode | SQL의 성공/실패 여부 정도를 판단할 수 있는 에러 코드 |
SQLSTATE | CLI표준에 따른 char*형의 에러 코드 (ex. 08S01) |
- 활용 예
SQLCODE는 $ALTIBASE_HOME/msg/manual.txt에 모두 정의가 되어 있음으로 해당 파일을 참조할 수 있으며 아래와 같이 사전 정의된 일부 값들을 사용할 수 도 있다. 만일, 타DBMS에서 변환할 경우나 사용자가 별도로 재정의 한 경우가 있다면 적절하게 변환해야 한다.
에러 정의 | 코드 값 | 설명 |
---|---|---|
SQL_ERROR | -1 | 처리에 오류가 발생한 경우 |
SQL_SUCCESS | 0 | 처리가 성공한 경우 |
SQL_SUCCESS_WITH_INFO | 1 | 처리는 성공이나 결과에 오류가 있는 경우 |
SES_DUPKEY_ERR | -69720 | 인덱스 중복이 발생한 경우 |
SQL_NO_DATA | 100 | 데이터가 없는 경우 |
SQL_INVALID_HANDLE | -2 | SQL처리에 필요한 내부 객체가 오류인 경우 |
Commit Mode
Altibase는 기본적으로 설정을 변경하지 않는 한 Auto-Commit mode로 동작한다. 즉, 변경 트랜잭션이 발생하면 해당 수행 결과가 정상이면 자동으로 DB에 반영되는 형태이다. 사용자가 이 설정을 NonAuto-Commit mode로 변경하고자 할 경우 $ALTIBASE_HOME/conf/altibase.properties 에 정의된 "AUTO_COMMIT = 1"을 "0"으로 변경하거나 프로그램 상에서 다음과 같은 명령을 수행해야 한다.
NonAuto-Commit mode로 변경한 이후에는 모든 트랜잭션의 수행 이후 반드시 명시적인 Commit/Rollback을 수행해야 한다.
Altibase v5부터는 SELECT문에 대한 명시적인 Commit/Rollback은 수행하지 않아도 되지만 LOB를 핸들링 하는 경우에는 반드시 NonAuto-Commit mode로 접근해야 하며 명시적인 Commit/Rollback도 수행 해야 한다. Auto-Commit으로 접근하는 경우 아래와 같은 오류가 발생한다.
변경트랜잭션에서의 오류(INSERT, UPDATE, DELETE)
조회 트랜잭션에서의 오류(SELECT)
또한, LOB에 대한 접근 이후 명시적인 Commit/Rollback을 하지 않으면 해당 트랜잭션에 의해 Lock이 유지되게 되어 리소스 측면에 장애를 유발할 수 있음으로 주의하도록 해야 한다.
System Signal 핸들링
Altibase 클라이언트 라이브러는 system signal 발생에 대해서 안전하지 않다. 예를 들어서 외부 원인에 의해 네트워크 접속이 종료된 경우 , SIGPIPE 신호를 받아 진행중인 응용 프로그램이 강제로 종료될 수도 있다. 이러한 강제 종료를 막기 위해서는 SIGPIPE 신호를 사용자 애플리케이션에서 처리해야 한다. 그러나 SIGPIPE 신호 처리를 하던 중에 Altibase 클라이언트 라이브러리의 함수를 호출하면 프로그램이 멈출 수 있기 때문에 호출하면 안된다.
하지만 신호 처리가 끝난 후에는 Altibase 클라이언트 라이브러리의 함수를 호출하면 가능하다
signal 핸들링 예제
기타 지원되지 않는 사항들
타 DBMS와 비교하여 지원되지 않는 사항을 설명한다.
- Dynamic Method4 방식은 지원하지 않는다
- Context 구문은 지원하지 않는다 ( 쓰레드를 고려한 사항 참조)
- Precompiler를 통해서는 Procedure의 typeset, Ref-Cursor, 배열 형태의 결과 셋을 받아 올 수 없다.
- system signal 발생에 대해서 안전하지 않다. system signal 처리는 사용자 코드에 의해서 처리되어야 한다.
APRE 기본 사용방법
여기서는 개발 예제 소스를 통해 상세한 설명을 언급한다. 타 DBMS을 변환할 경우 본 소스를 기반으로 참고하여 변환하도록 한다.
APRE*C/C++의 기본 사용법
Altibase Precompiler는 APRE*C/C++라고 호칭하며 실행파일은 "apre"이다. 사용자는 "*.sc" 를 확장자로 하는 소스로 개발해야 한다. 사용법은 다음과 같다.
정상적으로 컴파일이 되면 sample.cpp 라는 파일이 해당 디렉토리에 생성이 되며 아무 오류 없이 프롬프트 상으로 돌아온다. apre와 관련된 자세한 옵션은 『Altibase APRE(SES)C makefile』문서를 참고하도록 한다.
만일, C++이 C컴파일러로 “*.c” 파일이 필요한 경우에는 “-t cpp” 가 아닌 “-t c” 로 Precompile을 수행하면 된다.
기본적인 makefile
Altibase 개발을 위한 기본 헤더파일 및 라이브러리는 다음에 위치한다.
분류 | 위치 |
---|---|
헤더파일 | $ALTIBASE_HOME/include |
라이브러리 | $ALTIBASE_HOME/lib |
라이브러리에서 추가할 부분은 "-lapre –lodbccli" 이다. 이를 참고로 connect1.sc 를 컴파일하는 간단한 Makefile은 다음과 같이 작성할 수 있다.
컴파일을 위해서는 Altibase의 라이브러리 외에 시스템 라이브러리를 필요로 한다. 각 플랫폼 별로 필요한 시스템 라이브러리의 목록 및 makefile의 예제는 $ALTIBASE_HOME/install/altibase_env.mk 파일 내에 "LIBS" 태그에 정의된 목록을 사용하면 된다.
한가지 더 고려할 부분은 사용자가 C++컴파일러 아닌 C컴파일러를 사용할 경우에는 Altibase의 라이브러리가 C++로 제공되기 때문에 이를 호환하기 위한 C++ 시스템 라이브러리를 반드시 링크해야 한다. 자세한 사항은 『Altibase APRE(SES)C makefile』 문서를 참고하도록 한다.
호스트 변수
소스상에서 SQL문을 사용하여 코딩 할 경우 DBMS에 데이터에 대한 입출력 제어를 위해 사용하는 변수들을 모두 호스트 변수라고 지칭한다. Altibase v5.3.3 이전에서는 모든 호스트 변수는 반드시 “EXEC SQL BEGIN DECLARE SECTION” 과 “EXEC SQL END DECLARE SECTION” 절 내에 선언된 것들만 사용할 수 있었다.
하지만 새롭게 나온 5.3.3 이후 버전부터는 apre 옵션의 통해서 일반 변수까지 호스트 변수로 인식하는 것이 가능하다. (apre –parse full 옵션)
개발을 하는 과정에서 SELECT문의 Target절에 호스트 변수를 써야 할 경우가 발생할 수 있다. ALTIBASE 버전 5 이후부터는 CAST라는 연산자를 통해 다음과 같은 형태로 지원된다.
SQLCA 구조체
Altibase는 sqlca구조체를 통해 에러를 리턴 한다. 사용자는 다음의 사항을 통해 에러 코드 및 에러 메시지를 확인할 수 있다.
구조체 | 설명 | |
---|---|---|
sqlca.sqlcode | SQL_ERROR (-1) | 에러가 발생한 경우 |
SQL_SUCCESS (0) | 정상 처리된 경우 | |
SQL_SUCCESS_WITH_INFO (1) | 처리는 되었으나 사용자의 확인이 필요한 경우 | |
SQL_NO_DATA | 대상 데이터가 없는 경우 | |
sqlca.sqlerrm.sqlerrmc | 에러 메시지가 담겨 있다. | |
sqlca.sqlerrd[2] | 변경DML에 의한 경우는 처리된 레코드의 건수를 가지고 있으며 select문에 의한 경우는 호스트 변수가 배열인 경우 현재 fetch한 레코드가 담긴 변수의 배열 개수(누적이 아님)만을 가지고 있다. | |
SQLCODE | ALTIBASE에 정의된 에러 코드를 담고 있다. | |
SQLSTATE | CLI 표준 에러 코드를 담고 있다. (ex) 08S01 |
위 코드 값들은 이미 Precompile단계에서 소스에 정의되기 때문에 개발자가 별도로 재정의하거나 헤더에 포함할 필요는 없다.
Connect / Disconnect
Altibase는 별도의 Listener와 같은 설정이 없으며 DBMS내부 쓰레드에 직접 접속하는 형태로 구현되어 있다. 따라서, 접속할 대상 서버의 IP 및 PORT번호를 직접 입력하는 형태로 접속한다. 다음은 ALTIBASE에 접속하기 위한 기본 예제 코드이다.
Connection Type
연결 방식의 종류는 CONNTYPE 속성의 설정값으로 TCP/IP, unix Domain, IPC 방식 3가지 중에 한가지를 선택할 수 있다.
CONNTYPE | 설명 |
---|---|
CONNTYPE=1 | 프로그램과 DBMS간의 통신은 TCP/IP방식으로 수행한다. |
CONNTYPE=2 | 프로그램과 DBMS간의 통신은 unix Domain 방식으로 수행한다. |
CONNTYPE=3 | 프로그램과 DBMS간의 통신은 IPC 방식으로 수행한다. |
CONNTYPE=2, 3 방식은 모두 프로그램이 DBMS서버와 같은 장비 내에 위치해야지만 사용할 수 있다. 2가지 방식 모두 하드웨어 레벨까지 통신비용이 발생하지 않기 때문에 TCP/IP에 비해 빠른 성능을 내고자 할 경우 권장한다. IPC접속 방식을 선택할 경우에는 ALTIBASE_HOME/conf/altibase.properties 파일 내의 IPC_CHANNEL_COUNT를 1 이상의 값으로 조정해야 한다. 이 설정은 DB를 재 구동해야 사용 가능하며 사전에 IPC와 관련된 커널 설정값을 충분히 조정해야 한다.
Connection Name
연결 시점에 명시적인 이름을 주는 것이 가능한데 다음과 같이 수행한다.
명시적인 이름 또는 호스트 변수로 저장하여 처리가 가능하다.
Connection Close
연결의 해제 방법은 아래와 같으며 비정상적인 연결 종료가 발생하면 재 연결을 시도하기 전에는 반드시 "EXEC SQL FREE"를 수행하도록 한다.
Commit / Rollback
Commit/Rollback의 수행은 다음과 같이 할 수 있다.
DML 수행의 예
Altibase의 경우는 SELECT절의 INTO 절은 생략할 수 없다. 이외의 트랜잭션 상의 DML은 일반적인 SQL 사용법을 그대로 이용하면 된다.
Cursor
일반적인 cursor는 다음과 같이 사용한다.
FAC(Fetch Across Commit) 오류
Non-autocommit 환경에서 커서를 Open후 레코드 단위로 Fetch 하면서 Fetch 도중에 Commit/Rollback 하는 것은 ANSI 표준에서 권장하지 않는다. Altibase 는 ANSI 표준을 준수하여 기본적으로 FAC 시 오류가 발생한다. 그러나 Altibase v6.3.1 이상 버전부터는 Cursor Open시의 옵션을 통해서 FAC 를 수행할 수 있는 기능을 지원한다.
오류가 발생하는 코드의 예
FAC 오류 발생하는 코드의 예를 보여준다.
위 코드에서 fetch 이후 시점에 에러 체크를 하도록 하고 수행 중에 다음과 같은 오류가 발생할 수 있다. (Altibase v5.3기준)
이 시점에 실제 레코드 건수는 더 존재하지만 commit되는 시점에 이전에 열은 cursor1이 내부적으로 종료되면서 더 이상 fetch할 결과셋이 없어졌기 때문에 이러한 에러가 발생한다. (이 에러는 실제 데이터가 없는 경우와 동일하기 때문에 판단하기에 다소 애매할 수 있으나 기대한 건수 이하에서 이와 같은 오류가 발생할 경우 이러한 상황을 고려해 볼 수 있다.)
따라서, cursor를 사용하여 fetch하는 과정에서 별도의 변경 트랜잭션을 발생시켜야 하는 경우는 해당 세션을 auto-commit mode로 수행하거나 또는 별도의 연결 객체를 만들어 해당 세션을 통해 처리하도록 해야 한다.
FAC 오류 메세지
Altibase 버전에 따라서 FAC 에러 메세지는 약간씩 다르게 출력된다.
버전 | 에러코드 | 에러메세지 | 참고 페이지 |
---|---|---|---|
Altibase 4.3.9 | ERR-4103C | Request of fetching data to an unprepared SQL statement. | http://aid.altibase.com/x/6YKZ |
Altibase 5.3.3 ~ 6.1.1 | 100 | ||
Altibase 6.3.1 이상 | ERR-410D2 | Request of fetching data to an unprepared SQL statement. | http://aid.altibase.com/x/9oKZ |
별도의 연결을 만들어 FAC를 수행하는 예
FAC 연결 수행 예입니다.
별도의 연결을 사용할 경우에는 사용자가 고려할 사항은 전체 수행 흐름이 하나의 트랜잭션으로 묶여야 하는 경우 별도의 연결 객체를 사용할 경우 수행 도중 오류로 인해 일부는 commit되고 일부는 처리되지 못하는 상황이 발생할 수 있다. 만일, 하나의 트랜잭션 안에 All or Nothing 형태로 처리되어야 한다면 반드시 fetch-loop 밖에서 commit/rollback 구문을 사용하도록 해야 한다.
Cursor 선언시 "WITH HOLD" 구문 사용
Altibase v6.3.1 이후 부터는 "WITH HOLD" 구문으로 선언한 Cursor를 Open 한 경우에는 Commit/Rollback 수행후 트랜잭션 완료 후에도 커서가 닫히지 않는다. 세션이 non-autocommit 모드일 경우에만 유효하다. 자세한 설명은 『ALTIBASE CLI User's Manaul』 과 『ALTIBASE Precompiler Manaul』 을 참고하기 바란다.
Dynamic SQL
변경 트랜잭션의 경우와 조회 트랜잭션 2가지의 예로 설명한다.
변경 트랜잭션
조회 트랜잭션 예
테이블 명이 명시적이지 않거나 칼럼, 조회 조건 등이 바뀌어야 하는 경우 별도의 char*형의 변수에 SQL문을 만들고 해당 SQL문을 dynamic하게 사용하는 방법이다.
Altibase v5.1부터는 내부적으로 Plan-Cache라는 영역에 모든 세션들이 수행하는 실행계획을 공유하고 있다. 하지만, Dynamic SQL과 같이 매번 질의문이 달라지면 Plan-Cache에 이미 생성된 실행계획을 사용하지 않고 다시 Prepare/Execute형태로 동작하기 때문에 질의 성능이 Static SQL문 비해서는 느릴 수 밖에 없다.
Call Function
사용자가 생성한 또는 DBMS 내장 함수를 호출하는 방법의 예를 설명한다.
DBMS 내장함수 호출 예
사용자 함수 호출 예
항상 from dual이어야 할 필요는 없으며 사용자가 필요에 의해 임의의 테이블을 지정하여도 상관없다. (함수에서 사용자가 주의할 것은 리턴 절에 char/varchar가 오는 경우 반드시 리턴 되는 길이를 명시해야 한다. 명시하지 않을 경우 1byte만 리턴 되기 때문에 대부분 함수에서 다음과 같은 Exception이 발생하게 된다. “Invalid length of the data type”)
Call Procedure
프로시져는 함수와 달리 별도의 호출 방식을 통해 수행한다. 함수도 이와 동일한 방법으로도 사용할 수 있음으로 참고하도록 한다.
WHENEVER 구문
Altibase의 WHENEVER구문에서는 do/goto/continue/stop 등의 구문을 제공한다. 이 구문은 내장SQL문을 수행하기 전에 선언해야 한다. Whenever 구문의 조건문에는 다음과 같은 형태가 가능하다.
조건 | 설명 |
---|---|
SQLERROR | sqlca.sqlcode 가 SQL_ERROR인 경우 |
NOT FOUND | sqlca.sqlcode 가 SQL_NO_DATA인 경우 |
처리에 대한 부분은 다음과 같이 가능하다.
처리 | 설명 |
---|---|
DO [사용자 함수] | 사용자가 정의한 함수를 실행한다. |
CONTINUE | 에러를 무시하고 계속 진행한다. |
DO BREAK | 반복문을 빠져 나간다. 반복문 내에서만 유효하다. |
DO CONTINUE | 반복문 내의 처음 위치로 이동한다. 이 구문은 반복문 내에서만 유효하다. |
GOTO [Label] | 사용자가 지정한 곳으로 GOTO 수행한다. |
STOP | 연결을 해제하고 프로그램을 종료한다. |
사용의 예는 다음과 같다.
현재의 연결 상태 확인 및 Session Failover 기능
Altibase에서는 능동적으로 연결 객체에 대해 상태를 리턴 해주는 방법은 없으며 다만, 개발자가 질의를 수행한 이후 SQLSTATE의 상태를 체크하여 다음의 방법으로 연결이 종료되었음을 감지해 낼 수 있다.
다음과 같은 예제 소스를 공통 함수에 넣는 방법도 가능한 방법 중에 하나이다.
사용자 코드에 의한 Session Failover 기능
Altibase v5.3.3 이상 버전부터는 CTF (Connection Time Failover)/STF(Service Time Failover)라고 부르는 개념의 Session FailOver 기능을 제공한다. CTF는 프로그램이 최초에 연결을 시도하는 시점에 FailOver를 의미하며 STF는 연결된 이후에 질의를 수행하는 과정에 발생하는 연결에 대한 FailOver를 의미한다.
이 기능은 트랜잭션의 FailOver는 지원하지 않기 때문에 사용자는 Session FailOver이후의 비즈니스 로직을 재처리 하는 것을 반드시 고려해야 한다. 사용 예는 다음과 같다.
Altibase Failover 기능을 사용한
연결 String의 각 입력 항목의 의미는 다음과 같다.
항목 | 설명 |
---|---|
AlternateServers | FailOver를 할 대상 서버를 차례대로 IP:PORT 형태로 콤마(,)를 기준으로 나열한다. |
ConnectionRetryCount | 하나의 대상 서버에 대한 연결 시도 횟수를 의미한다. |
ConnectionRetryDelay | 이 간격(초)만큼 Sleep후 연결을 재시도한다. |
SessionFailOver | SessionFailOver 기능을 Service Time시에 사용할지 결정한다. 즉, SQL오류 발생시 자동으로 연결을 AlternateServers 목록에 있는 서버로 맺을 지 여부를 지정한다. (on/off) |
LoadBalance | on으로 할 경우 최초 접속 시에 DSN에 명시된 서버와 AlternateServers 목록 중에 랜덤 하게 선택하며 off로 하게 되면 DSN을 먼저 선택하고 이후 AlternateServers 목록에 기술된 순서대로 접속을 시도하게 된다. |
만일, Cursor Open시점에 에러가 발생하여 재 처리해야 할 경우에는 반드시 재처리 전에 해당 Cursor를 Close release까지 수행한 이후 재처리를 해야 한다.
CTF/STF와 관련된 부분은 『ALTIBASE UL FailOver 가이드』문서를 참고하도록 한다.
APRE 예제 프로그램
Altibase 설치 파일에 포함되어 있는 예제(Sample) 프로그램에 대해서 간략히 설명한다.
예제 프로그램
$ALTIBASE_HOME/sample/APRE 에 각종 예제들을 참고할 수 있다. 해당 디렉토리의 소스는 다음과 같이 참고할 수 있다.
분류 | 샘플 예제 소스 명 |
---|---|
DB 연결 예제 | |
호스트 변수 예제 | arrays1.sc arrays2.sc pointer.sc date.sc varchar.sc binary.sc |
Cursor 활용 예제 | |
Dynamic SQL 활용 예제 | |
Multi Connection 예제 | |
Thread 개발 환경의 예제 | |
DML별 사용 예제 | |
LOB 활용 예제 | BLOB/blobSample.sc CLOB/clobSample.sc |
PSM/Function 예제 | |
FailOver 예제 | Fail-Over/FailOverSample.sc |
본 문서에서는 예제 소스들을 복합적으로 응용하여 2개의 연결을 맺어 Cursor-fetch과정에서 별도의 테이블에 update를 수행하는 예를 기술한다.
자주 발생하는 오류 메세지
SQLCODE 및 sqlca.sqlerrm.sqlerrmc를 통해 확인되는 자주 발생하는 에러들을 정리해서 설명한다. SQLCODE는 동일한 sqlca.sqlerrm.sqlerrmc에 대해 2개가 존재할 수 있는데 이것은 Altibase 내부 모듈 중 오류가 발생한 모듈의 위치에 따라 다를 수 있기 때문이며 에러의 내용은 동일하기 때문에 조치 방법도 동일하다.
Connection does not exist. (SQLCODE=–2)
질의 처리 수행 과정에서 사용해야 할 연결 객체가 없거나 사라진 경우이다. 제대로 연결이 처리되었는지 여부를 확인하고 쓰레드 프로그램의 경우 EXEC SQL AT 절에 연결 명이 제대로 표기되었는지 확인해야 한다. 경우에 따라서는 DBMS서버에서 연결이 단절된 경우가 있을 수 있다. (오류 메시지 중 Timeout관련 메시지를 확인)
String data right truncated. (SQLCODE=1)
DB로부터 변수에 값을 담는 과정에서 선언된 변수의 길이가 작은 경우 발생한다. DB변수의 길이를 (데이터 길이+1byte)만큼 크게 변경하도록 한다.
Invalid size of data to bind to a host variable [ Column ID = <A%d>, Data Size = <B%d> , Declared Size of Host Variable = <C%d> ] (SQLCODE=-201144 or -266423)
칼럼의 (A+1)번째의 실제 데이터는 B의 크기를 갖는데 호스트 변수의 길이는 C의 크기를 갖기 때문에 데이터 값이 변수의 길이를 넘은 경우 발생한다. 변수의 길이를 데이터의 길이보다 크게 잡아야 한다. 간혹, 호스트 변수의 메모리가 프로그램의 이상으로 깨진 경우에도 이와 같은 오류가 발생하기 때문에 호스트 변수의 memset 또는 메모리가 깨진 경우가 없는지 확인해야 한다. 또는, 쓰레드 프로그램의 경우에서 다수의 SQL문을 하나의 커넥션을 통해 동시성 제어가 제대로 되지 못할 경우에도 발생할 수 있다
Calculation stack overflow (SQLCODE=-135187 or -659475)
내부에서 질의 처리 과정에서 사용되는 stack의 크기를 넘은 경우 발생한다. 이 경우 해당 질의를 수행하기 전에 다음과 같이 SQL문을 수행하도록 한다. 기본값은 1024이다.
Value overflow or Numeric value out of range (SQLCODE=-135184 or -659472 or -331890)
호스트 변수에 사용된 데이터의 값이 실제 DB에 정의된 칼럼의 표현 범위보다 큰 값이 입력된 경우이다. 데이터 값을 확인하고 필요 시 칼럼을 변경하도록 해야 한다.
Conversion not applicable (SQLCODE=-135180 or -659468)
ALTIBASE에 사용되는 칼럼의 데이터 타입 또는 호스트 변수의 타입간의 변환이 지원되지 않는 유형으로 사용한 경우에 발생한다.
이 외에도 CLOB/BLOB의 핸들링에 있어 변환되지 않는 데이터 타입을 갖는 호스트 변수가 사용될 경우도 에러가 발생할 수 있다.
Invalid length of the data type (SQLCODE=-135181 or -659469)
DB의 칼럼에 저장 가능한 길이보다 큰 데이터가 입력되는 경우 발생한다.
Invalid literal (SQLCODE=-135185 or -659473)
칼럼 타입이 숫자형으로 선언된 상태에서 사용한 호스트 변수에 숫자로 변환할 수 없는 문자열 있는 경우 발생한다. 또는, to_number()와 같은 내장 함수에서 입력 인자로 숫자 형태가 와야 하는데 문자열이 온 경우에서 발생한다. 숫자형에 맞는 데이터를 사용하도록 해야 한다.
Invalid character value for cast specification (SQLCODE=-331893)
숫자 형의 호스트 변수에 문자열을 담아 처리되는 경우 발생한다. 칼럼 타입에 맞는 호스트 변수를 선언하도록 한다.
Invalid cursor state. (SQLCODE=-331822) or Function sequence error (SQLCODE= -331796)
이 에러는 Cursor를 사용하기 위해 지켜야 할 순서가 올바르게 수행되지 않을 경우 발생한다. 혹은, 이미 데이터를 모두 읽은 cursor이거나 close된 cursor인데 다시 fetch를 부르는 경우도 이 에러가 발생한다.
The cursor must be opened for fetch (SQLCODE=-1) or The cursor does not exist (SQLCODE=-589857)
일반적인 Cursor의 사용은 (PREPARE->DECLARE->OPEN->FETCH->CLOSE)의 순서를 거쳐야 한다. 이 에러는 정상적으로 DECLARE/OEPN되지 않은 cursor를 FETCH하려고 시도하는 경우 에러가 발생한다.
Not enough insert values (SQLCODE=-200787)
INSERT구문에서 명시된 칼럼 개수와 호스트 변수의 개수가 일치하지 않을 경우 발생한다.
The tablespace does not have enough free space (SQLCODE=-69685 or -69923)
트랜잭션이 진행되는 과정에서 테이블스페이스의 용량이 모두 사용되어 공간이 없는 경우이다. 이 경우에는 해당 디스크 테이블스페이스의 경우는 데이터파일을 추가함으로 공간을 확보하고 메모리 테이블스페이스의 경우에는 불필요한 데이터의 삭제 또는 Compaction과정 등을 통해 가용 공간을 확보해야 한다.
Input literal is not long enough for date format. (SQLCODE=-135218)
날짜 함수에 입력된 문자열이 너무 짧은 경우 발생한다. 입력된 데이터에 오류가 없는지 확인해야 한다.
Literals in the input do not match format string. (SQLCODE=-135224)
날짜 함수에서 입력된 날짜의 문자열과 날짜 형식이 일치하지 않는 경우 발생한다.
The transaction is already active. (SQLCODE=-266311 or -266312)
세션 단위로 Commit-mode를 조정할 수 있는데 이 과정에서 아직, Commit/Rollback 되지 않은 트랜잭션이 존재하는 상태에서 Auto-Commit으로 변경하는 경우 발생한다. 따라서, 세션의 속성을 변경하는 과정에서 에러가 발생할 경우 이전에 발생한 트랜잭션의 존재 여부를 먼저 확인해 보도록 한다. 혹은, Commit/Rollback을 실행한 이후에 세션의 속성을 변경하도록 한다. 간혹, 쓰레드 프로그램 및 Connection Pool을 구현하여 사용하는 경우에서 연결 객체에 대한 사용자 관리 (즉, autocommit/NonAutoCommit을 혼용하여 사용하는 경우들)가 부주의한 경우 발생할 수 있다.
The row already exists in a unique index. (SQLCODE=-69720)
INSERT 혹은 UPDATE 구문에서 접근하거나 변경하는 값이 이미 primary-key 또는 unique index상에 데이터가 존재하는 경우이다. 이 경우는 조회를 통해 이미 해당하는 데이터 값이 존재하는지 확인하도록 한다.
Unable to insert (or update) NULL into NOT NULL column. (SQLCODE=- 200790)
INSERT 혹은 UPDATE 구문에서 입력하는 데이터 값 중에 칼럼이 NOT NULL인데 NULL값을 넣으려고 하는 경우 발생한다. 데이터 값들을 추적하여 NULL인 데이터가 발생하지 않도록 하거나 칼럼의 NOT NULL Constraints를 적절하게 변경해야 한다.
Indicator variable required but not supplied. (SQLCODE=-331841 or -594101 or 594103)
DB로부터 호스트 변수에 담긴 값이 NULL인 경우 이 에러가 발생한다. 이 에러는 SQL_SUCCESS_WITH_INFO로 리턴 된다. 즉, 넘겨준 부분이 NULL인 상태임을 인지 시켜 주는 오류이다. (실제 변수에는 어떤 값이 들어 있을지 보장할 수 없다.)
이 오류를 없애기 위해서는 칼럼에 NVL처리를 하거나 또는, 별도의 int 타입의 indicator변수를 사용하여 호스트 변수에 사용하는 방법으로 해결할 수 있다. 또는 apre옵션 중 -unsafe_null 옵션을 사용할 수도 있다.
Client's query exceeded in the execution time limitation. (SQLCODE=-4164)
질의를 수행하는 과정의 시간이 지정된 시간을 초과하는 경우 해당 질의는 이 에러가 리턴 된다. 문서에서 설명한 질의의 실행계획을 확인하고 필요한 튜닝 조치를 취하거나 만일, 이미 적절한 조치가 됐음에도 전체 처리해야 할 데이터의 양에 의한 경우라면 다음과 같이 수행한 후 질의를 처리하도록 한다.
EXEC SQL ALTER SESSION SET QUERY_TIMEOUT = 0;
"0"으로 설정하면 질의 처리에 대한 Timeout 설정에 상관 없이 수행이 지속된다. 단, 이렇게 할 경우 해당 쿼리가 완료될 때까지는 리소스를 대량으로 점유할 수 있음으로 변경에는 신중하게 결정할 것을 권고한다.
Communication link failure. (SQLCODE=-331843 or -331855)
질의를 처리하는 과정에서 서버 또는 네트웍의 오류로 인해 연결이 단절되는 경우 발생한다. 이 경우 먼저 $ALTIBASE_HOME/trc/altibase_boot.log 에 timeout과 관련된 로그가 기록되었는지 확인한다. 일반적으로 2개의 경우가 발생한다.
Fetch Timeout은 DBMS서버와 프로그램 간의 통신의 간격이 60초로 제한되어 있는데 이를 넘은 경우 서버에서 강제적으로 세션을 단절하는 경우를 의미한다.
UTrans Timeout은 사용자가 변경 트랜잭션을 발생한 후 Commit/Rollback을 수행하지 않은 채 유지하는 시간의 간격이 3600초로 제한되어 있는데 이를 초과한 경우 세션이 단절되게 되는 경우를 의미한다. 2가지 모두 다음과 같이 제한 값을 변경할 수 있다.
"0" 값으로 설정하면 해당 제한이 적용되지 않도록 동작한다. 다만, 개발자가 위와 같이 설정한 경우 QUERY_TIMEOUT의 경우와 마찬가지로 해당 트랜잭션이 지속되는 동안은 DBMS내부의 리소스를 계속 점유하고 경우에 따라 장애를 유발할 가능성이 있기 때문에 위의 문제를 원천적으로 해결할 방안을 모색할 것을 권고한다.
일부 네트웍의 문제 또는 L4, 방화벽의 Timeout등의 설정으로 altibase_boot.log에 오류 없이 단절되는 경우도 있기 때문에 이것은 별도의 PBT(Problem Tracking)과정을 통해 원인을 찾아야 한다.
타 DBMS에서 변환 시 고려사항
앞에서 설명한 각 부분별 내용 중 타DBMS에서 변환할 경우 고려할 부분을 표로 정리한다.
구분 | ALTIBASE 사용 예시 및 설명 |
---|---|
CONNECT/DISCONNECT | EXEC SQL CONNECT [AT :con_name] CONNECT :usr IDENTIFIED BY :pwd USING :opt;
자세한 사용은 위의 "CONNECT/DISCONNECT"절을 참고한다. |
함수의 인자 | void user_function (char *param1) { EXEC SQL BEGIN ARGUMENT SECTION; char *param1; EXEC SQL END ARGUMENT SECTION; } 또는, void user_function (char *param1) { EXEC SQL BEGIN DECLARE SECTION; char *H_param1; EXEC SQL END DECLARE SECTION;
H_param1 = param1; } |
에러 코드 | sqlca.sqlcode 및 SQLCODE, SQLSTATE등은 별도의 선언을 하지 않고 사용할 수 있으며 타DBMS와 에러 코드는 다르기 때문에 사용자가 적절하게 변환해야 한다. CLI 표준 코드를 사용한 경우라면 그대로 호환하여 사용할 수 있다.
EXEC SQL INCLUDE sqlca.h; 와 같은 구문은 필요하지 않다. |
호스트 변수의 선언 | ALTIBASE 5.3부터는 apre의 옵션에 따라 호스트 변수 선언절을 생략할 수 있다. 또는, 기존과 동일하게 선언절 내에 표기된 변수를 호스트 변수로 사용할 수 있다. EXEC SQL BEGIN DECLARE SECTION; char *H_param1; EXEC SQL END DECLARE SECTION;
호스트 변수의 초기화는 ALTIBASE 5.3.3 부터 지원하고 있다. |
헤더 파일의 경로 | 소스 내에서 헤더를 명시할 경우 다음과 같이 할 수 있다. EXEC SQL INCLUDE "…../user_header.h"; 또는, EXEC SQL OPTION (INCLUDE=/절대경로/); EXEC SQL INCLUDE user_header.h; |
헤더 파일 내의 호스트 변수의 선언 | #ifdef SESC_DECLARE ….. #endif 위와 같은 define절 내에 명시할 수 있다. |
SELECT 의 into절 생략 | 지원하지 않는다. |
SET TRANSACTION ~구문 | 지원하지 않는다. |