バージョン依存の条件付きコンパイル
冒頭でも述べたように、Oracle RDBMSの最新の機能を活用するために、対象データベースのバージョンに応じて異なるコードをコンパイルしなければならない場合はよくあります。PL/SQL条件付きコンパイルでこれをもっと簡単に行えるようにするために、10gR2リリースには新しいPL/SQL提供パッケージのDBMS_DB_VERSIONが付属しています。このパッケージは、バージョン番号とリリース番号を保持する単純な定数の集まりです。DBMS_DB_VERSIONを使用するコードは次のようになります。
...
$IF DBMS_DB_VERSION.VERSION=10 $THEN
... [version 10 code] ...
$ELSE
... [code for earlier versions]...
$END
...
コンパイル時に、2つの分岐の一方だけがパッケージにコンパイルされるので、メモリとオーバーヘッドの節約になります。
DBMS_DB_VERSIONパッケージの定数の詳細については、PL/SQLの提供パッケージに関するドキュメントを参照してください。
10gR2以前のデータベースでの条件付きコンパイル
PL/SQL条件付きコンパイルが10gR2の新しい機能であるなら、バージョン依存の条件付きコンパイルが何の役に立つのかと思う人もいるでしょう。実は、Oracleはこの新しい機能を以前のリリースにさかのぼって取り込むというきわめて異例の措置を講じています。PL/SQL条件付きコンパイルは、9iR2では9.2.0.6以降のパッチセットで、10gR1では10.1.0.4以降のパッチセットで利用できます。9.2.0.6では条件付きコンパイルがデフォルトで無効になっていますが、アンダースコア(隠し)パラメータを設定して有効にすることができます。10.1.0.4では、機能がデフォルトで有効になっていますが、同じアンダースコアパラメータを使って無効にすることができます(Oracleでは、Oracle技術サポートが直接指示したアンダースコアパラメータの値の変更のみをサポートしていることに注意してください)。10.2では、条件付きコンパイルを無効にすることはできず、アンダースコアパラメータは非推奨になっています。
DBMS_PREPROCESSORによる条件付きコンパイルの結果の確認
コードに条件付きコンパイルのディレクティブが含まれている場合、DBA_SOURCE内のコードはメモリ内のコンパイル済みコードと一致しなくなります。DBA_SOURCE内のテキストには、ソースのコンパイラディレクティブとすべての分岐が含まれます。幸い、新しい提供パッケージのDBMS_PREPROCESSORを使うと、コンパイル後のコードを確認することができます。
簡単な例として、先ほど軽量のデバッグフレームワークで使ったDebugPkgのコードに対してDBMS_PREPROCESSOR.PRINT_POST_PROCESSED_SOURCEを実行するとどうなるか見てみましょう(格納された定数DebugConstants.c_debugはFALSEに設定したままです)。
最初に、ccflagのdebug_onをTRUEに設定し、デバッグコードを含めてDebugPkgをコンパイルします。
SQL> alter package debugpkg compile plsql_ccflags ='debug_on:true' reuse settings ; Package altered.
次に、DBMS_PREPROCESSOR.PRINT_POST_PROCESSED_SOURCEを実行し、コンパイル済みのコードがどのようになるかを確認します。
SQL> begin 2> dbms_preprocessor.print_post_processed_source 3> ('PACKAGE BODY','BULKLOAD','DEBUGPKG'); 4> end; 5> / package body debugpkg is procedure debug (p_msg in varchar2, p_lineNum in number,p_plsUnit in varchar2) is v_error_string varchar2(32767); begin v_error_string := 'ERROR in ' || p_plsUnit || ', at line '
|| p_lineNum || ': ' || p_msg; dbms_output.put_line(substr(v_error_string,1,255)); end debug; end debugpkg; PL/SQL procedure successfully completed.
ご覧のように、コンパイル済みのソースには選択ディレクティブの$IF...$ENDがなく、デバッグコードを指定したコード分岐だけが含まれています。ccflagのdebug_onをFALSEに設定してDebugPkgを再コンパイルすると、代わりにもう一方の分岐が表示されます。
SQL> alter package debugpkg compile plsql_ccflags ='debug_on:false' reuse settings ; Package altered. SQL> begin 2> dbms_preprocessor.print_post_processed_source 6> ('PACKAGE BODY','BULKLOAD','DEBUGPKG'); 7> end; 8> / package body debugpkg is procedure debug (p_msg in varchar2, p_lineNum in number,
p_plsUnit in varchar2) is v_error_string varchar2(32767); begin null; end debug; end debugpkg; PL/SQL procedure successfully completed.
DBMS_PREPROCESSORを使用するときは、次の点に注意してください。
- 渡されるストアドプロシージャが有効である必要はありません。
- 匿名のPL/SQLブロック、またはソース行のPL/SQL表を渡すこともできます。
- 関連する関数の
GET_POST_PROCESSED_SOURCEは、処理後のソースコードをDBMS_OUTPUT.PUT_LINEで出力する代わりに、ソース行のPL/SQL表として返します。
エラーディレクティブを含むコードに対してDBMS_PREPROCESSORを実行すると、結果の該当する場所にエラーが表示されます。
SQL> begin 2> dbms_preprocessor.print_post_processed_source 9> ('PACKAGE BODY','BULKLOAD', 10> 'TESTERRDIRECTIVE'); 11> end; 12> / package body testErrDirective is procedure run is begin dbms_output.put_line('Beginning test run...'); ORA-06550: line 5, column 3: PLS-00179: $ERROR: Oh No! There's no code at line 6 in PL/SQL procedure successfully completed.
小さくて高速なランタイムコード
条件付きコンパイルは、使いやすくて幅広い目的に利用できます。ここで紹介した条件付きコンパイルの使い方は、ごく基本的なものにすぎません。例えば、顧客ごとにマスターコードをカスタマイズするような使い方もできます。個別にライセンスされる機能をメインコード本体に挿入し、ライセンスを受けていない顧客にはFALSEに設定したccflagで機能を隠すことができます。
条件付きコンパイルは、少なくとも、大量のif v_debug=true then... else...呼び出しがパフォーマンスに与える悪影響を懸念してきた開発者の悩みを解決します。条件付きコンパイルを使ってこれらの呼び出しを運用コードから完全に消し去り、同時に将来のデバッグのためにデバッグフレームワークを残しておくことができます。
小さくて高速なランタイムコードの恩恵を得るために、ぜひともこの応用範囲の広い新機能を今すぐ使い始めてください。
