오라클 호환성 기능은 DB2_COMPATIBILITY_VECTOR 레지스트리 변수에 값을 적용함으로서 오라클 문법/표현등을 사용하게 된다.

그러나 일부 기능은 데이터베이스를 생성하기 전에만 적용되는 것들이 있다.

Developerworks에 나온 문서(https://www.ibm.com/developerworks/mydeveloperworks/blogs/SQLTips4DB2LUW/entry/about_the_db2_compatibility_vector_and_what_not_to_say_at_the_dinner_table282?lang=en) 의 내용 및 기억을 더듬어보면

1. NUMBER

2. VARCHAR2

3. DATE

4. Oracle Data Dictionary

정도가 아닌가 싶다.

 

이 중 VARCHAR2를 세부적으로 들여다보면 특별한 기능을 포함하고 있다.

오라클이 공백과 NULL 값 구분을 하지 않기 때문에, DB2로 Data Migration을 하게 되면 이것은 문제가 된다. (DB2는 공백과 NULL을 구분하기에)

 

따라서 SQL 내에서 공백의 데이터를 처리하다보면 Oracle과는 다른 결과를 갖게 된다.

이 문제를 해결하기 위해서 VARCHAR2 (0x20) 값을 적용할 필요가 생긴다.

 

1. DB2에서 공백 값 테스트

$ db2 "values (COALESCE('','NULL'))"

1
----


$ db2 "values (COALESCE(' ','NULL'))"

1
----


$ db2 "values (COALESCE(NULL,'NULL'))"

1
----
NULL



$> db2 "values (bigint(''))"

1
--------------------


SQL0420N  Invalid character found in a character string argument of the function "BIGINT".  SQLSTATE=22018

 

2. 오라클의 공백 값 테스트

SQL> select nvl('','NULL') as C1 from dual;

C1
----
NULL


SQL> select nvl(' ','NULL') as C2 from dual;

C
-


SQL> select nvl(NULL,'NULL') as C3 from dual;

C3
----
NULL



SQL> select to_number('') as C4 from dual;

        C4
----------

 

4번째 SQL을 통하여 DB2에서는 “공백 값"이 숫자로 캐스팅되지 못하고 SQL0420N 오류가 발생했다.

 

오라클 호환성 (db2set DB2_COMPATIBILITY_VECTOR=20) 을 적용해도 “공백"값은 숫자형으로 형 변환되지 못한다.

 

이 경우 오라클처럼 “공백" 값을  숫자로 형변환 되도록 하기 위해서는 db2set DB2_COMPATIBILITY_VECTOR=20 를 적용하고 DB 재생성을 해야 된다.

$> db2set -all
[i] DB2_COMPATIBILITY_VECTOR=20

$> db2 drop db sample
$> db2stop
$> db2start
$> db2sampl
$> db2 connect to sample
$> db2 "values (bigint(''))"

1
--------------------
                   -

 

위 문제는 사전 테스트를 통하여 “공백"처리 문제가 발생함을 확인하는 경우 VARCHAR2 호환성을 적용되어야 할 것이다.

그렇지 않다면 SQL 수정이 되어야 할 것이다.

 

다른 관점에서는 “해당 DB가 오라클 호환성을 적용하고 생성된 DB인지” 확인하는 방법이 될 수도 있다.

예를 들어 DB2 구성 작업에 많은 수의 인스턴스 및 DB 생성 작업 시,  “오라클 호환성"을 적용하고 DB가 만들어져야 되는 상황이라면

오라클 호환성이 제대로 적용되어 생성된 것인지 확인하고 싶을 수 있다.

- 많은 반복 작업으로 작업 검증 절차를 빠뜨리거나

- 인스턴스 구성 후 자동으로 인스턴스가 실행 중인 상황에서, 호환성 적용하고 (인스턴스 재시작 없이) DB를 생성된 것은 아닌지

- 이미 구축된 DB2 환경에 (히스토리 없이 지원을 하게 되어) 오라클 호환성 관련된 문제가 발생한 경우 호환성 적용 시점이 언제인지 확인할 때

DB V10.5 케플러가 출시된 올해, V9.7 코브라는 이제 오래된 제품처럼 여겨진다.

얘기하고자 하는 내용은 V9.7 때 있었기 때문에 지금은 달라졌을 수도 있다고 생각한다.

 

샘플 데이터

db2 +p –tv << EOF
create table t1 (c1 int);
insert into t1 values (1),(2);
select * from t1;

EOF

 

테스트 SQL

select c1, case when c1=1 then '1234'

            else '12' end c1_string,

            length( case when c1=1 then '1234' else '12' end) c1_length

from t1

 

(Case 1) 오라클 호환성 없는 환경

C1       C1_STRING        C1_LENGTH
---       -------------       ---------------
1          1234                4
2          12                  
2

 

(Case 2) 오라클 호환성 켜지 않고 생성된 DB에 ORA값을 적용한 경우

C1 C1_STRING C1_LENGTH
--- ------------- ---------------
1    1234          4
2    12             4

 

위 2개의 사례로 보면 “오라클 호환성”을 적용함으로서 데이터 길이가 틀리게 인식됨을 확인할 수 있다.

 

IBM Lab에서는 다음과 같이 정리해서 답변을 주었다.

case1) ORA mode + DB2_COMPATIBILITY_VECTOR=

case2) ORA mode + DB2_COMPATIBILITY_VECTOR=ORA

case3) Non ORA mode + DB2_COMPATIBILITY_VECTOR=

C1 C1_STRING C1_LENGTH
--- ------------- ---------------
1   1234          4
2   12            
2

 

case4) Non ORA mode + DB2_COMPATIBILITY_VECTOR=ORA

C1 C1_STRING C1_LENGTH
--- ------------- ---------------
1    1234          4
2    12            
4

 

ORA mode 는 “호환성 변수를 적용하고 DB 생성”함을 의미한다.

 

결론은 “호환성 모드가 아닌 DB에 ORA 값을 적용한 경우, 문자열이 CHAR로 변환”이 된다는 점이다.

즉  출력되어야 문자열 중 “가장 긴 길이를 기준”으로 문자열 길이가 정해져서, 짧은 문자열이 출력되어도 패딩처리되어 문자열 길이는 동일하게 처리되는 것이다. (varchar로 인식이 되었다면 이런 문제는 발생하지 않았을 것이다.)

 

Trace 분석 결과 (0x20은 ASCII에서 공백문자를 의미함)

10509 data DB2 UDB runtime interpreter sqlri_trace_bno_zvals fnc (3.3.112.1463.0.0)

pid 3436680 tid 2829 cpid 2711578 node 0 sec 4 nsec 200418531 probe 0

bytes 17

Data1 (PD_TYPE_DEFAULT,12) Hexdump:

6161 6161 6161 2020 2020 2020 aaaaaa

 

개인적으로 오라클 호환성 변수 사용을 권장하지는 않지만, 사용을 해야 되는 경우 F 정도까지는 무난하지 않나 싶다.

오라클 호환성 옵션 사용 시 검토할 기술문서를 소개하고 마무리 해 본다.

 

https://www.ibm.com/developerworks/mydeveloperworks/blogs/SQLTips4DB2LUW/entry/about_the_db2_compatibility_vector_and_what_not_to_say_at_the_dinner_table282?lang=en

오라클 포팅작업을 하다보니 오라클 호환성 기능에 대해 새롭게 살펴보게 되는 것 같다.

오라클에서는 숫자형으로 선언된 컬럼에 공백값(‘’)을 입력하면 NULL 값 처리가 된다. DB2에서는 공백값을 입력하면 형 변환 오류가 발생하여 입력이 실패한다. 만일 문자열로 된 숫자 값 (예: ‘1234’) 식의 값을 입력하면 자동 캐스팅 되어 입력된다.

 

iBatis에 대해서는 잘 모르지만, DBMS Migration 작업을 하다보면 XML 문서에 SQL문들을 모아 놓고 dynamic 하게 SQL을 실행하는 환경을 보게 된다. 아마도 XML문서에 값들도 동적으로 받아 처리되도록 하다보니, 매개변수의 데이터 유형이 DB에 선언된 컬럼 유형과는 다르게 지정되는 경우가 많다. (아마도 개발편의성 때문에 대부분은 VARCHAR로 일괄 선언하는 경우가 많지 않을까 싶다.)

 

이렇게 되다 보니 숫자형으로 선언된 컬럼에 문자열 값이 입력이 되다보니 DB2에서는 자동으로 형 변환을 못하고 에러를 반환하는 경우가 많다. (V9.5 이후로 오라클 호환성 기능이 나오면서 자동형변환 처리는 많이 편해진 편이다.)

 

오라클처럼 공백값(‘’)을 NULL 값으로 처리하도록 하기 위해서는 호환성 벡터 0x20 값이 적용되어야 하며, 적용 후 DB 생성 작업을 해야 된다.

참고로 DB2 정보센터 문서에는 “호환성 벡터”를 적용하는 경우 DB locale은 유니코드(utf-8)을 사용할 것을 권고하고 있다.

또한 DB2 DeveloperWorks 기술문서에 VARCHAR2 (0x20) 값은 위험할 수 있다고 권고되는 값이니 업무 상 필요한 경우에만 사용하도록 주의해야 한다.

 

공백(‘’) 테스트 (오라클)

SQL> create table t1 (c1 integer, c2 integer);
SQL> insert into t1 values (1,'');
SQL> insert into t1 values (2,'   ');
         ORA-01722:
SQL> insert into t1 values (3,NULL);

SQL> select * from t1;

        C1         C2
---------- ----------
         1
         3

 

 

공백(‘’) 테스트 (DB2 – 호환성 적용 전)

db2 "create table t1(c1 int, c2 int)"
db2 “insert into t1 values (1,'')

SQL0420N  함수 "INTEGER"의 문자열 인수에 유효하지 않은 문자가 있습니다.

db2 “insert into t1 values (2,'   ')

SQL0420N  함수 "INTEGER"의 문자열 인수에 유효하지 않은 문자가 있습니다.


db2 "insert into t1 values (3,'1234')"
DB20000I  The SQL command completed successfully.

db2 "insert into t1 values (4,NULL)"
DB20000I  The SQL command completed successfully.

db2 "select * from t1"

C1          C2
----------- -----------
          3        1234
          4           -

  2 record(s) selected.


 

공백(‘’) 테스트 (DB2 – 호환성 적용 후)

db2set DB2_COMPATIBILITY_VECTOR=20
db2stop force
db2start
db2 create db test
db2 connect to test
db2 "create table t1(c1 int, c2 int)"
db2 “insert into t1 values (1,'')
DB20000I  The SQL command completed successfully.

db2 "insert into t1 values (2,'   ')"

SQL0420N  Invalid character found in a character string argument of the function "INTEGER".

 

db2 "select * from t1"

C1          C2
----------- -----------
          1           -

  1 record(s) selected.

 

참고로 0x20 값 적용하고 DB 생성 후, 0x20 값을 제거해도 공백(‘’)은 NULL 값으로 인식된다.

 

참고

1) developerWorks 오라클 호환성 기술문서

https://www.ibm.com/developerworks/mydeveloperworks/blogs/SQLTips4DB2LUW/entry/about_the_db2_compatibility_vector_and_what_not_to_say_at_the_dinner_table282?lang=en

 

2) 호환성 벡터 값

http://pic.dhe.ibm.com/infocenter/db2luw/v10r1/index.jsp?topic=%2Fcom.ibm.db2.luw.apdv.porting.doc%2Fdoc%2Fr0052867.html

IBM에서는 V9.5부터 DB2_COMPATIBILITY_VECTOR 라는 레지스트리 변수를 통하여 ORACLE의 특수 기능을 동일하게 사용하도록 지원하기 시작하였다.

ORACLE에서 DB2로 object들을 변환 작업할 때, 도움이 많이 되지만 DBMS가 다른 만큼 동일하게 작용하지 않는 부분이 존재한다. 개인적으로는 “오라클 호환성” 기능은 ORACLE 적인 SQL 등을 내부적으로 DB2 기능으로 mapping 혹은 변환시켜주는 기능이지 “Oracle SQL”을 직접 수행하는 기능은 아니라고 생각하고 있다.

보통은 DB2 V9.7에서 오라클 호환성을 사용하기 위해서는 레지스트리 변수를 DB2_COMPATIBILITY_VECTOR=ORA 로 설정을 한 후 DB를 생성하도록 안내를 한다. 면밀하게 살펴보지는 않았으나 ORACLE의 시스템 관리 뷰들의 생성 유무 차이가 있다.

일반적인 기능은 DB 생성 후에도 “오라클 호환성 변수”를 적용해도 (db2 restart는 필요함) 되는 것으로 알려져 있는데, 다음과 같이 “미묘한 차이”가 발생을 한다.

1. 오라클 호환성을 적용한 후 DB 생성한 경우

테이블 생성
> db2 "create table t1(c1 date, c2 timestamp)"

테이블 DDL 생성
> db2look -d test -e -z "INST97" -t "T1"

결과 확인

CREATE TABLE "INST97 "."T1" (

"C1" TIMESTAMP(0) ,

"C2" TIMESTAMP )

IN "USERSPACE1" ;

테이블 삭제

db2 drop table t1

 

오라클 호환성 제거

db2set DB2_COMPATIBILITY_VECTOR=

db2stop

db2start

 

테이블 생성

db2 "create table t1(c1 date, c2 timestamp)"

 

테이블 DDL문 생성

db2look -d test -e -z "INST97" -t "T1"

 

결과 확인

CREATE TABLE "INST97 "."T1" (

"C1" TIMESTAMP(0) ,

"C2" TIMESTAMP )

IN "USERSPACE1" ;

db2 "select * from t1"

C1                           C2

-------------------  --------------------------

2011-10-26-16.47.38   2011-10-26-16.47.38.548792

  테스트 결과에서 보듯이, date 값이 timestamp(0) 으로 변환됨을 알 수 있다.

반면, 오라클 호환성을 적용하지 않고 DB를 생성한 경우 date 컬럼 속성은 변경되지 않았다.

 

2. 오라클 호환성을 적용하지 않고 DB 생성 후 오라클 호환성 적용한 경우

오라클 호환성 적용
db2set DB2_COMPATIBILITY_VECTOR=ORA

db2stop
db2start

테이블 생성
db2 "create table t1(c1 date, c2 timestamp)"

테이블 DDL 생성
db2look -d test -e -z "INST97" -t "T1"

CREATE TABLE "INST97 "."T1" (

"C1" DATE ,

"C2" TIMESTAMP )

IN "IBMDB2SAMPLEREL" ;


데이터 값 조회
db2 "select * from t1"

C1              C2

----------   --------------------------

2011-10-26   2011-10-26-16.57.49.963273

오라클 호환성을 적용하지 않고 DB 생성한 후에는 오라클 호환성 적용과 상관없이 date 형변환은 발생하지 않았다.

만일, 오라클 호환성을 DB를 생성한 상태에서 date 컬럼의 형 변환 막을 방법은 없을 것 같다. 다만 Application에서 값을 가공 처리할 수는 있을 것 같다.

개인적으로는 오라클 호환성을 적용한 경우, SQL 해석기를 DB2로 할 것인지, Oracle로 할 것인지 사용자가 선택할 수 있는 장치가 마련되어야 하지 않은가 하는 생각이 든다.

IBM 기술지원센터에 문의를 해 보지 않아서 bug 여부는 확인하지 않았다.

+ Recent posts