条件付きコンパイル
条件付きコンパイルを使用すると、ソース・テキストを削除することなく、PL/SQLアプリケーションの機能をカスタマイズできます。
たとえば、次のことが可能です。
-
最新のデータベース・リリースで新機能を使用し、古いデータベース・リリースでアプリケーションを実行する場合にそれらの新機能を無効化することができます。
-
開発環境でデバッグ文またはトレース文をアクティブ化し、本番サイトでアプリケーションを実行する場合にそれらの文を隠ぺいすることができます。
ここでのトピック
条件付きコンパイルの動作方法
条件付きコンパイルでは、IF
文に似た選択ディレクティブを使用して、コンパイルするソース・テキストを選択します。
通常、選択ディレクティブの条件には問合せディレクティブが含まれています。エラー・ディレクティブは、ユーザー定義のエラーを呼び出します。すべての条件付きコンパイル・ディレクティブは、プリプロセッサ制御トークンとPL/SQLテキストで構成されています。
ここでのトピック
関連項目:
「静的な式」プリプロセッサ制御トークン
プリプロセッサ制御トークンによって、PL/SQLユニットがコンパイルされる前に処理されるコードが識別されます。
構文
$plsql_identifier
$
とplsql_identifier
の間に空白を入れることはできません。
文字$
はplsql_identifier
内でも使用できますが、そこでは特別な意味を持ちません。
次のプリプロセッサ制御トークンは予約されています。
-
$IF
-
$THEN
-
$ELSE
-
$ELSIF
-
$ERROR
plsql_identifier
の詳細は、「識別子」を参照してください。
選択ディレクティブ
選択ディレクティブは、コンパイルするソース・テキストを選択します。
構文
$IF boolean_static_expression $THEN text [ $ELSIF boolean_static_expression $THEN text ]... [ $ELSE text $END ]
boolean_static_expression
の構文の詳細は、「静的なブール式」を参照してください。text
は任意ですが、通常は文(「statement ::=」を参照)またはエラー・ディレクティブ(「エラー・ディレクティブ」を参照)です。
選択ディレクティブは、いずれかの静的なBOOLEAN
式の値がTRUE
であるか、またはすべての式が処理されるまで、使用されている順に式を評価します。いずれかの式の値がTRUE
の場合、そのテキストがコンパイルされますが、残りの式は評価されず、そのテキストは分析されません。値がTRUE
の式がなく、$ELSE
が存在する場合は、そのテキストがコンパイルされますが、存在しない場合は、どのテキストもコンパイルされません。
選択ディレクティブの例は、「条件付きコンパイルの例」を参照してください。
関連項目:
選択ディレクティブと同じロジックを持つIF
文の詳細は、「条件付き選択文」を参照してください
エラー・ディレクティブ
エラー・ディレクティブは、コンパイル時にユーザー定義のエラー・メッセージを生成します。
構文
$ERROR varchar2_static_expression $END
次のコンパイル時のエラー・メッセージを生成します。string
はvarchar2_static_expression
の値です。
PLS-00179: $ERROR: string
varchar2_static_expression
の構文の詳細は、「静的なVARCHAR2式」を参照してください。
エラー・ディレクティブの使用例は、例3-60を参照してください。
問合せディレクティブ
問合せディレクティブは、コンパイル環境の情報を提供します。
構文
$$name
name
(引用符で囲まれていないPL/SQL識別子)の詳細は、「識別子」を参照してください。
通常、問合せディレクティブは、選択ディレクティブのboolean_static_expression
で使用しますが、その型の変数またはリテラルを使用できるすべての場所で使用できます。また、通常のPL/SQLでは(変数ではなく)リテラルのみ使用可能な場所でも使用できます(たとえば、VARCHAR2
変数のサイズを指定するために使用できます)。
ここでのトピック
事前定義の問合せディレクティブ
事前定義の問合せディレクティブは、次のとおりです。
-
$$PLSQL_LINE
現行のPL/SQLユニットでディレクティブが使用されるソース行の番号を値として持つ
PLS_INTEGER
リテラル。選択ディレクティブの$$PLSQL_LINE
の例を次に示します。$IF $$PLSQL_LINE = 32 $THEN ...
-
$$PLSQL_UNIT
現行のPL/SQLユニットの名前を持つ
VARCHAR2
リテラル。現行のPL/SQLユニットが無名ブロックの場合、$$PLSQL_UNIT
の値はNULL
値になります。 -
$$PLSQL_UNIT_OWNER
現行のPL/SQLユニットの所有者を持つ
VARCHAR2
リテラル。現行のPL/SQLユニットが無名ブロックの場合、$$PLSQL_UNIT_OWNER
の値はNULL
値になります。 -
$$PLSQL_UNIT_TYPE
現行のPL/SQLユニットのタイプを持つ
VARCHAR2
リテラル。ANONYMOUS
BLOCK
、FUNCTION
、PACKAGE
、PACKAGE
BODY
、PROCEDURE
、TRIGGER
、TYPE
またはTYPE
BODY
のいずれか。無名ブロックまたは非DMLトリガー内では、$$PLSQL_UNIT_TYPE
の値はANONYMOUS BLOCK
になります。 -
$$
plsql_compilation_parameter
名前
plsql_compilation_parameter
は、PL/SQLコンパイル・パラメータ(PLSCOPE_SETTINGS
など)です。これらのパラメータの詳細は、表2-2を参照してください。
選択ディレクティブには静的なBOOLEAN
式が必要なため、VARCHAR2
比較で次のような$$PLSQL_UNIT
、$$PLSQL_UNIT_OWNER
または$$PLSQL_UNIT_TYPE
は使用できません。
$IF $$PLSQL_UNIT = 'AWARD_BONUS' $THEN ... $IF $$PLSQL_UNIT_OWNER IS HR $THEN ... $IF $$PLSQL_UNIT_TYPE IS FUNCTION $THEN ...
ただし、前述のディレクティブをNULL
と比較することはできます。たとえば:
$IF $$PLSQL_UNIT IS NULL $THEN ... $IF $$PLSQL_UNIT_OWNER IS NOT NULL $THEN ... $IF $$PLSQL_UNIT_TYPE IS NULL $THEN ...
例3-57 事前定義の問合せディレクティブ
この例は、SQL*Plusスクリプトでは、複数の事前定義の問合せディレクティブをPLS_INTEGER
およびVARCHAR2
リテラルとして使用し、値がどのように代入されるかを示しています。
SQL> CREATE OR REPLACE PROCEDURE p 2 AUTHID DEFINER IS 3 i PLS_INTEGER; 4 BEGIN 5 DBMS_OUTPUT.PUT_LINE('Inside p'); 6 i := $$PLSQL_LINE; 7 DBMS_OUTPUT.PUT_LINE('i = ' || i); 8 DBMS_OUTPUT.PUT_LINE('$$PLSQL_LINE = ' || $$PLSQL_LINE); 9 DBMS_OUTPUT.PUT_LINE('$$PLSQL_UNIT = ' || $$PLSQL_UNIT); 10 DBMS_OUTPUT.PUT_LINE('$$PLSQL_UNIT_OWNER = ' || $$PLSQL_UNIT_OWNER); 11 DBMS_OUTPUT.PUT_LINE('$$PLSQL_UNIT_TYPE = ' || $$PLSQL_UNIT_TYPE); 12 END; 13 / Procedure created. SQL> BEGIN 2 p; 3 DBMS_OUTPUT.PUT_LINE('Outside p'); 4 DBMS_OUTPUT.PUT_LINE('$$PLSQL_LINE = ' || $$PLSQL_LINE); 5 DBMS_OUTPUT.PUT_LINE('$$PLSQL_UNIT = ' || $$PLSQL_UNIT); 6 DBMS_OUTPUT.PUT_LINE('$$PLSQL_UNIT_OWNER = ' || $$PLSQL_UNIT_OWNER); 7 DBMS_OUTPUT.PUT_LINE('$$PLSQL_UNIT_TYPE = ' || $$PLSQL_UNIT_TYPE); 8 END; 9 /
結果:
Inside p i = 6 $$PLSQL_LINE = 8 $$PLSQL_UNIT = P $$PLSQL_UNIT_OWNER = HR $$PLSQL_UNIT_TYPE = PROCEDURE Outside p $$PLSQL_LINE = 4 $$PLSQL_UNIT = $$PLSQL_UNIT_OWNER = $$PLSQL_UNIT_TYPE = ANONYMOUS BLOCK PL/SQL procedure successfully completed.
例3-58 PL/SQLのコンパイル・パラメータの値の表示
この例では、PL/SQLコンパイル・パラメータの現在の値を表示します。
ノート:
SQL*Plus環境では、SHOW
PARAMETERS
コマンドを使用して、PL/SQLコンパイル・パラメータを含む初期化パラメータの現在の値を表示できます。SHOW
コマンドとPARAMETERS
オプションの詳細は、『SQL*Plusユーザーズ・ガイドおよびリファレンス』を参照してください。
BEGIN DBMS_OUTPUT.PUT_LINE('$$PLSCOPE_SETTINGS = ' || $$PLSCOPE_SETTINGS); DBMS_OUTPUT.PUT_LINE('$$PLSQL_CCFLAGS = ' || $$PLSQL_CCFLAGS); DBMS_OUTPUT.PUT_LINE('$$PLSQL_CODE_TYPE = ' || $$PLSQL_CODE_TYPE); DBMS_OUTPUT.PUT_LINE('$$PLSQL_OPTIMIZE_LEVEL = ' || $$PLSQL_OPTIMIZE_LEVEL); DBMS_OUTPUT.PUT_LINE('$$PLSQL_WARNINGS = ' || $$PLSQL_WARNINGS); DBMS_OUTPUT.PUT_LINE('$$NLS_LENGTH_SEMANTICS = ' || $$NLS_LENGTH_SEMANTICS); END; /
結果:
$$PLSCOPE_SETTINGS = IDENTIFIERS:NONE $$PLSQL_CCFLAGS = $$PLSQL_CODE_TYPE = INTERPRETED $$PLSQL_OPTIMIZE_LEVEL = 2 $$PLSQL_WARNINGS = ENABLE:ALL $$NLS_LENGTH_SEMANTICS = BYTE
問合せディレクティブへの値の代入
PLSQL_CCFLAGS
コンパイル・パラメータを使用して、問合せディレクティブに値を代入できます。
たとえば:
ALTER SESSION SET PLSQL_CCFLAGS = 'name1:value1, name2:value2, ... namen:valuen'
それぞれのvalue
は、BOOLEAN
リテラル(TRUE
、FALSE
またはNULL
)、あるいはPLS_INTEGER
リテラルである必要があります。value
のデータ型によって、name
のデータ型が決まります。
同じデータ型または異なるデータ型の値を指定して同じname
を複数回使用できます。先に行った代入は、後で行った代入によってオーバーライドされます。たとえば、次のコマンドでは、$$flag
の値は5、データ型はPLS_INTEGER
に設定されます。
ALTER SESSION SET PLSQL_CCFLAGS = 'flag:TRUE, flag:5'
コンパイル・パラメータを含む事前定義の問合せディレクティブに値を代入する場合、PLSQL_CCFLAGS
は使用しないことをお薦めします。コンパイル・パラメータに値を代入する場合は、ALTER
SESSION
文を使用することをお薦めします。
ALTER
SESSION
文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。
ノート:
PLSQL_CCFLAGS
のコンパイル時の値は、ストアドPL/SQLユニットのメタデータとともに格納されているため、ユニットを明示的に再コンパイルするときにその値を再利用できます。詳細は、「PL/SQLユニットおよびコンパイル・パラメータ」を参照してください。
PLSQL_CCFLAGS
の詳細は、『Oracle Databaseリファレンス』を参照してください。
例3-59 PLSQL_CCFLAGSによるそれ自体への値の代入
この例では、PLSQL_CCFLAGS
を使用して、ユーザー定義の問合せディレクティブ$$Some_Flag
に値を代入し、さらに、(推奨されてはいませんが)それ自体にも値を代入します。先に行った代入は後で行った代入によってオーバーライドされるため、$$Some_Flag
の結果の値は2になり、PLSQL_CCFLAGS
の結果の値はALTER
SESSION
文によって代入される値('Some_Flag:1, Some_Flag:2, PLSQL_CCFlags:99'
)ではなく、それ自体に代入される値(99)になります。
ALTER SESSION SET
PLSQL_CCFlags = 'Some_Flag:1, Some_Flag:2, PLSQL_CCFlags:99'
/
BEGIN
DBMS_OUTPUT.PUT_LINE($$Some_Flag);
DBMS_OUTPUT.PUT_LINE($$PLSQL_CCFlags);
END;
/
結果:
2 99
解決できない問合せディレクティブ
ソース・テキストがラップされていない場合、問合せディレクティブの値を判別できないと、PL/SQLによって警告が発行されます。
問合せディレクティブ($$
name
)を解決できず、ソース・テキストがラップされていない場合は、PL/SQLにより警告PLW-6003
が発行され、未解決の問合せディレクティブの値としてNULL
が代入されます。ソース・テキストがラップされている場合は、未解決の問合せディレクティブが示されないように、警告メッセージが無効になります。
PL/SQLソース・テキストのラップの詳細は、「PL/SQLのソース・テキストのラップ」を参照してください。
DBMS_DB_VERSIONパッケージ
DBMS_DB_VERSION
パッケージでは、Oracleバージョン番号、およびOracleのバージョンに基づいて条件付きコンパイルを簡単に選択する場合に有効なその他の情報を指定します。
DBMS_DB_VERSION
パッケージでは、次の静的定数が提供されます。
-
PLS_INTEGER
定数VERSION
は、現行のOracle Databaseのバージョンを識別します。 -
PLS_INTEGER
定数RELEASE
は、現行のOracle Databaseのリリース番号を識別します。 -
VER_LE_
v
形式のBOOLEAN
定数の値はそれぞれ、データベース・バージョンがv
以下の場合にTRUE
になり、それ以外の場合はFALSE
になります。 -
VER_LE_
v_r
形式のBOOLEAN
定数の値はそれぞれ、データベース・バージョンがv
以下でリリースがr
以下の場合にTRUE
になり、それ以外の場合はFALSE
になります。
DBMS_DB_VERSION
パッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。
条件付きコンパイルの例
選択およびユーザー定義の問合せディレクティブを使用する条件付きコンパイルの例。
例3-60 データベース・バージョンを確認するコード
この例では、データベース・バージョンおよびリリースがOracle Database 10gリリース2より前の場合はエラー・メッセージを生成し、それ以外の場合は、バージョンおよびリリースがサポート対象であるというメッセージを表示してOracle Database 10gリリース2から使用可能になったCOMMIT
文を使用します。
BEGIN $IF DBMS_DB_VERSION.VER_LE_10_1 $THEN -- selection directive begins $ERROR 'unsupported database release' $END -- error directive $ELSE DBMS_OUTPUT.PUT_LINE ( 'Release ' || DBMS_DB_VERSION.VERSION || '.' || DBMS_DB_VERSION.RELEASE || ' is supported.' ); -- This COMMIT syntax is newly supported in 10.2: COMMIT WRITE IMMEDIATE NOWAIT; $END -- selection directive ends END; /
結果:
Release 12.1 is supported.
例3-61 異なるデータベース・バージョンに対する異なるコードのコンパイル
この例では、ユーザー定義の問合せディレクティブ$$my_debug
および$$my_tracing
に値を設定し、条件付きコンパイルを使用します。
-
パッケージ
my_pkg
の仕様部で、サブタイプmy_real
のベース型を判断します(BINARY_DOUBLE
は、Oracle Databaseバージョン10g以上でのみ使用できます)。 -
パッケージ
my_pkg
の本体で、異なるデータベース・バージョンに対してmy_pi
およびmy_e
の値を別々に計算します -
プロシージャ
circle_area
で、問合せディレクティブ$$my_debug
の値がTRUE
の場合のみに一部のコードをコンパイルします。
ALTER SESSION SET PLSQL_CCFLAGS = 'my_debug:FALSE, my_tracing:FALSE'; CREATE OR REPLACE PACKAGE my_pkg AUTHID DEFINER AS SUBTYPE my_real IS $IF DBMS_DB_VERSION.VERSION < 10 $THEN NUMBER; $ELSE BINARY_DOUBLE; $END my_pi my_real; my_e my_real; END my_pkg; / CREATE OR REPLACE PACKAGE BODY my_pkg AS BEGIN $IF DBMS_DB_VERSION.VERSION < 10 $THEN my_pi := 3.14159265358979323846264338327950288420; my_e := 2.71828182845904523536028747135266249775; $ELSE my_pi := 3.14159265358979323846264338327950288420d; my_e := 2.71828182845904523536028747135266249775d; $END END my_pkg; / CREATE OR REPLACE PROCEDURE circle_area(radius my_pkg.my_real) AUTHID DEFINER IS my_area my_pkg.my_real; my_data_type VARCHAR2(30); BEGIN my_area := my_pkg.my_pi * (radius**2); DBMS_OUTPUT.PUT_LINE ('Radius: ' || TO_CHAR(radius) || ' Area: ' || TO_CHAR(my_area)); $IF $$my_debug $THEN SELECT DATA_TYPE INTO my_data_type FROM USER_ARGUMENTS WHERE OBJECT_NAME = 'CIRCLE_AREA' AND ARGUMENT_NAME = 'RADIUS'; DBMS_OUTPUT.PUT_LINE ('Data type of the RADIUS argument is: ' || my_data_type); $END END; / CALL DBMS_PREPROCESSOR.PRINT_POST_PROCESSED_SOURCE ('PACKAGE', 'HR', 'MY_PKG');
結果:
PACKAGE my_pkg AUTHID DEFINER AS SUBTYPE my_real IS BINARY_DOUBLE; my_pi my_real; my_e my_real; END my_pkg; Call completed.
処理後のソース・テキストの取得と出力
DBMS_PREPROCESSOR
パッケージでは、処理後の形式でPL/SQLのソース・テキストを取得して出力するサブプログラムが提供されます。
DBMS_PREPROCESSOR
パッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。
例3-62 処理後のソース・テキストの表示
この例では、DBMS_PREPROCESSOR
.PRINT_POST_PROCESSED_SOURCE
プロシージャを起動して、例3-61のmy_pkg
の処理後の形式を出力します。処理後のテキストに含まれない例3-61のコードの行は、空白行として表示されます。
CALL DBMS_PREPROCESSOR.PRINT_POST_PROCESSED_SOURCE (
'PACKAGE', 'HR', 'MY_PKG'
);
結果:
PACKAGE my_pkg AUTHID DEFINERs AS SUBTYPE my_real IS BINARY_DOUBLE; my_pi my_real; my_e my_real; END my_pkg;
条件付きコンパイル・ディレクティブの制限
条件付きコンパイル・ディレクティブは、これらのセマンティクス制限の対象となります。
条件付きコンパイル・ディレクティブは、(「CREATE TYPE文」で作成した)スキーマ・レベルのユーザー定義型では使用できません。次の型仕様部で、依存する型の属性構造と依存する表の列構造を決定する、型の属性構造を指定します。
注意:
条件付きコンパイル・ディレクティブを使用して型の属性構造を変更すると、依存オブジェクトが非同期になったり、依存表がアクセス不可になる場合があります。型の属性構造は、「ALTER TYPE文」を使用してのみ変更することをお薦めします。ALTER
TYPE
文は、変更を依存オブジェクトまで伝播します。
スキーマ・レベルの型の仕様部で条件付きコンパイル・ディレクティブが使用されていると、コンパイラはエラー「PLS-00180: プリプロセッサ・ディレクティブは、このコンテキストでサポートされていません
」を報告します。
すべての条件付きコンパイラの構造はPL/SQLプリプロセッサによって処理されるため、SQLパーサーは、ストアドPL/SQLユニットまたは無名ブロック内の最初の条件付きコンパイル・ディレクティブの場所に対して次の制限を強制します。
-
パッケージ仕様部、パッケージ本体、型本体、スキーマ・レベル・ファンクションおよびスキーマ・レベル・プロシージャには、条件コンパイル・ディレクティブが有効になる前に、ユニット名の識別子の後に少なくとも1つの空白でないPL/SQLトークンがあることが必要です。
ノート:
-
PL/SQLのコメント"--"または"/*"は、空白トークンとしてカウントされます。
-
トークンがPL/SQLで無効な場合は、PLS-00103エラーが発行されます。ただし、このルールに違反した状態で条件付きコンパイル・ディレクティブが使用されていると、ORAエラーが生成されます。
例3-63および例3-64では、最初の条件付きコンパイル・ディレクティブが、定義しているユニットの識別子に続く最初のPL/SQLトークンの後にあることを示しています。
-
-
トリガーまたは無名ブロックでは、キーワード
DECLARE
またはBEGIN
(いずれか先に使用されている方)の前に最初の条件付きコンパイル・ディレクティブを配置することはできません。
SQLパーサーでは、無名ブロックでプレースホルダが使用される場合、そのプレースホルダは条件付きコンパイル・ディレクティブで使用できないという制限もあります。たとえば:
BEGIN :n := 1; -- valid use of placeholder $IF ... $THEN :n := 1; -- invalid use of placeholder $END
例3-63 パッケージ仕様の定義で使用する条件付きコンパイル・ディレクティブ
この例は、パッケージ仕様の定義で、AUTHID
句の後のキーワードIS
の前に、最初の条件付きコンパイル・ディレクティブを配置する例を示しています。
CREATE OR REPLACE PACKAGE cc_pkg AUTHID DEFINER $IF $$XFLAG $THEN ACCESSIBLE BY(p1_pkg) $END IS i NUMBER := 10; trace CONSTANT BOOLEAN := TRUE; END cc_pkg;
結果:
Package created.
例3-64 サブプログラムの仮パラメータ・リストで使用する条件付きコンパイル・ディレクティブ
この例は、PL/SQLプロシージャ定義の仮パラメータ・リストで、左カッコの後に最初の条件付きコンパイル・ディレクティブが配置されることを示しています。
CREATE OR REPLACE PROCEDURE my_proc ( $IF $$xxx $THEN i IN PLS_INTEGER $ELSE i IN INTEGER $END ) IS BEGIN NULL; END my_proc;
結果:
Procedure created.