![]() ![]() ![]() ![]() |
Oracle Tuxedo システムでは、関数が失敗すると、tperrno(5) 変数を使用してプロセスに情報が提供されます。すべての ATMI 関数は、正常に処理が行われた場合、整数またはポインタを返します。エラーが発生した場合、-1
または NULL
を返し、tperrno()
にエラーの原因を示す値を設定します。サービス ルーチンを終了させるために使用する tpreturn() や tpforward() など、呼び出し側に戻らない関数の場合、成功か失敗かを確認する唯一の方法は要求元の tperrno()
変数です。
tperrordetail(3c) と tpstrerrordetail(3c) 関数を使用すると、現在のスレッドへの Oracle Tuxedo システムの最新の呼び出しで発生したエラーの詳細を取得できます。tperrordetail()
は、そのシンボリック名で表される整数値を返します。この整数値は、tpstrerrordetail()
の引数として使用され、エラー メッセージを表す文字列を指すポインタを取得します。このポインタは、userlog(3c) または fprintf()
の引数として使用できます。返されるシンボリック名については、『Oracle Tuxedo C リファレンス』の「tperrordetail(3c)」を参照してください。
tpurcode(5) は、ユーザ定義の条件だけを通知します。tpurcode
の値は、tpreturn() の rcode
引数の値に設定されます。tpreturn()
でエラーまたはトランザクション タイムアウトが発生しない限り、tpreturn()
の rval
引数の値に関係なく、tpurcode
の値が設定されます。
tperrno(5) に返されるコードは、エラーの種類を示します。次の表は、そのエラーの種類を示しています。
TPETRAN2
|
|
|
脚注 1 にあるように、tperrno(5) によって通知される 4 種類のエラーは、すべての ATMI 関数で発生するエラーです。それ以外のエラーの種類は、特定の ATMI 関数だけで発生します。以下に、一部のエラーの種類について詳しく説明します。
アボートの原因となるエラーについては、「致命的なトランザクション エラー」を参照してください。
Oracle Tuxedo のシステム エラーは、問題がアプリケーション レベルではなくシステム レベルで発生していることを示します。Oracle Tuxedo のシステム エラーが発生すると、エラーの原因を示すメッセージが中央イベント ログに書き込まれ、tperrno(5) に TPESYSTEM
が返されます。詳細については、「中央イベント ログ」を参照してください。これらのエラーは、アプリケーションではなくシステムで発生するので、エラーの修正についてはシステム管理者に問い合わせてください。
呼び出し記述子のエラーは、呼び出し記述子の数が上限値を超えている場合、または無効な値を参照している場合に発生します。非同期呼び出しや会話型呼び出しでは、未処理の呼び出し記述子の数が上限値を超えると、TPELIMIT
が返されます。操作に対して無効な呼び出し記述子の値が指定されている場合は、TPEBADDESC
が返されます。
呼び出し記述子エラーが発生するのは、非同期呼び出しまたは会話型呼び出しを行った場合だけです。同期呼び出しでは、呼び出し記述子は使用されません。非同期呼び出しでは、呼び出し記述子を使用して対応する要求に応答が対応付けられます。会話型送受信用の関数は、呼び出し記述子を使用して接続を識別します。つまり、接続を開始する呼び出しでは、呼び出し記述子を使用できることが大切です。
呼び出し記述子エラーのトラブル シューティングでは、アプリケーション レベルで特定のエラーを調べます。
システムでは、コンテキスト (または Oracle Tuxedo アプリケーションへの対応付け) ごとに未処理の呼び出し記述子 (応答) を 50 個まで使用できます。この上限値はシステムで定義されているので、アプリケーションで再定義することはできません。
会話型接続を同時に行う場合の呼び出し記述子に関する制限は、応答時の制限ほど厳しくありません。上限値は、アプリケーション管理者がコンフィグレーション ファイルに定義します。アプリケーションが実行中ではない場合、管理者はコンフィグレーション ファイルの RESOURCES
セクションの MAXCONV
パラメータを変更できます。アプリケーションが実行中の場合も、MACHINES
セクションは動的に変更できます。詳細については、『Tuxedo コマンド リファレンス』の「tmconfig、wtmconfig(1)」を参照してください。
呼び出し記述子は無効になることがあります。無効な記述子が参照されると、次の場合に、tperrno(5) にエラーが返されます。
TPNOTRAN
フラグを設定せずに送信されたトランザクション応答が取得されずに残っている場合。
会話型サービスで不明な記述子が指定されると、tpsend()、tprecv()、および tpdiscon() 関数は TPEBADDESC
を返します。
会話型接続の確立後に tpsend() と tprecv() が TPEEVENT
エラーで失敗した場合、イベントが発生します。tpsend() でデータを送信できるかどうかは、発生したイベントによって決まります。システムは、関数呼び出しに渡される revent
パラメータに TPEEVENT
を返します。行われる処理は、発生したイベントによって異なります。
会話型イベントの詳細については、「会話型通信イベント」を参照してください。
処理の結果として複製オブジェクトが生成されるような操作が試みられると、tperrno(5) に TPEMATCH
エラー コードが返されます。次の表は、TPEMATCH
エラー コードを返す関数とその原因を示しています。
これらの関数の詳細については、『Oracle Tuxedo C リファレンス』を参照してください。
一般的な通信呼び出しのエラーは、呼び出しが同期または非同期で行われたかどうかに関係なく、どのような通信呼び出しでも発生する可能性があります。tperrno(5) には、TPESVCFAIL
、TPESVCERR
、TPEBLOCK
、または TPGOTSIG
エラーが返されます。
tpcall() または tpgetrply() を呼び出した結果、通信の応答部分が失敗すると、tperrno(5) に TPESVCERR
または TPSEVCFAIL
が返されます。tpreturn() に渡された引数でエラーが判別され、この関数で実行する処理が決定されます。
引数の処理中に tpreturn() でエラーが発生すると、システムはエラーを元の要求元に返し、tperrno(5) に TPESVCERR
を設定します。受信側では、tperrno()
の値を調べてエラーの発生を確認します。システムでは、tpreturn()
関数からのデータ送信は行われず、tpgetrply() でエラーが発生した場合は、呼び出し記述子が無効なものと見なされます。
tpreturn() で TPESVCERR
エラーが発生していない場合、rval
に返された値で呼び出しが成功したか失敗したかを判断できます。アプリケーションで rval
パラメータに TPFAIL
が指定されると、システムは tperrno(5) に TPESVCFAIL
を返し、呼び出し側にデータ メッセージを送信します。rval
に TPSUCCESS
が設定されると、呼び出し側に制御が正常に戻り、tperrno()
は設定されず、呼び出し側がデータを受信します。
TPEBLOCK
および TPGOTSIG
エラー コードは、メッセージの要求側に返される場合も応答側に返される場合もあるので、すべての通信呼び出しに対して返される可能性があります。
ブロッキング状態が発生している場合に、要求を同期または非同期に送信するプロセスでブロッキング状態を無視するように flags
パラメータに TPPNOBLOCK
が設定されていると、システムは TPEBLOCK
を返します。たとえば、システムのキューがすべていっぱいになっている場合、要求が送信されるとブロッキング状態になります。
tpcall() がブロッキング状態を示していない場合は、通信の送信部分だけに影響します。要求の送信に成功すると、その呼び出しが応答を待っている間にブロッキング状態が存在したとしても、TPEBLOCK
は返されません。
flags
に TPNOBLOCK
を設定して呼び出しを行った場合、tpgetrply() が応答を待っている間にブロッキング状態が発生すると、tpgetrply()
に TPEBLOCK
が返されます。この状況は、メッセージがその時点で使用できない場合などに発生します。
TPGOTSIG
エラーは、シグナルによってシステム コールに割り込みが発生したことを示します。このような状況は、実際にはエラーではありません。通信用の関数で flags
パラメータに TPSIGRSTRT
が設定されていると、呼び出しは失敗せず、tperrno(5) に TPGOTSIG
エラー コードは返されません。
無効な引数によるエラーは、関数に渡された引数が無効であることを示しています。引数を取る ATMI 関数では、無効な引数が渡されると関数は失敗します。呼び出し側に制御が戻る関数の場合、関数は失敗して、tperrno(5) に TPEINVAL
が設定されます。tpreturn() または tpforward() の場合、要求を開始して結果を待っている tpcall() または tpgetrply() に対して、tperrno()
に TPESVCERR
が設定されます。
関数に有効な引数だけを渡すようにすると、無効な引数によるアプリケーション レベルでのエラーを修正できます。
管理要求が失敗すると、tpadmcall(3c) 関数は tperrno(5) に TPEMIB
を返します。outbuf
は更新され、エラーの原因を示す FML32 フィールドが設定されて呼び出し側に返されます。エラーの原因の詳細については、『Oracle Tuxedo のファイル形式とデータ記述方法』の「MIB(5)」と「TM_MIB(5)」を参照してください。
バッファ タイプを識別するためのデータ構造体やシステム テーブルにエントリがないと、エラーが発生します。エントリ タイプのエラーを示す TPENOENT
の意味は、そのエラーを返す関数によって異なります。次の表は、このエラーを返す関数とエラーのさまざまな原因を示しています。
オペレーティング システムのエラーは、オペレーティング システム コールが失敗したことを示します。tperrno(5) に TPEOS
が返されます。UNIX システムの場合、失敗したシステム コールを識別する整数値がグローバル変数 Uunixerr
に返されます。オペレーティング システム エラーを修正するには、システム管理者に問い合わせてください。
呼び出し側プロセスに、アプリケーションに参加するために必要なパーミッションが設定されていない場合、tpinit() 呼び出しは失敗して、tperrno(5) に TPEPERM
が返されます。パーミッションは、コンフィグレーション ファイルに設定されるもので、アプリケーションには設定されません。このエラーが発生した場合は、アプリケーション管理者に問い合わせて、必要なパーミッションがコンフィグレーション ファイルに設定されていることを確認してください。
ATMI 関数の呼び出しが間違った順序で行われた場合、または間違ったプロセスを使用して行われた場合、プロトコル エラーが発生します。たとえば、アプリケーションに参加する前に、クライアントがサーバとの通信の開始を試みると、このエラーが発生します。また、開始プロセスではなくトランザクションの参加リソースによって tpcommit() が呼び出された場合も、このエラーが発生します。
ATMI 呼び出しを正しい順序で正しく使用すると、アプリケーション レベルでプロトコル エラーを修正できます。
プロトコル エラーの原因を特定するには、次の事柄を確認してください。
プロトコル エラーでは、tperrno(5) に TPEPROTO
値が返されます。
詳細については、『Oracle Tuxedo C リファレンス』の「C 言語アプリケーション トランザクション モニタ インタフェースについて」を参照してください。
特定のキューへの登録またはキューからの取り出しに失敗した場合、tpenqueue(3c) または tpdequeue(3c) 関数は、tperrno(5) に TPEDIAGNOSTIC
を返します。処理が失敗した原因は、ctl
を介して返される診断値によって判別できます。有効な ctl
フラグについては、『Oracle Tuxedo C リファレンス』の「tpenqueue(3c)」または「tpdequeue(3c)」を参照してください。
アプリケーション ドメインに参加する Oracle Tuxedo システムのリリース間で互換性に問題がある場合、Oracle Tuxedo システムは tperrno(5) に TPERELEASE
を返します。
たとえば、tpnotify(3c) 関数を呼び出す際に、呼び出し側が対象クライアントから承認メッセージを受け取るまでブロックすることを示す TPACK
フラグが設定されている場合、対象クライアントが TPACK
承認プロトコルがサポートされていない旧バージョンの Oracle Tuxedo システムを使用していると、TPERELEASE
エラーが返されます。
リソース マネージャ エラーは、tpopen(3c) および tpclose(3c) を呼び出したときに発生し、tperrno(5) に TPERMERR
が返されます。リソース マネージャを正しくオープンできなかった場合、tpopen()
でこのエラー コードが返されます。同じように、リソース マネージャを正しくクローズできなかった場合、tpclose()
でこのエラー コードが返されます。Oracle Tuxedo システムでは、移植性を保つために、この種類のエラーでは詳細な情報は返されません。リソース マネージャ エラーの正確な内容を判断するには、リソース マネージャに問い合わせる必要があります。
Oracle Tuxedo システムでは、タイムアウト エラーがサポートされており、アプリケーションがサービス要求またはトランザクションを待つ時間に制限があります。Oracle Tuxedo システムでサポートされている設定可能なタイムアウト機構は、ブロッキング タイムアウトとトランザクション タイムアウトの 2 種類です。
ブロッキング タイムアウトは、アプリケーションがサービス要求に対する応答を待つ時間の上限値を指定します。アプリケーション管理者は、コンフィグレーション ファイルにシステムのブロッキング タイムアウトを設定します。
トランザクション タイムアウトは、トランザクション (サービス要求が行われる場合もあり) の有効期間を定義します。アプリケーションのトランザクション タイムアウトを定義するには、tpbegin() に timeout
引数を渡します。
通信呼び出しでは、ブロッキング タイムアウトまたはトランザクション タイムアウトのいずれかが返され、tpcommit() ではトランザクション タイムアウトだけが返されます。いずれの場合も、トランザクション モードのプロセスで呼び出しが失敗して TPETIME
が返された場合は、トランザクション タイムアウトが発生しています。
デフォルトでは、プロセスがトランザクション モードではない場合、ブロッキング タイムアウトが実行されます。通信呼び出しの flags
パラメータに TPNOTIME
を設定すると、フラグの設定値はブロッキング タイムアウトだけに適用されます。プロセスがトランザクション モードの場合はブロッキング タイムアウトは実行されず、TPNOTIME
フラグが設定されていても関係ありません。
プロセスがトランザクション モードではない場合に、非同期呼び出しでブロッキング タイムアウトが発生すると、ブロックされている通信呼び出しは失敗します。ただし、呼び出し記述子は有効なままであり、再度呼び出しを行う場合に使用できます。ほかの通信には影響ありません。
トランザクション タイムアウトが発生すると、非同期トランザクション応答の呼び出し記述子 (TPNOTRAN
フラグが指定されていないもの) は無効になり、参照できなくなります。
呼び出しがトランザクション モードで行われていない場合、または flags
パラメータに TPNOBLOCK
が設定されていない場合、TPETIME
は通信呼び出しでブロッキング タイムアウトが発生したことを示します。
注意 : | TPNOBLOCK フラグが設定されている場合、ブロッキング状態が存在すると呼び出しは直ちに戻るので、ブロッキング タイムアウトは発生しません。 |
タイムアウト エラーの処理の詳細については、「トランザクションについて」を参照してください。
トランザクション、および致命的なエラーと致命的ではないエラーについては、「トランザクションについて」を参照してください。
プロセスに対する要求または応答が不明なタイプのバッファで送信された場合、型付きバッファのエラーが返されます。要求データ バッファの送信先のサービスでバッファ タイプが認識されない場合、tpcall()、tpacall()、および tpconnect() 関数は TPEITYPE
を返します。
プロセスで認識されるバッファ タイプは、コンフィグレーション ファイルとプロセスにリンクされている Oracle Tuxedo システム ライブラリの両方で識別されるものです。これらのライブラリは、プロセスで認識される型付きバッファを識別するデータ構造体を定義および初期化します。プロセスごとにライブラリを作成するか、またはバッファ タイプが定義されたアプリケーション固有のファイルのコピーをアプリケーションで用意することができます。アプリケーションでは、バッファ タイプ スイッチと呼ばれるバッファ タイプ データ構造体をプロセスごとに設定できます。詳細については、『Oracle Tuxedo のファイル形式とデータ記述方法』の「tuxtypes(5)」および「typesw(5)」を参照してください。
呼び出し側で認識されないか、または使用できないバッファで応答メッセージが送信されると、tpcall()、tpgetrply()、tpdequeue(3c)、および tprecv() 関数は TPEOTYPE
を返します。呼び出し側で使用できないバッファの場合、そのバッファ タイプはタイプ スイッチに含まれています。ただし、返されたタイプは応答の受信用に割り当てられたタイプと一致せず、また呼び出し側は異なるバッファ タイプを使用することはできません。呼び出し側は、flags
に TPNOCHANGE
を設定して、このような状況を示します。その場合、厳密なタイプ チェックが行われ、違反が見つかると TPEOTYPE
が返されます。デフォルトでは、緩やかなタイプ チェックが行われます。その場合、呼び出し側で認識される限り、最初に割り当てられたタイプ以外のバッファ タイプが返されることもあります。応答の送信では、応答バッファは呼び出し側で認識できるものでなければなりません。また、厳密なタイプ チェックが指定されている場合は、それに従う必要があります。
アプリケーション内では、tpreturn() の rcode
引数を使用して、呼び出し側のプログラムにユーザ定義のエラーに関する情報を渡すことができます。また、システムは、tpurcode
の値に tpreturn()
の rcode
引数の値を設定します。tpreturn(3c) または tpurcode(5) の詳細については、『Oracle Tuxedo C リファレンス』と『Oracle Tuxedo のファイル形式とデータ記述方法』をそれぞれ参照してください。
アプリケーションのロジックは、戻り値がある呼び出しのエラー条件を調べ、エラー発生時に適切な処理を行うように設計します。特に、次を確認します。
-1
または NULL
値が返されていないかどうかを確認します。どちらの値が返されるかは、呼び出す関数によって異なります。
ATMI では、tpstrerrordetail(3c)、tpstrerror(3c)、および Fstrerror、Fstrerror32(3fml) の 3 種類の関数がサポートされており、Oracle Tuxedo システムと FML のメッセージ カタログからエラー メッセージのテキストを取得します。これらの関数は、対応するエラー メッセージを指すポインタを返します。このポインタを使用して、userlog(3c) などに、ポインタが指すテキストを送ることができます。tpstrerrordetail(3c) および tpstrerror(3c) の詳細については、『Oracle Tuxedo C リファレンス』を参照してください。Fstrerror、Fstrerror32(3fml) の詳細については、『Oracle Tuxedo FML リファレンス』を参照してください。
次のサンプル コードは、エラーの一般的な処理方法を示しています。この例では、atmicall()
関数は、一般的な ATMI 呼び出しを表しています。switch 文 (21 行目) の後のコードに注意してください。この例では、アプリケーション定義の戻りコードの解釈に tpurcode
を使用する方法が示されています。
001 #include <stdio.h>
002 #include "atmi.h"
003
004 main()
005
006 {
007 int rtnval;
008
009 if (tpinit((TPINIT *) NULL) == -1)
010error message, exit program;
011 if (tpbegin(30, 0) == -1)
012error message, tpterm, exit program;
013
014allocate any buffers,
015make atmi calls
016check return value
017
018 rtnval =atmicall()
;
019
020 if (rtnval == -1) {
021 switch(tperrno) {
022 case TPEINVAL:
023 fprintf(stderr, "Invalid arguments were given to atmicall\n");
024 fprintf(stderr, "e.g., service name was null or flags wrong\n");
025 break;
026 case ...:
027 fprintf(stderr, ".. .");
028 break;
029
030Include all error cases described in the atmicall(3) reference
031page.
032Other return codes are not possible, so there should be no
033default within the switch statement.
034
035 if (tpabort(0) == -1) {
036 char *p;
037 fprintf(stderr, "abort was attempted but failed\n");
038 p = tpstrerror(tperrno);
039 userlog("%s", p);
040 }
041 }
042 else
043 if (tpcommit(0) == -1)
044 fprintf(stderr, "REPORT program failed at commit time\n");
045
046The following code fragment shows how an application-specific
047return code can be examined
.
048 .
049 .
050 .
051 ret = tpcall("servicename", (char*)sendbuf, 0, (char **)&rcvbuf, &rcvlen, \
052 (long)0);
053 .
054 .
055 .
056 (void) fprintf(stdout, "Returned tpurcode is: %d\n", tpurcode);
057
058
059 free all buffers
060 tpterm();
061 exit(0);
062 }
tperrno(5) の値は、各問題の詳細を示し、どのレベルで問題の解決が可能かを示しています。アプリケーションで、ある処理に特定のエラー条件が定義されている場合、tpurcode
の値にも同じことが言えます。
次のサンプル コードは、tpstrerrordetail(3c) 関数を使用して、エラー発生時の詳細情報を取得する方法を示しています。
001 #include <stdio.h>
002 #include <string.h>
003 #include <atmi.h> /* BEA Tuxedo ヘッダ ファイル */
004 #define LOOP_ITER 100
005 #if defined(__STDC__) || defined(__cplusplus)
006 main(int argc, char *argv[])
007 #else
008 main(argc, argv)
009 int argc;
010 char *argv[];
011 #endif
012 {
013 char *sendbuf, *rcvbuf;
014 long sendlen, rcvlen;
015 int ret;
016 int i;
017 if(argc != 2) {
018 (void) fprintf(stderr, "Usage: simpcl string\n");
019 exit(1);
020 }
021 /* クライアント プロセスとして BEA Tuxedo システムにアタッチ */
022 if (tpinit((TPINIT *) NULL) == -1) {
023 (void) fprintf(stderr, "Tpinit failed\n");
024 exit(1);
025 }
026 sendlen = strlen(argv[1]);
027
028 /* 要求および応答用に STRING 型バッファを割り当て */
029
030 if((sendbuf = (char *) tpalloc("STRING", NULL, sendlen+1)) == NULL) {
031 (void) fprintf(stderr,"Error allocating send buffer\n");
032 tpterm();
033 exit(1);
034 }
035
036 if((rcvbuf = (char *) tpalloc("STRING", NULL, sendlen+1)) == NULL) {
037 (void) fprintf(stderr,"Error allocating receive buffer\n");
038 tpfree(sendbuf);
039 tpterm();
040 exit(1);
041 }
042
043 for( i=0; i<LOOP_ITER; i++) {
044 (void) strcpy(sendbuf, argv[1]);
045
046 /* サービス TOUPPER を要求し、応答を待機 */
047 ret = tpcall("TOUPPER", (char *)sendbuf, 0, (char **)&rcvbuf, &rcvlen, (long)0);
048
049 if(ret == -1) {
050 (void) fprintf(stderr, "Can't send request to service
TOUPPER\n");
051 (void) fprintf(stderr, "Tperrno = %d, %s\n", tperrno, tpstrerror(tperrno));
052
053 ret = tperrordetail(0);
054 if(ret == -1) {
055 (void) fprintf(stderr, "tperrodetail() failed!\n");
056 (void) fprintf(stderr, "Tperrno = %d, %s\n", tperrno, tpstrerror(tperrno));
057 }
058 else if (ret != 0) {
059 (void) fprintf( stderr, "errordetail:%s\n",
060 tpstrerrordetail( ret, 0));
061 }
062 tpfree(sendbuf);
063 tpfree(rcvbuf);
064 tpterm();
065 exit(1);
066 }
067 (void) fprintf(stdout, "Returned string is: %s\n", rcvbuf);
068 }
069
070 /* バッファを解放して BEA Tuxedo システムからデタッチ */
071 tpfree(sendbuf);
072 tpfree(rcvbuf);
073 tpterm();
074 return(0);
}
以下の節では、各種のプログラミング機能がトランザクション モードでどのように動作するかについて説明します。まず、トランザクション モードのコーディングで従うべき基本的な通信規則について説明します。
トランザクション モードで実行するコードを記述する場合は、以下の基本的な通信規則に従います。
flags
パラメータに TPNOTRAN
または TPNOREPLY
を設定します。TPNOTRAN
フラグが指定されていないもの) を取得する必要があります。TPNOTRAN
フラグを設定して、トランザクションがロールバックされた後でも通信の結果が保持されるようにします。TPEBADDESC
が返されます。TPETIME
が設定されます。flags
パラメータに TPNOREPLY
、TPNOBLOCK
、または TPNOTRAN
を設定できます。TPEBADDESC
が返されます。この規則には、コードをトランザクション モードで実行するかどうかに関係なく従います。TPNOTRAN
フラグが設定されていないもの) はすべて無効になり、以降この記述子を参照すると TPEBADDESC
が返されます。
以下の節では、トランザクションに関連するエラーについて説明します。
トランザクション エラーが発生すると、tperrno(5) に TPETRAN
が返されます。ただし、このようなエラーの意味は、そのエラーを返す関数によって異なります。次の表は、トランザクション エラーを返す関数と、考えられるエラーの原因を示しています。
致命的なトランザクション エラーが発生した場合、アプリケーションでは、開始プロセスで tpabort() を呼び出してトランザクションを明示的にアボートしなければなりません。そのため、トランザクションにとって致命的なエラーを認識することが大切です。次の 3 つの場合、トランザクションは失敗します。
TPESVCERR
が設定されます。rval
引数が TPFAIL
に設定されています。tperrno(5) に TPESVCFAIL
が設定されます。type
または subtype
が不明であるか、または呼び出し側で使用できないので、成功したか失敗したかを判断できません。tperrno(5) に TPEOTYPE
が設定されます。TPETIME
が設定されます。TPEPROTO
が設定されます。
トランザクションにとって致命的なプロトコル エラーが発生するのは、トランザクションの不正な参加リソースから tpcommit() が呼び出された場合だけです。このエラーは、アプリケーション内で開発段階に修正できます。
開始プロセスまたは参加リソースで障害が発生した後、またはトランザクションがタイムアウトになった後で、tpcommit() が呼び出されると、暗黙的なアボート エラーになります。その場合、コミットは失敗するので、トランザクションをアボートする必要があります。
通信呼び出しで TPESVCERR
、TPESVCFAIL
、TPEOTYPE
、または TPETIME
が返された場合、tpabort() を呼び出してトランザクションを明示的にアボートしなければなりません。トランザクションを明示的にアボートする前に、未処理の呼び出し記述子を待つ必要はありません。ただし、これらの記述子は、呼び出しがアボートされた後は無効と見なされるので、トランザクション終了後にこれらの記述子へのアクセスを試みると、TPEBADDESC
が返されます。
TPESVCERR
、TPESVCFAIL
、および TPEOTYPE
の場合、トランザクションがタイムアウトにならない限り、引き続き通信呼び出しを行うことができます。これらのエラーが返された場合、トランザクションは「アボートのみ」にマークされます。これ以降の処理の結果を保持するには、flags
パラメータに TPNOTRAN
を設定して通信用の関数を呼び出します。このフラグを設定すると、「アボートのみ」にマークされたトランザクションで実行された処理は、トランザクションがアボートしてもロールバックされません。
トランザクション タイムアウトが発生しても通信を続けることはできますが、次のような通信要求を行うことはできません。
そのため、非同期呼び出しを行うには、flags
パラメータに TPNOREPLY
、TPNOBLOCK
、または TPNOTRAN
を設定する必要があります。
tpcommit() 関数は、TP_COMMIT_CONTROL
の設定に応じて、TPEHAZARD
または TPEHEURISTIC
を返します。
TP_COMMIT_CONTROL
に TP_CMT_LOGGED
を設定すると、2 フェーズ コミットの第 2 フェーズの実行前にアプリケーションに制御が移ります。その場合、第 2 フェーズ中に発生したヒューリスティックな判断がアプリケーションで認識されないことがあります。
TPEHAZARD
または TPEHEURISTIC
は 1 フェーズ コミットで返すことができます。ただし、これが可能なのは、トランザクションに関与しているリソース マネージャが 1 つだけで、1 フェーズ コミットでこのリソース マネージャがヒューリスティックな判断を返すか、なんらかの障害の発生を示す場合です。
TP_COMMIT_CONTROL
に TP_CMT_COMPLETE
を設定すると、リソース マネージャがヒューリスティックな判断を通知する場合は TPEHEURISTIC
が返され、リソース マネージャがなんらかの障害を通知する場合は TPEHAZARD
が返されます。TPEHAZARD
は、コミットの第 2 フェーズ (または 1 フェーズ コミット) で参加リソースになんらかの障害が発生し、トランザクションが正常終了したかどうかがわからない状況を示します。
「トランザクション エラー」で説明したように、Oracle Tuxedo アプリケーションでは、ブロッキング タイムアウトとトランザクション タイムアウトの 2 種類のタイムアウトが発生します。以下の節では、各種のプログラミング機能へのトランザクション タイムアウトの影響について説明します。タイムアウトの詳細については、「トランザクション エラー」を参照してください。
tpcommit() を呼び出した後でタイムアウトが発生した場合、トランザクションはどのような状態になるでしょうか。トランザクションがタイムアウトになり、そのトランザクションがアボートされたことがシステムで認識されると、システムは tperrno(5) に TPEABORT
を設定して、そのような状況の発生を通知します。トランザクションの状態が不明な場合は、エラー コードに TPETIME
を設定します。
トランザクションの状態が明確ではない場合、リソース マネージャに問い合わせる必要があります。まず、トランザクションによって行われた変更が適用されたかどうかを確認します。これにより、トランザクションがコミットされたか、またはアボートされたかを判断できます。
トランザクション モードのプロセスで、flags
引数に TPNOTRAN
を設定して通信呼び出しを行うと、呼び出されたサービスは現在のトランザクションに参加できません。サービス要求の成功や失敗は、トランザクションの結果に影響しません。トランザクションは、サービスから応答が返されるのを待つ間にタイムアウトになる場合もあります。これは、そのサービスがトランザションに参加しているかどうかには関係ありません。
TPNOTRAN
フラグの使用方法の詳細については、「tpreturn() および tpforward() 関数」を参照してください。
トランザクション モードで実行中にプロセスを呼び出すと、tpreturn() および tpforward() は、トランザクションのサービス部分をそのトランザクションの完了時にコミットまたはアボートできる状態にします。同じトランザクションでサービスを何度も呼び出すことができます。システムは、トランザクションの開始プロセスによって tpcommit() または tpabort() が呼び出されない限り、トランザクションを完全にはコミットまたはアボートしません。
サービス内で行われた通信呼び出しのすべての未処理の記述子が取得されるまで、tpreturn() または tpforward() を呼び出すことはできません。rval
に TPSUCCESS
を設定して、未処理の記述子で tpreturn()
を呼び出すと、プロトコル エラーが発生し、tpgetrply() を待機中のプロセスに TPESVCERR
が返されます。そのプロセスがトランザクション モードになっている場合、呼び出し側は「アボートのみ」にマークされます。トランザクションの開始プロセスが tpcommit() を呼び出した場合も、トランザクションが暗黙的にアボートされます。rval
に TPFAIL
を設定して、未処理の記述子で tpreturn()
を呼び出すと、tpgetrply()
を待機中のプロセスに TPESVCFAIL
が返されます。トランザクションへの影響は同じです。
トランザクション モードで実行中に tpreturn() を呼び出すと、tpreturn() で発生したプロセス エラー、またはアプリケーションによって rval
に設定された値で示されるエラーにより、トランザクションの結果に影響することがあります。
tpforward() を使用すると、ある時点までは要求が正しく処理されていることを示すことができます。アプリケーション エラーが検出されない場合、システムは tpforward()
を呼び出します。アプリケーション エラーが検出された場合、システムは TPFAIL
を設定して tpreturn() を呼び出します。tpforward()
を正しく呼び出さないと、システムはその呼び出しをプロセス エラーと見なし、エラー メッセージを要求元に返します。
tpterm() 関数は、アプリケーションからクライアント コンテキストを削除します。
クライアント コンテキストがトランザクション モードになっている場合、呼び出しは失敗して、tperrno(5) に TPEPROTO
が返されます。クライアント コンテキストは、トランザクション モードでアプリケーションの一部として残ります。
呼び出しが成功すると、現在の実行スレッドはアプリケーション内に存在しなくなるため、クライアント コンテキストは、トランザクションと通信したりトランザクションに参加できなくなります。
ATMI 関数を使ってトランザクションを定義すると、Oracle Tuxedo システムによって内部呼び出しが実行され、トランザクションに参加している各リソース マネージャにグローバル トランザクション情報が渡されます。tpcommit() や tpabort() を呼び出すと、各リソース マネージャに対して内部呼び出しが行われ、呼び出し側のグローバル トランザクションのために行われていた作業がコミットまたはアボートされます。
グローバル トランザクションが開始された場合 (明示的でも暗黙的でも)、アプリケーション コードでリソース マネージャのトランザクション関数を明示的に呼び出すことはできません。このトランザクション規則に従わないと、不安定な結果が生じます。tpgetlev() 関数を使用すると、リソース マネージャのトランザクション関数を呼び出す前に、グローバル トランザクション内に既にプロセスがあるかどうかを確認できます。
リソース マネージャによっては、トランザクションの整合性レベルなど、特定のパラメータをプログラマが設定できるものがあります。その場合、リソース マネージャ間のインタフェースで使用可能なオプションを指定します。そのようなオプションは、次の 2 つの方法で使用できるようになります。
詳細については、リソース マネージャのマニュアルを参照してください。
オプションの設定方法はリソース マネージャによって異なります。たとえば、Oracle Tuxedo システムの SQL リソース マネージャの場合、set transaction
文を使用して、Oracle Tuxedo システムによって既に開始されているトランザクションに対する特定のオプション (整合性レベルとアクセス モード) が決まります。
トランザクション モードになっている呼び出し側が、現在のトランザクションに参加するために別のサービスを呼び出した場合、次のようになります。
TPNOREPLY
フラグを使用することはできません。
TPNOTRAN
フラグを設定して通信呼び出しを行い、呼び出されたときにトランザクションが自動的に開始するようにサービスが設定されている場合、呼び出し側プロセスと呼び出されたプロセスはどちらもトランザクション モードになります。ただし、この 2 つは別々のトランザクションを構成します。この状況では、次の処理が行われます。
tpreturn()
呼び出しが、トランザクションの開始プロセスの役割を果たします。例については、「AUTOTRAN が設定された tpforward( ) と tpreturn() のトランザクションでの役割」を参照してください。
TPNOTRAN
を設定して通信呼び出しを行い、呼び出されたサービスが自動的にトランザクション モードにならないように設定されている場合、tpbegin()、tpcommit()、および tpabort() を明示的に呼び出すと、サービスで複数のトランザクションを定義できます。その結果、tpreturn() が呼び出される前にトランザクションを完了できます。
tpreturn()
の役割は常に同じです。rval
に任意の値を返します。TPESVCFAIL
、TPEITYPE
/TPEOTYPE
、および TPESVCERR
の一般的な規則に従います。
Oracle Tuxedo システムで提供されるサブルーチン tpsvrinit()、tpsvrdone()、tpsvrthrinit(3c)、および tpsvrthrdone(3c) は、トランザクションで使用される場合は特定の規則に従う必要があります。
注意 : | tpsvrthrinit(3c) と tpsvrthrdone(3c) は、マルチスレッド アプリケーションだけで指定できます。tpsvrinit() と tpsvrdone() は、スレッド アプリケーションでも非スレッド アプリケーションでも指定できます。 |
Oracle Tuxedo システム サーバは、初期化時に tpsvrinit() または tpsvrthrinit(3c) を呼び出します。特に、tpsvrinit()
または tpsvrthrinit(3c) は、呼び出し側プロセスがサーバになった後、サービス要求の処理を開始する前に呼び出されます。tpsvrinit()
または tpsvrthrinit(3c) で非同期通信を実行した場合、関数が戻る前にすべての応答が取得されなければなりません。この処理が行われなかった場合、システムは保留中の応答があっても無視して、サーバを終了します。tpsvrinit()
または tpsvrthrinit(3c) でトランザクションを定義した場合、関数が戻る前にすべての非同期応答を取得して、トランザクションを終了しなければなりません。この処理が行われなかった場合、システムは未処理の応答が残っていてもトランザクションをアボートし、それらの応答をすべて無視します。その場合、サーバは正常に終了します。
Oracle Tuxedo システム サーバ用ルーチンは、サービス要求の処理が完了した後、ルーチンを終了する前に tpsvrdone() または tpsvrthrdone(3c) を呼び出します。この時点で、サーバのサービス宣言は取り消されますが、サーバ自体はアプリケーションから分離していません。tpsvrdone()
または tpsvrthrdone(3c) で通信を開始した場合、これらの関数は未処理の応答をすべて取得してから戻る必要があります。この処理が行われなかった場合、システムは保留中の応答があっても無視して、サーバを終了します。tpsvrdone()
または tpsvrthrdone(3c) 内でトランザクションを開始した場合、トランザクションはすべての応答を取得してから終了しなければなりません。この処理が行われなかった場合、システムは応答が残っていてもトランザクションをアボートし、応答を無視します。この場合もサーバは終了します。
中央イベント ログには、Oracle Tuxedo アプリケーションで発生する重要なイベントが記録されます。これらのイベントに関するメッセージは、アプリケーション クライアントとサービスが userlog(3c) 関数を介してログに出力されます。
中央イベント ログの分析は、アプリケーションで行う必要があります。userlog(3c) に記録するイベントに関しては、厳密なガイドラインを定義しておきます。ほとんど問題にならないようなメッセージを記録しないようにすると、アプリケーションのデバッグが簡単になります。
Windows 2003 プラットフォームの中央イベント ログの設定の詳細については、『Windows NT での Oracle Tuxedo システムの使用』を参照してください。
アプリケーション管理者は、コンフィグレーション ファイルに、各マシン上の userlog(3c) エラー メッセージ ファイル名の接頭辞として使用する絶対パス名を定義します。userlog(3c) 関数は、月、日、年を表す mmddyy
の形式で日付を生成し、この日付をパス名の接頭辞に付加して中央イベント ログの完全なファイル名を構成します。毎日、新しいファイルが作成されます。そのため、中央イベント ログに数日間にわたってメッセージが送信された場合、メッセージはそれぞれ異なるファイルに書き込まれます。
hhmmss
)。uname
(1) コマンドから返される名前が使用されます。
各メッセージの本文の前には、そのメッセージのカタログ名と番号が付きます。
printf
(3S) 形式の省略可能な引数。
たとえば、mach1
(uname
コマンドから返される名前) という UNIX マシン上で、セキュリティ プログラムが午後 4:22:14
に次のような呼び出しを行ったとします。
userlog("Unknown User '%s' \n", usrnm);
162214.mach1!security.23451: Unknown User 'abc'
この例では、security のプロセス ID は 23451
、変数 usrnm
の値は abc
です。
前述のメッセージが、アプリケーションではなく Oracle Tuxedo システムによって生成された場合は、次のようになります。
162214.mach1!security.23451: LIBSEC_CAT: 999: Unknown User 'abc'
この例では、メッセージのカタログ名は LIBSEC_CAT
、メッセージ番号は 999
です。
プロセスがトランザクション モードのときにメッセージが中央イベント ログに送られると、ユーザ ログ エントリのタグにはそのほかの要素が付加されます。これらの要素は、リテラル文字列の gtrid
と、それに続く 3 桁の long 型の 16 進数で構成されます。これらの整数はグローバル トランザクションをユニークに識別するもので、グローバル トランザクション識別子、つまり gtrid
と呼ばれます。この識別子は主に管理上の目的で使用されます。また、中央イベント ログでメッセージの前に付加されるタグの中に挿入されます。システムがトランザクション モードで中央イベント ログにメッセージを書き込むと、ログ エントリは次のようになります。
162214.mach1!security.23451: gtrid x2 x24e1b803 x239:
Unknown User 'abc'
イベント ログにメッセージを書き込むには、次の手順に従います。
char *
型の変数に割り当て、その変数名を呼び出しの引数として使用します。.
.
.
/* トランザクションでアクセスするデータベースをオープン */
if(tpopen() == -1) {
userlog("tpsvrinit: Cannot open database %s, tpstrerror(tperrno)");
return(-1);
}
.
.
.
この例では、tpopen(3c) が -1
を返した場合、メッセージが中央イベント ログに送られます。
userlog(3c) の文法は、UNIX システムの printf
(3S) 関数と同じです。どちらの関数の形式でも、リテラル文字列や変換仕様を指定して、可変個引数を使用できます。
userlog(3c) 文を使用して、アプリケーション ソフトウェアをデバッグできます。しかし、問題が複雑な場合は、デバッガ コマンドを使用することもあります。
以下の節では、UNIX および Windows 2003 プラットフォーム上でアプリケーションをデバッグする方法について説明します。
UNIX システムの標準デバッグ コマンドは、dbx
(1) です。このツールの詳細については、UNIX システムのリファレンス マニュアルで dbx
(1) を参照してください。-g
オプションを使用してクライアント プロセスをコンパイルすると、dbx
(1) のリファレンス ページで説明されている手順に従ってこれらのプロセスをデバッグできます。
dbx client
サーバ プログラムのデバッグは、これよりも複雑な作業です。通常、サーバは tmboot
コマンドを使用して起動します。このコマンドは、サーバを正しいマシン上で正しいオプションを使って起動します。dbx
を使用する場合は、tmboot
コマンドからではなく、サーバを直接実行する必要があります。サーバを直接実行するには、dbx
コマンドによって表示されるプロンプトの後に、r
(run
の省略形) を入力します。
Oracle Tuxedo の tmboot(1) コマンドは、サーバであらかじめ定義されている main()
に、非公開のコマンドライン オプションを渡します。サーバを直接実行するには、これらのオプションを r
サブコマンドに手動で渡す必要があります。指定する必要のあるオプションを確認するには、-n
と -d 1
オプションを指定して tmboot
を実行します。-n
オプションは、tmboot
が起動処理を行わないことを指定します。-d 1
は、レベル 1 のデバッグ文を表示することを指定します。デフォルトでは、-d 1
オプションは、すべてのプロセスに関する情報を返します。1 つのプロセスに関する情報だけが必要な場合は、必要に応じてオプションを追加して要求を指定できます。詳細については、『Tuxedo コマンド リファレンス』を参照してください。
tmboot -n -d 1
を実行すると、次の例に示すように、tmboot
からサーバの main()
に渡されるコマンドライン オプションのリストが出力されます。
exec server -g 1 -i 1 -u sfmax -U /tuxdir/appdir/ULOG -m 0 -A
必要なコマンドライン オプションを確認したら、dbx
(1) の r
サブコマンドでサーバ プログラムを直接実行できます。次は、コマンドラインの例です。
*r -g 1 -i 1 -u sfmax -U /tuxdir/appdir/ULOG -m 0 -A
コンフィグレーションの一部として既に動作中のサーバを実行する場合は、dbx
(1) は使用しません。使用した場合、サーバは正常に終了して、サーバが複製されたことを示すメッセージが中央イベント ログに書き込まれます。
Windows 2003 プラットフォームには、Microsoft Visual C++ 環境の一部としてグラフィカル デバッガが提供されています。このツールの詳細については、Microsoft Visual C++ のリファレンス マニュアルを参照してください。
Microsoft Visual C++ のデバッガを起動するには、次のように start
コマンドを入力します。
start msdev -p process_ID
注意 : | Microsoft Visual C++ 5.0 以前のデバッガを使用する場合は、次のように start コマンドを入力します。 |
注意 : | start msdev -p process_id |
デバッガを起動して自動的にプロセスに入るには、次のようにプロセス名と引数を start
コマンドラインに指定します。
start msdev filename argument
たとえば、デバッガを起動し、引数に ConvertThisString
を指定して simpcl.exe
プロセスに入るには、次のコマンドを入力します。
start msdev simpcl.exe ConvertThisString
ユーザ モード例外が発生すると、メッセージが表示されて、デフォルトのシステム デバッガを起動して、プログラム障害の発生場所、レジストリやスタックの状態を調べるように求められます。Windows 2003 環境では、ユーザ モード例外の障害発生時にはデフォルトのデバッガとして「ワトソン博士」が使用され、Win32 SDK 環境ではカーネル デバッガが使用されます。
ユーザ モード例外の障害発生時に使用される Windows 2003 システムのデフォルト デバッガを変更するには、次の手順に従います。
注意 : | Microsoft Visual C++ 5.0 以前のデバッガを使用する場合は、次のようにコマンドを入力します。 |
注意 : | msvc.exe -p %ld -e %ld |
トランザクションの整合性、メッセージの通信、およびリソースへのアクセスは、オンライン トランザクション処理 (OLTP) アプリケーションの主要な要件です。
ここでは、リソース マネージャにアクセスする SQL 文と共に動作する通信ルーチン、バッファ管理、ATMI トランザクションを示すサンプル コードを示します。ここで示す例は、Oracle Tuxedo 銀行業務アプリケーション (bankapp
) の ACCT
サーバから抜粋した CLOSE_ACCT
サービスです。
この例は、最初の SQL 文でデータベースにアクセスする前に、set transaction
文 (49 行目) を使用して、トランザクションの整合性レベルとアクセス モードを設定する方法を示しています。読み取り/書き込みの権限が指定されている場合、整合性レベルはデフォルトで高い整合性に設定されます。ACCOUNT_ID
の値に基づいて口座を解約するために、SQL クエリで引き出し額を決定します (50 ~ 58 行目)。
tpalloc() は、WITHDRAWAL
サービスへの要求メッセージ用のバッファを割り当て、ACCOUNT_ID
と引き出し額がバッファに格納されます (62 ~ 74 行目)。次に、tpcall() を介して WITHDRAWAL
サービスに要求が送信されます (79 行目)。その後、SQL の delete
文で、該当する口座を削除してデータベースを更新します (86 行目)。
すべての処理が成功すると、サービス内で割り当てられたバッファが解放され (98 行目)、サービスに送信された TPSVCINFO
データ バッファが更新されて、トランザクションが正常に終了したことが示されます (99 行目)。サービスが開始プロセスであった場合、ここでトランザクションが自動的にコミットされます。tpreturn() は、口座の解約を要求したクライアント プロセスに、TPSUCCESS
と更新後のバッファを返します。最後に、要求されたサービスが正常に終了したことが、フォームのステータス行に示されます。
各関数呼び出しの後、成功したか失敗したかが確認されます。エラーが発生した場合、サービスで割り当てられたバッファが解放され、サービスで開始されたトランザクションがアボートされ、TPSVCINFO
バッファが更新されてエラーの原因が示されます (80 ~ 83 行目)。最後に、tpreturn() が TPFAIL
を返し、更新されたバッファ内のメッセージがフォームのステータス行に表示されます。
注意 : | サービス ルーチンでグローバル トランザクションの整合性レベルを指定する場合、同じトランザクションに参加するすべてのサービス ルーチンで、同じようにレベルを定義する必要があります。 |
001 #include <stdio.h> /* UNIX */
002 #include <string.h> /* UNIX */
003 #include <fml.h> /* BEA Tuxedo システム */
004 #include <atmi.h> /* BEA Tuxedo System */
005 #include <Usysflds.h> /* BEA Tuxedo システム */
006 #include <sqlcode.h> /* BEA Tuxedo システム */
007 #include <userlog.h> /* BEA Tuxedo システム */
008 #include "bank.h" /* BANKING #defines */
009 #include "bank.flds.h" /* bankdb フィールド */
010 #include "event.flds.h" /* イベント フィールド */
011
012
013 EXEC SQL begin declare section;
014 static long account_id; /* 口座番号 */
015 static long branch_id; /* 支店番号 */
016 static float bal, tlr_bal; /* 収支 */
017 static char acct_type; /* 口座の種類 */
018 static char last_name[20], first_name[20]; /* 姓、名 */
019 static char mid_init; /* 中間名の頭文字 */
020 static char address[60]; /* 住所 */
021 static char phone[14]; /* 電話番号 */
022 static long last_acct; /* 支店で最後に開いた口座 */
023 EXEC SQL end declare section;
024 static FBFR *reqfb; /* 要求メッセージ用のフィールド化バッファ */
025 static long reqlen; /* 要求バッファの長さ */
026 static char amts[BALSTR]; /* 浮動小数点の文字列表現 */
027 code for OPEN_ACCT service
028 /*
029 * 口座を解約するためのサービス
030 */
031 void
032 #ifdef __STDC__
033 LOSE_ACCT(TPSVCINFO *transb)
034 #else
035 CLOSE_ACCT(transb)
036 TPSVCINFO *transb;
037 #endif
038 {
039 FBFR *transf; /* デコードされたメッセージのフィールド化バッファ */
040 /* TPSVCINFO データ バッファへのポインタを設定 */
041 transf = (FBFR *)transb->data;
042 /* 口座番号が妥当かどうかを確認 */
043 if (((account_id = Fvall(transf, ACCOUNT_ID, 0)) < MINACCT) ||
044 (account_id > MAXACCT)) {
045 (void)Fchg(transf, STATLIN, 0, "Invalid account number", (FLDLEN)0);
046 tpreturn(TPFAIL, 0, transb->data, 0L, 0);
047 }
048 /* トランザクション レベルを設定 */
049 EXEC SQL set transaction read write;
050 /* 削除する金額を取得 */
051 EXEC SQL declare ccur cursor for
052 select BALANCE from ACCOUNT where ACCOUNT_ID = :account_id;
053 EXEC SQL open ccur;
054 EXEC SQL fetch ccur into :bal;
055 if (SQLCODE != SQL_OK) { /* 何も見つからなかった場合 */
056 (void)Fchg(transf, STATLIN, 0, getstr("account",SQLCODE), (FLDLEN)0);
057 EXEC SQL close ccur;
058 tpreturn(TPFAIL, 0, transb->data, 0L, 0);
059 }
060 /* 最終的な引き出しを実行 */
061 /* 引出要求バッファを設定 */
062 if ((reqfb = (FBFR *)tpalloc("FML",NULL,transb->len)) == (FBFR *)NULL) {
063 (void)userlog("tpalloc failed in close_acct\n");
064 (void)Fchg(transf, STATLIN, 0,
065 "Unable to allocate request buffer", (FLDLEN)0);
066 tpreturn(TPFAIL, 0, transb->data, 0L, 0);
067 }
068 reqlen = Fsizeof(reqfb);
069 (void)Finit(reqfb,reqlen);
070 /* 要求バッファに番号を格納 */
071 (void)Fchg(reqfb,ACCOUNT_ID,0,(char *)&account_id, (FLDLEN)0);
072 /* 要求バッファに金額を格納 */
073 (void)sprintf(amts,"%.2f",bal);
074 (void)Fchg(reqfb,SAMOUNT,0,amts, (FLDLEN)0);
075 /* この引き出しの優先順位を上げる */
076 if (tpsprio(PRIORITY, 0L) == -1)
077 (void)userlog("Unable to increase priority of withdraw");
078 /* withdraw サービスで残額を削除するために tpcall を呼び出す */
079 if (tpcall("WITHDRAWAL", (char *)reqfb, 0L, (char **)&reqfb,
080 (long *)&reqlen,TPSIGRSTRT) == -1) {
081 (void)Fchg(transf, STATLIN, 0,"Cannot make withdrawal", (FLDLEN)0);
082 tpfree((char *)reqfb);
083 tpreturn(TPFAIL, 0,transb->data, 0L, 0);
084 }
085 /* 口座レコードを削除 */
086 EXEC SQL delete from ACCOUNT where current of ccur;
087 if (SQLCODE != SQL_OK) { /* 削除に失敗した場合 */
088 (void)Fchg(transf, STATLIN, 0,"Cannot close account", (FLDLEN)0);
089 EXEC SQL close ccur;
090 tpfree((char *)reqfb);
091 tpreturn(TPFAIL, 0, transb->data, 0L, 0);
092 }
093 EXEC SQL close ccur;
094 /* 処理が成功した場合の応答バッファを準備 */
095 (void)Fchg(transf, SBALANCE, 0, Fvals(reqfb,SAMOUNT,0), (FLDLEN)0);
096 (void)Fchg(transf, FORMNAM, 0, "CCLOSE", (FLDLEN)0);
097 (void)Fchg(transf, STATLIN, 0, " ", (FLDLEN)0);
098 tpfree((char *)reqfb);
099 tpreturn(TPSUCCESS, 0, transb->data, 0L, 0);
100 }
![]() ![]() ![]() |