more..
#include "prompt.h"
exec sql include sqlca;
#define DEADABORT -60 /* DEAD LOCK ERROR CODE */
#define UNIQUE -1 /* UNIQUE VALUE ERROR CODE */
#define TRUE 1
void do_transaction();
int main()
{
exec sql begin declare section;
char cust_cid[5], cust_aid[4], cust_pid[4], cust_month[4];
float quantord, cust_qty, cust_dollars, cust_price, cust_discnt;
int ocount, cust_ordno, check_qty;
char connstr[] = "s200203937/s200203937";
exec sql end declare section;
char quantordstr[10];
int count, count1;
int dead, i, j=0, result, view;
/* orders 테이블 을 출력하기위한 curosr 설정 */
exec sql declare ordno_cursor cursor for select ordno from orders ;
/* DB 접속 */
exec sql connect :connstr;
while(1){ /* 수행을 반복하기위한 while 문 */
count = 0;
count1 =0;
exec sql whenever sqlerror goto do_rollback;
exec sql whenever sqlerror continue;
do_again: /* goto 문 */
/* 사용자로 부터 주문을 입력받는다. */
while ((prompt(" Please enter values : ",5, cust_cid, 4, cust_aid, 3, cust_pid, 3, quantordstr,6, cust_month, 3)) <0
|| (sscanf(quantordstr, "%d",&quantord) != 1)){
/* 입력값이 올바르지 않을경우 에러표시 후 exit */
printf(" invalid input !! [ex] c001 a01 p01 100000 jan \n");
goto do_error;
}
do_transaction();
/******************************** TRANSACTION START ************************************/
exec sql whenever sqlerror goto do_rollback;
exec sql whenever not found goto notfound;
exec sql select discnt into :cust_discnt from customers where cid = :cust_cid;
/* customers 테이블에서 찾는 row 가 존재 하지 않을때 goto notfound 로 이동한다. */
exec sql whenever sqlerror continue;
while(TRUE){ /* 교착상태등 을 위한 반복분 수행 */
/* select 문에서 찾는 row 가 존재 하지 않을때 goto notfound_other 로 이동한다. */
exec sql whenever not found goto notfound_other;
/* 재고량을 검사하기 전에 해당 row 를 lock 시킨다. ( for update ) */
exec sql update products set quantity = quantity - 0 where pid = :cust_pid;
exec sql select quantity, price into :cust_qty, :cust_price from products where pid = :cust_pid ;
/* 재고량을 검사하기 위한 조건문을 실행한다. 재고량이 입력값보다 적으면 에러표시후 입력창으로 되돌아간다. */
check_qty = atoi(quantordstr);
if(cust_qty - check_qty < 0){
printf(" shortage products! please input again\n");
exec sql rollback work;
goto do_again;
}
/* orders 의 ordno 최대값을 알아 내어 + 1 한다. */
exec sql select max(ordno) into : cust_ordno from orders;
cust_ordno = cust_ordno + 1;
/* orders 테이블의 dollars를 계산한다. */
cust_dollars = (check_qty * cust_price) - ( (check_qty * cust_price) * (cust_discnt * 0.01) ) ;
/* products 테이블 에서 재고량을 업데이트 한다. */
exec sql update products set quantity = quantity - :check_qty where pid = :cust_pid;
/* orders 테이블에 insert 한다. */
exec sql insert into orders (ordno, month, cid, aid, pid, qty, dollars)
values(:cust_ordno, :cust_month, :cust_cid, :cust_aid, :cust_pid, :check_qty, :cust_dollars );
/* deadlock 발생시 조건문을 시행한다. */
if(sqlca.sqlcode == DEADABORT){
count ++;
if(count < 4 ) /* deadlock 발생시 총 4번 rollback을 시도한다. */
exec sql rollback work;
else{ /* 4번이상 시도했을경우 에러표시후 exit */
dead = sqlca.sqlcode;
goto deadlock_error;
}
/* unique constraint 발생시 조건문을 시행한다. */
}else if(sqlca.sqlcode == UNIQUE){
count1 ++;
if(count1 < 4 ){ /* unique constraint 발생시 총 4번 rollback을 시도한다. */
exec sql rollback work;
}else{ /* 4번이상 시도했을경우 에러표시후 exit */
dead = sqlca.sqlcode;
goto unique_constraint_error;
}
}else if(sqlca.sqlcode < 0) /* 그 외의 에러일 경우 */
goto do_rollback;
else break; /*** 에러가 없을 경우 반복문에서 나온다. ***/
} /* end of while */
if(sqlca.sqlcode < 0)
goto do_rollback;
/************************** COMMIT DB *****************************/
/* commit 여부를 물어본다. */
while((prompt(" are you commit ? YES [ 1 ] NO [ 0 ] : ",1,view,1)) < 0)
break;
result = strcmp(view, "1");
if(result == 0 ){
printf("\n");
printf("--------------- insert complete !! ---------------\n");
printf("\n");
/* commit 하여 DB에 저장한다. */
exec sql commit work ;
/* commit 후 orders 테이블 출력 여부를 물어본다. */
while((prompt(" See orders table ? Enter the choice YES [ 1 ] NO [ 0 ] : ",1,view,1)) < 0)
goto do_again;
result = strcmp(view, "1");
if(result == 0 ){
exec sql whenever sqlerror goto do_rollback;
exec sql whenever sqlerror continue;
/* ordno 의 총개수를 얻는다. ( orders 테이블의 총 row 개수 ) */
exec sql select count(ordno) into :ocount from orders;
exec sql open ordno_cursor; /* cursor open */
printf("\n");
printf(" ORDNO MON CID AID PID QTY DOLLARS \n");
printf("---------- --- ---- --- --- ---------- -----------\n");
/* orders 테이블의 총 row 개수 만큼 반복 실행한다. */
for( i = 0 ; i < ocount ; i ++){
/* cursor 가 실행되면서 orders 테이블 의 row 를 프린트한다. */
exec sql fetch ordno_cursor into :cust_ordno;
exec sql select ordno, month, cid, aid, pid, qty, dollars into :cust_ordno, :cust_month, :cust_cid,
:cust_aid, :cust_pid, :check_qty, :cust_dollars from orders where ordno = :cust_ordno;
if( j == 11){
j = 0;
printf("\n");
printf(" ORDNO MON CID AID PID QTY DOLLARS \n");
printf("---------- --- ---- --- --- ---------- -----------\n");
}
printf(" %d %s %s %s %s\t%6d%12.0f\n",cust_ordno, cust_month, cust_cid,
cust_aid, cust_pid, check_qty, cust_dollars);
j++;
} /* end of for loop */
exec sql close ordno_cursor;
printf("\n");
printf(" %d rows selected.\n", ocount);
printf("\n");
} /* end of IF */
goto do_again;
} /* end of while */
} /* end of while */
/****************************** GOTO SECTION ************************************/
notfound:
exec sql rollback work;
printf(" customers '%s' is not exists !! please input again \n",cust_cid );
goto do_again;
notfound_other:
exec sql rollback work;
printf(" not exists value !! please input again\n" );
goto do_again;
do_rollback:
exec sql rollback release;
printf("[insert error]-> ");
print_dberror();
return 1;
do_error:
exec sql rollback release;
return 1;
deadlock_error:
exec sql rollback release;
printf(" DEADLOCK ERROR TIME OUT CODE : %d \n", dead);
return 1;
unique_constraint_error:
exec sql rollback release;
printf(" UNIQUE VALUE INSERT ERROR : %d \n", dead);
return 1;
}
/*************************** TRANSACTION Declare *********************************/
void do_transaction (void)
{
exec sql set transaction isolation level serializable;
return;
}
댓글 없음:
댓글 쓰기