DB 사용자 정의 데이터 타입

티베로 DBMS가 제공하는 tbJDBC에서 사용자 정의 데이터 타입을 처리하는 방법을 설명합니다.

JDBC 표준에서는 사용자 정의 데이터 타입(User Defined Types) 지원을 위해서 java.sql.Array, ja va.sql.Struct 인터페이스를 제공하고 있습니다.

  • Array 타입: 동일한 타입의 원소들을 모아서 저장하기 위한 타입

  • Struct 타입: 여러 가지 타입의 원소들을 저장하기 위한 타입

Array 타입

tbJDBC는 java.sql.Array 인터페이스를 구현한 com.tmax.tibero.jdbc.TbArray 클래스를 제공합니다.

Array 데이터 타입 선언

사용자는 아래와 같이 Array 타입을 정의할 수 있습니다.

create or replace type t_varr    is varray(16)     of varchar2(128);

create or replace type t_tbl     is table          of varchar2(128);

Array 데이터 타입 IN

Array를 객체를 만들고 PSM 프러시저의 IN 인자로 전달하기 위해서 아래의 과정으로 처리합니다.

  1. Connection 객체로부터 Array를 생성합니다.

public Array Connection.createArrayOf(String typeName, Object[] elements) 
throws SQLException;

  1. 프러시저에 Array 객체를 바인딩합니다.

CallabaleStatement의 setObject()를 통해서 Array 객체를 PSM 프러시저에 넘길 수 있습니다.

아래는 Array를 객체를 만들고 PSM 프러시저의 IN 인자로 전달하는 예제입니다.

StringBuffer sbProc = new StringBuffer();

sbProc.append("begin "); 
sbProc.append(" print_varr(?); "); 
sbProc.append("end; ");

Object[] attributes = new Object[16]; 
for (int i = 0; i < 16; i++) {
        attributes[i] = "abc" + i;
}

Array arr = conn.createArrayOf("TIBERO.T_VARR", attributes); 

CallableStatement cstmt = conn.prepareCall(sbProc.toString()); 

cstmt.setObject(1, arr);
cstmt.execute();

int status = 0; 
int i = 0;
while (status == 0) {
      cstmt = conn.prepareCall("{call sys.dbms_output.get_line(?, ?)}"); 
      cstmt.registerOutParameter(1, java.sql.Types.VARCHAR); 
      cstmt.registerOutParameter(2, java.sql.Types.NUMERIC); 
      cstmt.execute();
        
      status = cstmt.getInt(2); '
      if (status != 0)
           break;
      String retStr = cstmt.getString(1); 
      String ret[] = retStr.split(":"); 
      System.out.println(ret[1]);
}

Array 데이터 타입 OUT

프러시저로부터 OUT 인자 형태로 Array 객체를 받아오기 위해, 아래의 단계로 처리합니다.

  1. OUT 바인딩을 통한 프러시저를 호출하면 프러시저는 Array 타입 객체를 돌려줍니다.

  2. CallableStatement.getArray() 함수를 통해 Array 객체를 받아옵니다.

  3. Array 객체로부터 값을 받아옵니다.

아래는 프러시저로부터 OUT 인자 형태로 Array 객체를 받아오는 예제입니다. (p_out_t_varr 프러시저는 16개의 문자열 배열을 돌려주도록 작성되어 있습니다.)

sbProc.append("begin ");
sbProc.append(" p_out_t_varr(?, ?); "); 
sbProc.append("end; ");

CallableStatement cstmt = conn.prepareCall(sbProc.toString()); 
cstmt.registerOutParameter(1, Types.ARRAY, "TIBERO.T_VARR"); 
cstmt.setString(2, "abc");
cstmt.execute();

TbArray arr = (TbArray) cstmt.getArray(1); 

Object obj = arr.getArray();

String[] bdArr = (String[]) obj; 
assertEquals(16, bdArr.length);
for (int i = 0; i < bdArr.length; i++)
    { System.out.println(bdArr[i]);
}


Struct 타입

build-in 타입의 collection을 처리하는 Array와 달리 Struct는 여러 종류의 타입을 묶어서 나타내는 경우에 사용합니다. tbJDBC는 java.sql.Struct 인터페이스를 구현한 com.tmax.tibero.jdbc.Tb Struct 클래스를 제공합니다.

Struct 데이터 타입 선언

아래와 같이 Struct 타입을 선언할 수 있습니다.

create or replace type t_obj is object (obj_id number, name varchar(128), d date);

Struct 데이터 타입 IN

Struct 객체를 IN 인자로 전달하기 위해서는 아래의 단계로 처리합니다.

  1. Connection 객체로부터 Struct를 생성합니다.

public Struct Connection.createStruct(String typeName, Object[] attributes)

  1. 프러시저에 Struct 객체를 바인딩합니다.

CallabaleStatement의 setObject()를 통해서 Struct 객체를 PSM 프러시저에 넘길 수 있습니다.

아래는 Struct 객체를 IN 인자로 전달하는 예제입니다. print_obj 프러시저는 Struct 객체를 인자로 받아서 처리하는 기능을 담당합니다.

StringBuffer sbProc = new StringBuffer();

sbProc.append("begin "); 
sbProc.append(" print_obj(?); "); 
sbProc.append("end; ");

Object[] attributes = new Object[3]; 
attributes[0] = 1;
attributes[1] = "abc1";
Calendar cal = Calendar.getInstance(); 
cal.set(2012, 11, 21); // 2012. 12. 21
attributes[2] = new Date(cal.getTimeInMillis());

TbStruct struct = conn.createStruct("TIBERO.T_OBJ", attributes);

CallableStatement cstmt = conn.prepareCall(sbProc.toString());
cstmt.setObject(1, struct);
int row = cstmt.executeUpdate();

Struct 데이터 타입 OUT

프러시저로부터 Struct 객체를 OUT 인자 형태로 받아오기 위해 아래의 단계로 처리합니다.

  1. OUT 바인딩을 통한 프러시저를 호출한다. 프러시저는 Struct 타입의 객체를 돌려줍니다.

  2. CallableStatement.getStruct() 함수를 통해 Struct 객체를 받아옵니다.

  3. Struct 객체로부터 값을 받아옵니다.

아래는 프러시저로부터 Struct 객체를 OUT 인자형태로 받아오는 예제입니다. p_out_t_obj 프러시저는 NUMBER, VARCHAR, DATE 형태의 object 객체를 돌려줍니다.

StringBuffer sbProc = new StringBuffer();

sbProc.append("begin ");
sbProc.append(" p_out_t_obj(?); ");
sbProc.append("end; ");

CallableStatement cstmt = conn.prepareCall(sbProc.toString());
cstmt.registerOutParameter(1, Types.STRUCT, "TIBERO.T_OBJ");
cstmt.execute();

Struct struct = (Struct) cstmt.getObject(1);
Object[] structArr = struct.getAttributes();

System.out.println(structArr.length);

System.out.println("number : " + structArr[0]);
System.out.println("varchar : " + structArr[1]);
System.out.println("date : " + structArr[2]);


Array, Struct 타입 테스트 코드

아래는 위의 Array, Struct 타입 생성 및 테스트를 위한 프러시저 코드입니다.

create or replace type t_obj is object (obj_id number, name varchar(128), d date);
/
create or replace type t_varr is varray(16) of varchar2(128);
/
create or replace type t_varr_varr is varray(8) of t_varr;
/
create or replace type t_tbl is table of varchar2(128);
/
create or replace type t_tbl_tbl is table of t_tbl;
/
create or replace type t_varr_obj is varray(4) of t_obj;
/
create or replace type t_tbl_obj is table of t_obj;
/
create or replace procedure p_out_t_obj(o out t_obj)
is
begin
    o := t_obj(1,'abc',to_date('1900-01-01', 'YYYY-MM-DD')); end;
/
create or replace procedure p_out_t_varr(o out t_varr, str varchar2) 
as
    o_val t_varr; 
begin
    o_val := t_varr();
    
    for i in 1 .. 16 loop 
        o_val.extend;
        o_val(i) := str || to_char(i); 
    end loop;
    o := o_val; 
end;
/
create or replace procedure p_out_t_varr_varr(o out t_varr_varr) 
as
    o_val t_varr_varr; 
begin
    o_val := t_varr_varr();
    
    for i in 1 .. 8 loop 
        o_val.extend;
        p_out_t_varr(o_val(i), 'elem' || to_char(i)); 
    end loop;
    o := o_val; 
end;
/
create or replace procedure p_out_t_tbl(o out t_tbl, str varchar2) 
as
    o_val t_tbl; 
begin
    o_val := t_tbl();
    
    for i in 1 .. 4 loop 
        o_val.extend;
        o_val(i) := str || to_char(i); 
    end loop;
    o := o_val; 
end;
/
create or replace procedure p_out_t_tbl_tbl(o out t_tbl_tbl) 
as
    o_val t_tbl_tbl; 
begin
    o_val := t_tbl_tbl();
    
    for i in 1 .. 2 loop 
        o_val.extend;
        p_out_t_tbl(o_val(i), 'elem' || to_char(i)); 
    end loop;
    o := o_val; 
end;
/
create or replace procedure p_out_t_varr_obj(o out t_varr_obj) 
as
    o_val t_varr_obj; 
begin
    o_val := t_varr_obj(); 
    for i in 1 .. 4 loop
        o_val.extend;
        p_out_t_obj(o_val(i)); 
    end loop;
    o := o_val; 
end;
/
create or replace procedure p_out_t_tbl_obj(o out t_tbl_obj) 
as
    o_val t_tbl_obj; 
begin
    o_val := t_tbl_obj(); 
    for i in 1 .. 6 loop
        o_val.extend; 
        p_out_t_obj(o_val(i));
    end loop;
    o := o_val; 
end;
/
create or replace procedure print_obj(p in t_obj) 
as
begin
    dbms_output.put_line('obj_id:' || p.obj_id); 
    dbms_output.put_line('name :' || p.name); 
    dbms_output.put_line('d :' || p.d);
end;
/
create or replace procedure print_varr(p in t_varr) 
as
begin
    for i in 1 .. 16 loop 
        dbms_output.put_line(to_char(i) || ':' || p(i));
    end loop; 
end;
/
create or replace procedure print_varr_varr(p in t_varr_varr) 
as
begin
    for i in 1 .. 8 loop 
        print_varr(p(i));
    end loop; 
end;
/
create or replace procedure print_tbl(p in t_tbl) 
as
begin
    for i in 1 .. 4 loop
        dbms_output.put_line(to_char(i) || ':' || p(i)); 
    end loop;
end;
/
create or replace procedure print_tbl_tbl(p in t_tbl_tbl) 
as
begin
    for i in 1 .. 2 loop 
        print_tbl(p(i));
    end loop; 
end;
/
create or replace procedure print_varr_obj(p in t_varr_obj) 
as
begin
    for i in 1 .. 4 loop 
        print_obj(p(i));
    end loop; 
end;
/
create or replace procedure print_tbl_obj(p in t_tbl_obj) 
as
begin
    for i in 1 .. 6 loop 
        print_obj(p(i));
    end loop; 
end;
/

Last updated