「同じ 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 プロファイラ完全ガイドも参照してください。