DBMS_OUTPUTパッケージによって、ストアド・プロシージャ、パッケージおよびトリガーからメッセージを送信できます。このパッケージは、PL/SQLデバッグ情報の表示に特に便利です。
この章では、次の項目について説明します。
概要
セキュリティ・モデル
使用上の注意
例外
ルールおよび制限
例
表タイプ
オブジェクト・タイプ
この項では、DBMS_OUTPUTパッケージの使用に関連する項目について説明します。
通常、このパッケージは、デバッグに使用されるか、あるいはメッセージとレポート(プロシージャにSQLコマンドDESCRIBEを適用するなどして生成)をSQL*DBAまたはSQL*Plusに表示するために使用されます。
このパッケージに含まれているPUTプロシージャおよびPUT_LINEプロシージャによって、別のトリガー、プロシージャまたはパッケージで読み込めるバッファに情報を設定できます。別のPL/SQLプロシージャまたは無名ブロックでは、GET_LINEプロシージャおよびGET_LINESプロシージャをコールして、バッファに入れた情報を表示できます。
パッケージを無効にすると、サブプログラムに対するすべてのコールが無視されます。これによって、クライアントが情報を処理できる場合のみにサブプログラムが使用可能になるように、アプリケーションを設計できます。
dbmsotpt.sqlスクリプトは、ユーザーSYSとして実行する必要があります。これによって、パブリック・シノニムDBMS_OUTPUTが作成され、このパッケージに対するEXECUTE許可がpublicに付与されます。
GET_LINEをコールしない場合、またはSQL*Plusのスクリーンにメッセージを表示しない場合、バッファに入れたメッセージは無視されます。
SQL*Plusは、SQL文または無名PL/SQLコールを発行した後にGET_LINESをコールします。
SQL*PlusにSET SERVEROUTPUT ONを入力すると、次のコマンドが実行されます。
DBMS_OUTPUT.ENABLE (buffer_size => NULL);
この場合、出力に制限はありません。
通常は、アプリケーション・コードでDISABLEプロシージャまたはENABLEプロシージャを起動しないでください。SQL*Plusなどの外部ツールによって出力を表示するかどうかを制御できなくなる可能性があるためです。
|
注意: DBMS_OUTPUTを使用して送信するメッセージは、送信サブプログラムまたはトリガーが完了するまでは実際に送信されません。プロシージャの実行中に出力をフラッシュするメカニズムはありません。 |
例1: トリガーを使用した出力
トリガーを使用して、デバッグ処理の結果を出力できます。たとえば、次のコマンドを実行するトリガーをコード化できます。
DBMS_OUTPUT.PUT_LINE('I got here:'||:new.col||' is the new value');
DBMS_OUTPUTパッケージを使用可能にした場合、このPUT_LINEによって生成されたテキストはバッファに入れられ、トリガー文(トリガーを起動させるINSERT、DELETEまたはUPDATEが想定できます)の実行後に、情報行を取り出すことができます。次に例を示します。
BEGIN DBMS_OUTPUT.GET_LINE(:buffer, :status); END;
これによって、スクリーンにバッファを表示できます(オプション)。statusが0(ゼロ)以外で戻るまで、GET_LINEへのコールを繰り返します。パフォーマンス向上のためには、行の配列を戻すことができるGET_LINESプロシージャへのコールを使用してください。
例2: ストアド・プロシージャとトリガーのデバッグ
DBMS_OUTPUTパッケージは、一般的に、ストアド・プロシージャおよびトリガーをデバッグするために使用されます。また、「例3: オブジェクトに関する情報の取得」で示すように、このパッケージを使用すると、オブジェクトの情報を取り出し、その出力をフォーマットできます。
このファンクションは、従業員表を問い合せて、指定部門の給与合計を戻します。このファンクションには、次のようにPUT_LINEプロシージャへのコールがいくつか含まれます。
CREATE FUNCTION dept_salary (dnum NUMBER) RETURN NUMBER IS
CURSOR emp_cursor IS
SELECT sal, comm FROM emp WHERE deptno = dnum;
total_wages NUMBER(11, 2) := 0;
counter NUMBER(10) := 1;
BEGIN
FOR emp_record IN emp_cursor LOOP
emp_record.comm := NVL(emp_record.comm, 0);
total_wages := total_wages + emp_record.sal
+ emp_record.comm;
DBMS_OUTPUT.PUT_LINE('Loop number = ' || counter ||
'; Wages = '|| TO_CHAR(total_wages)); /* Debug line */
counter := counter + 1; /* Increment debug counter */
END LOOP;
/* Debug line */
DBMS_OUTPUT.PUT_LINE('Total wages = ' ||
TO_CHAR(total_wages));
RETURN total_wages;
END dept_salary;
EMP表には、次の行が含まれているとします。
EMPNO SAL COMM DEPT ----- ------- -------- ------- 1002 1500 500 20 1203 1000 30 1289 1000 10 1347 1000 250 20
ユーザーがSQL*Plusの次の文を実行したとします。
SET SERVEROUTPUT ON VARIABLE salary NUMBER; EXECUTE :salary := dept_salary(20);
出力ペインには、次の情報が表示されます。
Loop number = 1; Wages = 2000 Loop number = 2; Wages = 3250 Total wages = 3250 PL/SQL procedure successfully executed.
例3: オブジェクトに関する情報の取得
この例では、ユーザーはすでにEXPLAIN PLANコマンドを使用して、ある文の実行計画に関する情報を取り出し、その情報をPLAN_TABLEに格納してあります。また、ユーザーはこの文に文IDを割り当ててあります。EXPLAIN_OUTプロシージャの例では、表から情報を取り出し、出力をネスト形式でフォーマットして、SQL文を処理するステップの順序を厳密に記述しています。
/****************************************************************/
/* Create EXPLAIN_OUT procedure. User must pass STATEMENT_ID to */
/* to procedure, to uniquely identify statement. */
/****************************************************************/
CREATE OR REPLACE PROCEDURE explain_out
(statement_id IN VARCHAR2) AS
-- Retrieve information from PLAN_TABLE into cursor EXPLAIN_ROWS.
CURSOR explain_rows IS
SELECT level, id, position, operation, options,
object_name
FROM plan_table
WHERE statement_id = explain_out.statement_id
CONNECT BY PRIOR id = parent_id
AND statement_id = explain_out.statement_id
START WITH id = 0
ORDER BY id;
BEGIN
-- Loop through information retrieved from PLAN_TABLE:
FOR line IN explain_rows LOOP
-- At start of output, include heading with estimated cost.
IF line.id = 0 THEN
DBMS_OUTPUT.PUT_LINE ('Plan for statement '
|| statement_id
|| ', estimated cost = ' || line.position);
END IF;
-- Output formatted information. LEVEL determines indention level.
DBMS_OUTPUT.PUT_LINE (lpad(' ',2*(line.level-1)) ||
line.operation || ' ' || line.options || ' ' ||
line.object_name);
END LOOP;
END;
DBMS_OUTPUTパッケージは、GET_LINESプロシージャで使用するために、2つのコレクション・タイプを宣言します。
パッケージの外部で定義されたこのタイプは、PUTプロシージャおよびPUT_LINEプロシージャを介して送信されたテキストを取得するために、GET_LINESプロシージャで使用されます。
表106-2 DBMS_OUTPUTパッケージのサブプログラム
| サブプログラム | 説明 |
|---|---|
|
|
メッセージの出力を使用禁止にします。 |
|
|
メッセージの出力を使用可能にします。 |
|
|
バッファから1行取り出します。 |
|
|
バッファから行の配列を1つ取り出します。 |
|
|
|
|
|
行の一部をバッファに設定します。 |
|
|
行をバッファに設定します。 |
このプロシージャは、PUT、PUT_LINE、NEW_LINE、GET_LINEおよびGET_LINESへのコールを使用禁止にして、残っている情報のバッファをパージします。
ENABLEプロシージャと同様に、SQL*PlusのSERVEROUTPUTオプションを使用する場合は、このプロシージャをコールする必要はありません。
このプロシージャは、PUT、PUT_LINE、NEW_LINE、GET_LINEおよびGET_LINESへのコールを使用可能にします。DBMS_OUTPUTパッケージがアクティブ化されていない場合、これらのプロシージャへのコールは無視されます。
このプロシージャは、バッファに入れられた単一行の情報を取り出します。
使用上の注意
単一行または行の配列をバッファから取り出すことができます。バッファに入れられた単一行の情報を取り出すには、GET_LINEプロシージャをコールします。サーバーへのコール数を減らすには、GET_LINESプロシージャをコールして、バッファから行の配列を取り出します。
SQL*Plusを使用している場合は、特別のSET SERVEROUTPUT ONコマンドを使用して、この情報を自動的に表示できます。
GET_LINEまたはGET_LINESをコールしてから、次にPUT、PUT_LINEまたはNEW_LINEをコールする前に取り出されなかった行は、次のメッセージとの混同を避けるために廃棄されます。
このプロシージャは、バッファから行の配列を取り出します。
構文
DBMS_OUTPUT.GET_LINES ( lines OUT CHARARR, numlines IN OUT INTEGER); DBMS_OUTPUT.GET_LINES ( lines OUT DBMSOUTPUT_LINESARRAY, numlines IN OUT INTEGER);
使用上の注意
単一行または行の配列をバッファから取り出すことができます。バッファに入れられた単一行の情報を取り出すには、GET_LINEプロシージャをコールします。サーバーへのコール数を減らすには、GET_LINESプロシージャをコールして、バッファから行の配列を取り出します。
SQL*Plusを使用している場合は、特別のSET SERVEROUTPUT ONコマンドを使用して、この情報を自動的に表示できます。
GET_LINEまたはGET_LINESをコールしてから、次にPUT、PUT_LINEまたはNEW_LINEをコールする前に取り出されなかった行は、次のメッセージとの混同を避けるために廃棄されます。
このプロシージャは、行端マーカーを設定します。GET_LINEプロシージャおよびGET_LINESプロシージャは、改行で区切られた行を戻します。PUT_LINEプロシージャまたはNEW_LINEプロシージャへのすべてのコールによって、GET_LINE(S)で戻される行が生成されます。
このプロシージャは、行の一部をバッファに設定します。
|
注意: NUMBERデータ・タイプを使用するPUTプロシージャは使用されなくなります。現在はサポートされますが、このリリースに含まれているのは下位互換性を保つという理由にすぎません。 |
使用上の注意
PUTを複数回コールすることによって個別に情報行を作成するか、PUT_LINEをコールして情報行全体をバッファに設定することができます。
PUT_LINEをコールすると、指定した項目には行端マーカーが自動的に付きます。PUTをコールして行を作成する場合は、NEW_LINEをコールして行端マーカーを追加する必要があります。GET_LINEおよびGET_LINESは、改行文字で終了していない行は戻しません。
行が行制限を超えた場合は、エラー・メッセージを受信します。
PUTまたはPUT_LINEで作成した出力はバッファに入れられます。この出力は、それをバッファに入れたPL/SQLプログラム・ユニットがコール元に戻るまで取り出せません。
たとえば、SQL*Plusは、PL/SQLプログラムが完了するまでDBMS_OUTPUTメッセージを表示しません。PL/SQLプログラム内でDBMS_OUTPUTバッファをフラッシュするメカニズムはありません。
SQL> SET SERVEROUTPUT ON
SQL> BEGIN
2 DBMS_OUTPUT.PUT_LINE ('hello');
3 DBMS_LOCK.SLEEP (10);
4 END;
このプロシージャは、行をバッファに設定します。
|
注意: NUMBERデータ・タイプを使用するPUT_LINEプロシージャは使用されなくなります。現在はサポートされますが、このリリースに含まれているのは下位互換性を保つという理由にすぎません。 |
使用上の注意
PUTを複数回コールすることによって個別に情報行を作成するか、PUT_LINEをコールして情報行全体をバッファに設定することができます。
PUT_LINEをコールすると、指定した項目には行端マーカーが自動的に付きます。PUTをコールして行を作成する場合は、NEW_LINEをコールして行端マーカーを追加する必要があります。GET_LINEおよびGET_LINESは、改行文字で終了していない行は戻しません。
行が行制限を超えた場合は、エラー・メッセージを受信します。
PUTまたはPUT_LINEで作成した出力はバッファに入れられます。この出力は、それをバッファに入れたPL/SQLプログラム・ユニットがコール元に戻るまで取り出せません。
たとえば、SQL*Plusは、PL/SQLプログラムが完了するまでDBMS_OUTPUTメッセージを表示しません。PL/SQLプログラム内でDBMS_OUTPUTバッファをフラッシュするメカニズムはありません。次に例を示します。
SQL> SET SERVEROUTPUT ON
SQL> BEGIN
2 DBMS_OUTPUT.PUT_LINE ('hello');
3 DBMS_LOCK.SLEEP (10);
4 END;