지금 우리 완전 비밀 요원처럼 행동하는 거 알지? 우리 함수랑 프로시저들은 미션을 수행해: 데이터 처리하고, 계산하고, 아니면 그냥 데이터베이스 안에서 마법 부리기도 하고. 근데 뭔가 잘못되면 어떻게 알지? "데이터 마사지 욕조"가 어디서 망가졌는지 어떻게 파악해? 이럴 때 로깅이랑 에러 처리가 진짜 도움 돼.
기억나? PostgreSQL이랑 PL/pgSQL에서 어떻게 "소통"하고 로그 남기는지 이미 살짝 봤었잖아:
RAISE NOTICE: 완전 편안하고 친근한 느낌 — "야, 여기 다 괜찮은데, 혹시 궁금하면 한 번 봐봐~".RAISE WARNING: 살짝 더 큰 목소리 — "어, 뭔가 이상한데? 한 번 확인해볼래?".RAISE EXCEPTION: 완전 비상사이렌 — "멈춰! 알고리즘에 문제 생겼어! 더 망가지기 전에 실행 중단했어!".
이 각각의 레벨은 다 역할이 있으니까, 언제 뭘 써야 할지 잘 골라야 해.
이런 메시지들이 코드에서 어떻게 보이는지 한 번 볼까:
DO $$
BEGIN
-- NOTICE 레벨 (다 괜찮고, 그냥 알림)
RAISE NOTICE '그냥 알림: 데이터 처리 시작했어';
-- WARNING 레벨 (뭔가 수상함)
RAISE WARNING '경고: 컬럼 데이터 포맷이 이상할 수도 있음';
-- EXCEPTION 레벨 (치명적 에러)
RAISE EXCEPTION '에러: 입력값이 허용되지 않아!';
END $$;
언제 써야 하냐면:
RAISE NOTICE— 디버깅이나 편하게 정보 출력할 때.RAISE WARNING— 데이터가 뭔가 잘못됐을 때 경고 주고 싶을 때.RAISE EXCEPTION— 진짜 심각한 에러라서 함수 실행을 멈춰야 할 때.
RAISE EXCEPTION으로 에러 처리하기
RAISE EXCEPTION은 진짜 비상정지 버튼이야. 뭔가 잘못되면 함수 실행을 바로 멈추고 에러 메시지 남길 수 있어.
기본 사용법은 이렇게 생겼어:
RAISE EXCEPTION '너의 에러 메시지';
근데 메시지를 더 자세하게 만들고 싶으면 변수도 쓸 수 있어:
DECLARE
input_value INTEGER;
BEGIN
input_value := NULL;
IF input_value IS NULL THEN
RAISE EXCEPTION '에러: 입력값이 NULL이야. INTEGER 값이 필요해';
END IF;
END;
메시지 포맷팅
메시지 안에 변수 바로 넣을 수도 있어:
DECLARE
var1 TEXT := '데이터';
var2 INTEGER := 42;
BEGIN
RAISE EXCEPTION '처리 중 에러: % (ID %)', var1, var2;
END;
출력: 처리 중 에러: 데이터 (ID 42).
예시: 데이터 검증
예를 들어, 어떤 프로시저가 사람 나이를 받아. 나이가 음수면 당연히 에러 내야지:
CREATE OR REPLACE FUNCTION validate_age(age INTEGER)
RETURNS VOID AS $$
BEGIN
IF age < 0 THEN
RAISE EXCEPTION '나이는 음수일 수 없어: %', age;
END IF;
END;
$$ LANGUAGE plpgsql;
-- 함수 호출
SELECT validate_age(-5); -- 에러 발생
RAISE NOTICE로 알림 주기
RAISE EXCEPTION이 사이렌이라면, RAISE NOTICE는 그냥 어깨 툭툭 치는 느낌이야. 이 레벨로 함수 안에서 무슨 일이 일어나는지 설명하는 코멘트 남길 수 있어.
RAISE NOTICE 언제 쓰냐면:
- 디버깅 정보 출력 (예: 변수 현재 값 등).
- 단계 시작이나 계산 결과 알릴 때.
예시: 정보 메시지
CREATE OR REPLACE FUNCTION calculate_discount(price NUMERIC, discount_rate NUMERIC)
RETURNS NUMERIC AS $$
DECLARE
final_price NUMERIC;
BEGIN
RAISE NOTICE '할인 전 가격: %', price;
RAISE NOTICE '할인율: %', discount_rate;
final_price := price - (price * discount_rate);
RAISE NOTICE '최종 가격: %', final_price;
RETURN final_price;
END;
$$ LANGUAGE plpgsql;
-- 함수 호출
SELECT calculate_discount(100, 0.2);
-- 출력:
-- NOTICE: 할인 전 가격: 100
-- NOTICE: 할인율: 0.2
-- NOTICE: 최종 가격: 80
실전 예시: 단계별 계획과 로깅
예를 들어, 복잡한 데이터 처리 프로시저가 있는데, 지금 어느 단계인지 알고 싶을 때:
CREATE OR REPLACE FUNCTION process_data_step_by_step()
RETURNS VOID AS $$
BEGIN
RAISE NOTICE '1단계: 데이터 준비';
-- 첫 번째 단계 로직
RAISE NOTICE '2단계: 데이터 검증';
-- 두 번째 단계 로직
RAISE NOTICE '3단계: 데이터 저장';
-- 세 번째 단계 로직
END;
$$ LANGUAGE plpgsql;
-- 함수 호출
SELECT process_data_step_by_step();
-- 로그에 단계별 실행이 표시됨
또 다른 예시도 있어. 상상해봐, 어떤 가게가 일정 금액 이상 주문에만 할인해준다고 하자:
CREATE OR REPLACE FUNCTION apply_discount(order_amount NUMERIC)
RETURNS NUMERIC AS $$
BEGIN
IF order_amount < 50 THEN
RAISE EXCEPTION '에러: 주문 금액은 최소 50이어야 해, 현재 금액: %', order_amount;
END IF;
RETURN order_amount * 0.9; -- 10% 할인 적용
END;
$$ LANGUAGE plpgsql;
-- 함수 호출
SELECT apply_discount(30); -- 에러: 주문 금액은 최소 50이어야 해
흔한 실수들
실수 1: 파라미터 없이 메시지 로깅하기.
이렇게 하면 큰 프로시저에서 정보가 너무 부족해:
RAISE NOTICE '에러 발생'; -- 왜? 어디서? 어떻게?
추천: 항상 컨텍스트를 추가해:
RAISE NOTICE 'process_data() 함수에서 에러: 입력값: %', input_value;
실수 2: RAISE EXCEPTION을 RAISE WARNING만으로도 충분할 때 쓰는 것.
예외를 너무 남발하면 코드가 자꾸 멈춰서 데이터 처리하기 힘들어져.
팁: 로깅 레벨을 잘 생각해서 써. 디버깅엔 NOTICE, 진짜 중요한 순간엔 EXCEPTION!
실수 3: 아예 로깅을 안 하는 것.
이건 어두운 방에서 열쇠 찾는 거랑 똑같아. 로그 없으면 복잡한 프로세스 디버깅이 거의 불가능해져.
팁: 함수가 크고 복잡할수록 중요한 단계마다 RAISE NOTICE 꼭 추가해.
GO TO FULL VERSION