ORA-06502는 PL/SQL 블록에서 변수 할당이나 연산 시 데이터 타입·길이·범위가 맞지 않을 때 발생하는 가장 흔한 런타임 에러다. VARCHAR2 변수에 선언 길이보다 긴 문자열을 넣거나, NUMBER 변수에 정밀도를 초과하는 값을 넣거나, TO_NUMBER가 변환 불가능한 문자열을 만났을 때 즉시 던져진다. SQL 레벨의 ORA-01438, ORA-01722와 형제 격이지만 발생 위치가 PL/SQL이라는 점이 다르다. 본 글은 ORA-06502의 정확한 의미, 두 가지 주요 하위 메시지, 일곱 가지 발생 원인, 진단 흐름, 그리고 %TYPE·VALUE_ERROR·DEFAULT NULL ON CONVERSION ERROR까지 실전 해결 패턴을 정리한다.

주요 원인 / VARCHAR2 버퍼 부족, CHAR 패딩 초과, NUMBER 정밀도, TO_NUMBER 실패, NOT NULL 위반, PLS_INTEGER 오버플로, CONCAT 결과 초과
근본 해법 /
%TYPE 선언, 입력 검증, VALUE_ERROR 예외, DEFAULT NULL ON CONVERSION ERROR목차
가장 자주 보이는 두 가지 하위 메시지는 다음과 같다.
"character string buffer too small" ━ VARCHAR2·CHAR 변수의 선언 길이가 할당하려는 값보다 작음
"numeric or value error" ━ 숫자 변환 실패 또는 NUMBER 정밀도 초과
오라클 공식 원인 설명은 "산술, 숫자, 문자열, 변환, 또는 제약 조건 오류가 발생함"이다. 즉 PL/SQL이 변수에 값을 넣거나 연산을 수행하는 순간 데이터 타입·길이·범위·NULL 가능성 같은 제약이 깨졌다는 광범위한 신호다.
1. ORA-06502가 던져지는 시점
ORA-06502는 PL/SQL 런타임에서만 발생한다. SQL 단독 실행에서는 비슷한 상황이 ORA-01438, ORA-01722, ORA-12899 같은 SQL 레벨 에러로 표현된다. 대표적인 트리거 시점은 다음과 같다.
- 변수 선언 후 첫 할당 ━ 길이·범위 위반
- 계산 결과 할당 ━ NUMBER 정밀도, PLS_INTEGER 범위 초과
- TO_NUMBER, TO_DATE ━ 변환 실패
- CONCAT ━ 결과가 대상 버퍼 초과
- NOT NULL 변수에 NULL 대입
- 컬렉션/레코드 필드 할당 ━ 내부 필드에서 동일 검증
2. 발생 원인 일곱 가지
원인 1 / VARCHAR2 선언 길이 부족
가장 흔한 케이스다. 변수 선언 시 추정한 길이보다 실제 값이 길 때 발생한다.
-- VARCHAR2(5)에 6자리 문자열 → ORA-06502
DECLARE
v VARCHAR2(5);
BEGIN
v := 'ABCDEF';
END;
/
-- ORA-06502: PL/SQL: numeric or value error:
-- character string buffer too small
원인 2 / CHAR 패딩 후 CONCAT 초과
CHAR 타입은 선언 길이만큼 공백 패딩된다. CHAR(5)에 'A'를 넣으면 'A '로 저장된다. 이 패딩이 CONCAT 결과를 의외로 길게 만들어 버퍼를 넘긴다.
-- CHAR(5) 자동 패딩 함정
DECLARE
a CHAR(5) := 'A'; -- 실제 저장: 'A '
b CHAR(5) := 'B';
v VARCHAR2(9);
BEGIN
v := a || b; -- 'A B ' = 10자 → 초과
END;
/
원인 3 / TO_NUMBER 변환 실패
비숫자 문자열을 TO_NUMBER로 변환하면 발생한다. SQL 레벨에서는 ORA-01722지만 PL/SQL 변수에 할당하는 시점이면 ORA-06502다.
-- 비숫자 문자열 변환 → ORA-06502
DECLARE
n NUMBER;
BEGIN
n := TO_NUMBER('Yes');
END;
/
원인 4 / NUMBER 정밀도 초과
NUMBER(p)·NUMBER(p,s)로 선언한 변수에 정밀도를 넘는 값을 할당하면 발생한다.
-- NUMBER(3)에 4자리 → ORA-06502
DECLARE
n NUMBER(3);
BEGIN
n := 4321;
END;
/
원인 5 / NOT NULL 변수에 NULL 대입
PL/SQL 변수에 NOT NULL 제약을 걸 수 있다. 그 변수에 NULL을 대입하면 ORA-06502가 발생한다.
DECLARE
n NUMBER(4) NOT NULL := 10;
BEGIN
n := NULL;
END;
/
원인 6 / PLS_INTEGER 오버플로
PLS_INTEGER는 32비트 부호 있는 정수다. 범위는 -2,147,483,648 ~ 2,147,483,647이며, 연산 결과가 이를 넘으면 ORA-06502가 발생한다.
-- PLS_INTEGER 오버플로
DECLARE
a PLS_INTEGER := 2147483647;
BEGIN
a := a + 1;
END;
/
-- ORA-06502
대안으로 SIMPLE_INTEGER가 있다. 같은 32비트지만 오버플로 시 wrap-around 되어 예외가 발생하지 않는다. 단 NULL 불가다.
원인 7 / 컬렉션 인덱스/필드 위반
연관 배열의 인덱스가 키 도메인을 벗어나거나, 레코드의 NOT NULL 필드에 NULL이 들어가는 경우 등 컬렉션·레코드 내부에서도 같은 검증이 작동한다.
3. 재현 시나리오 종합
다섯 가지 케이스를 한 번에 보여주는 PL/SQL 블록은 다음과 같다.
-- 버퍼 초과
DECLARE v VARCHAR2(5); BEGIN v := 'ABCDEF'; END;
-- 정밀도 초과
DECLARE n NUMBER(3); BEGIN n := 4321; END;
-- 변환 실패
DECLARE n NUMBER; BEGIN n := TO_NUMBER('abc'); END;
-- NOT NULL 위반
DECLARE n NUMBER NOT NULL := 1;
BEGIN n := NULL; END;
-- PLS_INTEGER 오버플로
DECLARE a PLS_INTEGER := 2147483647;
BEGIN a := a + 1; END;
4. 진단 — 정확한 위치 찾기
ORA-06502 메시지만으로는 어느 줄에서 어떤 변수가 문제였는지 알기 어렵다. PL/SQL 백트레이스 함수로 정확한 위치를 추출한다.
-- 진단 블록 템플릿
DECLARE
v VARCHAR2(5);
BEGIN
v := 'ABCDEF';
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('SQLCODE: '||SQLCODE);
DBMS_OUTPUT.PUT_LINE('SQLERRM: '||SQLERRM);
DBMS_OUTPUT.PUT_LINE('STACK: '||
DBMS_UTILITY.FORMAT_ERROR_STACK);
DBMS_OUTPUT.PUT_LINE('BACKTRACE: '||
DBMS_UTILITY.FORMAT_ERROR_BACKTRACE);
END;
/
FORMAT_ERROR_BACKTRACE는 예외가 발생한 정확한 라인 번호를 알려준다. 단 RAISE로 예외를 재발생시키면 백트레이스가 그 지점부터 다시 시작하므로 원본 라인이 손실된다. PLSQL_OPTIMIZE_LEVEL=3(인라이닝)에서도 라인 번호가 부정확할 수 있으므로 디버깅 중에는 일시적으로 2 이하로 낮추는 것이 좋다.
5. 해결 방법
패턴 A / %TYPE으로 컬럼 일치
테이블 컬럼 값을 받는 변수는 반드시 %TYPE으로 선언한다. 컬럼 정의가 바뀌어도 자동으로 따라간다.
-- 컬럼 정의를 그대로 따름
DECLARE
v_name emp.ename%TYPE;
v_sal emp.sal%TYPE;
BEGIN
SELECT ename, sal INTO v_name, v_sal
FROM emp WHERE empno = 7369;
END;
/
패턴 B / VALUE_ERROR 예외 처리
ORA-06502는 사전 정의 예외 VALUE_ERROR로 catch할 수 있다. 변환·할당이 실패해도 흐름이 중단되지 않도록 처리한다.
DECLARE
v_input VARCHAR2(20) := '1.5e10x';
v_num NUMBER;
BEGIN
v_num := TO_NUMBER(v_input);
EXCEPTION
WHEN VALUE_ERROR THEN
v_num := NULL;
DBMS_OUTPUT.PUT_LINE('변환 실패, NULL로 처리');
END;
/
패턴 C / 12c+ DEFAULT NULL ON CONVERSION ERROR
Oracle 12c 이후 TO_NUMBER·TO_DATE·CAST에 변환 실패 시 기본값을 반환하는 옵션이 추가됐다. 예외 없이 NULL을 받아 흐름을 그대로 진행할 수 있다.
-- 변환 실패 시 NULL 반환 (12c+)
DECLARE
n NUMBER;
BEGIN
n := TO_NUMBER('abc' DEFAULT NULL ON CONVERSION ERROR);
-- n = NULL, 예외 없음
END;
/
패턴 D / 사전 검증
REGEXP·길이 검사로 변환 전에 형식을 점검한다. 디버깅이 쉽고 비즈니스 의미 메시지를 줄 수 있다.
-- TO_NUMBER 전 정규식 검증
DECLARE
v_input VARCHAR2(20) := '1234.56';
v_num NUMBER;
BEGIN
IF REGEXP_LIKE(v_input, '^-?\d+(\.\d+)?$') THEN
v_num := TO_NUMBER(v_input);
ELSE
RAISE_APPLICATION_ERROR(-20001, '유효한 숫자 형식이 아님');
END IF;
END;
/
패턴 E / 정밀도·범위 여유
NUMBER 정밀도는 꼭 필요한 경우가 아니면 지정하지 않는다. PLS_INTEGER 대신 INTEGER, NUMBER, 또는 SIMPLE_INTEGER(랩어라운드 허용) 사용을 검토한다.
-- 정밀도 없는 NUMBER는 사실상 무제한
DECLARE
n NUMBER := 99999999999;
BEGIN
n := n * 100; -- 안전
END;
/
-- 카운터에 PLS_INTEGER 대신 NUMBER 사용
DECLARE
cnt NUMBER := 0;
BEGIN
FOR i IN 1..10000000 LOOP
cnt := cnt + 1;
END LOOP;
END;
/
6. 인접 에러와의 구분
ORA-06502는 SQL 레벨 형제와 PL/SQL 스택 추적 에러가 있다.
| 에러 코드 | 발생 레벨 | 전형적 시나리오 |
|---|---|---|
| ORA-06502 | PL/SQL 변수 할당·연산 | 버퍼 부족, 정밀도, 변환 실패 |
| ORA-01438 | SQL 컬럼 INSERT/UPDATE | NUMBER(p,s) 컬럼 정밀도 초과 |
| ORA-01722 | SQL 변환 | SELECT 등에서 비숫자 → NUMBER |
| ORA-12899 | SQL 문자열 컬럼 | VARCHAR2 컬럼 길이 초과 INSERT |
| ORA-06512 | PL/SQL 스택 트레이스 | "at line N" — 발생 위치 동반 |
| ORA-01426 | PL/SQL 산술 오버플로 | NUMERIC_OVERFLOW 예외 |
핵심 구분 ━ 06502는 PL/SQL 변수 측, 01438·01722·12899는 SQL 측, 06512는 06502 등의 발생 라인을 알려주는 동반 표시 에러다.
ORA-06512는 PL/SQL 스택 트레이스를 알려주는 부가 메시지다. "at line N" 또는 "at package.procedure, line N" 형태로 06502가 발생한 정확한 위치를 보여 준다. 두 에러가 항상 짝으로 출력되며, 06512의 라인 번호가 진짜 디버깅 시작점이다.
Q2. %TYPE을 모든 변수에 써도 되나요?
권장 패턴이다. 컬럼 변경 시 코드를 다시 컴파일하지 않아도 따라가므로 유지보수가 쉽다. 단점은 컴파일 의존성이 늘어 컬럼 변경 시 패키지가 INVALID 상태로 전환된다는 점이며, 자동 재컴파일로 대부분 해결된다.
Q3. PLS_INTEGER와 NUMBER의 성능 차이는 큰가요?
PLS_INTEGER는 하드웨어 정수 연산을 사용해 NUMBER보다 빠르다. 루프 카운터·인덱스 등 단순 정수 연산에는 PLS_INTEGER가 유리하다. 단 오버플로 가능성이 있으면 NUMBER 또는 SIMPLE_INTEGER(랩어라운드 허용)를 고려한다.
Q4. SIMPLE_INTEGER는 언제 쓰나요?
NULL이 들어올 수 없고 오버플로를 무시할 수 있는 카운터·해시 계산 등에 적합하다. 컴파일러가 NULL 검사와 오버플로 검사를 모두 생략해 PLS_INTEGER보다도 빠르다. 단점은 NULL 불가, 오버플로 시 wrap-around로 잘못된 결과 가능.
Q5. DEFAULT NULL ON CONVERSION ERROR는 모든 변환 함수에 쓸 수 있나요?
12c부터 TO_NUMBER, TO_DATE, TO_TIMESTAMP, TO_BINARY_FLOAT, TO_BINARY_DOUBLE, CAST가 지원한다. TO_CHAR 등 출력 변환에는 적용되지 않는다. 입력 검증·변환 실패에 NULL을 허용해도 무방한 모든 시나리오에서 매우 유용하다.
7. 예방 체크리스트와 결론
ORA-06502는 변수 선언과 입력 검증을 신중히 다루면 거의 차단할 수 있다. 다음 항목을 점검한다.
- ✓테이블 컬럼 값을 받는 변수는
%TYPE또는%ROWTYPE - ✓일반 문자열 변수는 가변 길이 VARCHAR2(4000) 권장, CHAR는 피함
- ✓NUMBER는 정밀도 불필요시 미지정으로 선언
- ✓외부 입력은 TO_NUMBER·TO_DATE 전 REGEXP·길이 검증
- ✓12c 이상이면
DEFAULT NULL ON CONVERSION ERROR활용 - ✓VALUE_ERROR 예외 핸들러 표준화 (에러 로그 + 의미 있는 응답)
- ✓PLS_INTEGER 사용 시 오버플로 가능성 사전 검토, 큰 범위는 NUMBER
- ✓디버깅 중 FORMAT_ERROR_BACKTRACE 활용, PLSQL_OPTIMIZE_LEVEL 2 이하
ORA-06502는 "값과 변수의 약속이 깨졌다"는 단순한 신호다. PL/SQL이 컴파일 시점에 모든 길이·범위를 보장할 수 없으므로 런타임에 그 약속을 검사하다 발견한 위반이다. 답은 두 가지로 압축된다 ━ 변수 선언을 명확하고 충분히 크게, 입력 검증을 명시적으로. %TYPE으로 컬럼과 일치시키고, 외부 입력은 변환 전 검증하고, VALUE_ERROR로 예외 흐름을 끊지 않도록 하면 ORA-06502는 더 이상 갑작스러운 장애가 아닌 예측 가능한 신호가 된다.
#ORA06502 #numericorvalueerror #오라클에러 #PLSQL #VARCHAR2 #NUMBER #PLSINTEGER #VALUEERROR #TOTYPE #백트레이스 #ORA01438 #ORA01722 #ORA06512 #PL_SQL예외 #PL_SQL디버깅
댓글