Oracle ORA-06546 오류 원인과 해결 방법 완벽 가이드

ORA-06546
2026년 09월 01일 | DBMS Error 가이드

이 글에서 다루는 내용

ORA-06546 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.

ORA-06546 DDL statement is executed in an illegal context 는?

ORA-06546 에러는 PL/SQL 블록 내에서 DDL(Data Definition Language) 문장이 허용되지 않는 컨텍스트에서 실행될 때 발생하는 오류입니다. Oracle에서는 일반 PL/SQL 블록 내에서 CREATE, DROP, ALTER, TRUNCATE 같은 DDL 문장을 직접 실행할 수 없으며, 이를 시도할 경우 이 에러가 발생합니다. 특히 함수(Function), 트리거(Trigger), 또는 정적 SQL이 사용되는 컨텍스트에서 DDL을 직접 호출할 때 자주 마주치는 에러입니다.


주요 발생 원인

1. PL/SQL 블록 내에서 DDL 문장 직접 실행

가장 흔한 원인으로, 일반 익명 PL/SQL 블록이나 저장 프로시저 내에서 CREATE TABLE, DROP TABLE 등의 DDL 문장을 정적 SQL 형태로 직접 작성했을 때 발생합니다. Oracle의 PL/SQL 엔진은 컴파일 시점에 DDL 문장을 처리할 수 없기 때문에, 반드시 동적 SQL을 통해 실행해야 합니다. 이 규칙을 위반하면 ORA-06546이 즉시 발생합니다.

2. 함수(Function) 또는 트리거(Trigger) 내에서 DDL 실행 시도

Oracle 함수나 DML 트리거 내부에서 DDL 문장을 실행하려 할 때 이 에러가 발생합니다. 함수는 쿼리 내에서 호출될 수 있기 때문에 트랜잭션 일관성을 위해 DDL 실행 자체가 금지되어 있습니다. DML 트리거 역시 실행 중인 트랜잭션의 일부이기 때문에, 트리거 내에서 DDL을 실행하면 암묵적 커밋(Implicit Commit)이 발생하는 문제로 인해 허용되지 않습니다.

3. EXECUTE IMMEDIATE를 잘못된 컨텍스트에서 사용

EXECUTE IMMEDIATE를 사용하더라도, 이를 잘못된 컨텍스트(예: 함수 내부, 또는 특정 제약이 있는 컨텍스트)에서 사용하면 ORA-06546이 발생할 수 있습니다. 특히 트리거에서 EXECUTE IMMEDIATE로 DDL을 실행하면 Oracle이 이를 차단합니다. 이 경우에는 DBMS_JOB 또는 DBMS_SCHEDULER를 활용하여 별도의 세션에서 DDL을 실행하는 방식으로 우회해야 합니다.


해결 방법

원인 1 해결: EXECUTE IMMEDIATE를 사용한 동적 DDL 실행

PL/SQL 블록 내에서 DDL을 실행하려면 반드시 EXECUTE IMMEDIATE를 사용해야 합니다.

잘못된 예시 (ORA-06546 발생):

BEGIN
    -- 아래처럼 직접 DDL을 작성하면 ORA-06546 발생
    CREATE TABLE emp_backup AS SELECT * FROM employees;
END;
/

올바른 예시 (EXECUTE IMMEDIATE 사용):

BEGIN
    -- EXECUTE IMMEDIATE를 사용하여 DDL을 동적으로 실행
    EXECUTE IMMEDIATE 'CREATE TABLE emp_backup AS SELECT * FROM employees';
    DBMS_OUTPUT.PUT_LINE('테이블 생성 완료');
EXCEPTION
    WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE('에러 발생: ' || SQLERRM);
END;
/
-- 테이블 DROP 후 재생성하는 예시
BEGIN
    BEGIN
        EXECUTE IMMEDIATE 'DROP TABLE emp_backup';
    EXCEPTION
        WHEN OTHERS THEN
            IF SQLCODE != -942 THEN  -- ORA-00942: 테이블 없음은 무시
                RAISE;
            END IF;
    END;

    EXECUTE IMMEDIATE 'CREATE TABLE emp_backup (
        emp_id   NUMBER,
        emp_name VARCHAR2(100),
        hire_date DATE
    )';

    DBMS_OUTPUT.PUT_LINE('emp_backup 테이블 생성 완료');
END;
/

원인 2 해결: 트리거 내 DDL 우회 – DBMS_SCHEDULER 활용

트리거 내에서 DDL이 필요한 경우, DBMS_SCHEDULER를 이용해 별도의 Job으로 실행합니다.

CREATE OR REPLACE TRIGGER trg_after_insert
AFTER INSERT ON orders
FOR EACH ROW
BEGIN
    -- 트리거 내에서 직접 DDL 실행 불가 → DBMS_SCHEDULER로 우회
    DBMS_SCHEDULER.CREATE_JOB(
        job_name        => 'JOB_CREATE_BACKUP_' || TO_CHAR(SYSDATE, 'YYYYMMDDHH24MISS'),
        job_type        => 'PLSQL_BLOCK',
        job_action      => 'BEGIN EXECUTE IMMEDIATE ''CREATE TABLE orders_bak_' 
                           || TO_CHAR(SYSDATE, 'YYYYMMDD') 
                           || ' AS SELECT * FROM orders''; END;',
        start_date      => SYSTIMESTAMP + INTERVAL '1' SECOND,
        enabled         => TRUE,
        auto_drop       => TRUE
    );
END;
/

원인 3 해결: 함수 내 DDL 처리 – 프로시저로 분리

함수 내에서 DDL을 실행해야 하는 구조라면, 해당 로직을 프로시저로 분리하고 함수에서는 프로시저를 호출하지 않도록 설계를 변경해야 합니다.

-- 잘못된 함수 설계 (ORA-06546 발생)
CREATE OR REPLACE FUNCTION fn_create_temp_table RETURN VARCHAR2 IS
BEGIN
    EXECUTE IMMEDIATE 'CREATE GLOBAL TEMPORARY TABLE temp_data (id NUMBER)';
    RETURN 'SUCCESS';
END;
/

-- 올바른 접근: 프로시저로 분리
CREATE OR REPLACE PROCEDURE sp_create_temp_table IS
BEGIN
    EXECUTE IMMEDIATE 'CREATE GLOBAL TEMPORARY TABLE temp_data (
        id     NUMBER,
        value  VARCHAR2(200)
    )';
    DBMS_OUTPUT.PUT_LINE('임시 테이블 생성 완료');
EXCEPTION
    WHEN OTHERS THEN
        IF SQLCODE = -955 THEN  -- ORA-00955: 이미 존재하는 경우
            DBMS_OUTPUT.PUT_LINE('이미 존재하는 테이블입니다.');
        ELSE
            RAISE;
        END IF;
END;
/

-- 프로시저 실행
BEGIN
    sp_create_temp_table;
END;
/

TRUNCATE와 같은 DDL도 반드시 동적 SQL로

-- TRUNCATE는 DML이 아닌 DDL이므로 반드시 EXECUTE IMMEDIATE 필요
BEGIN
    EXECUTE IMMEDIATE 'TRUNCATE TABLE emp_backup';
    DBMS_OUTPUT.PUT_LINE('TRUNCATE 완료');
END;
/

예방 방법

1. PL/SQL 코딩 표준 수립: DDL은 반드시 EXECUTE IMMEDIATE 사용 원칙 적용

팀 내 PL/SQL 코딩 가이드라인에 “PL/SQL 블록 내 모든 DDL 문장은 반드시 EXECUTE IMMEDIATE를 통해 실행한다”는 규칙을 명문화하세요. 코드 리뷰 단계에서 정적 DDL 사용 여부를 체크리스트에 포함시키면 실수를 사전에 방지할 수 있습니다. 또한 개발 환경에서 컴파일 단계에서 이를 검증하는 스크립트를 도입하면 더욱 효과적입니다.

2. 트리거와 함수의 책임 범위를 명확히 설계

트리거와 함수는 DDL을 실행할 수 없는 구조적 제약이 있음을 항상 인식하고, 설계 단계에서 DDL이 필요한 로직은 반드시 프로시저 또는 독립 스크립트로 분리하도록 아키텍처를 구성하세요. 특히 DDL이 필요한 자동화 작업은 DBMS_SCHEDULER를 활용하여 별도 Job으로 분리하는 패턴을 표준으로 채택하면, ORA-06546뿐만 아니라 트랜잭션 관련 다양한 문제를 예방할 수 있습니다.


관련 에러

  • ORA-06550: PL/SQL 컴파일 오류로, DDL 문장을 잘못 작성했을 때 함께 나타나는 경우가 많습니다.
  • ORA-00900: INVALID SQL STATEMENT – DDL을 잘못된 위치에서 실행할 때 발생하는 유사 에러입니다.
  • ORA-04092: 트리거 내에서 COMMIT 또는 ROLLBACK을 시도할 때 발생하며, DDL의 암묵적 커밋 이슈와 연관됩니다.
  • ORA-14552: DDL, COMMIT, ROLLBACK을 쿼리 또는 DML 내에서 실행할 수 없을 때 발생하며, ORA-06546과 유사한 컨텍스트에서 발생합니다.

DBMS 에러 코드 시리즈

주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.

본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.

댓글 남기기