#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sqlca.h>
/* ==== 소스 데이터 구조체 ==== */
typedef struct {
int id;
char name[50];
double amount;
} SRC_DATA;
/* ==== 상수 정의 ==== */
#define FETCH_SIZE 1000 /* FETCH 단위 */
#define COMMIT_SIZE 10000 /* COMMIT 단위 */
#define MAX_ROWS 100000000 /* 최대 누적 가능 데이터 (100GB면 메모리 주의) */
/* ==== 호스트 변수 ==== */
EXEC SQL BEGIN DECLARE SECTION;
VARCHAR src_user[50];
VARCHAR tgt_user[50];
EXEC SQL END DECLARE SECTION;
/* ==== 전역 변수 ==== */
SRC_DATA *src_data = NULL;
long total_cnt = 0;
long commit_cnt = 0;
long alloc_size = 0;
/* ==== 함수 선언 ==== */
void sql_error(const char *msg);
int main() {
int i;
long rows;
/* ==== DB 접속 ==== */
strcpy((char *)src_user.arr, "SRCUSER/PASSWORD@SRCDB");
src_user.len = strlen((char *)src_user.arr);
strcpy((char *)tgt_user.arr, "TGTUSER/PASSWORD@TGTDB");
tgt_user.len = strlen((char *)tgt_user.arr);
EXEC SQL CONNECT :src_user;
if (sqlca.sqlcode != 0) sql_error("Source CONNECT");
EXEC SQL AT :tgt_user CONNECT :tgt_user;
if (sqlca.sqlcode != 0) sql_error("Target CONNECT");
printf("Connected both DBs.\n");
/* ==== 커서 선언 ==== */
EXEC SQL DECLARE src_cur CURSOR FOR
SELECT id, name, amount FROM big_table;
EXEC SQL OPEN src_cur;
/* ==== 메모리 초기화 ==== */
alloc_size = FETCH_SIZE;
src_data = (SRC_DATA *)malloc(sizeof(SRC_DATA) * alloc_size);
if (!src_data) {
printf("Memory allocation error.\n");
exit(1);
}
/* ==== 1단계: FETCH & APPEND ==== */
while (1) {
SRC_DATA temp[FETCH_SIZE];
EXEC SQL FETCH src_cur INTO :temp;
rows = sqlca.sqlerrd[2];
if (rows == 0) break;
/* ==== 누적 저장 ==== */
if (total_cnt + rows > alloc_size) {
alloc_size *= 2; /* 2배씩 확장 */
src_data = (SRC_DATA *)realloc(src_data, sizeof(SRC_DATA) * alloc_size);
if (!src_data) {
printf("Memory realloc error.\n");
exit(1);
}
}
memcpy(&src_data[total_cnt], temp, sizeof(SRC_DATA) * rows);
total_cnt += rows;
if (total_cnt % (FETCH_SIZE * 100) == 0)
printf("Fetched %ld rows so far...\n", total_cnt);
}
EXEC SQL CLOSE src_cur;
EXEC SQL COMMIT;
printf("All FETCH completed. Total rows = %ld\n", total_cnt);
/* ==== 2단계: INSERT LOOP ==== */
for (i = 0; i < total_cnt; i++) {
EXEC SQL AT :tgt_user
INSERT INTO temp_table (id, name, amount)
VALUES (:src_data[i].id, :src_data[i].name, :src_data[i].amount);
commit_cnt++;
if (commit_cnt >= COMMIT_SIZE) {
EXEC SQL AT :tgt_user COMMIT;
printf("Committed %ld rows...\n", i + 1);
commit_cnt = 0;
}
}
/* ==== 잔여 데이터 COMMIT ==== */
if (commit_cnt > 0) {
EXEC SQL AT :tgt_user COMMIT;
printf("Final commit completed.\n");
}
EXEC SQL AT :tgt_user DISCONNECT;
EXEC SQL DISCONNECT;
free(src_data);
printf("All data transferred successfully.\n");
return 0;
}
/* ==== 에러 처리 ==== */
void sql_error(const char *msg) {
printf("SQL ERROR: %s\n", msg);
printf("SQLCODE: %ld\n", sqlca.sqlcode);
EXEC SQL WHENEVER SQLERROR CONTINUE;
EXEC SQL ROLLBACK;
exit(1);
}
|