【Oracle】PL/SQL 条件付きコンパイル完全ガイド|$IF/$THEN/$END・DBMS_DB_VERSION・デバッグフラグまで解説

「同じ PL/SQL コードを Oracle 11g と 19c の両方で動かす必要がある」「本番環境ではデバッグ出力を除いてコンパイルしたい」という場面で役立つのが PL/SQL の条件付きコンパイル(Conditional Compilation)です。

C 言語の #ifdef に相当するプリプロセッサ機能が PL/SQL にも用意されています。$IF$THEN$END ディレクティブで、コンパイル時に評価した条件に応じてコードの一部を含める・除外することができます。

この記事でわかること

  • 条件付きコンパイルの基本構文($IF / $THEN / $ELSIF / $ELSE / $END)
  • DBMS_DB_VERSION を使った Oracle バージョン分岐
  • PLSQL_CCFLAGS でカスタムフラグを定義する方法
  • $$PLSQL_UNIT・$$PLSQL_LINE などの組み込みインクワイアリディレクティブ
  • $ERROR でコンパイル時エラーを発生させる方法
  • DBMS_PREPROCESSOR でコンパイル前後のソースを確認する方法
スポンサーリンク

条件付きコンパイルの基本構文

条件付きコンパイルのディレクティブはすべて $ で始まります。通常の PL/SQL 文法とは区別されるため、条件が偽のブランチは構文チェックも受けません。

$IF / $THEN / $ELSIF / $ELSE / $END の基本構文
-- 条件付きコンパイルの基本構文
CREATE OR REPLACE PROCEDURE show_compilation_info AS
BEGIN
    -- $IF は コンパイル時 に評価される(実行時ではない)
    $IF $$DEBUG_MODE $THEN
        -- DEBUG_MODE フラグが TRUE のときのみコンパイルされる
        DBMS_OUTPUT.PUT_LINE('[DEBUG] 手続き開始 at ' || TO_CHAR(SYSTIMESTAMP));
    $ELSE
        NULL;  -- フラグが FALSE のときはこの NULL だけがコンパイルされる
    $END

    -- メインの処理
    DBMS_OUTPUT.PUT_LINE('処理実行中');

    $IF $$DEBUG_MODE $THEN
        DBMS_OUTPUT.PUT_LINE('[DEBUG] 処理完了');
    $END
END show_compilation_info;
/
-- 注意: $$DEBUG_MODE が定義されていない場合は NULL として扱われ $ELSE ブランチが使われる
-- 未定義フラグは常に NULL(FALSE 扱い)になる

DBMS_DB_VERSION でバージョン分岐する

DBMS_DB_VERSION パッケージには Oracle バージョンの定数が定義されており、条件付きコンパイルで $IF DBMS_DB_VERSION.VER_LE_11 $THEN のようにバージョン分岐できます。

DBMS_DB_VERSION を使ったバージョン互換コード
CREATE OR REPLACE FUNCTION get_top_n_salaries(p_n IN NUMBER) RETURN SYS_REFCURSOR AS
    v_cursor SYS_REFCURSOR;
BEGIN
    $IF DBMS_DB_VERSION.VER_LE_11 $THEN
        -- Oracle 11g 以前: ROWNUM でページング
        OPEN v_cursor FOR
            SELECT employee_id, salary
            FROM (
                SELECT employee_id, salary,
                       ROWNUM AS rn
                FROM employees
                ORDER BY salary DESC
            )
            WHERE rn <= p_n;

    $ELSE
        -- Oracle 12c 以降: FETCH FIRST ... ROWS ONLY(推奨)
        OPEN v_cursor FOR
            SELECT employee_id, salary
            FROM employees
            ORDER BY salary DESC
            FETCH FIRST p_n ROWS ONLY;
    $END

    RETURN v_cursor;
END get_top_n_salaries;
/

-- DBMS_DB_VERSION の主な定数
-- VERSION: メジャーバージョン番号(例: 19)
-- RELEASE: リリース番号(例: 0)
-- VER_LE_9:  9.x 以下なら TRUE
-- VER_LE_10: 10.x 以下なら TRUE
-- VER_LE_11: 11.x 以下なら TRUE
-- VER_LE_12: 12.x 以下なら TRUE
-- VER_LE_18: 18.x 以下なら TRUE
-- VER_LE_19: 19.x 以下なら TRUE

-- バージョン番号を直接比較する場合
-- $IF DBMS_DB_VERSION.VERSION >= 19 $THEN ... $END

PLSQL_CCFLAGS でカスタムフラグを定義する

PLSQL_CCFLAGS パラメータでユーザー定義のフラグを設定できます。セッションレベルで設定してコンパイルすることで、フラグに応じた内容でコードをコンパイルできます。

PLSQL_CCFLAGS の設定とコンパイル
-- セッションレベルでデバッグフラグを有効にしてコンパイルする
ALTER SESSION SET PLSQL_CCFLAGS = 'debug_mode:TRUE, perf_logging:TRUE';

-- デバッグフラグが有効な状態でプロシージャをコンパイルする
CREATE OR REPLACE PROCEDURE process_data AS
BEGIN
    $IF $$DEBUG_MODE $THEN
        DBMS_OUTPUT.PUT_LINE('[DEBUG] process_data 開始');
    $END

    -- 本処理 ...

    $IF $$PERF_LOGGING $THEN
        -- パフォーマンスログを記録する(開発環境のみ有効)
        INSERT INTO perf_log(proc_name, logged_at)
        VALUES ('process_data', SYSTIMESTAMP);
    $END
END process_data;
/

-- 本番環境ではフラグを FALSE にしてコンパイルする
ALTER SESSION SET PLSQL_CCFLAGS = 'debug_mode:FALSE, perf_logging:FALSE';
-- または PLSQL_CCFLAGS を空にする(すべてのフラグが NULL/FALSE になる)
ALTER SESSION SET PLSQL_CCFLAGS = '';

-- フラグの値を確認する(コンパイル後のフラグはソースに記録されない)
SELECT name, plsql_ccflags
FROM ALL_PLSQL_OBJECT_SETTINGS
WHERE name = 'PROCESS_DATA' AND owner = 'HR';

組み込みインクワイアリディレクティブ($$PLSQL_UNIT 等)

Oracle が自動的に提供するインクワイアリディレクティブ($$ で始まる)があります。これらはコンパイル時に値が確定するため、デバッグ情報の埋め込みに便利です。

組み込みインクワイアリディレクティブの使い方
CREATE OR REPLACE PROCEDURE demo_inquire_directives AS
BEGIN
    -- $$PLSQL_UNIT: 現在のプログラムユニット名
    DBMS_OUTPUT.PUT_LINE('Unit: ' || $$PLSQL_UNIT);
    -- → 'DEMO_INQUIRE_DIRECTIVES'

    -- $$PLSQL_LINE: 現在のソース行番号
    DBMS_OUTPUT.PUT_LINE('Line: ' || $$PLSQL_LINE);
    -- → この行が実行された行番号

    -- $$PLSQL_UNIT_OWNER: 所有者スキーマ名
    DBMS_OUTPUT.PUT_LINE('Owner: ' || $$PLSQL_UNIT_OWNER);

    -- $$PLSQL_UNIT_KIND: プログラム種別(PROCEDURE / FUNCTION / PACKAGE BODY 等)
    DBMS_OUTPUT.PUT_LINE('Kind: ' || $$PLSQL_UNIT_KIND);
END demo_inquire_directives;
/

-- エラーメッセージにユニット名と行番号を含める実用例
CREATE OR REPLACE PROCEDURE example_proc AS
BEGIN
    IF 1 = 0 THEN
        NULL;
    END IF;
EXCEPTION
    WHEN OTHERS THEN
        -- エラーログにファイル名・行番号を自動で含める
        log_error(
            p_proc_name  => $$PLSQL_UNIT || ':L' || $$PLSQL_LINE,
            p_error_code => SQLCODE,
            p_error_msg  => SQLERRM
        );
        RAISE;
END example_proc;
/

$ERROR でコンパイル時エラーを発生させる

$ERROR でサポートされていない環境でコンパイルを防ぐ
-- 特定バージョン以下での使用を禁止する例
CREATE OR REPLACE PROCEDURE require_19c AS
BEGIN
    $IF DBMS_DB_VERSION.VERSION < 19 $THEN
        $ERROR 'このプロシージャは Oracle 19c 以上が必要です' $END
    $END

    -- Oracle 19c 以降でしか使えない機能をここに書く
    DBMS_OUTPUT.PUT_LINE('Oracle 19c 以降で実行中');
END require_19c;
/
-- 18c 以下のデータベースでこれをコンパイルしようとすると
-- PLS-00179: $ERROR: このプロシージャは Oracle 19c 以上が必要です
-- というコンパイルエラーが発生する

-- DBMS_PREPROCESSOR でコンパイル後のソースを確認する
BEGIN
    DBMS_PREPROCESSOR.PRINT_POST_PROCESSED_SOURCE(
        object_type => 'PROCEDURE',
        schema_name => 'HR',
        object_name => 'SHOW_COMPILATION_INFO'
    );
END;
/
-- 条件付きコンパイル後に実際にコンパイルされたコードが表示される

まとめ

  • $IF / $THEN / $ELSIF / $ELSE / $END:PL/SQL の条件付きコンパイルディレクティブ。コンパイル時に評価され、偽のブランチは構文チェック対象外になる
  • DBMS_DB_VERSION:Oracle バージョンを定数として提供する。VER_LE_xx でバージョン分岐してバージョン互換コードを書ける
  • PLSQL_CCFLAGS:カスタムフラグをセッションまたはシステムレベルで定義できる。本番は FALSE、開発は TRUE にしてデバッグコードを切り替える
  • $$PLSQL_UNIT / $$PLSQL_LINE:組み込みインクワイアリディレクティブ。エラーメッセージへのソース位置の埋め込みに便利
  • $ERROR:コンパイル時にエラーを発生させて使用条件を強制できる

例外処理と組み合わせてデバッグ情報を記録する方法は 例外処理完全ガイドを参照してください。DBMS_PROFILER でプロシージャのボトルネックを特定する方法は PL/SQL プロファイラ完全ガイドも参照してください。