- pc 파일. 전처리에서 에러나고 있음. 그 전에.
// ====================================================================
// employee_service.pc
// - DB 접속/해제 및 CRUD (Create, Read, Update, Delete) 로직 구현
// ====================================================================
#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
// ⚠️ PCC-S-02201 오류 해결: 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;
// -----------------------------------------------------------
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 로직에서 사용할 변수 선언
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) {
EXEC SQL BEGIN DECLARE SECTION;
char l_search_id[6];
EXEC SQL END DECLARE SECTION;
// 입력받은 사번을 Host Variable에 복사
strcpy(l_search_id, emp_id);
EXEC SQL SELECT EMPL_ID, FULL_NAME, HIRE_DATE, MARRIED, GENDER, SALARY
INTO :result_emp->emp_id, :result_emp->full_name, :result_emp->hire_date,
:result_emp->married, :result_emp->gender, :result_emp->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 오류
}
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;
strcpy(l_del_id, emp_id);
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; // 성공
}