DBMS_PIPE
パッケージによって、同じインスタンスにある複数のセッションの通信を行います。Oracleパイプは、UNIXで使用するパイプと概念は似ていますが、オペレーティング・システムのパイプ・メカニズムを使用して実装されていません。
この章では、次の項目について説明します。
概要
セキュリティ・モデル
定数
使用上の注意
例外
例
パイプ機能には、次のような潜在的な応用例があります。
外部サービス・インタフェース: RDBMS外部にあるユーザー記述のサービスと通信できます。これは、共有サーバー・プロセスで効果的に行うことができるため、サービスの複数インスタンスが同時に実行されます。さらに、サービスは非同期で使用できます。サービスのリクエスタは、待機応答をブロックする必要がありません。リクエスタは、(タイムアウトに関係なく)後でチェックできます。このサービスは、Oracleがサポートする任意の3GL言語で記述できます。
独立したトランザクション: パイプは、独立したトランザクション(トリガーで検出されたセキュリティ違反のロギングなど)内で操作を実行できる別のセッションと通信できます。
アラート(トランザクション以外): ポーリングするための待機プロセスを要求せずに、別のプロセスを転送できます。アプリケーションにアラートを通知するAFTER行またはAFTER文トリガーがある場合、アプリケーションは、このアラートをデータが変更された可能性を示すためのアラートとして処理します。アプリケーションはそのデータを読み込み、現行の値を取得します。これはAFTERトリガーなので、アプリケーションは、SELECT
FOR
UPDATE
を行って正しいデータを読み込んだことを確認しようとします。
デバッグ: トリガーおよびストアド・プロシージャは、デバッグ情報をパイプに送信できます。別のセッションは、パイプからの読込みを続行し、その内容をスクリーンに表示したりファイルに書き込むことができます。
コンセントレータ: これは、少数のネットワーク接続に対して多数のユーザーがいる場合のユーザーの多重化や、複数のユーザー・トランザクションを1つのDBMSトランザクションに集中化する場合のパフォーマンス改善に役立ちます。
セキュリティは、DBMS_PIPE
パッケージのGRANT
EXECUTE
を使用して実現できます。これは、CREATE_PIPE
ファンクションのprivate
パラメータを使用してパイプを作成し、特定の機能、特定のユーザーやロールへのパイプ名を表示するのみのカバー・パッケージを記述することによって行われます。
セキュリティ要件に応じて、パブリック・パイプまたはプライベート・パイプのいずれかを選択できます。
Oracleパイプを介して送信する情報は、システム・グローバル領域(SGA)にバッファリングされます。パイプ内のすべての情報は、インスタンスがシャットダウンすると失われます。
注意: パイプはトランザクションから独立しています。トランザクション制御に影響を与える可能性がある場合は、注意してパイプを使用してください。 |
DBMS_PIPEの操作は、次のトピックに関して行われます。
パブリック・パイプは、暗黙的または明示的に作成できます。暗黙的なパブリック・パイプの場合、パイプは最初の参照時に自動的に作成され、データがなくなると消去されます。パイプ記述子はSGAに格納されるため、空のパイプがキャッシュから削除されるまで、スペースを使用するオーバーヘッドが若干あります。
privateフラグをFALSE
に設定し、CREATE_PIPE
ファンクションをコールして、明示的な
パブリック・パイプを作成します。明示的に作成したパイプは、REMOVE_PIPE
ファンクションをコールして割当て解除する必要があります。
パブリック・パイプのドメインは、明示的または暗黙的にパイプが作成されたスキーマです。
各パブリック・パイプは非同期に動作します。スキーマ・ユーザーがDBMS_PIPE
パッケージに対するEXECUTE
許可を持ち、パブリック・パイプ名を知っている場合にかぎり、任意の数のスキーマ・ユーザーがパブリック・パイプへの書込みを行うことができます。ただし、バッファに入っている情報を1人のユーザーが読み込むと、その情報はバッファから消去されるため、同じパイプの他のユーザーは読み込むことができません。
送信側セッションでは、PACK_MESSAGE
プロシージャに1つ以上コールを行ってメッセージを作成します。このプロシージャは、セッションのローカル・メッセージ・バッファにメッセージを追加します。このバッファ内の情報は、メッセージ送信に使用するパイプ名を指定したSEND_MESSAGE
ファンクションをコールして送信されます。SEND_MESSAGE
をコールすると、ローカル・バッファにスタックされたすべてのメッセージが送信されます。
メッセージを受信するプロセスは、メッセージを受信するパイプ名を指定したRECEIVE_MESSAGE
ファンクションをコールします。次に、UNPACK_MESSAGE
プロシージャをコールして、メッセージ内の各項目にアクセスします。
CREATE_PIPE
ファンクションをコールして、プライベート・パイプを明示的に作成します。プライベート・パイプは、一度作成されると、REMOVE_PIPE
ファンクションをコールして明示的に割当て解除するまで共有メモリーに存続します。プライベート・パイプは、データベース・インスタンスがシャットダウンしたときにも割当て解除されます。
メモリーに暗黙的なパイプが存在し、そのパイプと作成しようとするプライベート・パイプが同じ名前の場合、プライベート・パイプは作成できません。この場合は、CREATE_PIPE
からエラーが戻されます。
プライベート・パイプへのアクセスは、次のように限定されます。
パイプ作成者と同じユーザーIDで実行中のセッション
パイプ作成者と同じユーザーID権限ドメインで実行中のストアド・サブプログラム
SYSDBA
として接続したユーザー
これ以外のユーザーがパイプ上のメッセージの送受信やパイプの削除を試みると、即時にエラーが発生します。別のユーザーが同じ名前のパイプを作成しようとしても、エラーが発生します。
パブリック・パイプと同様に、SEND_MESSAGE
をコールする前にPACK_MESSAGE
へのコールを使用して、最初にメッセージを作成する必要があります。同様に、RECEIVE_MESSAGE
をコールしてメッセージを取り出してから、UNPACK_MESSAGE
をコールしてメッセージ内の項目にアクセスする必要があります。
この例は、デバッグ情報をパイプに設定するために、PL/SQLプログラムがコールできるプロシージャを示しています。
CREATE OR REPLACE PROCEDURE debug (msg VARCHAR2) AS status NUMBER; BEGIN DBMS_PIPE.PACK_MESSAGE(LENGTH(msg)); DBMS_PIPE.PACK_MESSAGE(msg); status := DBMS_PIPE.SEND_MESSAGE('plsql_debug'); IF status != 0 THEN raise_application_error(-20099, 'Debug error'); END IF; END debug;
次のPro*Cコードでは、前述の例のPLSQL_DEBUG
パイプから受信したメッセージが表示されます。Pro*Cセッションが別のウィンドウで実行されている場合、このセッションは、別のセッションで実行中のPL/SQLプログラムからデバッグ・プロシージャに送信されるメッセージの表示に使用できます。
#include <stdio.h> #include <string.h> EXEC SQL BEGIN DECLARE SECTION; VARCHAR username[20]; int status; int msg_length; char retval[2000]; EXEC SQL END DECLARE SECTION; EXEC SQL INCLUDE SQLCA; void sql_error(); main() { -- Prepare username: strcpy(username.arr, "SCOTT/TIGER"); username.len = strlen(username.arr); EXEC SQL WHENEVER SQLERROR DO sql_error(); EXEC SQL CONNECT :username; printf("connected\n"); -- Start an endless loop to look for and print messages on the pipe: FOR (;;) { EXEC SQL EXECUTE DECLARE len INTEGER; typ INTEGER; sta INTEGER; chr VARCHAR2(2000); BEGIN chr := ''; sta := dbms_pipe.receive_message('plsql_debug'); IF sta = 0 THEN DBMS_PIPE.UNPACK_MESSAGE(len); DBMS_PIPE.UNPACK_MESSAGE(chr); END IF; :status := sta; :retval := chr; IF len IS NOT NULL THEN :msg_length := len; ELSE :msg_length := 2000; END IF; END; END-EXEC; IF (status == 0) printf("\n%.*s\n", msg_length, retval); ELSE printf("abnormal status, value is %d\n", status); } } void sql_error() { char msg[1024]; int rlen, len; len = sizeof(msg); sqlglm(msg, &len, &rlen); printf("ORACLE ERROR\n"); printf("%.*s\n", rlen, msg); exit(1); }
この例は、PL/SQLとPro*Cコードによって、PL/SQLストアド・プロシージャ(または無名ブロック)がPL/SQLプロシージャをコールし、コマンドをリスニングしているPro*Cプログラムにパイプを介してそのコマンドを送信する処理を示します。
Pro*Cプログラムはスリープして、名前付きパイプにメッセージが着信するのを待ちます。メッセージが着信すると、Pro*Cプログラムはこれを処理し、system()コールを使用したUNIXコマンドの実行、埋込みSQLを使用したSQLコマンドの実行など、必要なアクションを行います。
DAEMON.SQL
は、PL/SQLパッケージ用のソース・コードです。このパッケージには、DBMS_PIPE
パッケージを使用してPro*Cデーモンに対してメッセージを送受信するプロシージャが含まれています。完全なハンドシェイクが使用されていることに注意してください。このデーモンは、常にメッセージをパッケージに返信します(STOP
コマンドの場合は除きます)。これによって、PL/SQLプロシージャはPro*Cデーモンが動作していることを確認できるため、デーモンのこの機能は重要です。
SQL*PlusまたはEnterprise Managerを使用して、無名PL/SQLブロックからDAEMONパッケージ・プロシージャをコールできます。次に例を示します。
SQLPLUS> variable rv number SQLPLUS> execute :rv := DAEMON.EXECUTE_SYSTEM('ls -la');
これにより、UNIXシステムでは、Pro*Cデーモンによってコマンドsystem("ls -la")が実行されます。
最初にデーモンを実行する必要があることに留意してください。デーモンは、バックグラウンドで実行したり、デーモンをコールしたSQL*PlusまたはEnterprise Managerセッションの近くにある別のウィンドウで実行できます。
また、DAEMON
.SQL
は、DBMS_OUTPUT
パッケージを使用して結果を表示します。この例を動作させるには、このパッケージに対するEXECUTE権限が必要です。
DAEMON.SQL例。次の例は、PL/SQL DAEMON
パッケージのコード例です。
CREATE OR REPLACE PACKAGE daemon AS FUNCTION execute_sql(command VARCHAR2, timeout NUMBER DEFAULT 10) RETURN NUMBER; FUNCTION execute_system(command VARCHAR2, timeout NUMBER DEFAULT 10) RETURN NUMBER; PROCEDURE stop(timeout NUMBER DEFAULT 10); END daemon; / CREATE OR REPLACE PACKAGE BODY daemon AS FUNCTION execute_system(command VARCHAR2, timeout NUMBER DEFAULT 10) RETURN NUMBER IS status NUMBER; result VARCHAR2(20); command_code NUMBER; pipe_name VARCHAR2(30); BEGIN pipe_name := DBMS_PIPE.UNIQUE_SESSION_NAME; DBMS_PIPE.PACK_MESSAGE('SYSTEM'); DBMS_PIPE.PACK_MESSAGE(pipe_name); DBMS_PIPE.PACK_MESSAGE(command); status := DBMS_PIPE.SEND_MESSAGE('daemon', timeout); IF status <> 0 THEN RAISE_APPLICATION_ERROR(-20010, 'Execute_system: Error while sending. Status = ' || status); END IF; status := DBMS_PIPE.RECEIVE_MESSAGE(pipe_name, timeout); IF status <> 0 THEN RAISE_APPLICATION_ERROR(-20011, 'Execute_system: Error while receiving. Status = ' || status); END IF; DBMS_PIPE.UNPACK_MESSAGE(result); IF result <> 'done' THEN RAISE_APPLICATION_ERROR(-20012, 'Execute_system: Done not received.'); END IF; DBMS_PIPE.UNPACK_MESSAGE(command_code); DBMS_OUTPUT.PUT_LINE('System command executed. result = ' || command_code); RETURN command_code; END execute_system; FUNCTION execute_sql(command VARCHAR2, timeout NUMBER DEFAULT 10) RETURN NUMBER IS status NUMBER; result VARCHAR2(20); command_code NUMBER; pipe_name VARCHAR2(30); BEGIN pipe_name := DBMS_PIPE.UNIQUE_SESSION_NAME; DBMS_PIPE.PACK_MESSAGE('SQL'); DBMS_PIPE.PACK_MESSAGE(pipe_name); DBMS_PIPE.PACK_MESSAGE(command); status := DBMS_PIPE.SEND_MESSAGE('daemon', timeout); IF status <> 0 THEN RAISE_APPLICATION_ERROR(-20020, 'Execute_sql: Error while sending. Status = ' || status); END IF; status := DBMS_PIPE.RECEIVE_MESSAGE(pipe_name, timeout); IF status <> 0 THEN RAISE_APPLICATION_ERROR(-20021, 'execute_sql: Error while receiving. Status = ' || status); END IF; DBMS_PIPE.UNPACK_MESSAGE(result); IF result <> 'done' THEN RAISE_APPLICATION_ERROR(-20022, 'execute_sql: done not received.'); END IF; DBMS_PIPE.UNPACK_MESSAGE(command_code); DBMS_OUTPUT.PUT_LINE ('SQL command executed. sqlcode = ' || command_code); RETURN command_code; END execute_sql; PROCEDURE stop(timeout NUMBER DEFAULT 10) IS status NUMBER; BEGIN DBMS_PIPE.PACK_MESSAGE('STOP'); status := DBMS_PIPE.SEND_MESSAGE('daemon', timeout); IF status <> 0 THEN RAISE_APPLICATION_ERROR(-20030, 'stop: error while sending. status = ' || status); END IF; END stop; END daemon;
DAEMON.PC例。次の例は、Pro*Cデーモンのコード例です。バージョン1.5.x以降のPro*Cプリコンパイラを使用して、このコードをプリコンパイルする必要があります。この例には埋込みPL/SQLコードが含まれているため、USERID
およびSQLCHECK
オプションも指定する必要があります。
注意: PL/SQLブロックでVARCHAR 出力ホスト変数を使用するには、そのブロックの入力前に長さの要素を初期化する必要があります。 |
proc iname=daemon userid=scott/tiger sqlcheck=semantics
次に、通常の方法で、Cコンパイルしてリンクします。
#include <stdio.h> #include <string.h> EXEC SQL INCLUDE SQLCA; EXEC SQL BEGIN DECLARE SECTION; char *uid = "scott/tiger"; int status; VARCHAR command[20]; VARCHAR value[2000]; VARCHAR return_name[30]; EXEC SQL END DECLARE SECTION; void connect_error() { char msg_buffer[512]; int msg_length; int buffer_size = 512; EXEC SQL WHENEVER SQLERROR CONTINUE; sqlglm(msg_buffer, &buffer_size, &msg_length); printf("Daemon error while connecting:\n"); printf("%.*s\n", msg_length, msg_buffer); printf("Daemon quitting.\n"); exit(1); } void sql_error() { char msg_buffer[512]; int msg_length; int buffer_size = 512; EXEC SQL WHENEVER SQLERROR CONTINUE; sqlglm(msg_buffer, &buffer_size, &msg_length); printf("Daemon error while executing:\n"); printf("%.*s\n", msg_length, msg_buffer); printf("Daemon continuing.\n"); } main() { command.len = 20; /*initialize length components*/ value.len = 2000; return_name.len = 30; EXEC SQL WHENEVER SQLERROR DO connect_error(); EXEC SQL CONNECT :uid; printf("Daemon connected.\n"); EXEC SQL WHENEVER SQLERROR DO sql_error(); printf("Daemon waiting...\n"); while (1) { EXEC SQL EXECUTE BEGIN :status := DBMS_PIPE.RECEIVE_MESSAGE('daemon'); IF :status = 0 THEN DBMS_PIPE.UNPACK_MESSAGE(:command); END IF; END; END-EXEC; IF (status == 0) { command.arr[command.len] = '\0'; IF (!strcmp((char *) command.arr, "STOP")) { printf("Daemon exiting.\n"); break; } ELSE IF (!strcmp((char *) command.arr, "SYSTEM")) { EXEC SQL EXECUTE BEGIN DBMS_PIPE.UNPACK_MESSAGE(:return_name); DBMS_PIPE.UNPACK_MESSAGE(:value); END; END-EXEC; value.arr[value.len] = '\0'; printf("Will execute system command '%s'\n", value.arr); status = system(value.arr); EXEC SQL EXECUTE BEGIN DBMS_PIPE.PACK_MESSAGE('done'); DBMS_PIPE.PACK_MESSAGE(:status); :status := DBMS_PIPE.SEND_MESSAGE(:return_name); END; END-EXEC; IF (status) { printf ("Daemon error while responding to system command."); printf(" status: %d\n", status); } } ELSE IF (!strcmp((char *) command.arr, "SQL")) { EXEC SQL EXECUTE BEGIN DBMS_PIPE.UNPACK_MESSAGE(:return_name); DBMS_PIPE.UNPACK_MESSAGE(:value); END; END-EXEC; value.arr[value.len] = '\0'; printf("Will execute sql command '%s'\n", value.arr); EXEC SQL WHENEVER SQLERROR CONTINUE; EXEC SQL EXECUTE IMMEDIATE :value; status = sqlca.sqlcode; EXEC SQL WHENEVER SQLERROR DO sql_error(); EXEC SQL EXECUTE BEGIN DBMS_PIPE.PACK_MESSAGE('done'); DBMS_PIPE.PACK_MESSAGE(:status); :status := DBMS_PIPE.SEND_MESSAGE(:return_name); END; END-EXEC; IF (status) { printf("Daemon error while responding to sql command."); printf(" status: %d\n", status); } } ELSE { printf ("Daemon error: invalid command '%s' received.\n", command.arr); } } ELSE { printf("Daemon error while waiting for signal."); printf(" status = %d\n", status); } } EXEC SQL COMMIT WORK RELEASE; exit(0);
ユーザー作成の3GLコードを、OCIまたはプリコンパイラ・プログラムに設定します。プログラムは、データベースに接続してPL/SQLコードを実行し、パイプから要求を読み込み、結果を計算してから、PL/SQLコードを実行して、パイプ上の結果をリクエスタに返信します。
次に、株式サービス要求の例を示します。すべてのサービス要求についてパイプに渡す引数の推奨する順序を次に示します。
protocol_version VARCHAR2 - '1', 10 bytes or less returnpipe VARCHAR2 - 30 bytes or less service VARCHAR2 - 30 bytes or less arg1 VARCHAR2/NUMBER/DATE ... argn VARCHAR2/NUMBER/DATE
結果を戻すための推奨する書式を次に示します。
success VARCHAR2 - 'SUCCESS' if OK, otherwise error message arg1 VARCHAR2/NUMBER/DATE ... argn VARCHAR2/NUMBER/DATE
OCIまたはPRO*(疑似コードで)を使用して、株価要求サーバーを次のように設定します。
<loop forever> BEGIN dbms_stock_server.get_request(:stocksymbol); END; <figure out price based on stocksymbol (probably from some radio signal), set error if can't find such a stock> BEGIN dbms_stock_server.return_price(:error, :price); END;
クライアントは次のように設定します。
BEGIN :price := stock_request('YOURCOMPANY'); end;
前述の株価要求サーバーでコールしたストアド・プロシージャdbms_stock_server
は、次のように設定します。
CREATE OR REPLACE PACKAGE dbms_stock_server IS PROCEDURE get_request(symbol OUT VARCHAR2); PROCEDURE return_price(errormsg IN VARCHAR2, price IN VARCHAR2); END; CREATE OR REPLACE PACKAGE BODY dbms_stock_server IS returnpipe VARCHAR2(30); PROCEDURE returnerror(reason VARCHAR2) IS s INTEGER; BEGIN dbms_pipe.pack_message(reason); s := dbms_pipe.send_message(returnpipe); IF s <> 0 THEN raise_application_error(-20000, 'Error:' || to_char(s) || ' sending on pipe'); END IF; END; PROCEDURE get_request(symbol OUT VARCHAR2) IS protocol_version VARCHAR2(10); s INTEGER; service VARCHAR2(30); BEGIN s := dbms_pipe.receive_message('stock_service'); IF s <> 0 THEN raise_application_error(-20000, 'Error:' || to_char(s) || 'reading pipe'); END IF; dbms_pipe.unpack_message(protocol_version); IF protocol_version <> '1' THEN raise_application_error(-20000, 'Bad protocol: ' || protocol_version); END IF; dbms_pipe.unpack_message(returnpipe); dbms_pipe.unpack_message(service); IF service != 'getprice' THEN returnerror('Service ' || service || ' not supported'); END IF; dbms_pipe.unpack_message(symbol); END; PROCEDURE return_price(errormsg in VARCHAR2, price in VARCHAR2) IS s INTEGER; BEGIN IF errormsg is NULL THEN dbms_pipe.pack_message('SUCCESS'); dbms_pipe.pack_message(price); ELSE dbms_pipe.pack_message(errormsg); END IF; s := dbms_pipe.send_message(returnpipe); IF s <> 0 THEN raise_application_error(-20000, 'Error:'||to_char(s)|| ' sending on pipe'); END IF; END; END;
クライアントがコールするプロシージャは、次のように設定します。
CREATE OR REPLACE FUNCTION stock_request (symbol VARCHAR2) RETURN VARCHAR2 IS s INTEGER; price VARCHAR2(20); errormsg VARCHAR2(512); BEGIN dbms_pipe.pack_message('1'); -- protocol version dbms_pipe.pack_message(dbms_pipe.unique_session_name); -- return pipe dbms_pipe.pack_message('getprice'); dbms_pipe.pack_message(symbol); s := dbms_pipe.send_message('stock_service'); IF s <> 0 THEN raise_application_error(-20000, 'Error:'||to_char(s)|| ' sending on pipe'); END IF; s := dbms_pipe.receive_message(dbms_pipe.unique_session_name); IF s <> 0 THEN raise_application_error(-20000, 'Error:'||to_char(s)|| ' receiving on pipe'); END IF; dbms_pipe.unpack_message(errormsg); IF errormsg <> 'SUCCESS' THEN raise_application_error(-20000, errormsg); END IF; dbms_pipe.unpack_message(price); RETURN price; END;
一般的に、株式サービス・アプリケーション・サーバーに対してのみDBMS_STOCK_SERVICE
のGRANT
EXECUTE
を実行し、このサービスを利用できるユーザーに対してのみstock_request
のGRANT
EXECUTE
を実行します。
表112-2 DBMS_PIPEパッケージのサブプログラム
サブプログラム | 説明 |
---|---|
|
パイプを作成します(プライベート・パイプの場合は必須です)。 |
|
バッファにある次の項目のデータ・タイプを戻します。 |
|
ローカル・バッファにメッセージを作成します。 |
|
名前付きパイプの内容をパージします。 |
|
名前付きパイプからローカル・バッファにメッセージをコピーします。 |
|
名前付きパイプを削除します。 |
|
ローカル・バッファの内容をパージします。 |
|
メッセージを名前付きパイプに送信します。名前付きパイプが存在しない場合は、パブリック・パイプが暗黙的に作成されます。 |
|
一意のセッション名を戻します。 |
|
バッファにある次の項目にアクセスします。 |
このファンクションは、パブリック・パイプまたはプライベート・パイプを明示的に作成します。private
フラグがTRUE
の場合、パイプ作成者がそのプライベート・パイプの所有者として割り当てられます。
明示的に作成されたパイプは、REMOVE_PIPE
をコールするか、またはインスタンスをシャットダウンすることによってのみ削除できます。
構文
DBMS_PIPE.CREATE_PIPE ( pipename IN VARCHAR2, maxpipesize IN INTEGER DEFAULT 8192, private IN BOOLEAN DEFAULT TRUE) RETURN INTEGER;
パラメータ
表112-3 CREATE_PIPEファンクションのパラメータ
パラメータ | 説明 |
---|---|
|
作成するパイプの名前。
注意: |
|
パイプの最大サイズ(バイト単位)。 パイプ上のすべてのメッセージの合計サイズは、この数を超えることはできません。この最大値を超えると、そのメッセージはブロックされます。デフォルトの パイプの |
|
デフォルトの パブリック・パイプは、 |
戻り値
表112-4 CREATE_PIPEファンクションの戻り値
戻り値 | 説明 |
---|---|
|
成功。 パイプが存在し、パイプを作成するユーザーにそのパイプの使用が認可されている場合、Oracleは0(ゼロ)を戻して成功であることを示し、パイプ内のデータはそのまま残ります。
|
|
命名競合のために失敗。 同じ名前のパイプが存在し、別のユーザーがそのパイプを作成した場合、Oracleではエラー |
このファンクションは、ローカル・メッセージ・バッファにある次の項目のタイプを判別します。
RECEIVE_MESSAGE
をコールして、ローカル・バッファにパイプ情報を設定した後、NEXT_ITEM_TYPE
をコールします。
このプロシージャは、ユーザーのメッセージをローカル・メッセージ・バッファに作成します。メッセージを送信するためには、最初にPACK_MESSAGE
を1回以上コールします。次に、SEND_MESSAGE
をコールして、ローカル・バッファにあるメッセージを名前付きパイプに送信します。
このプロシージャは、VARCHAR2
、NCHAR
、NUMBER
、DATE
、RAW
およびROWID
タイプの項目を受け入れるためにオーバーロードされます。バッファ内の各項目には、データ・バイトの他に、項目のタイプを示すための1バイト、および長さを格納するための2バイトが必要です。メッセージを終了するには、さらに1バイトが必要で、VARCHAR
以外のすべてのタイプのオーバーヘッドは4バイトです。
構文
DBMS_PIPE.PACK_MESSAGE ( item IN VARCHAR2); DBMS_PIPE.PACK_MESSAGE ( item IN NCHAR); DBMS_PIPE.PACK_MESSAGE ( item IN NUMBER); DBMS_PIPE.PACK_MESSAGE ( item IN DATE); DBMS_PIPE.PACK_MESSAGE_RAW ( item IN RAW); DBMS_PIPE.PACK_MESSAGE_ROWID ( item IN ROWID);
プラグマ
pragma restrict_references(pack_message,WNDS,RNDS); pragma restrict_references(pack_message_raw,WNDS,RNDS); pragma restrict_references(pack_message_rowid,WNDS,RNDS);
このプロシージャは、名前付きパイプの内容を空にします。
暗黙的に作成された空のパイプは、LRUアルゴリズムに従って、共有グローバル領域から削除されます。したがって、PURGE
をコールすると、暗黙的に作成したパイプに関連するメモリーを空にできます。
このファンクションは、メッセージをローカル・メッセージ・バッファにコピーします。
構文
DBMS_PIPE.RECEIVE_MESSAGE ( pipename IN VARCHAR2, timeout IN INTEGER DEFAULT maxwait) RETURN INTEGER;
使用上の注意
パイプからメッセージを受信するには、最初にRECEIVE_MESSAGE
をコールします。メッセージを受信すると、メッセージはパイプから削除されるため、メッセージは1回しか受信できません。暗黙的に作成されたパイプは、最後のレコードがそのパイプから削除された後で削除されます。
RECEIVE_MESSAGE
のコール時に指定したパイプがすでに存在しない場合、Oracleはパイプを暗黙的に作成してメッセージの受信を待ちます。メッセージが指定したタイムアウト時間内に着信しなかった場合、そのコールは戻され、パイプは削除されます。
メッセージの受信後、1つ以上のUNPACK_MESSAGE
をコールして、メッセージ内の個別の項目にアクセスする必要があります。UNPACK_MESSAGE
プロシージャは、DATE
、NUMBER
、VARCHAR2
タイプの項目をアンパックするためにオーバーロードされ、さらに、RAW
およびROWID
項目をアンパックするための2つのプロシージャがあります。アンパックするデータのタイプが不明の場合は、NEXT_ITEM_TYPE
をコールして、バッファ内にある次の項目のタイプを判別します。
このプロシージャは、PACK_MESSAGE
およびUNPACK_MESSAGE
の位置設定インジケータを0(ゼロ)にリセットします。
すべてのパイプが1つのバッファを共有しているため、新規パイプを使用する前にバッファをリセットすると効果的です。これにより、初めてメッセージをパイプに送信するとき、バッファ内に残っていた期限切れのメッセージを誤って送信することがなくなります。
このファンクションは、明示的に作成されたパイプを削除します。
SEND_MESSAGE
で暗黙的に作成されたパイプは、空になると自動的に削除されます。ただし、CREATE_PIPE
で明示的に作成されたパイプは、REMOVE_PIPE
をコールするか、またはインスタンスをシャットダウンした場合にのみ削除されます。パイプ内の未使用のレコードは、パイプが削除される前にすべて削除されます。
これは、暗黙的に作成されたパイプでPURGE
をコールするのに似ています。
このファンクションは、メッセージを名前付きパイプに送信します。
PACK_MESSAGE
へのコールで入力されたメッセージは、ローカル・メッセージ・バッファに格納されます。CREATE_PIPE
を使用するとパイプを明示的に作成でき、それ以外の場合は暗黙的に作成されます。
構文
DBMS_PIPE.SEND_MESSAGE ( pipename IN VARCHAR2, timeout IN INTEGER DEFAULT MAXWAIT, maxpipesize IN INTEGER DEFAULT 8192) RETURN INTEGER;
パラメータ
表112-15 SEND_MESSAGEファンクションのパラメータ
パラメータ | 説明 |
---|---|
|
メッセージを設定するパイプの名前。 明示的なパイプを使用している場合、この名前は、 注意: |
|
パイプにメッセージを設定する間の待機時間(秒単位)。 デフォルト値は定数 |
|
パイプの最大サイズ(バイト単位)。 パイプ上のすべてのメッセージの合計サイズは、この数を超えることはできません。この最大値を超えると、そのメッセージはブロックされます。デフォルトは8192バイトです。 パイプの
|
戻り値
表112-16 SEND_MESSAGEファンクションの戻り値
戻り値 | 説明 |
---|---|
|
成功。 パイプが存在し、パイプを作成するユーザーにそのパイプの使用が認可されている場合、Oracleは0(ゼロ)を戻して成功であることを示し、パイプ内のデータはそのまま残ります。
|
|
タイムアウト。 このプロシージャは、パイプでロックが取得できないか、またはパイプがいっぱいで使用できない理由でタイムアウトできます。暗黙的に作成されたパイプが空の場合、そのパイプは削除されます。 |
|
割込みが発生しました。 暗黙的に作成されたパイプが空の場合、そのパイプは削除されます。 |
|
権限が不十分です。 同じ名前のパイプが存在し、別のユーザーがそのパイプを作成した場合、Oracleではエラー |
このファンクションは、現在データベースに接続しているすべてのセッション間での一意の名前を受け取ります。
同じセッションからこのファンクションを複数回コールしても、常に同じ値が戻されます。このファンクションは、SEND_MESSAGE
およびRECEIVE_MESSAGE
のコールにPIPENAME
パラメータを提供するのに役立ちます。
このプロシージャは、バッファから項目を取り出します。
RECEIVE_MESSAGE
をコールして、ローカル・バッファにパイプ情報を設定した後、UNPACK_MESSAGE
をコールします。
注意: UNPACK_MESSAGE プロシージャは、VARCHAR2 、NCHAR 、NUMBER またはDATE タイプの項目を戻すためにオーバーロードされています。さらに、RAW およびROWID 項目をアンパックするための2つのプロシージャがあります。 |
構文
DBMS_PIPE.UNPACK_MESSAGE ( item OUT VARCHAR2); DBMS_PIPE.UNPACK_MESSAGE ( item OUT NCHAR); DBMS_PIPE.UNPACK_MESSAGE ( item OUT NUMBER); DBMS_PIPE.UNPACK_MESSAGE ( item OUT DATE); DBMS_PIPE.UNPACK_MESSAGE_RAW ( item OUT RAW); DBMS_PIPE.UNPACK_MESSAGE_ROWID ( item OUT ROWID);