드디어 오라클 마지막 질문 ㅜ.ㅜ
글쓴이: cjy1126 / 작성시간: 수, 2003/04/02 - 9:20오후
답변해주신분들 정말 감사합니다.
sample 파일과 책... 가장 중요한 답변 덕에 스터디 프로젝트 임무인 select를 해냈습니다. ^^
그런데 또 문제가 생겼습니다.
제가 전해줄 파일은 db.pc proc로 컴파일한 파일인 db.c db.h 2개이고
테스트용으로 main.c 파일을 만들었습니다.
이건 db.h 입니다.
#include <stdio.h> #include <string.h> #include <sqlca.h> #include <stdlib.h> #include <sqlda.h> #include <sqlcpr.h> void oracle_connect(); void cursor_define(); void select_addr(char *addr[]); void oracle_close();
이건 proc로 컴파일한 db.c 입니다.
#include "db.h"
char *username="mini";
char *password="mini";
char saddr[16];
void oracle_connect()
{
EXEC SQL CONNECT :username IDENTIFIED BY :password;
printf("\nConnected to ORACLE as user: %s\n", username);
}
void cursor_define()
{
EXEC SQL DECLARE select CURSOR FOR SELECT SADDR FROM SERVER;
}
void select_addr(char *addr[])
{
int i;
for(i=0; i<10; i++)
memset(addr[i], '\0', (sizeof(char)*16));
EXEC SQL OPEN select;
EXEC SQL WHENEVER NOT FOUND DO break;
i=0;
for( ; ; )
{
EXEC SQL FETCH select INTO :saddr;
strcpy(addr[i], saddr);
i++;
}
EXEC SQL CLOSE select;
}
void oracle_close()
{
EXEC SQL COMMIT WORK RELEASE;
exit(0);
}
test용 main.c 입니다.
#include "db.h"
main()
{
char *addr[10];
int i;
for(i=0; i<10; i++)
addr[i] = (char *)malloc(sizeof(char)*16);
oracle_connect();
cursor_define();
select_addr(addr);
for(i=0; addr[i]!=NULL; i++)
printf("%s\n", addr[i]);
oracle_close();
}
출력이 이렇게 되네요.
[root@CP36 mini]# ./db Connected to ORACLE as user: mini 192.168.2.37 211.218.217.1 192.168.3.73 200.123.245.0 ]惶홼 ? U?R? ? 횾?> Segmentation fault [root@CP36 mini]#
포인터 배열 10개를 미리 만들어서 select를 받았는데, 실제 데이타는 4개가 있었습니다.
오라클과 C가 NULL 개념이 달라서 그런거 같은데, 해결 방법을 모르겠습니다.
그렇다고 i<10까지 찍으면 빈줄이 6줄 생기고... 난감하네요 ㅜ.ㅜ
도움 부탁드립니다.
Forums:


패치한 후에..
패치한 후에... sqlca.sqlcode 값을 확인해서
제대로 패치 했는지 확인해봐야 겠죠
아래는 예입니다.,
/**********************************************************************/ /* 주식 계좌복구 */ /**********************************************************************/ int re_geja_func_01() { char geja1[12], geja2[12], id[21], start_ymd[9]; double seed_money; int rtn = 0; EXEC SQL DECLARE cur_func_01 CURSOR FOR SELECT A.geja, NVL(B.geja, 'NULL'), A.id, A.start_ymd, A.seed_money FROM moredb.moresgeja a, moredb.moresyesu b WHERE a.geja_gb = '01' AND a.geja = b.geja (+) AND a.end_ymd >= :Base_ymd order by a.geja; EXEC SQL OPEN cur_func_01; if (sqlca.sqlcode != 0) { OUT("[%s] re_geja_func_01 : OPEN CURSOR Error [%d][%s]\n", pname, sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); return -1; } for (;;){ memset(geja1, 0x00, sizeof(geja1)); memset(geja2, 0x00, sizeof(geja2)); memset(id, 0x00, sizeof(id)); memset(start_ymd, 0x00, sizeof(start_ymd)); seed_money = 0.0; EXEC SQL FETCH cur_func_01 INTO :geja1, :geja2, :id, :start_ymd, :seed_money; if (sqlca.sqlcode == 1403) break; if (sqlca.sqlcode != 0) { OUT("[%s] re_geja_func_01 : FETCH CURSOR Error [%d][%s]\n", pname, sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); EXEC SQL CLOSE cur_func_01; return -1; } OUT("[%s] FETCH geja[%s]<->[%s] id[%.8s] ymd[%s] seed_money[%12.0f]\n", pname, geja1, geja2, id, start_ymd, seed_money); /* 계좌정보가 삭제되었다.. 복구 작업 시작. */ if(memcmp(geja1, geja2, 11) != 0) { printf("[%s] FETCH geja[%s]<->[%s] id[%.8s] ymd[%s] seed_money[%12.0f]\n", pname, geja1, geja2, id, start_ymd, seed_money); rtn = StockGejaRegistry(start_ymd, geja1); if(rtn < 0) { OUT("[%s] re_geja_func_01 : StockGejaRegistry Error rtn[%d] ymd[%s] geja[%s] \n", pname, rtn, start_ymd, geja1); EXEC SQL CLOSE cur_func_01; return -2; } rtn = StockGejaCashInOut(start_ymd, geja1, seed_money); if(rtn < 0) { OUT("[%s] re_geja_func_01 : StockGejaCashInOut Error rtn[%d] ymd[%s] geja[%s] seed[%.0f]", pname, rtn, start_ymd, geja1, seed_money); EXEC SQL CLOSE cur_func_01; return -3; } } } EXEC SQL CLOSE cur_func_01; return 1; }울랄라~ 호기심 천국~!!
http://www.ezdoum.com
ㅜ.ㅜ
답변 감사합니다.
그런데... 이해가 안돼요 :cry:
^^;
EXEC SQL FETCH cur_func_01 INTO :geja1, :geja2, :id, :start_ymd, :seed_money; if (sqlca.sqlcode == 1403) break; if (sqlca.sqlcode != 0) { OUT("[%s] re_geja_func_01 : FETCH CURSOR Error [%d][%s]\n", pname, sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); EXEC SQL CLOSE cur_func_01; return -1; }exec로 sql문을 실행하면
sqlca.sqlcode에 상태코드가 들어가게 됩니다.
그래서 select해서 아무것도 없거나 fetch가 안되거나 하면
알아 챌수가 있는거죠.
1403이 record not found 입니다.
pro*c 책 중에 이부분을 안다루는 게 없을텐데.. ^^
책 색인에서 한번 찾아보세요...
그리고 pro*c로 돌리고 나면 c파일이 생기는데,
pro*c가 만들어낸 c파일을 한번 열어서 분석해보세요
그럼 오라클이 뭘 어떻게 원하는지 pc파일을 어케 만들어야 하는지
계념을 잡는데 도움이 됩니다.
울랄라~ 호기심 천국~!!
http://www.ezdoum.com
네 pro*c 책을 찾아보겠습니다.
지금 oracle bible 영진책을 보고 있어서요.
pro*c가 엄청 조금 나왔네요.
설명도 거의 없고 -_-;
설명대로 sqlca.sqlcode == 1403 해도 여전히 쓰레기가 나오네요.
지금 sqlca 와 sqlcode로 맹서치중입니다 ^^
답변 감사합니다.
오늘 너무 많은걸 배워서 기쁘네요 ^^
sqlcode 값이 0 이면 성공입니다.
sqlcode가 -1403 이면 더이상 데이터가 없는것으로 간주합니다. 그런데 일단 0이 아니면 에러니까 루프를 벗어나야 합니다.
그리고 fetch 할때 한개씩 할때(실제로는 보통 몇십개씩 fetch하는게 더 좋고, 더 자세하게 할려면 descriptor를 사용하는게 좋죠)는 배열이 아니라 한개의 구조체를 계속 재사용합니다.
========================================
* The truth will set you free.
ㅡ.ㅡ
보통 오라클에서 커서를 사용해서 하나의 row씩 처리하는 문의 구조는 다음과 같습니다.
declare cursor_name cursor ......; open cursor_name ..; while (1) { fetch .. into ....; if (SQLCODE == 1403) break; else if (SQLCODE != 0) { 오류처리; break; } 받아온 데이터 처리; } close cursor_name;1403은 DB 모드에 따라서 틀려질 수 있는 값이니까 define 문을 사용하셔도 되겠구요. SQLCODE는 sqlca.sqlcode를 의미하고요.
아마 님의 경우에는 WHENEVER NOT FOUND DO break;
문을 주셨으니까 SQLCODE를 검사 안해도 오라클에서 알아서 빠져나오도록
했을꺼 같습니다. 근데 다른 오류는 검사를 하지 않으셨네요. 실제로 쓰실 때에는 다른 오류도 검사하도록 하셔야 할꺼구요.
문제는 데이터를 가져온 후 출력할 때 출력조건 (NULL) 때문에 그렇습니다.
프로그램 초기에 10개의 포인터 배열을 만들고, 그 다음 문장에서 배열의 포인터들에 malloc()을 통해서 값을 할당해 주잖아요.
그러면 addr[i] 값을은 NULL이 아니라 할당된 주소를 가리키고 있습니다.
select_addr에 들어가서 해 주는 일은 각 배열의 포인터가 가리키고 있는 주소공간을 '\0' 들로 채워주고요.
for 루프를 돌면서 fetch를 통해서 DB에 들어있는 데이터를 addr[0]부터 쭈욱 채워주고요.
그리고는 select_addr()을 빠져나와서 main()에서 for loop를 이용해서 받아온 데이터를 출력하죠.
만일 4개의 데이터가 있었으면, 님께서는 addr[4] 가 NULL 이 되기를 기대하셔서 addr[4] != NULL 조건을 만족하지 않아서 for loop가 끝나기를 바랄텐데요,,
addr[4] 는 분명 '\0' 이 16개 들어있는 것은 맞지만 addr[4] 자체는 NULL 이 아닙니다. addr[4] 는 '\0'이 16개 들어있는 공간을 가리키는 주소값이 들어있습니다.
for 문을 다음과 같이 수정하시면 될 것입니다.
for(i=0; addr[i][0]!='\0'; i++) printf("%s\n", addr[i]);아니면 select_addr에서 몇개의 데이터를 fetch했는지 counter를 명시적으로 파라메터로 주고 받든지요.
다른 얘기 하나.
cursor 이름으로 select를 사용한 건 혼란을 일으킬만하니까 다른 것으로 바꾸시는 게 좋을 듯 합니다. ^^
select 한 건수는 sqlca.sqlerrd[2]
select 한 건수는 sqlca.sqlerrd[2] 입니다.
즉, sqlca 구조체의 멤버중에 sqlerrd 라는 이름의 int 형 배열이 있는데 이들중 3번째 ([2] 니까) 값에 실행한 횟수가 들어있습니다.
또 sqlca.sqlerrd[2]는 fetch뿐 아니라 insert, update. delete 건수도 들어간다고 하더군요.
(그럼 sqlca.sqlerrd[0], sqlca.sqlerrd[1] , sqlca.sqlerrd[3] 등은 뭐죠?)
내 자식들도 나처럼 !!
...흠..
malloc.... 초기화 안되는....... NULL 이 아니라서...
댓글 달기