2026년 06월 25일 | DBMS Error 가이드
이 글에서 다루는 내용
ORA-01001 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
ORA-01001 invalid cursor 는?
ORA-01001 에러는 Oracle 데이터베이스에서 유효하지 않은 커서(Cursor)를 사용하려 할 때 발생하는 오류입니다. 커서가 이미 닫혀 있거나, 열리지 않은 상태에서 FETCH 또는 CLOSE 작업을 시도하거나, 잘못된 커서 변수를 참조할 경우 이 에러가 발생합니다. 주로 PL/SQL 코드에서 커서 생명주기(Lifecycle)를 제대로 관리하지 못했을 때 나타나며, 복잡한 애플리케이션 로직에서 특히 자주 목격됩니다.
주요 발생 원인
1. 이미 닫힌 커서에 FETCH 또는 CLOSE 시도
커서를 명시적으로 CLOSE한 이후에 다시 FETCH하거나 한 번 더 CLOSE를 호출하면 ORA-01001이 발생합니다. 이는 가장 흔한 원인으로, 반복문이나 예외 처리 블록 내에서 커서 상태를 추적하지 않고 무조건 CLOSE를 호출하는 패턴에서 자주 나타납니다. 특히 예외 처리(EXCEPTION) 섹션에서 커서가 이미 닫혔는지 확인하지 않고 CLOSE를 재호출하는 코드가 대표적입니다.
2. 열리지 않은 커서에서 FETCH 시도
커서를 OPEN하지 않은 상태에서 바로 FETCH를 시도하면 이 에러가 발생합니다. 조건 분기 로직에서 특정 조건에 따라 OPEN이 실행되지 않았음에도 불구하고 FETCH가 호출되는 경우가 대표적입니다. 코드 복잡도가 높아질수록 OPEN 여부를 놓치기 쉬우므로 커서 상태 체크 로직이 필수적입니다.
3. REF CURSOR의 잘못된 사용 또는 NULL 커서 참조
SYS_REFCURSOR나 REF CURSOR 타입을 사용하는 경우, 커서 변수가 초기화되지 않았거나 NULL 상태에서 FETCH를 시도하면 ORA-01001이 발생합니다. 프로시저 간에 커서를 파라미터로 전달할 때 OUT 파라미터가 제대로 할당되지 않은 채 사용되는 경우도 이에 해당합니다. 특히 동적 SQL(OPEN FOR)과 결합하여 사용할 때 초기화 누락이 발생하기 쉽습니다.
해결 방법
원인 1 해결: 커서 상태 확인 후 CLOSE
커서를 닫기 전에 반드시 %ISOPEN 속성으로 커서가 열려 있는지 확인하세요.
DECLARE
CURSOR emp_cur IS
SELECT employee_id, first_name, salary
FROM employees
WHERE department_id = 10;
v_emp_id employees.employee_id%TYPE;
v_name employees.first_name%TYPE;
v_salary employees.salary%TYPE;
BEGIN
OPEN emp_cur;
LOOP
FETCH emp_cur INTO v_emp_id, v_name, v_salary;
EXIT WHEN emp_cur%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_name || ' : ' || v_salary);
END LOOP;
-- %ISOPEN으로 상태 확인 후 CLOSE (ORA-01001 방지)
IF emp_cur%ISOPEN THEN
CLOSE emp_cur;
END IF;
EXCEPTION
WHEN OTHERS THEN
-- 예외 발생 시에도 커서 상태 확인 후 안전하게 CLOSE
IF emp_cur%ISOPEN THEN
CLOSE emp_cur;
END IF;
RAISE;
END;
/
원인 2 해결: OPEN 여부를 확인한 뒤 FETCH 수행
조건 분기 로직이 있는 경우, FETCH 전에 커서가 열려 있는지 반드시 확인하세요.
DECLARE
CURSOR dept_cur IS
SELECT department_id, department_name
FROM departments
WHERE location_id = 1700;
v_dept_id departments.department_id%TYPE;
v_dept_name departments.department_name%TYPE;
v_flag BOOLEAN := TRUE; -- 조건에 따라 FALSE가 될 수 있음
BEGIN
IF v_flag THEN
OPEN dept_cur;
END IF;
-- OPEN 여부 확인 후 FETCH (ORA-01001 방지 핵심)
IF dept_cur%ISOPEN THEN
LOOP
FETCH dept_cur INTO v_dept_id, v_dept_name;
EXIT WHEN dept_cur%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_dept_id || ' : ' || v_dept_name);
END LOOP;
CLOSE dept_cur;
ELSE
DBMS_OUTPUT.PUT_LINE('커서가 열리지 않아 FETCH를 건너뜁니다.');
END IF;
END;
/
원인 3 해결: REF CURSOR 초기화 및 NULL 체크
REF CURSOR를 사용할 때는 반드시 OPEN 후 FETCH하고, NULL 여부를 체크하세요.
-- REF CURSOR를 사용하는 프로시저 예제
CREATE OR REPLACE PROCEDURE get_employees_by_dept (
p_dept_id IN NUMBER,
p_cur OUT SYS_REFCURSOR
)
IS
BEGIN
-- REF CURSOR를 OPEN FOR로 올바르게 초기화
OPEN p_cur FOR
SELECT employee_id, first_name, salary
FROM employees
WHERE department_id = p_dept_id;
END;
/
-- 호출부에서의 올바른 사용법
DECLARE
v_ref_cur SYS_REFCURSOR;
v_emp_id employees.employee_id%TYPE;
v_name employees.first_name%TYPE;
v_salary employees.salary%TYPE;
BEGIN
-- 프로시저 호출로 REF CURSOR 초기화
get_employees_by_dept(10, v_ref_cur);
-- NULL 또는 미열림 상태 방어 코드
IF v_ref_cur IS NOT NULL THEN
LOOP
FETCH v_ref_cur INTO v_emp_id, v_name, v_salary;
EXIT WHEN v_ref_cur%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_emp_id || ' | ' || v_name || ' | ' || v_salary);
END LOOP;
IF v_ref_cur%ISOPEN THEN
CLOSE v_ref_cur;
END IF;
END IF;
EXCEPTION
WHEN INVALID_CURSOR THEN
DBMS_OUTPUT.PUT_LINE('ORA-01001: 유효하지 않은 커서입니다. 커서 상태를 확인하세요.');
IF v_ref_cur%ISOPEN THEN
CLOSE v_ref_cur;
END IF;
WHEN OTHERS THEN
IF v_ref_cur%ISOPEN THEN
CLOSE v_ref_cur;
END IF;
RAISE;
END;
/
예방 방법
1. 커서 생명주기를 명확히 관리하는 코딩 표준 수립
모든 PL/SQL 코드에서 커서는 반드시 OPEN → FETCH → CLOSE 순서를 지키고, EXCEPTION 블록에서도 %ISOPEN 속성을 이용한 안전 종료 패턴을 팀 전체의 코딩 표준으로 정의하세요. 가능하면 명시적 커서 대신 FOR 루프 커서(FOR rec IN cursor_name LOOP)를 사용하면 Oracle이 자동으로 OPEN/CLOSE를 처리해 주므로 ORA-01001 발생 가능성을 원천적으로 줄일 수 있습니다.
-- FOR 루프를 활용한 안전한 커서 사용 (OPEN/CLOSE 자동 처리)
BEGIN
FOR rec IN (SELECT employee_id, first_name FROM employees WHERE department_id = 20)
LOOP
DBMS_OUTPUT.PUT_LINE(rec.employee_id || ' : ' || rec.first_name);
END LOOP;
-- 별도의 OPEN/CLOSE 불필요 - ORA-01001 위험 없음
END;
/
2. 예외 처리 블록에서 커서 상태를 항상 방어적으로 처리
모든 PL/SQL 블록의 EXCEPTION 섹션에서는 커서가 열려 있을 가능성이 있는 경우 반드시 %ISOPEN 체크를 포함한 CLOSE 로직을 작성하세요. 코드 리뷰 체크리스트에 “EXCEPTION 블록 내 커서 CLOSE 여부”를 항목으로 추가하면 사전 예방에 큰 도움이 됩니다.
관련 에러
- ORA-01000: maximum open cursors exceeded — 커서를 CLOSE하지 않아 오픈 커서 수가 한계를 초과할 때 발생하며, ORA-01001과 함께 커서 관리 부실의 대표적 결과입니다.
- ORA-06511: PL/SQL: cursor already open — 이미 열린 커서를 다시 OPEN하려 할 때 발생합니다. ORA-01001과 반대 방향의 커서 상태 오류입니다.
- ORA-01002: fetch out of sequence — COMMIT/ROLLBACK 이후 FOR UPDATE 커서에서 FETCH를 시도할 때 발생하며, 커서 무효화와 관련된 에러입니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.