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を実行します。
表103-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;
パラメータ
表103-3 CREATE_PIPEファンクションのパラメータ
| パラメータ | 説明 |
|---|---|
|
|
作成するパイプの名前。
注意: |
|
|
パイプの最大サイズ(バイト単位)。 パイプ上のすべてのメッセージの合計サイズは、この数を超えることはできません。この最大値を超えると、そのメッセージはブロックされます。デフォルトの パイプの |
|
|
デフォルトの パブリック・パイプは、 |
戻り値
表103-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;
パラメータ
表103-15 SEND_MESSAGEファンクションのパラメータ
| パラメータ | 説明 |
|---|---|
|
|
メッセージを設定するパイプの名前。 明示的なパイプを使用している場合、この名前は、 注意: |
|
|
パイプにメッセージを設定する間の待機時間(秒単位)。 デフォルト値は定数 |
|
|
パイプの最大サイズ(バイト単位)。 パイプ上のすべてのメッセージの合計サイズは、この数を超えることはできません。この最大値を超えると、そのメッセージはブロックされます。デフォルトは8192バイトです。 パイプの
|
戻り値
表103-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);