5. Array Binding과 Array Fetch#
이 장은 여러 건의 데이터를 한꺼번에 처리하는 방법인 array binding과 array fetch에 대해서 설명한다.
개요#
Array Binding은 한 SQL문의 각 파라미터에 대해 배열의 값들을 한꺼번에 서버로 전달하는 방법이다. 이 방법을 사용하면 네트워크 전송 횟수가 줄어들어서 속도 향상을 얻을 수 있다.
Array Fetch는 질의 결과 집합의 행을 클라이언트에서 지정한 배열의 크기만큼 한꺼번에 서버로부터 가져오는 방법이다. 이 방법도 Array Binding과 마찬가지로 네트워크 전송 횟수를 줄이므로 속도 향상을 얻을 수 있다.
다음 그림은 Array Binding을 간략하게 도식화한 것이다. 네트워크 전송 횟수가 줄어들어 짧은 시간에 더 많은 데이터를 전송할 수 있음을 알 수 있다.
Array Binding과 Array Fetch에 대한 더 자세한 설명은 CLI User's Manual를 참고한다.
ALTIBASE_BIND 구조체 사용하기#
Array 방식으로 응용 프로그램을 작성하려면, 원래 방식과 마찬가지로 ALTIBASE_BIND 구조체와 함께 altibase_stmt_bind_param() 또는 altibase_stmt_bind_result() 함수를 이용해야 한다.
altibase_stmt_set_array_bind() 또는 altibase_stmt_set_array_fetch() 를 통해서 배열의 크기 (Array Size)가 설정되었으면, ACI 라이브러리는 array 방식을 사용하는 것이라고 판단한다. 또한, ACI 라이브러리는 ALTIBASE_BIND 구조체가 지정된 array방식에 맞춰서 설정되었을 것이라고 간주한다. 따라서, array 방식을 사용할 때는 ALTIBASE_BIND 구조체의 buffer와 buffer_length 멤버를 주의해서 설정해야 한다.
buffer#
ALTIBASE_BIND 구조체의 buffer 멤버에는 설정된 배열 크기만큼의 배열 변수가 지정되어야 한다.
다음은 ALTIBASE_BIND_INTEGER 타입의 5개의 요소를 갖는 배열을 바인딩하는 소스 코드 예제이다.
#define ARRAY_SIZE 5
/* ... omit ... */
int int_dat[ARRAY_SIZE];
ALTIBASE_BIND bind;
/* ... omit ... */
bind.buffer_type = ALTIBASE_BIND_INTEGER;
bind.buffer = int_dat;
만약 buffer에 지정한 변수의 배열 크기가 설정된 배열 크기보다 크다면, 설정된 배열 크기를 제외한 나머지 요소는 무시될 것이다.
buffer_length#
바인딩할 값이 ALTIBASE_BIND_STRING 처럼 크기가 정해져 있지 않는 타입이라면, ALTIBAE_BIND 구조체의 buffer_length 멤버 값도 정확하게 설정되어야 한다.
다음은 최대 크기가 50인 CHAR 칼럼을 위해서 5개의 요소를 갖는 배열을 바인딩하는 소스 코드 예제이다.
#define ARRAY_SIZE 5
#define STR_SIZE 50
/* ... omit ... */
char str_dat[ARRAY_SIZE][STR_SIZE];
ALTIBASE_BIND bind;
/* ... omit ... */
bind.buffer_type = ALTIBASE_BIND_STRING;
bind.buffer = str_dat;
bind.buffer_length = STR_SIZE;
ALTIBASE_BIND_INTEGER 처럼 크기가 정해져 있는 타입의 경우에는 buffer_length 값이 버퍼의 크기로 설정될 필요가 없다. 버퍼가 고정된 크기의 타입일 경우 buffer_length가 0으로 초기화 되어 있으면, ACI 라이브러리는 데이타를 담는데 필요한 크기만큼을 버퍼에 할당했다고 간주한다.
Array Binding#
Array Binding은 한 SQL문의 각 파라미터에 대해 배열 변수를 바인딩하여 한꺼번에 배열의 값들을 서버로 전달하는 방법이다. 이 방법은 네트워크 전송 횟수를 줄이므로 속도 향상을 얻을 수 있다.
예제
#define ARRAY_SIZE 2
#define PARAM_COUNT 2
#define STR_SIZE 50
#define QSTR "INSERT INTO t1 VALUES (?, ?)"
int int_dat[ARRAY_SIZE];
char str_dat[ARRAY_SIZE][STR_SIZE];
ALTIBASE_LONG length[PARAM_COUNT][ARRAY_SIZE];
ALTIBASE altibase;
ALTIBASE_STMT stmt;
ALTIBASE_BIND bind[PARAM_COUNT];
int rc;
int i;
/* ... omit ... */
int_dat[0] = 1;
int_dat[1] = 2;
strcpy(str_dat[0], "test1");
strcpy(str_dat[1], "test2");
length[0][0] = sizeof(int);
length[0][1] = sizeof(int);
length[1][0] = strlen(str_dat[0]);
length[1][1] = ALTIBASE_NTS;
memset(bind, 0, sizeof(bind));
bind[0].buffer_type = ALTIBASE_BIND_INTEGER;
bind[0].buffer = int_dat;
bind[0].length = length[0];
bind[1].buffer_type = ALTIBASE_BIND_STRING;
bind[1].buffer = str_dat;
bind[1].buffer_length = STR_SIZE;
bind[1].length = length[1];
stmt = altibase_stmt_init(altibase);
/* ... check return value ... */
rc = altibase_stmt_prepare(stmt, QSTR);
/* ... check return value ... */
rc = altibase_stmt_set_array_bind(stmt, ARRAY_SIZE);
/* ... check return value ... */
rc = altibase_stmt_bind_param(stmt, bind);
/* ... check return value ... */
rc = altibase_stmt_execute(stmt);
/* ... check return value ... */
printf("processed : %d\n", altibase_stmt_processed(stmt));
for (i = 0; i < ARRAY_SIZE; i++)
{
printf("%d status : %d\n", i, altibase_stmt_status(stmt)[i]);
}
Array Fetch#
Array Fetch는 질의 결과 집합의 행을 클라이언트에서 지정한 배열의 크기만큼 한꺼번에 서버로부터 가져오는 방법이다.
Array Fetch를 사용할 때는 altibase_stmt_fetch() 수행 시 가져온 행의 개수가 설정된 배열의 크기보다 적을 수 있다. 따라서 altibase_stmt_fetch() 수행 후에는 altibase_stmt_fetched()를 이용해서 실제로 받아온 행의 개수를 확인해야 한다. altibase_stmt_fetched()가 반환한 값이 설정된 배열의 크기보다 작으면, 더 이상 가져올 행이 없음을 의미한다.
예제
#define ARRAY_SIZE 2
#define FIELD_COUNT 2
#define STR_SIZE 50
#define QSTR "SELECT * FROM t1"
int int_dat[ARRAY_SIZE];
char str_dat[ARRAY_SIZE][STR_SIZE];
ALTIBASE_LONG length[FIELD_COUNT][ARRAY_SIZE];
ALTIBASE_BOOL is_null[FIELD_COUNT][ARRAY_SIZE];
ALTIBASE altibase;
ALTIBASE_STMT stmt;
ALTIBASE_BIND bind[FIELD_COUNT];
int rc;
int i;
int row;
int fetched;
int status;
/* ... omit ... */
stmt = altibase_stmt_init(altibase);
/* ... check return value ... */
rc = altibase_stmt_prepare(stmt, QSTR);
/* ... check return value ... */
rc = altibase_stmt_execute(stmt);
/* ... check return value ... */
rc = altibase_stmt_set_array_fetch(stmt, ARRAY_SIZE);
/* ... check return value ... */
memset(bind, 0, sizeof(bind));
bind[0].buffer_type = ALTIBASE_BIND_INTEGER;
bind[0].buffer = int_dat;
bind[0].length = length[0];
bind[0].is_null = is_null[0];
bind[1].buffer_type = ALTIBASE_BIND_STRING;
bind[1].buffer = str_dat;
bind[1].buffer_length = STR_SIZE;
bind[1].length = length[1];
bind[1].is_null = is_null[1];
rc = altibase_stmt_bind_result(stmt, bind);
/* ... check return value ... */
do
{
rc = altibase_stmt_fetch(stmt);
if (rc == ALTIBASE_NO_DATA)
{
break;
}
if (ALTIBASE_NOT_SUCCEEDED(rc))
{
/* ... error handling ... */
break;
}
fetched = altibase_stmt_fetched(stmt);
for (i = 0; i < fetched; i++)
{
printf("row %d : ", row);
status = altibase_stmt_status(stmt)[i];
if (ALTIBASE_ROW_SUCCEEDED(status))
{
if (is_null[0][i] == ALTIBASE_TRUE)
{
printf("{null}");
}
else
{
printf("%d", int_dat[i]);
}
printf(", ");
if (is_null[1][i] == ALTIBASE_TRUE)
{
printf("{null}");
}
else
{
printf("(%d) %s", length[1][i], str_dat[i]);
}
}
else
{
printf("{status:%d}", status);
}
printf("\n");
row++;
}
} while (fetched == ARRAY_SIZE);