#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// employee.h는 구조체 선언이 빠졌으므로, 함수 원형만 가져옵니다.
#include "employee.h"
// 1. Pro*C 필수 영역: SQLCA 및 호스트 변수 선언
EXEC SQL INCLUDE SQLCA;
EXEC SQL BEGIN DECLARE SECTION;
// DB 접속 정보 (사용자 환경에 맞게 수정 필요)
char db_user[] = "scott";
char db_pass[] = "tiger";
char db_connect_string[] = "ORCL"; // TNS 이름 또는 SID
// EMPLOYEE_T 정의를 여기에 직접 포함 (Pro*C에서 구조체를 DECLARE SECTION 안에서 사용 가능하도록)
struct EMPLOYEE_T {
char emp_id[6];
char full_name[31];
char hire_date[9];
char married[2];
long long salary;
char gender[2];
};
typedef struct EMPLOYEE_T EMPLOYEE_T;
EXEC SQL END DECLARE SECTION;
// ====================================================================
// Connection Logic
// ====================================================================
// DB 연결
void connect_db() {
printf("DB 연결 시도 중...\\n");
// [사용자 이름/패스워드]@[연결 문자열] 형식으로 연결
EXEC SQL CONNECT :db_user IDENTIFIED BY :db_pass USING :db_connect_string;
if (sqlca.sqlcode != 0) {
printf(" [DB ERROR] 연결 실패 (SQLCODE: %d): %s\\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
exit(1);
}
printf("DB에 성공적으로 연결되었습니다.\\n");
}
// DB 연결 해제
void disconnect_db() {
EXEC SQL COMMIT RELEASE; // 모든 트랜잭션 커밋 및 연결 해제
printf("DB 연결이 해제되었습니다.\\n");
}
// ====================================================================
// A. READ (조회)
// ====================================================================
// 1. 전체 목록 조회 (READ All)
EMPLOYEE_T* select_all_employees(int* count) {
// DB 로직에서 사용할 변수 선언 (호스트 변수는 DECLARE SECTION 안에 있어야 함)
EXEC SQL BEGIN DECLARE SECTION;
EMPLOYEE_T current_emp;
EXEC SQL END DECLARE SECTION;
// 조회 결과를 담을 동적 배열 포인터
EMPLOYEE_T* employees = NULL;
int found_count = 0;
// 커서 선언 (전체 조회)
EXEC SQL DECLARE emp_cursor CURSOR FOR
SELECT EMPL_ID, FULL_NAME, HIRE_DATE, MARRIED, GENDER, SALARY
FROM EMPLOYEES
ORDER BY EMPL_ID;
EXEC SQL OPEN emp_cursor;
// 데이터 Fetch 및 동적 배열에 추가
while (1) {
EXEC SQL FETCH emp_cursor INTO
:current_emp.emp_id, :current_emp.full_name, :current_emp.hire_date,
:current_emp.married, :current_emp.gender, :current_emp.salary;
if (sqlca.sqlcode == 1403) break; // NO DATA FOUND
if (sqlca.sqlcode != 0) {
printf(" [DB ERROR] 전체 조회 오류 (SQLCODE: %d): %s\\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
EXEC SQL CLOSE emp_cursor;
*count = 0;
if (employees != NULL) free(employees);
return NULL;
}
// 동적 메모리 재할당 (새로운 레코드를 위한 공간 확보)
employees = (EMPLOYEE_T*)realloc(employees, (found_count + 1) * sizeof(EMPLOYEE_T));
if (employees == NULL) {
printf(" [MEMORY ERROR] 메모리 할당 실패\\n");
EXEC SQL CLOSE emp_cursor;
*count = 0;
return NULL;
}
// 현재 조회된 데이터를 동적 배열의 마지막 위치에 복사
employees[found_count] = current_emp;
found_count++;
}
EXEC SQL CLOSE emp_cursor;
*count = found_count;
return employees; // 조회된 직원 정보 배열 포인터 반환
}
// 2. 상세 목록 조회 (READ One)
int select_employee_by_id(const char* emp_id, EMPLOYEE_T* result_emp) {
// Pro*C INTO 에는 DECLARE SECTION 에 선언된 호스트 변수만 사용 가능하므로,
// 로컬 호스트 변수에 SELECT 결과를 받고 그 뒤에 result_emp에 복사합니다.
EXEC SQL BEGIN DECLARE SECTION;
char l_search_id[6];
char l_emp_id[6];
char l_full_name[31];
char l_hire_date[9];
char l_married[2];
char l_gender[2];
long long l_salary;
EXEC SQL END DECLARE SECTION;
// 입력받은 사번을 Host Variable에 복사
memset(l_search_id, 0, sizeof(l_search_id));
strncpy(l_search_id, emp_id, sizeof(l_search_id)-1);
EXEC SQL SELECT EMPL_ID, FULL_NAME, HIRE_DATE, MARRIED, GENDER, SALARY
INTO :l_emp_id, :l_full_name, :l_hire_date, :l_married, :l_gender, :l_salary
FROM EMPLOYEES
WHERE EMPL_ID = :l_search_id;
if (sqlca.sqlcode == 1403) {
return -1; // 데이터 없음 (NO DATA FOUND)
} else if (sqlca.sqlcode != 0) {
printf(" [DB ERROR] 상세 조회 오류 (SQLCODE: %d): %s\\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
return -2; // DB 오류
}
// SELECT로 얻은 호스트 변수 값을 호출자 result_emp에 복사
memset(result_emp, 0, sizeof(EMPLOYEE_T));
strncpy(result_emp->emp_id, l_emp_id, sizeof(result_emp->emp_id)-1);
strncpy(result_emp->full_name, l_full_name, sizeof(result_emp->full_name)-1);
strncpy(result_emp->hire_date, l_hire_date, sizeof(result_emp->hire_date)-1);
strncpy(result_emp->married, l_married, sizeof(result_emp->married)-1);
strncpy(result_emp->gender, l_gender, sizeof(result_emp->gender)-1);
result_emp->salary = l_salary;
return 0; // 성공
}
// ====================================================================
// B. CREATE, UPDATE, DELETE (추가, 수정, 삭제)
// ====================================================================
// 3. 직원 정보 추가 (CREATE)
int insert_employee(const EMPLOYEE_T* new_emp) {
EXEC SQL BEGIN DECLARE SECTION;
EMPLOYEE_T l_emp;
EXEC SQL END DECLARE SECTION;
// 구조체 복사
l_emp = *new_emp;
EXEC SQL INSERT INTO EMPLOYEES (EMPL_ID, FULL_NAME, HIRE_DATE, MARRIED, GENDER, SALARY)
VALUES (:l_emp.emp_id, :l_emp.full_name, :l_emp.hire_date, :l_emp.married, :l_emp.gender, :l_emp.salary);
if (sqlca.sqlcode != 0) {
printf(" [DB ERROR] 직원 추가 오류 (SQLCODE: %d): %s\\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
return -1; // DB 오류
}
EXEC SQL COMMIT; // 변경 사항 반영
return 0; // 성공
}
// 4. 직원 정보 수정 (UPDATE)
int update_employee(const EMPLOYEE_T* updated_emp) {
EXEC SQL BEGIN DECLARE SECTION;
EMPLOYEE_T l_emp;
EXEC SQL END DECLARE SECTION;
l_emp = *updated_emp;
EXEC SQL UPDATE EMPLOYEES
SET FULL_NAME = :l_emp.full_name,
HIRE_DATE = :l_emp.hire_date,
MARRIED = :l_emp.married,
GENDER = :l_emp.gender,
SALARY = :l_emp.salary
WHERE EMPL_ID = :l_emp.emp_id;
if (sqlca.sqlcode != 0 && sqlca.sqlcode != 100) {
printf(" [DB ERROR] 직원 수정 오류 (SQLCODE: %d): %s\\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
return -1; // DB 오류
}
if (sqlca.sqlcode == 100 || sqlca.sqlcode == 1403) { // 100은 UPDATE/DELETE 시 레코드가 없을 때 주로 발생
return 100; // 수정된 데이터 없음 (사번 없음)
}
EXEC SQL COMMIT; // 변경 사항 반영
return 0; // 성공
}
// 5. 직원 정보 삭제 (DELETE)
int delete_employee(const char* emp_id) {
EXEC SQL BEGIN DECLARE SECTION;
char l_del_id[6];
EXEC SQL END DECLARE SECTION;
memset(l_del_id, 0, sizeof(l_del_id));
strncpy(l_del_id, emp_id, sizeof(l_del_id)-1);
EXEC SQL DELETE FROM EMPLOYEES
WHERE EMPL_ID = :l_del_id;
if (sqlca.sqlcode != 0 && sqlca.sqlcode != 100) {
printf(" [DB ERROR] 직원 삭제 오류 (SQLCODE: %d): %s\\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
return -1; // DB 오류
}
if (sqlca.sqlcode == 100 || sqlca.sqlcode == 1403) {
return 100; // 삭제된 데이터 없음 (사번 없음)
}
EXEC SQL COMMIT; // 변경 사항 반영
return 0; // 성공
}
/* Result Sets Interface */
#ifndef SQL_CRSR
# define SQL_CRSR
struct sql_cursor
{
unsigned int curocn;
void *ptr1;
void *ptr2;
unsigned int magic;
};
typedef struct sql_cursor sql_cursor;
typedef struct sql_cursor SQL_CURSOR;
#endif /* SQL_CRSR */
/* Thread Safety */
typedef void * sql_context;
typedef void * SQL_CONTEXT;
/* Object support */
struct sqltvn
{
unsigned char *tvnvsn;
unsigned short tvnvsnl;
unsigned char *tvnnm;
unsigned short tvnnml;
unsigned char *tvnsnm;
unsigned short tvnsnml;
};
typedef struct sqltvn sqltvn;
struct sqladts
{
unsigned int adtvsn;
unsigned short adtmode;
unsigned short adtnum;
sqltvn adttvn[1];
};
typedef struct sqladts sqladts;
static struct sqladts sqladt = {
1,1,0,
};
/* Binding to PL/SQL Records */
struct sqltdss
{
unsigned int tdsvsn;
unsigned short tdsnum;
unsigned char *tdsval[1];
};
typedef struct sqltdss sqltdss;
static struct sqltdss sqltds =
{
1,
0,
};
/* File name & Package Name */
struct sqlcxp
{
unsigned short fillen;
char filnam[60];
};
static const struct sqlcxp sqlfpn =
{
59,
"C:\\\\Users\\\\USER\\\\source\\\\repos\\\\EmployeesAPP\\\\employee_service.pc"
};
static unsigned int sqlctx = 2028736147;
static struct sqlexd {
unsigned int sqlvsn;
unsigned int arrsiz;
unsigned int iters;
unsigned int offset;
unsigned short selerr;
unsigned short sqlety;
unsigned int occurs;
const short *cud;
unsigned char *sqlest;
const char *stmt;
sqladts *sqladtp;
sqltdss *sqltdsp;
void **sqphsv;
unsigned int *sqphsl;
int *sqphss;
void **sqpind;
int *sqpins;
unsigned int *sqparm;
unsigned int **sqparc;
unsigned short *sqpadto;
unsigned short *sqptdso;
unsigned int sqlcmax;
unsigned int sqlcmin;
unsigned int sqlcincr;
unsigned int sqlctimeout;
unsigned int sqlcnowait;
int sqfoff;
unsigned int sqcmod;
unsigned int sqfmod;
void *sqhstv[7];
unsigned int sqhstl[7];
int sqhsts[7];
void *sqindv[7];
int sqinds[7];
unsigned int sqharm[7];
unsigned int *sqharc[7];
unsigned short sqadto[7];
unsigned short sqtdso[7];
} sqlstm = {12,7};
/* SQLLIB Prototypes */
extern void sqlcxt (void **, unsigned int *,
struct sqlexd *, const struct sqlcxp *);
extern void sqlcx2t(void **, unsigned int *,
struct sqlexd *, const struct sqlcxp *);
extern void sqlbuft(void **, char *);
extern void sqlgs2t(void **, char *);
extern void sqlorat(void **, unsigned int *, void *);
/* Forms Interface */
static const int IAPSUCC = 0;
static const int IAPFAIL = 1403;
static const int IAPFTL = 535;
extern void sqliem(unsigned char *, signed int *);
static const char *sq0003 =
"select EMPL_ID ,FULL_NAME ,HIRE_DATE ,MARRIED ,GENDER ,SALARY from EMPLOYE\\
ES order by EMPL_ID ";
typedef struct { unsigned short len; unsigned char arr[1]; } VARCHAR;
typedef struct { unsigned short len; unsigned char arr[1]; } varchar;
/* cud (compilation unit data) array */
static const short sqlcud0[] =
{12,4274,846,0,0,
5,0,0,0,0,0,27,36,0,0,4,4,0,1,0,1,97,0,0,1,97,0,0,1,97,0,0,1,10,0,0,
36,0,0,2,0,0,30,47,0,0,0,0,0,1,0,
51,0,0,3,107,0,9,73,0,0,0,0,0,1,0,
66,0,0,3,0,0,13,77,0,0,6,0,0,1,0,2,97,0,0,2,97,0,0,2,97,0,0,2,97,0,0,2,97,0,0,
2,3,0,0,
105,0,0,3,0,0,15,84,0,0,0,0,0,1,0,
120,0,0,3,0,0,15,94,0,0,0,0,0,1,0,
135,0,0,3,0,0,15,103,0,0,0,0,0,1,0,
150,0,0,4,124,0,4,128,0,0,7,1,0,1,0,2,97,0,0,2,97,0,0,2,97,0,0,2,97,0,0,2,97,0,
0,2,3,0,0,1,97,0,0,
193,0,0,5,106,0,3,166,0,0,6,6,0,1,0,1,97,0,0,1,97,0,0,1,97,0,0,1,97,0,0,1,97,0,
0,1,3,0,0,
232,0,0,6,0,0,29,174,0,0,0,0,0,1,0,
247,0,0,7,101,0,5,186,0,0,6,6,0,1,0,1,97,0,0,1,97,0,0,1,97,0,0,1,97,0,0,1,3,0,
0,1,97,0,0,
286,0,0,8,0,0,29,203,0,0,0,0,0,1,0,
301,0,0,9,41,0,2,216,0,0,1,1,0,1,0,1,97,0,0,
320,0,0,10,0,0,29,228,0,0,0,0,0,1,0,
};
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// employee.h는 구조체 선언이 빠졌으므로, 함수 원형만 가져옵니다.
#include "employee.h"
// 1. Pro*C 필수 영역: SQLCA 및 호스트 변수 선언
/* EXEC SQL INCLUDE SQLCA;
*/
/*
* $Header: sqlca.h 24-apr-2003.12:50:58 mkandarp Exp $ sqlca.h
*/
/* Copyright (c) 1985, 2003, Oracle Corporation. All rights reserved. */
/*
NAME
SQLCA : SQL Communications Area.
FUNCTION
Contains no code. Oracle fills in the SQLCA with status info
during the execution of a SQL stmt.
NOTES
**************************************************************
*** ***
*** This file is SOSD. Porters must change the data types ***
*** appropriately on their platform. See notes/pcport.doc ***
*** for more information. ***
*** ***
**************************************************************
If the symbol SQLCA_STORAGE_CLASS is defined, then the SQLCA
will be defined to have this storage class. For example:
#define SQLCA_STORAGE_CLASS extern
will define the SQLCA as an extern.
If the symbol SQLCA_INIT is defined, then the SQLCA will be
statically initialized. Although this is not necessary in order
to use the SQLCA, it is a good pgming practice not to have
unitialized variables. However, some C compilers/OS's don't
allow automatic variables to be init'd in this manner. Therefore,
if you are INCLUDE'ing the SQLCA in a place where it would be
an automatic AND your C compiler/OS doesn't allow this style
of initialization, then SQLCA_INIT should be left undefined --
all others can define SQLCA_INIT if they wish.
If the symbol SQLCA_NONE is defined, then the SQLCA variable will
not be defined at all. The symbol SQLCA_NONE should not be defined
in source modules that have embedded SQL. However, source modules
that have no embedded SQL, but need to manipulate a sqlca struct
passed in as a parameter, can set the SQLCA_NONE symbol to avoid
creation of an extraneous sqlca variable.
MODIFIED
lvbcheng 07/31/98 - long to int
jbasu 12/12/94 - Bug 217878: note this is an SOSD file
losborne 08/11/92 - No sqlca var if SQLCA_NONE macro set
Clare 12/06/84 - Ch SQLCA to not be an extern.
Clare 10/21/85 - Add initialization.
Bradbury 01/05/86 - Only initialize when SQLCA_INIT set
Clare 06/12/86 - Add SQLCA_STORAGE_CLASS option.
*/
#ifndef SQLCA
#define SQLCA 1
struct sqlca
{
/* ub1 */ char sqlcaid[8];
/* b4 */ int sqlabc;
/* b4 */ int sqlcode;
struct
{
/* ub2 */ unsigned short sqlerrml;
/* ub1 */ char sqlerrmc[70];
} sqlerrm;
/* ub1 */ char sqlerrp[8];
/* b4 */ int sqlerrd[6];
/* ub1 */ char sqlwarn[8];
/* ub1 */ char sqlext[8];
};
#ifndef SQLCA_NONE
#ifdef SQLCA_STORAGE_CLASS
SQLCA_STORAGE_CLASS struct sqlca sqlca
#else
struct sqlca sqlca
#endif
#ifdef SQLCA_INIT
= {
{'S', 'Q', 'L', 'C', 'A', ' ', ' ', ' '},
sizeof(struct sqlca),
0,
{ 0, {0}},
{'N', 'O', 'T', ' ', 'S', 'E', 'T', ' '},
{0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0}
}
#endif
;
#endif
#endif
/* end SQLCA */
/* EXEC SQL BEGIN DECLARE SECTION; */
// DB 접속 정보 (사용자 환경에 맞게 수정 필요)
char db_user[] = "scott";
char db_pass[] = "tiger";
char db_connect_string[] = "ORCL"; // TNS 이름 또는 SID
// EMPLOYEE_T 정의를 여기에 직접 포함 (Pro*C에서 구조체를 DECLARE SECTION 안에서 사용 가능하도록)
struct EMPLOYEE_T {
char emp_id[6];
char full_name[31];
char hire_date[9];
char married[2];
long long salary;
char gender[2];
};
typedef struct EMPLOYEE_T EMPLOYEE_T;
/* EXEC SQL END DECLARE SECTION; */
// ====================================================================
// Connection Logic
// ====================================================================
// DB 연결
void connect_db() {
printf("DB 연결 시도 중...\\n");
// [사용자 이름/패스워드]@[연결 문자열] 형식으로 연결
/* EXEC SQL CONNECT :db_user IDENTIFIED BY :db_pass USING :db_connect_string; */
{
struct sqlexd sqlstm;
sqlstm.sqlvsn = 12;
sqlstm.arrsiz = 4;
sqlstm.sqladtp = &sqladt;
sqlstm.sqltdsp = &sqltds;
sqlstm.iters = (unsigned int )10;
sqlstm.offset = (unsigned int )5;
sqlstm.cud = sqlcud0;
sqlstm.sqlest = (unsigned char *)&sqlca;
sqlstm.sqlety = (unsigned short)4352;
sqlstm.occurs = (unsigned int )0;
sqlstm.sqhstv[0] = ( void *)db_user;
sqlstm.sqhstl[0] = (unsigned int )0;
sqlstm.sqhsts[0] = ( int )0;
sqlstm.sqindv[0] = ( void *)0;
sqlstm.sqinds[0] = ( int )0;
sqlstm.sqharm[0] = (unsigned int )0;
sqlstm.sqadto[0] = (unsigned short )0;
sqlstm.sqtdso[0] = (unsigned short )0;
sqlstm.sqhstv[1] = ( void *)db_pass;
sqlstm.sqhstl[1] = (unsigned int )0;
sqlstm.sqhsts[1] = ( int )0;
sqlstm.sqindv[1] = ( void *)0;
sqlstm.sqinds[1] = ( int )0;
sqlstm.sqharm[1] = (unsigned int )0;
sqlstm.sqadto[1] = (unsigned short )0;
sqlstm.sqtdso[1] = (unsigned short )0;
sqlstm.sqhstv[2] = ( void *)db_connect_string;
sqlstm.sqhstl[2] = (unsigned int )0;
sqlstm.sqhsts[2] = ( int )0;
sqlstm.sqindv[2] = ( void *)0;
sqlstm.sqinds[2] = ( int )0;
sqlstm.sqharm[2] = (unsigned int )0;
sqlstm.sqadto[2] = (unsigned short )0;
sqlstm.sqtdso[2] = (unsigned short )0;
sqlstm.sqphsv = sqlstm.sqhstv;
sqlstm.sqphsl = sqlstm.sqhstl;
sqlstm.sqphss = sqlstm.sqhsts;
sqlstm.sqpind = sqlstm.sqindv;
sqlstm.sqpins = sqlstm.sqinds;
sqlstm.sqparm = sqlstm.sqharm;
sqlstm.sqparc = sqlstm.sqharc;
sqlstm.sqpadto = sqlstm.sqadto;
sqlstm.sqptdso = sqlstm.sqtdso;
sqlstm.sqlcmax = (unsigned int )100;
sqlstm.sqlcmin = (unsigned int )2;
sqlstm.sqlcincr = (unsigned int )1;
sqlstm.sqlctimeout = (unsigned int )0;
sqlstm.sqlcnowait = (unsigned int )0;
sqlcxt((void **)0, &sqlctx, &sqlstm, &sqlfpn);
}
if (sqlca.sqlcode != 0) {
printf(" [DB ERROR] 연결 실패 (SQLCODE: %d): %s\\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
exit(1);
}
printf("DB에 성공적으로 연결되었습니다.\\n");
}
// DB 연결 해제
void disconnect_db() {
/* EXEC SQL COMMIT RELEASE; */
{
struct sqlexd sqlstm;
sqlstm.sqlvsn = 12;
sqlstm.arrsiz = 4;
sqlstm.sqladtp = &sqladt;
sqlstm.sqltdsp = &sqltds;
sqlstm.iters = (unsigned int )1;
sqlstm.offset = (unsigned int )36;
sqlstm.cud = sqlcud0;
sqlstm.sqlest = (unsigned char *)&sqlca;
sqlstm.sqlety = (unsigned short)4352;
sqlstm.occurs = (unsigned int )0;
sqlcxt((void **)0, &sqlctx, &sqlstm, &sqlfpn);
}
// 모든 트랜잭션 커밋 및 연결 해제
printf("DB 연결이 해제되었습니다.\\n");
}
// ====================================================================
// A. READ (조회)
// ====================================================================
// 1. 전체 목록 조회 (READ All)
EMPLOYEE_T* select_all_employees(int* count) {
// DB 로직에서 사용할 변수 선언 (호스트 변수는 DECLARE SECTION 안에 있어야 함)
/* EXEC SQL BEGIN DECLARE SECTION; */
EMPLOYEE_T current_emp;
/* EXEC SQL END DECLARE SECTION; */
// 조회 결과를 담을 동적 배열 포인터
EMPLOYEE_T* employees = NULL;
int found_count = 0;
// 커서 선언 (전체 조회)
/* EXEC SQL DECLARE emp_cursor CURSOR FOR
SELECT EMPL_ID, FULL_NAME, HIRE_DATE, MARRIED, GENDER, SALARY
FROM EMPLOYEES
ORDER BY EMPL_ID; */
/* EXEC SQL OPEN emp_cursor; */
{
struct sqlexd sqlstm;
sqlstm.sqlvsn = 12;
sqlstm.arrsiz = 4;
sqlstm.sqladtp = &sqladt;
sqlstm.sqltdsp = &sqltds;
sqlstm.stmt = sq0003;
sqlstm.iters = (unsigned int )1;
sqlstm.offset = (unsigned int )51;
sqlstm.selerr = (unsigned short)1;
sqlstm.cud = sqlcud0;
sqlstm.sqlest = (unsigned char *)&sqlca;
sqlstm.sqlety = (unsigned short)4352;
sqlstm.occurs = (unsigned int )0;
sqlstm.sqcmod = (unsigned int )0;
sqlcxt((void **)0, &sqlctx, &sqlstm, &sqlfpn);
}
// 데이터 Fetch 및 동적 배열에 추가
while (1) {
/* EXEC SQL FETCH emp_cursor INTO
:current_emp.emp_id, :current_emp.full_name, :current_emp.hire_date,
:current_emp.married, :current_emp.gender, :current_emp.salary; */
{
struct sqlexd sqlstm;
sqlstm.sqlvsn = 12;
sqlstm.arrsiz = 6;
sqlstm.sqladtp = &sqladt;
sqlstm.sqltdsp = &sqltds;
sqlstm.iters = (unsigned int )1;
sqlstm.offset = (unsigned int )66;
sqlstm.selerr = (unsigned short)1;
sqlstm.cud = sqlcud0;
sqlstm.sqlest = (unsigned char *)&sqlca;
sqlstm.sqlety = (unsigned short)4352;
sqlstm.occurs = (unsigned int )0;
sqlstm.sqfoff = ( int )0;
sqlstm.sqfmod = (unsigned int )2;
sqlstm.sqhstv[0] = ( void *)(current_emp.emp_id);
sqlstm.sqhstl[0] = (unsigned int )6;
sqlstm.sqhsts[0] = ( int )0;
sqlstm.sqindv[0] = ( void *)0;
sqlstm.sqinds[0] = ( int )0;
sqlstm.sqharm[0] = (unsigned int )0;
sqlstm.sqadto[0] = (unsigned short )0;
sqlstm.sqtdso[0] = (unsigned short )0;
sqlstm.sqhstv[1] = ( void *)(current_emp.full_name);
sqlstm.sqhstl[1] = (unsigned int )31;
sqlstm.sqhsts[1] = ( int )0;
sqlstm.sqindv[1] = ( void *)0;
sqlstm.sqinds[1] = ( int )0;
sqlstm.sqharm[1] = (unsigned int )0;
sqlstm.sqadto[1] = (unsigned short )0;
sqlstm.sqtdso[1] = (unsigned short )0;
sqlstm.sqhstv[2] = ( void *)(current_emp.hire_date);
sqlstm.sqhstl[2] = (unsigned int )9;
sqlstm.sqhsts[2] = ( int )0;
sqlstm.sqindv[2] = ( void *)0;
sqlstm.sqinds[2] = ( int )0;
sqlstm.sqharm[2] = (unsigned int )0;
sqlstm.sqadto[2] = (unsigned short )0;
sqlstm.sqtdso[2] = (unsigned short )0;
sqlstm.sqhstv[3] = ( void *)(current_emp.married);
sqlstm.sqhstl[3] = (unsigned int )2;
sqlstm.sqhsts[3] = ( int )0;
sqlstm.sqindv[3] = ( void *)0;
sqlstm.sqinds[3] = ( int )0;
sqlstm.sqharm[3] = (unsigned int )0;
sqlstm.sqadto[3] = (unsigned short )0;
sqlstm.sqtdso[3] = (unsigned short )0;
sqlstm.sqhstv[4] = ( void *)(current_emp.gender);
sqlstm.sqhstl[4] = (unsigned int )2;
sqlstm.sqhsts[4] = ( int )0;
sqlstm.sqindv[4] = ( void *)0;
sqlstm.sqinds[4] = ( int )0;
sqlstm.sqharm[4] = (unsigned int )0;
sqlstm.sqadto[4] = (unsigned short )0;
sqlstm.sqtdso[4] = (unsigned short )0;
sqlstm.sqhstv[5] = ( void *)&(current_emp.salary);
sqlstm.sqhstl[5] = (unsigned int )sizeof(long long);
sqlstm.sqhsts[5] = ( int )0;
sqlstm.sqindv[5] = ( void *)0;
sqlstm.sqinds[5] = ( int )0;
sqlstm.sqharm[5] = (unsigned int )0;
sqlstm.sqadto[5] = (unsigned short )0;
sqlstm.sqtdso[5] = (unsigned short )0;
sqlstm.sqphsv = sqlstm.sqhstv;
sqlstm.sqphsl = sqlstm.sqhstl;
sqlstm.sqphss = sqlstm.sqhsts;
sqlstm.sqpind = sqlstm.sqindv;
sqlstm.sqpins = sqlstm.sqinds;
sqlstm.sqparm = sqlstm.sqharm;
sqlstm.sqparc = sqlstm.sqharc;
sqlstm.sqpadto = sqlstm.sqadto;
sqlstm.sqptdso = sqlstm.sqtdso;
sqlcxt((void **)0, &sqlctx, &sqlstm, &sqlfpn);
}
if (sqlca.sqlcode == 1403) break; // NO DATA FOUND
if (sqlca.sqlcode != 0) {
printf(" [DB ERROR] 전체 조회 오류 (SQLCODE: %d): %s\\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
/* EXEC SQL CLOSE emp_cursor; */
{
struct sqlexd sqlstm;
sqlstm.sqlvsn = 12;
sqlstm.arrsiz = 6;
sqlstm.sqladtp = &sqladt;
sqlstm.sqltdsp = &sqltds;
sqlstm.iters = (unsigned int )1;
sqlstm.offset = (unsigned int )105;
sqlstm.cud = sqlcud0;
sqlstm.sqlest = (unsigned char *)&sqlca;
sqlstm.sqlety = (unsigned short)4352;
sqlstm.occurs = (unsigned int )0;
sqlcxt((void **)0, &sqlctx, &sqlstm, &sqlfpn);
}
*count = 0;
if (employees != NULL) free(employees);
return NULL;
}
// 동적 메모리 재할당 (새로운 레코드를 위한 공간 확보)
employees = (EMPLOYEE_T*)realloc(employees, (found_count + 1) * sizeof(EMPLOYEE_T));
if (employees == NULL) {
printf(" [MEMORY ERROR] 메모리 할당 실패\\n");
/* EXEC SQL CLOSE emp_cursor; */
{
struct sqlexd sqlstm;
sqlstm.sqlvsn = 12;
sqlstm.arrsiz = 6;
sqlstm.sqladtp = &sqladt;
sqlstm.sqltdsp = &sqltds;
sqlstm.iters = (unsigned int )1;
sqlstm.offset = (unsigned int )120;
sqlstm.cud = sqlcud0;
sqlstm.sqlest = (unsigned char *)&sqlca;
sqlstm.sqlety = (unsigned short)4352;
sqlstm.occurs = (unsigned int )0;
sqlcxt((void **)0, &sqlctx, &sqlstm, &sqlfpn);
}
*count = 0;
return NULL;
}
// 현재 조회된 데이터를 동적 배열의 마지막 위치에 복사
employees[found_count] = current_emp;
found_count++;
}
/* EXEC SQL CLOSE emp_cursor; */
{
struct sqlexd sqlstm;
sqlstm.sqlvsn = 12;
sqlstm.arrsiz = 6;
sqlstm.sqladtp = &sqladt;
sqlstm.sqltdsp = &sqltds;
sqlstm.iters = (unsigned int )1;
sqlstm.offset = (unsigned int )135;
sqlstm.cud = sqlcud0;
sqlstm.sqlest = (unsigned char *)&sqlca;
sqlstm.sqlety = (unsigned short)4352;
sqlstm.occurs = (unsigned int )0;
sqlcxt((void **)0, &sqlctx, &sqlstm, &sqlfpn);
}
*count = found_count;
return employees; // 조회된 직원 정보 배열 포인터 반환
}
// 2. 상세 목록 조회 (READ One)
int select_employee_by_id(const char* emp_id, EMPLOYEE_T* result_emp) {
// Pro*C INTO 에는 DECLARE SECTION 에 선언된 호스트 변수만 사용 가능하므로,
// 로컬 호스트 변수에 SELECT 결과를 받고 그 뒤에 result_emp에 복사합니다.
/* EXEC SQL BEGIN DECLARE SECTION; */
char l_search_id[6];
char l_emp_id[6];
char l_full_name[31];
char l_hire_date[9];
char l_married[2];
char l_gender[2];
long long l_salary;
/* EXEC SQL END DECLARE SECTION; */
// 입력받은 사번을 Host Variable에 복사
memset(l_search_id, 0, sizeof(l_search_id));
strncpy(l_search_id, emp_id, sizeof(l_search_id)-1);
/* EXEC SQL SELECT EMPL_ID, FULL_NAME, HIRE_DATE, MARRIED, GENDER, SALARY
INTO :l_emp_id, :l_full_name, :l_hire_date, :l_married, :l_gender, :l_salary
FROM EMPLOYEES
WHERE EMPL_ID = :l_search_id; */
{
struct sqlexd sqlstm;
sqlstm.sqlvsn = 12;
sqlstm.arrsiz = 7;
sqlstm.sqladtp = &sqladt;
sqlstm.sqltdsp = &sqltds;
sqlstm.stmt = "select EMPL_ID ,FULL_NAME ,HIRE_DATE ,MARRIED ,GENDER ,S\\
ALARY into :b0,:b1,:b2,:b3,:b4,:b5 from EMPLOYEES where EMPL_ID=:b6";
sqlstm.iters = (unsigned int )1;
sqlstm.offset = (unsigned int )150;
sqlstm.selerr = (unsigned short)1;
sqlstm.cud = sqlcud0;
sqlstm.sqlest = (unsigned char *)&sqlca;
sqlstm.sqlety = (unsigned short)4352;
sqlstm.occurs = (unsigned int )0;
sqlstm.sqhstv[0] = ( void *)l_emp_id;
sqlstm.sqhstl[0] = (unsigned int )6;
sqlstm.sqhsts[0] = ( int )0;
sqlstm.sqindv[0] = ( void *)0;
sqlstm.sqinds[0] = ( int )0;
sqlstm.sqharm[0] = (unsigned int )0;
sqlstm.sqadto[0] = (unsigned short )0;
sqlstm.sqtdso[0] = (unsigned short )0;
sqlstm.sqhstv[1] = ( void *)l_full_name;
sqlstm.sqhstl[1] = (unsigned int )31;
sqlstm.sqhsts[1] = ( int )0;
sqlstm.sqindv[1] = ( void *)0;
sqlstm.sqinds[1] = ( int )0;
sqlstm.sqharm[1] = (unsigned int )0;
sqlstm.sqadto[1] = (unsigned short )0;
sqlstm.sqtdso[1] = (unsigned short )0;
sqlstm.sqhstv[2] = ( void *)l_hire_date;
sqlstm.sqhstl[2] = (unsigned int )9;
sqlstm.sqhsts[2] = ( int )0;
sqlstm.sqindv[2] = ( void *)0;
sqlstm.sqinds[2] = ( int )0;
sqlstm.sqharm[2] = (unsigned int )0;
sqlstm.sqadto[2] = (unsigned short )0;
sqlstm.sqtdso[2] = (unsigned short )0;
sqlstm.sqhstv[3] = ( void *)l_married;
sqlstm.sqhstl[3] = (unsigned int )2;
sqlstm.sqhsts[3] = ( int )0;
sqlstm.sqindv[3] = ( void *)0;
sqlstm.sqinds[3] = ( int )0;
sqlstm.sqharm[3] = (unsigned int )0;
sqlstm.sqadto[3] = (unsigned short )0;
sqlstm.sqtdso[3] = (unsigned short )0;
sqlstm.sqhstv[4] = ( void *)l_gender;
sqlstm.sqhstl[4] = (unsigned int )2;
sqlstm.sqhsts[4] = ( int )0;
sqlstm.sqindv[4] = ( void *)0;
sqlstm.sqinds[4] = ( int )0;
sqlstm.sqharm[4] = (unsigned int )0;
sqlstm.sqadto[4] = (unsigned short )0;
sqlstm.sqtdso[4] = (unsigned short )0;
sqlstm.sqhstv[5] = ( void *)&l_salary;
sqlstm.sqhstl[5] = (unsigned int )sizeof(long long);
sqlstm.sqhsts[5] = ( int )0;
sqlstm.sqindv[5] = ( void *)0;
sqlstm.sqinds[5] = ( int )0;
sqlstm.sqharm[5] = (unsigned int )0;
sqlstm.sqadto[5] = (unsigned short )0;
sqlstm.sqtdso[5] = (unsigned short )0;
sqlstm.sqhstv[6] = ( void *)l_search_id;
sqlstm.sqhstl[6] = (unsigned int )6;
sqlstm.sqhsts[6] = ( int )0;
sqlstm.sqindv[6] = ( void *)0;
sqlstm.sqinds[6] = ( int )0;
sqlstm.sqharm[6] = (unsigned int )0;
sqlstm.sqadto[6] = (unsigned short )0;
sqlstm.sqtdso[6] = (unsigned short )0;
sqlstm.sqphsv = sqlstm.sqhstv;
sqlstm.sqphsl = sqlstm.sqhstl;
sqlstm.sqphss = sqlstm.sqhsts;
sqlstm.sqpind = sqlstm.sqindv;
sqlstm.sqpins = sqlstm.sqinds;
sqlstm.sqparm = sqlstm.sqharm;
sqlstm.sqparc = sqlstm.sqharc;
sqlstm.sqpadto = sqlstm.sqadto;
sqlstm.sqptdso = sqlstm.sqtdso;
sqlcxt((void **)0, &sqlctx, &sqlstm, &sqlfpn);
}
if (sqlca.sqlcode == 1403) {
return -1; // 데이터 없음 (NO DATA FOUND)
} else if (sqlca.sqlcode != 0) {
printf(" [DB ERROR] 상세 조회 오류 (SQLCODE: %d): %s\\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
return -2; // DB 오류
}
// SELECT로 얻은 호스트 변수 값을 호출자 result_emp에 복사
memset(result_emp, 0, sizeof(EMPLOYEE_T));
strncpy(result_emp->emp_id, l_emp_id, sizeof(result_emp->emp_id)-1);
strncpy(result_emp->full_name, l_full_name, sizeof(result_emp->full_name)-1);
strncpy(result_emp->hire_date, l_hire_date, sizeof(result_emp->hire_date)-1);
strncpy(result_emp->married, l_married, sizeof(result_emp->married)-1);
strncpy(result_emp->gender, l_gender, sizeof(result_emp->gender)-1);
result_emp->salary = l_salary;
return 0; // 성공
}
// ====================================================================
// B. CREATE, UPDATE, DELETE (추가, 수정, 삭제)
// ====================================================================
// 3. 직원 정보 추가 (CREATE)
int insert_employee(const EMPLOYEE_T* new_emp) {
/* EXEC SQL BEGIN DECLARE SECTION; */
EMPLOYEE_T l_emp;
/* EXEC SQL END DECLARE SECTION; */
// 구조체 복사
l_emp = *new_emp;
/* EXEC SQL INSERT INTO EMPLOYEES (EMPL_ID, FULL_NAME, HIRE_DATE, MARRIED, GENDER, SALARY)
VALUES (:l_emp.emp_id, :l_emp.full_name, :l_emp.hire_date, :l_emp.married, :l_emp.gender, :l_emp.salary); */
{
struct sqlexd sqlstm;
sqlstm.sqlvsn = 12;
sqlstm.arrsiz = 7;
sqlstm.sqladtp = &sqladt;
sqlstm.sqltdsp = &sqltds;
sqlstm.stmt = "insert into EMPLOYEES (EMPL_ID,FULL_NAME,HIRE_DATE,MARRI\\
ED,GENDER,SALARY) values (:b0,:b1,:b2,:b3,:b4,:b5)";
sqlstm.iters = (unsigned int )1;
sqlstm.offset = (unsigned int )193;
sqlstm.cud = sqlcud0;
sqlstm.sqlest = (unsigned char *)&sqlca;
sqlstm.sqlety = (unsigned short)4352;
sqlstm.occurs = (unsigned int )0;
sqlstm.sqhstv[0] = ( void *)(l_emp.emp_id);
sqlstm.sqhstl[0] = (unsigned int )6;
sqlstm.sqhsts[0] = ( int )0;
sqlstm.sqindv[0] = ( void *)0;
sqlstm.sqinds[0] = ( int )0;
sqlstm.sqharm[0] = (unsigned int )0;
sqlstm.sqadto[0] = (unsigned short )0;
sqlstm.sqtdso[0] = (unsigned short )0;
sqlstm.sqhstv[1] = ( void *)(l_emp.full_name);
sqlstm.sqhstl[1] = (unsigned int )31;
sqlstm.sqhsts[1] = ( int )0;
sqlstm.sqindv[1] = ( void *)0;
sqlstm.sqinds[1] = ( int )0;
sqlstm.sqharm[1] = (unsigned int )0;
sqlstm.sqadto[1] = (unsigned short )0;
sqlstm.sqtdso[1] = (unsigned short )0;
sqlstm.sqhstv[2] = ( void *)(l_emp.hire_date);
sqlstm.sqhstl[2] = (unsigned int )9;
sqlstm.sqhsts[2] = ( int )0;
sqlstm.sqindv[2] = ( void *)0;
sqlstm.sqinds[2] = ( int )0;
sqlstm.sqharm[2] = (unsigned int )0;
sqlstm.sqadto[2] = (unsigned short )0;
sqlstm.sqtdso[2] = (unsigned short )0;
sqlstm.sqhstv[3] = ( void *)(l_emp.married);
sqlstm.sqhstl[3] = (unsigned int )2;
sqlstm.sqhsts[3] = ( int )0;
sqlstm.sqindv[3] = ( void *)0;
sqlstm.sqinds[3] = ( int )0;
sqlstm.sqharm[3] = (unsigned int )0;
sqlstm.sqadto[3] = (unsigned short )0;
sqlstm.sqtdso[3] = (unsigned short )0;
sqlstm.sqhstv[4] = ( void *)(l_emp.gender);
sqlstm.sqhstl[4] = (unsigned int )2;
sqlstm.sqhsts[4] = ( int )0;
sqlstm.sqindv[4] = ( void *)0;
sqlstm.sqinds[4] = ( int )0;
sqlstm.sqharm[4] = (unsigned int )0;
sqlstm.sqadto[4] = (unsigned short )0;
sqlstm.sqtdso[4] = (unsigned short )0;
sqlstm.sqhstv[5] = ( void *)&(l_emp.salary);
sqlstm.sqhstl[5] = (unsigned int )sizeof(long long);
sqlstm.sqhsts[5] = ( int )0;
sqlstm.sqindv[5] = ( void *)0;
sqlstm.sqinds[5] = ( int )0;
sqlstm.sqharm[5] = (unsigned int )0;
sqlstm.sqadto[5] = (unsigned short )0;
sqlstm.sqtdso[5] = (unsigned short )0;
sqlstm.sqphsv = sqlstm.sqhstv;
sqlstm.sqphsl = sqlstm.sqhstl;
sqlstm.sqphss = sqlstm.sqhsts;
sqlstm.sqpind = sqlstm.sqindv;
sqlstm.sqpins = sqlstm.sqinds;
sqlstm.sqparm = sqlstm.sqharm;
sqlstm.sqparc = sqlstm.sqharc;
sqlstm.sqpadto = sqlstm.sqadto;
sqlstm.sqptdso = sqlstm.sqtdso;
sqlcxt((void **)0, &sqlctx, &sqlstm, &sqlfpn);
}
if (sqlca.sqlcode != 0) {
printf(" [DB ERROR] 직원 추가 오류 (SQLCODE: %d): %s\\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
return -1; // DB 오류
}
/* EXEC SQL COMMIT; */
{
struct sqlexd sqlstm;
sqlstm.sqlvsn = 12;
sqlstm.arrsiz = 7;
sqlstm.sqladtp = &sqladt;
sqlstm.sqltdsp = &sqltds;
sqlstm.iters = (unsigned int )1;
sqlstm.offset = (unsigned int )232;
sqlstm.cud = sqlcud0;
sqlstm.sqlest = (unsigned char *)&sqlca;
sqlstm.sqlety = (unsigned short)4352;
sqlstm.occurs = (unsigned int )0;
sqlcxt((void **)0, &sqlctx, &sqlstm, &sqlfpn);
}
// 변경 사항 반영
return 0; // 성공
}
// 4. 직원 정보 수정 (UPDATE)
int update_employee(const EMPLOYEE_T* updated_emp) {
/* EXEC SQL BEGIN DECLARE SECTION; */
EMPLOYEE_T l_emp;
/* EXEC SQL END DECLARE SECTION; */
l_emp = *updated_emp;
/* EXEC SQL UPDATE EMPLOYEES
SET FULL_NAME = :l_emp.full_name,
HIRE_DATE = :l_emp.hire_date,
MARRIED = :l_emp.married,
GENDER = :l_emp.gender,
SALARY = :l_emp.salary
WHERE EMPL_ID = :l_emp.emp_id; */
{
struct sqlexd sqlstm;
sqlstm.sqlvsn = 12;
sqlstm.arrsiz = 7;
sqlstm.sqladtp = &sqladt;
sqlstm.sqltdsp = &sqltds;
sqlstm.stmt = "update EMPLOYEES set FULL_NAME=:b0,HIRE_DATE=:b1,MARRIE\\
D=:b2,GENDER=:b3,SALARY=:b4 where EMPL_ID=:b5";
sqlstm.iters = (unsigned int )1;
sqlstm.offset = (unsigned int )247;
sqlstm.cud = sqlcud0;
sqlstm.sqlest = (unsigned char *)&sqlca;
sqlstm.sqlety = (unsigned short)4352;
sqlstm.occurs = (unsigned int )0;
sqlstm.sqhstv[0] = ( void *)(l_emp.full_name);
sqlstm.sqhstl[0] = (unsigned int )31;
sqlstm.sqhsts[0] = ( int )0;
sqlstm.sqindv[0] = ( void *)0;
sqlstm.sqinds[0] = ( int )0;
sqlstm.sqharm[0] = (unsigned int )0;
sqlstm.sqadto[0] = (unsigned short )0;
sqlstm.sqtdso[0] = (unsigned short )0;
sqlstm.sqhstv[1] = ( void *)(l_emp.hire_date);
sqlstm.sqhstl[1] = (unsigned int )9;
sqlstm.sqhsts[1] = ( int )0;
sqlstm.sqindv[1] = ( void *)0;
sqlstm.sqinds[1] = ( int )0;
sqlstm.sqharm[1] = (unsigned int )0;
sqlstm.sqadto[1] = (unsigned short )0;
sqlstm.sqtdso[1] = (unsigned short )0;
sqlstm.sqhstv[2] = ( void *)(l_emp.married);
sqlstm.sqhstl[2] = (unsigned int )2;
sqlstm.sqhsts[2] = ( int )0;
sqlstm.sqindv[2] = ( void *)0;
sqlstm.sqinds[2] = ( int )0;
sqlstm.sqharm[2] = (unsigned int )0;
sqlstm.sqadto[2] = (unsigned short )0;
sqlstm.sqtdso[2] = (unsigned short )0;
sqlstm.sqhstv[3] = ( void *)(l_emp.gender);
sqlstm.sqhstl[3] = (unsigned int )2;
sqlstm.sqhsts[3] = ( int )0;
sqlstm.sqindv[3] = ( void *)0;
sqlstm.sqinds[3] = ( int )0;
sqlstm.sqharm[3] = (unsigned int )0;
sqlstm.sqadto[3] = (unsigned short )0;
sqlstm.sqtdso[3] = (unsigned short )0;
sqlstm.sqhstv[4] = ( void *)&(l_emp.salary);
sqlstm.sqhstl[4] = (unsigned int )sizeof(long long);
sqlstm.sqhsts[4] = ( int )0;
sqlstm.sqindv[4] = ( void *)0;
sqlstm.sqinds[4] = ( int )0;
sqlstm.sqharm[4] = (unsigned int )0;
sqlstm.sqadto[4] = (unsigned short )0;
sqlstm.sqtdso[4] = (unsigned short )0;
sqlstm.sqhstv[5] = ( void *)(l_emp.emp_id);
sqlstm.sqhstl[5] = (unsigned int )6;
sqlstm.sqhsts[5] = ( int )0;
sqlstm.sqindv[5] = ( void *)0;
sqlstm.sqinds[5] = ( int )0;
sqlstm.sqharm[5] = (unsigned int )0;
sqlstm.sqadto[5] = (unsigned short )0;
sqlstm.sqtdso[5] = (unsigned short )0;
sqlstm.sqphsv = sqlstm.sqhstv;
sqlstm.sqphsl = sqlstm.sqhstl;
sqlstm.sqphss = sqlstm.sqhsts;
sqlstm.sqpind = sqlstm.sqindv;
sqlstm.sqpins = sqlstm.sqinds;
sqlstm.sqparm = sqlstm.sqharm;
sqlstm.sqparc = sqlstm.sqharc;
sqlstm.sqpadto = sqlstm.sqadto;
sqlstm.sqptdso = sqlstm.sqtdso;
sqlcxt((void **)0, &sqlctx, &sqlstm, &sqlfpn);
}
if (sqlca.sqlcode != 0 && sqlca.sqlcode != 100) {
printf(" [DB ERROR] 직원 수정 오류 (SQLCODE: %d): %s\\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
return -1; // DB 오류
}
if (sqlca.sqlcode == 100 || sqlca.sqlcode == 1403) { // 100은 UPDATE/DELETE 시 레코드가 없을 때 주로 발생
return 100; // 수정된 데이터 없음 (사번 없음)
}
/* EXEC SQL COMMIT; */
{
struct sqlexd sqlstm;
sqlstm.sqlvsn = 12;
sqlstm.arrsiz = 7;
sqlstm.sqladtp = &sqladt;
sqlstm.sqltdsp = &sqltds;
sqlstm.iters = (unsigned int )1;
sqlstm.offset = (unsigned int )286;
sqlstm.cud = sqlcud0;
sqlstm.sqlest = (unsigned char *)&sqlca;
sqlstm.sqlety = (unsigned short)4352;
sqlstm.occurs = (unsigned int )0;
sqlcxt((void **)0, &sqlctx, &sqlstm, &sqlfpn);
}
// 변경 사항 반영
return 0; // 성공
}
// 5. 직원 정보 삭제 (DELETE)
int delete_employee(const char* emp_id) {
/* EXEC SQL BEGIN DECLARE SECTION; */
char l_del_id[6];
/* EXEC SQL END DECLARE SECTION; */
memset(l_del_id, 0, sizeof(l_del_id));
strncpy(l_del_id, emp_id, sizeof(l_del_id)-1);
/* EXEC SQL DELETE FROM EMPLOYEES
WHERE EMPL_ID = :l_del_id; */
{
struct sqlexd sqlstm;
sqlstm.sqlvsn = 12;
sqlstm.arrsiz = 7;
sqlstm.sqladtp = &sqladt;
sqlstm.sqltdsp = &sqltds;
sqlstm.stmt = "delete from EMPLOYEES where EMPL_ID=:b0";
sqlstm.iters = (unsigned int )1;
sqlstm.offset = (unsigned int )301;
sqlstm.cud = sqlcud0;
sqlstm.sqlest = (unsigned char *)&sqlca;
sqlstm.sqlety = (unsigned short)4352;
sqlstm.occurs = (unsigned int )0;
sqlstm.sqhstv[0] = ( void *)l_del_id;
sqlstm.sqhstl[0] = (unsigned int )6;
sqlstm.sqhsts[0] = ( int )0;
sqlstm.sqindv[0] = ( void *)0;
sqlstm.sqinds[0] = ( int )0;
sqlstm.sqharm[0] = (unsigned int )0;
sqlstm.sqadto[0] = (unsigned short )0;
sqlstm.sqtdso[0] = (unsigned short )0;
sqlstm.sqphsv = sqlstm.sqhstv;
sqlstm.sqphsl = sqlstm.sqhstl;
sqlstm.sqphss = sqlstm.sqhsts;
sqlstm.sqpind = sqlstm.sqindv;
sqlstm.sqpins = sqlstm.sqinds;
sqlstm.sqparm = sqlstm.sqharm;
sqlstm.sqparc = sqlstm.sqharc;
sqlstm.sqpadto = sqlstm.sqadto;
sqlstm.sqptdso = sqlstm.sqtdso;
sqlcxt((void **)0, &sqlctx, &sqlstm, &sqlfpn);
}
if (sqlca.sqlcode != 0 && sqlca.sqlcode != 100) {
printf(" [DB ERROR] 직원 삭제 오류 (SQLCODE: %d): %s\\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
return -1; // DB 오류
}
if (sqlca.sqlcode == 100 || sqlca.sqlcode == 1403) {
return 100; // 삭제된 데이터 없음 (사번 없음)
}
/* EXEC SQL COMMIT; */
{
struct sqlexd sqlstm;
sqlstm.sqlvsn = 12;
sqlstm.arrsiz = 7;
sqlstm.sqladtp = &sqladt;
sqlstm.sqltdsp = &sqltds;
sqlstm.iters = (unsigned int )1;
sqlstm.offset = (unsigned int )320;
sqlstm.cud = sqlcud0;
sqlstm.sqlest = (unsigned char *)&sqlca;
sqlstm.sqlety = (unsigned short)4352;
sqlstm.occurs = (unsigned int )0;
sqlcxt((void **)0, &sqlctx, &sqlstm, &sqlfpn);
}
// 변경 사항 반영
return 0; // 성공
}
// ====================================================================
// employee_main.c
// - UI 및 프로그램 흐름 제어 로직 구현
// ====================================================================
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "employee.h" // 함수 원형 포함
// employee.h에서 제거된 EMPLOYEE_T 구조체 정의를 여기에 직접 포함
struct EMPLOYEE_T {
char emp_id[6];
char full_name[31];
char hire_date[9];
char married[2];
long long salary;
char gender[2];
};
typedef struct EMPLOYEE_T EMPLOYEE_T;
// -----------------------------------------------------------
// ====================================================================
// A. 공통 UI 함수 (employee.h에 선언)
// ====================================================================
// 직원 정보 출력 함수 (Service 함수가 반환한 데이터를 받아서 출력만 담당)
void display_employee_info(EMPLOYEE_T emp, int detail_mode) {
char on_leave_status[] = "Working"; // 재직 상태는 현재 코드에서 임의로 "Working"으로 고정
if (detail_mode == 0) {
// 목록 조회 모드 (간략 정보)
printf("%-10s // %-20s // %s\\n",
emp.emp_id, emp.full_name, on_leave_status);
}
else {
// 상세 조회 모드
printf("\\n--- 직원 상세 정보 ---\\n");
printf(" - 사번 (EMP_ID) : %s\\n", emp.emp_id);
printf(" - 이름 (FULL_NAME) : %s\\n", emp.full_name);
printf(" - 입사일 (HIRE_DATE): %s\\n", emp.hire_date);
printf(" - 결혼 여부 : %s\\n", emp.married);
printf(" - 성별 (GENDER) : %s\\n", emp.gender);
printf(" - 연봉 (SALARY) : %lld\\n", emp.salary); // long long에 맞게 %lld 사용
printf(" - 재직 상태 : %s\\n", on_leave_status);
printf("----------------------\\n");
}
}
// ====================================================================
// B. Presentation Layer (각 기능별 화면/입력 처리 로직)
// ====================================================================
// 1. 전체 직원 목록 조회 UI
void print_all_employees_ui() {
int count = 0;
// **Service 함수 호출:** DB에서 데이터 조회
EMPLOYEE_T* employees = select_all_employees(&count);
printf("\\n============================================\\n");
printf(" ? DB에서 가져온 전체 직원 목록 ?\\n");
printf("============================================\\n");
printf("%-10s // %-20s // %s\\n", "사번", "이름", "상태");
printf("--------------------------------------------\\n");
if (count > 0 && employees != NULL) {
// 화면 출력 로직
for (int i = 0; i < count; i++) {
display_employee_info(employees[i], 0);
}
}
else if (count == 0) {
printf("조회된 직원이 없습니다.\\n");
}
else {
printf("데이터 조회 중 오류가 발생했습니다.\\n");
}
printf("============================================\\n");
printf("총 %d명의 직원을 DB에서 조회했습니다.\\n", count);
// 메모리 해제
if (employees != NULL) free(employees); // 더 이상 메모리 사용 안하니, 메모리 초기화.
}
// 2. 특정 직원 상세 조회 UI
void print_employee_detail_ui() {
char search_id[6];
EMPLOYEE_T detail_emp;
printf("\\n조회할 사원의 사번(EMP_ID)을 입력하세요: ");
if (scanf("%s", search_id) != 1) return;
// **Service 함수 호출:** DB에서 데이터 조회
int result = select_employee_by_id(search_id, &detail_emp);
if (result == 0) {
display_employee_info(detail_emp, 1); // 성공 시 화면 출력
}
else if (result == -1) {
printf("\\n 사번 [%s]에 해당하는 직원을 찾을 수 없습니다.\\n", search_id);
}
else {
printf("\\n 상세 조회 처리 중 DB 오류가 발생했습니다.\\n");
}
}
// 3. 직원 추가 UI (CREATE)
void insert_employee_ui() {
EMPLOYEE_T new_emp;
printf("\\n--- 신규 직원 정보 입력 ---\\n");
printf("사번 (EMP_ID, 5자): "); if (scanf("%s", new_emp.emp_id) != 1) return;
printf("이름 (FULL_NAME): "); if (scanf("%s", new_emp.full_name) != 1) return;
printf("입사일 (HIRE_DATE, YYYYMMDD): "); if (scanf("%s", new_emp.hire_date) != 1) return;
printf("결혼 여부 (Y/N): "); if (scanf("%s", new_emp.married) != 1) return;
printf("성별 (M/F): "); if (scanf("%s", new_emp.gender) != 1) return;
printf("연봉 (SALARY): ");
if (scanf("%lld", &new_emp.salary) != 1) {
printf("오류: 연봉 입력이 올바르지 않습니다.\\n");
// 입력 버퍼 비우기
while (getchar() != '\\n');
return;
}
// **Service 함수 호출:** DB에 데이터 추가
int result = insert_employee(&new_emp);
if (result == 0) {
printf("\\n 사번 [%s] 직원이 성공적으로 추가되었습니다.\\n", new_emp.emp_id);
}
else {
printf("\\n 직원 추가 중 오류가 발생했습니다. (DB 에러)\\n");
}
}
// 4. 직원 정보 수정 UI (UPDATE)
void update_employee_ui() {
char search_id[6];
EMPLOYEE_T old_emp, updated_emp;
printf("\\n--- 직원 정보 수정 ---\\n");
printf("수정할 직원의 사번(EMP_ID)을 입력하세요: ");
if (scanf("%s", search_id) != 1) return;
// 먼저 기존 데이터 조회 (수정할 대상이 있는지 확인)
if (select_employee_by_id(search_id, &old_emp) != 0) {
printf("사번 [%s]에 해당하는 직원을 찾을 수 없습니다.\\n", search_id);
return;
}
// 사번은 수정하지 않으므로 복사
strcpy(updated_emp.emp_id, old_emp.emp_id);
printf("수정 전 이름: %s\\n", old_emp.full_name);
printf("새 이름 (FULL_NAME): "); if (scanf("%s", updated_emp.full_name) != 1) return;
printf("새 입사일 (HIRE_DATE, %s): ", old_emp.hire_date); if (scanf("%s", updated_emp.hire_date) != 1) return;
printf("새 결혼 여부 (Y/N, %s): ", old_emp.married); if (scanf("%s", updated_emp.married) != 1) return;
printf("새 성별 (M/F, %s): ", old_emp.gender); if (scanf("%s", updated_emp.gender) != 1) return;
printf("새 연봉 (SALARY, %lld): ", old_emp.salary);
if (scanf("%lld", &updated_emp.salary) != 1) {
printf("오류: 연봉 입력이 올바르지 않습니다.\\n");
// 입력 버퍼 비우기
while (getchar() != '\\n');
return;
}
// **Service 함수 호출:** DB에 데이터 수정
int result = update_employee(&updated_emp);
if (result == 0) {
printf("\\n 사번 [%s] 직원의 정보가 성공적으로 수정되었습니다.\\n", updated_emp.emp_id);
}
else if (result == 100) {
printf("\\n 수정 대상 직원을 찾을 수 없습니다. (사번 불일치)\\n");
}
else {
printf("\\n 직원 정보 수정 중 오류가 발생했습니다. (DB 에러)\\n");
}
}
// 5. 직원 삭제 UI (DELETE)
void delete_employee_ui() {
char delete_id[6];
printf("\\n--- 직원 삭제 ---\\n");
printf("삭제할 직원의 사번(EMP_ID)을 입력하세요: ");
if (scanf("%s", delete_id) != 1) return;
// **Service 함수 호출:** DB에서 데이터 삭제
int result = delete_employee(delete_id);
if (result == 0) {
printf("\\n 사번 [%s] 직원이 성공적으로 삭제되었습니다.\\n", delete_id);
}
else if (result == 100) {
printf("\\n 사번 [%s]에 해당하는 직원을 찾을 수 없습니다.\\n", delete_id);
}
else {
printf("\\n 직원 삭제 중 오류가 발생했습니다. (DB 에러)\\n");
}
}
// ====================================================================
// C. Main 로직 (프로그램의 시작과 종료, 흐름 제어)
// ====================================================================
// 메인 메뉴 표시
void display_main_menu() {
printf("\\n====================================\\n");
printf(" [ 직원 관리 프로그램 ] \\n");
printf("====================================\\n");
printf(" 1. 전체 목록 조회 (READ All) \\n");
printf(" 2. 상세 정보 조회 (READ One) \\n");
printf(" 3. 신규 직원 추가 (CREATE) \\n");
printf(" 4. 직원 정보 수정 (UPDATE) \\n");
printf(" 5. 직원 정보 삭제 (DELETE) \\n");
printf(" 6. 프로그램 종료 (EXIT) \\n");
printf("------------------------------------\\n");
printf("선택 > ");
}
int main() {
int choice;
connect_db(); // 1. DB 연결 (Service Layer 호출)
while (1) {
display_main_menu();
if (scanf("%d", &choice) != 1) {
// 잘못된 입력 처리 (문자 입력 등)
printf("\\n 잘못된 입력입니다. 1~6 사이의 숫자를 입력해주세요.\\n");
// 입력 버퍼 비우기
while (getchar() != '\\n');
continue;
}
switch (choice) {
case 1:
print_all_employees_ui(); // 전체 조회 UI 호출
break;
case 2:
print_employee_detail_ui(); // 상세 조회 UI 호출
break;
case 3:
insert_employee_ui(); // 추가 UI 호출
break;
case 4:
update_employee_ui(); // 수정 UI 호출
break;
case 5:
delete_employee_ui(); // 삭제 UI 호출
break;
case 6:
printf("\\n프로그램을 종료합니다.\\n");
disconnect_db(); // 2. DB 연결 해제 (Service Layer 호출)
return 0;
default:
printf("\\n 올바른 메뉴 번호를 선택해주세요. (1~6)\\n");
break;
}
}
return 0;
}
// ====================================================================
// employee.h
// - 직원 구조체(EMPLOYEE_T) 선언 및 모든 함수 원형 선언
// ====================================================================
#ifndef EMPLOYEE_H
#define EMPLOYEE_H
#include <stdio.h>
// 1. Pro*C 오류 방지: 구조체 정의는 .pc 파일과 .main.c 파일에 직접 포함
// -- 이 헤더 파일에는 구조체의 정의를 두지 않습니다.
struct EMPLOYEE_T; // 불완전 타입 선언
typedef struct EMPLOYEE_T EMPLOYEE_T; // typedef만 남겨둠
// 2. Service Layer (DB 로직) 함수 원형 선언
// READ
EMPLOYEE_T* select_all_employees(int* count);
int select_employee_by_id(const char* emp_id, EMPLOYEE_T* result_emp);
// CREATE, UPDATE, DELETE
int insert_employee(const EMPLOYEE_T* new_emp);
int update_employee(const EMPLOYEE_T* updated_emp);
int delete_employee(const char* emp_id);
// Connection // connect_db, disconnect_db 는 DB 연결 및 해제 기능을 선언하는 거. void는 반환값이 없는 거.
void connect_db();
void disconnect_db();
// 3. Presentation Layer (공통 UI 로직) 함수 원형 선언
void display_employee_info(EMPLOYEE_T emp, int detail_mode);
#endif // EMPLOYEE_H