12 マルチスレッド・アプリケーション
開発プラットフォームがスレッドをサポートしていない場合、この章は無視してもかまいません。
この章の内容は、次のとおりです。
12.1 スレッドの概要
マルチスレッド・アプリケーションでは、共有のアドレス空間で複数のスレッドが実行されます。スレッドはプロセス内で実行される軽量のサブプロセスです。コードとデータ・セグメントは共有しますが、独自のプログラム・カウンタ、マシン・レジスタおよびスタックがあります。スレッド・ローカル属性なしで作業記憶域で宣言された変数は(ローカル記憶域あるいはスレッド・ローカル記憶域とは異なり)、すべてのスレッドに共通のものになります。アプリケーション内部の複数のスレッドから変数へのアクセスを管理するため、相互排他的なメカニズムが多くの場面で必要になります。mutexは、データの整合性が保たれることを保証する同期化メカニズムです。
mutexの詳細は、マルチスレッドの説明を参照してください。マルチスレッド・アプリケーションの詳細は、スレッド・ファンクションのマニュアルを参照してください。
Pro*COBOLは、マルチスレッド・アプリケーション対応のプラットフォームで、次のものを使用したマルチスレッドOracleサーバー・アプリケーションの開発に対応しています。
-
スレッド・セーフのコードを生成するコマンドライン・オプション。
-
マルチスレッドに対応した埋込みSQL文およびディレクティブ。
-
スレッド・セーフSQLLIBおよびその他のクライアント側Oracleライブラリ。
ノート:
プラットフォームによりサポートするスレッド・パッケージが異なるため、使用しているプラットフォーム固有のOracleマニュアルを参照して、Oracleがスレッド・パッケージをサポートしているかを調べてください。
この章では、前述の機能を使用してマルチスレッドPro*COBOLアプリケーションを開発する方法を説明します。
-
マルチスレッド・アプリケーション用のランタイム・コンテキスト。
-
ランタイム・コンテキストを使用するための2つのモデル。
-
マルチスレッド・アプリケーションのユーザー・インタフェース機能。
-
Pro*COBOLでマルチスレッド・アプリケーションを作成するためのプログラミングに関する注意事項。
-
マルチスレッドPro*COBOLアプリケーションのサンプル。
12.2 Pro*COBOLのランタイム・コンテキスト
Pro*COBOLには、スレッドと接続を疎結合するためのランタイム・コンテキストの概念が導入されています。ランタイム・コンテキストには、次のリソースおよびその現在の状態が含まれます。
-
1つ以上のOracleサーバーへのゼロまたはそれ以上の接続。
-
サーバー接続に使用されるゼロまたはそれ以上のカーソル。
-
MODE、HOLD_CURSOR、RELEASE_CURSORおよびSELECT_ERRORなどのインライン・オプション。
スレッドと接続の間の疎結合をサポートしているのみでなく、Pro*COBOLではスレッドとランタイム・コンテキストを疎結合できます。Pro*COBOLを使用すると、アプリケーションでランタイム・コンテキストを処理するハンドルを定義し、そのハンドルをスレッド間で渡すことができます。
たとえば、対話形式のアプリケーションで、スレッドT1を作成し、問合せを実行して先頭の10行をアプリケーションに戻します。その後、T1は終了します。必要なユーザー入力が取得されると、別のスレッドT2が作成され(または既存のスレッドが使用され)、T1のランタイム・コンテキストがT2に渡されます。T2は同じカーソルを処理して次の10行をフェッチできます。図12-1はこの処理を示します。
12.3 ランタイム・コンテキストの使用モデル
マルチスレッド・アプリケーションでランタイム・コンテキストを使用する際に考えられる2つのモデルは次のとおりです。
-
複数のスレッドで1つのランタイム・コンテキストを共有。
-
複数のスレッドで別々のランタイム・コンテキストを使用。
いずれのモデルを使用した場合も、複数のスレッドで同時に1つのランタイム・コンテキストを共有することはできません。2つ以上のスレッドで同じランタイム・コンテキストを同時に使用すると、ランタイム・エラーが発生します。
12.3.1 複数のスレッドで1つのランタイム・コンテキストを共有
「スレッド間でのコンテキストの共有」に、マルチスレッド環境で実行されるアプリケーションを示します。1つ以上のSQL文を処理するために、様々なスレッドが1つのランタイム・コンテキストを共有します。この場合も、同時に複数のスレッドでランタイム・コンテキストを共有することはできません。「スレッド間でのコンテキストの共有」のmutexは、同時使用を防ぐ方法を示しています。
12.3.2 複数のスレッドで複数のランタイム・コンテキストを共有
図12-3は、複数のランタイム・コンテキストを使用して複数のスレッドを実行するアプリケーションを示します。この場合、各スレッドは専用のランタイム・コンテキストを使用するため、アプリケーションにはmutexは必要ありません。
12.4 マルチスレッド・アプリケーションのユーザー・インタフェース機能
Pro*COBOLには、マルチスレッド・アプリケーションに対応した次のユーザー・インタフェース機能があります。
-
LOCAL-STORAGE節およびTHREAD-LOCAL-STORAGE節にホスト変数の宣言が可能。
-
コマンドライン・オプションTHREADS=YES | NO。
-
埋込みSQL文およびディレクティブ。
-
スレッド・セーフSQLLIBパブリック・ファンクション。
12.4.1 THREADSオプション
Pro*COBOLでは、「マルチスレッド・プログラミングに関する考慮事項」に説明されたガイドラインに従ってコマンドラインにTHREADS=YESを指定すると、スレッド・セーフのコードが生成されます。Pro*COBOLでは、THREADS=YESを指定すると、すべてのSQL文がユーザー定義のランタイム・コンテキストのスコープ内で実行されます。プログラムがこの要件を満たしていないと、プリコンパイラ・エラーが戻されます。
12.4.2 ランタイム・コンテキストの埋込みSQL文およびディレクティブ
ランタイム・コンテキストおよびスレッドの定義と使用に対応した埋込みSQLおよびディレクティブは、次のとおりです。
-
EXEC SQL ENABLE THREADS END-EXEC.
-
EXEC SQL CONTEXT ALLOCATE :context_var END-EXEC.
-
EXEC SQL CONTEXT USE { :context_var | DEFAULT} END-EXEC.
-
EXEC SQL CONTEXT FREE :context_var END-EXEC.
前述のEXEC SQL文では、context_varはランタイム・コンテキストに対するハンドルで、次のようにSQL-CONTEXT型として宣言する必要があります。
01 SQL-CONTEXT context_var END-EXEC.
DEFAULTを使用すると、別のCONTEXT USE文でオーバーライドされるまで、以降のすべての埋込みSQL文にデフォルト(グローバル)ランタイム・コンテキストが使用されます。
様々なコンテキスト文の使用例は、後述の例を参照してください。
12.4.2.1 SQL-CONTEXTのホスト表の使用禁止
SQL-CONTEXTのホスト表は宣言できません。かわりに、S9(9) COMP変数のホスト表を宣言し、SQL-CONTEXTとしてサブプログラムに宣言した後に、1つずつサブプログラムに渡してください。
12.4.2.2 EXEC SQL ENABLE THREADS
この実行SQL文は、複数のスレッドをサポートするプロセスを初期化します。このSQL文は、マルチスレッド・アプリケーションを含むプログラム内の最初の実行SQL文にしてください。アプリケーションのすべてのファイルにおいて、ENABLE THREADS文は1回しか使用できません。それ以上使用した場合はエラーとなります。詳細は、「ENABLE THREADS (実行可能埋込みSQL拡張機能)」を参照してください。
12.4.2.3 EXEC SQL CONTEXT ALLOCATE
この実行SQL文は指定されたランタイム・コンテキストにメモリーを割り当てて初期化します。ランタイム・コンテキスト変数はSQL_CONTEXT型として宣言する必要があります。詳細は、「CONTEXT ALLOCATE (実行可能埋込みSQL拡張機能)」を参照してください。
12.4.2.4 EXEC SQL CONTEXT USE
EXEC SQL CONTEXT USEディレクティブは、以降の実行SQL文に指定されたランタイム・コンテキストを使用するようにプリコンパイラに指示します。ランタイム・コンテキストを指定するには、EXEC SQL CONTEXT ALLOCATE文で事前に割り当てる必要があります。
EXEC SQL CONTEXT USEディレクティブは、EXEC SQL WHENEVERディレクティブと同様に動作します。つまり、COBOLの標準スコープ・ルールに関係なく、指定されたソース・ファイルでこの文とともに動作するすべての実行SQL文に対して有効です。
詳細は、「CONTEXT USE (Oracle埋込みSQLディレクティブ)」および「CONTEXT ALLOCATE (実行可能埋込みSQL拡張機能)」を参照してください。
12.4.3 Pro*C/C++プログラムとの対話
ランタイム・コンテキストは、連絡節で定義した引数を使用して渡すことができます。マルチスレッドPro*C/C++プログラムはPro*COBOLサブプログラムを、またPro*COBOLプログラムはPro*C/C++で記述されたサブプログラムをコールできます。
12.4.4 マルチスレッド・プログラミングに関する考慮事項
Oracleでは、必ずスレッド・セーフのSQLLIBコードが生成されますが、スレッドと正常に動作するようにソース・コードを設計するのはプログラマの責任です。たとえば、使用する変数のスコープは慎重に決定してください。
また、マルチスレッドでは次のような設計上の要件を考慮してください。
-
各ランタイム・コンテキストにSQLCAを1つ含めます。
-
通常は自動変数であるSQLCAのように、スレッド・セーフ・グループ項目としてランタイム・コンテキストごとにSQLDAを宣言します。
-
スレッド・セーフ方式でホスト変数を宣言するときは、静的ホスト変数およびグローバル・ホスト変数の使用に注意してください。
-
複数のスレッドで1つのランタイム・コンテキストを同時に使用しないでください。
-
デフォルトのデータベース接続を使用するか、AT句でデータベース接続を明示的に定義します。
ランタイム・コンテキストでは、EXEC SQL UPDATEなどの実行可能埋込みSQL文は1つのみにしてください。
プリコンパイル済アプリケーションの既存の要件も適用されます。たとえば、特定のカーソルへの参照はすべて同じソース・ファイルに含まれている必要があります。
12.4.5 複数のコンテキストの例
次のコードは、複数のコンテキストを使用する方法と、コンテキスト使用文のスコープを示します。
12.4.5.1 例1
この例では、スレッドが生成されないため、プリコンパイル・オプションをTHREADS=YESに設定する必要はありません。
IDENTIFICATION DIVISION. PROGRAM-ID. MAIN. ... * declare a context area 01 CTX1 SQL-CONTEXT. 01 UID1 PIC X(11) VALUE "SCOTT/TIGER". 01 UID2 PIC X(10) VALUE "MARY/LION" PROCEDURE DIVISION. ... * allocate context area EXEC SQL CONTEXT ALLOCATE :CTX1 END-EXEC. EXEC SQL CONTEXT USE :CTX1 END-EXEC. * all statements until the next context use will use CTX1 EXEC SQL CONNECT :UID1 END-EXEC. EXEC SQL SELECT .... EXEC SQL CONTEXT USE DEFAULT END-EXEC. * all statements physically after the preceding lines will use the default context EXEC SQL CONNECT :UID2 END-EXEC. EXEC SQL INSERT ... ...
12.4.5.2 例2
次の例は、複数のコンテキストを示します。コンテキストの1つは生成されたスレッドに使用され、もう1つはメイン・プログラムに使用されます。開始したスレッド、SUBPRGM1はコンテキストCTX1を使用し、CTX1はLINKAGE SECTIONを介して渡されます。この例から、CONTEXT USE文のスコープもわかります。
ノート:
この例のプログラム・ファイルに加え、この項では以降のすべての例のメイン・プログラムを、THREADS=YESオプションを設定してプリコンパイルする必要があります。
IDENTIFICATION DIVISION. PROGRAM-ID. MAIN. ... * declare two context areas 01 CTX1 SQL-CONTEXT. 01 CTX2 SQL-CONTEXT. PROCEDURE DIVISION. * enable threading EXEC SQL ENABLE THREADS END-EXEC. * allocate context areas EXEC SQL CONTEXT ALLOCATE :CTX1 END-EXEC. EXEC SQL CONTEXT ALLOCATE :CTX2 END-EXEC. * include your code to start thread "SUBPGM1" using CTX1 here. EXEC SQL CONTEXT USE :CTX2 END-EXEC. * all statement physically after the preceding lines will use CTX2 EXEC SQL CONNECT :USERID END-EXEC. EXEC SQL INSERT ..... ...
スレッドSUBPRGM1
は別のファイルに入ります。
PROGRAM-ID. SUBPRGM1. ... 01 USERID PIC X(11) VALUE "SCOTT/TIGER". LINKAGE SECTION. 01 CTX1 SQL-CONTEXT. PROCEDURE DIVISION USING CTX1. EXEC SQL CONTEXT USE :CTX1 END-EXEC. EXEC SQL CONNECT :USERID END-EXEC. EXEC SQL SELECT ... ...
12.4.5.3 例3
次の例では複数のスレッドが使用されます。各スレッドには、それぞれ別のコンテキストを使用します。スレッドを同時実行する場合は、各スレッドに専用のコンテキストが必要になります。コンテキストは、START文のUSING CLAUSEを使用してスレッドに渡され、スレッド・サブプログラムのLINKAGE SECTIONに宣言されます。
IDENTIFICATION DIVISION. PROGRAM-ID. MAIN. ... DATA DIVISION. 01 CTX1 SQL-CONTEXT. 01 CTX2 SQL-CONTEXT. PROCEDURE DIVISION. ... EXEC SQL ENABLE THREADS END-EXEC. EXEC SQL CONTEXT ALLOCATE :CTX1 END-EXEC. EXEC SQL CONTEXT ALLOCATE :CTX2 END-EXEC. * include your code to start thread "SUBPGM" using CTX1 here. * include your code to start thread "SUBPGM" using CTX2 here. ...
スレッドSUBPGMは別のファイルに入ります。
PROGRAM-ID. SUBPGM. ... DATA DIVISION. ... 01 USERID PIC X(11) VALUE "SCOTT/TIGER". ... LINKAGE SECTION. 01 CTX SQL-CONTEXT. PROCEDURE DIVISION USING CTX. EXEC SQL CONTEXT USE :CTX END-EXEC. EXEC SQL CONNECT :USERID END-EXEC. EXEC SQL SELECT .... ...
12.4.5.4 例4
次の例では、前の例を基にしていますが、トップレベルのプログラムで接続し、コンテキストとともにその接続がスレッド・サブプログラムに渡されます。
IDENTIFICATION DIVISION. PROGRAM-ID. MAIN. ... DATA DIVISION. 01 CTX1 SQL-CONTEXT. 01 CTX2 SQL-CONTEXT. 01 USERID PIC X(11) VALUE "SCOTT/TIGER". ROCEDURE DIVISION. EXEC SQL ENABLE THREADS END-EXEC. EXEC SQL CONTEXT ALLOCATE :CTX1 END-EXEC. EXEC SQL CONTEXT ALLOCATE :CTX2 END-EXEC. EXEC SQL CONTEXT USE :CTX1 END-EXEC. EXEC SQL CONNECT :USERID END-EXEC. EXEC SQL CONTEXT USE :CTX2 END-EXEC. EXEC SQL CONNECT :USERID END-EXEC. * include your code to start thread "SUBPGM" using CTX1 here. * include your code to start thread "SUBPGM" using CTX2 here. ...
スレッドSUBPRGM
は別のファイルに入ります。
PROGRAM-ID. SUBPGM. ... LINKAGE SECTION. 01 CTX SQL-CONTEXT. PROCEDURE DIVISION USING CTX. EXEC SQL CONTEXT USE :CTX END-EXEC. EXEC SQL SELECT .... ...
12.4.5.5 例5
次の例は、1つのコンテキストを共有する複数のスレッドを示します。この場合、スレッドをシリアライズする必要があります。
IDENTIFICATION DIVISION. PROGRAM-ID. MAIN. ... DATA DIVISION. 01 CTX1 SQL-CONTEXT. PROCEDURE DIVISION. EXEC SQL ENABLE THREADS END-EXEC. EXEC SQL CONTEXT ALLOCATE :CTX1 END-EXEC. * include your code to start thread1 "SUBPGM1" using CTX1 here. * include your code to wait for thread1 here. * include your code to start thread2 "SUBPGM2" using CTX1 here. ...
2つのスレッドは別々に2つのファイルに入れられます。最初のファイルの内容は次のとおりです。
PROGRAM-ID. SUBPGM1. ... DATA DIVISION. .. 01 USERID PIC X(11) VALUE "SCOTT/TIGER". ... LINKAGE SECTION. 01 CTX SQL-CONTEXT. PROCEDURE DIVISION USING CTX. EXEC SQL CONTEXT USE :CTX END-EXEC. ... EXEC SQL CONNECT :USERID END-EXEC.
もう1つのファイルにはSUBPGM2が入ります。
PROGRAM-ID. SUBPGM2. ... DATA DIVISION. ... LINKAGE SECTION. 01 CTX SQL-CONTEXT. PROCEDURE DIVISION USING CTX. EXEC SQL CONTEXT USE :CTX END-EXEC. EXEC SELECT .... ...
12.5 マルチスレッドの例
この複数ファイルで構成されるアプリケーションは、SQLLIBランタイム・コンテキスト領域(SQL-CONTEXT)を使用して複数のスレッドに対応する1つの方法を示します。THREADS=YESを設定して再コンパイルします。
メイン・プログラム、orathrd2は、sqllibコンテキストを格納するS9(9) COMP変数の配列を宣言します。orathrd2は、次の文を通じてスレッドを使用可能にします。
EXEC SQL ENABLE THREADS END-EXEC.
次に、(oracon.pco
ファイル内の)サブプログラムoraconをコールして、スレッドを割り当てます。さらに、oraconは割り当てられたコンテキストごとに接続を確立します。
ORTHRD2は、THREAD-1またはTHREAD-2のいずれかのスレッド・エントリ・ポイントにコンテキストを渡します。THREAD-1は、1人の従業員の給与を選択して表示するのみです。THREAD-2は、その従業員の給与を選択して更新します。THREAD-2はCOMMITを発行するので、コミット後にSELECTを実行するスレッドから更新を参照できます。(ただし、更新と同時実行するスレッドでは参照できません。)更新とコミットのタイミングは不確定であるため、実行ごとに出力が異なる点に注意してください。
同時スレッドにはそれぞれ別のコンテキストが必要であることに注意してください。コンテキストは後続のスレッドに渡して使用することができますが、スレッドは同一のコンテキストを同時に使用することができません。このモデルは接続プーリングに使用することができます。接続プーリングでは、最初に最大数の接続が作成され、ユーザーの要求を実行するため、使用可能な接続がスレッドに渡されます。
現時点ではSQL-CONTEXTの配列を宣言できないため、S9(9) COMP変数の配列が使用されます。
ノート: このプログラムは、SolarisおよびMicroFocus ServerExpressコンパイラを実行するSunワークステーション用に開発されていて、ベンダー固有のディレクティブおよび機能を使用します。
マルチスレッドに対応するCOBOL文の詳細は、使用するプラットフォームのマニュアルを参照してください。
メイン・プログラムは、ファイルorathrd2.pco
にあります。
$SET REENTRANT MF IDENTIFICATION DIVISION. PROGRAM-ID. ORATHRD2. ENVIRONMENT DIVISION. DATA DIVISION. WORKING-STORAGE SECTION. 78 MAX-LOOPS VALUE 10. 01 THREAD-ID USAGE POINTER. 01 TP-1 USAGE THREAD-POINTER OCCURS MAX-LOOPS. 01 IDEN-4 PIC 9(4). 01 LOOP-COUNTER PIC 9(2) COMP-X EXTERNAL. 01 PEMPNO PIC S9(4) COMP EXTERNAL. 01 ISAL PIC S9(4) COMP VALUE ZERO. EXEC SQL INCLUDE SQLCA END-EXEC. THREAD-LOCAL-STORAGE SECTION. 01 CONTEXT-AREA PIC S9(9) COMP OCCURS MAX-LOOPS. PROCEDURE DIVISION. MAIN SECTION. PERFORM INITIALISATION PERFORM ORACLE-CONNECTIONS VARYING LOOP-COUNTER FROM 1 BY 1 UNTIL LOOP-COUNTER > MAX-LOOPS PERFORM VARYING LOOP-COUNTER FROM 1 BY 1 UNTIL LOOP-COUNTER > MAX-LOOPS PERFORM START-THREAD END-PERFORM STOP RUN. *--------------------------------------------------------------- * CHECK THAT WE ARE RUNNING UNDER A MULTI THREADED RTS. *--------------------------------------------------------------- INITIALISATION SECTION. CALL "CBL_THREAD_SELF" USING THREAD-ID ON EXCEPTION DISPLAY "NO THREAD SUPPORT IN THIS RTS" STOP RUN END-CALL IF RETURN-CODE = 1008 DISPLAY "CANNOT RUN THIS TEST ON SINGLE THREADED RTS" STOP RUN END-IF DISPLAY "MULTI-THREAD RTS" * ENABLING THREADS MUST BE DONE ONCE BEFORE ANY CONTEXT USEAGE EXEC SQL ENABLE THREADS END-EXEC. IF SQLCODE NOT = ZERO DISPLAY 'ERROR ENABLING ORACLE THREAD SUPPORT ' ' - ABORTING : ' SQLERRMC STOP RUN END-IF * SET A VALUE FOR THE EMPLOYEE NUMBER. BECAUSE THIS IS AN * EXTERNAL VARIABLE, A COPY OF ITS VALUE IS VISIBLE TO THE * OTHER MODULES IN THIS APPLICATION MOVE 7566 TO PEMPNO EXIT SECTION. *----------------------------------------------------------------- * CREATE THREADS AND START WITH EITHER THREAD-1 OR THREAD-2 *----------------------------------------------------------------- START-THREAD SECTION. IF LOOP-COUNTER = 2 OR LOOP-COUNTER = 5 START "THREAD-2 " USING CONTEXT-AREA(LOOP-COUNTER) IDENTIFIED BY TP-1(LOOP-COUNTER) STATUS IS IDEN-4 ON EXCEPTION DISPLAY "THREAD CREATE FAILED" END-START IF IDEN-4 NOT = ZERO DISPLAY "THREAD CREATE FAILED RETURNED " IDEN-4 END-IF ELSE START "THREAD-1 " USING CONTEXT-AREA(LOOP-COUNTER) IDENTIFIED BY TP-1(LOOP-COUNTER) STATUS IS IDEN-4 ON EXCEPTION DISPLAY "THREAD CREATE FAILED" END-START IF IDEN-4 NOT = ZERO DISPLAY "THREAD CREATE FAILED RETURNED " IDEN-4 END-IF END-IF. START-THREAD-END. EXIT SECTION. *----------------------------------------------------------------- * ALLOCATE CONTEXT AREAS ESTABLISH CONNECTION WITH EACH AREA. *----------------------------------------------------------------- ORACLE-CONNECTIONS SECTION. CALL "ORACON" USING CONTEXT-AREA(LOOP-COUNTER). ORACLE-CONNECTIONS-END. EXIT SECTION.
ファイルthread-1.pco
の内容は次のとおりです。
* This is Thread 1. It selects and displays the data for * the employee. The context area upon which a connection * has been established is passed to the thread through the * linkage section. In a multi-file application, you * can pass the context through the linkage section. * Precompile with THREADS=YES. * $SET REENTRANT MF IDENTIFICATION DIVISION. PROGRAM-ID. THREAD-1. ENVIRONMENT DIVISION. DATA DIVISION. WORKING-STORAGE SECTION. 01 PEMPNO PIC S9(4) COMP EXTERNAL. LOCAL-STORAGE SECTION. 01 DEMPNO PIC Z(4) VALUE ZERO. 01 PEMP-NAME1 PIC X(15) VARYING VALUE SPACES. 01 PSAL-VALUE1 PIC S9(7)V99 COMP-3 VALUE ZERO. 01 ISAL1 PIC S9(4) COMP VALUE ZERO. 01 DSAL-VALUE PIC +(7).99 VALUE ZERO. EXEC SQL INCLUDE SQLCA END-EXEC. LINKAGE SECTION. 01 CONTEXT-AREA1 SQL-CONTEXT. *--------------------------------------------------------------- * USING THE PASSED IN CONTEXT, SELECT AND DISPLAY THE * DATA FOR EMPLOYEE. *--------------------------------------------------------------- PROCEDURE DIVISION USING CONTEXT-AREA1. MAIN SECTION. EXEC SQL WHENEVER SQLERROR GOTO SELECT-ERROR END-EXEC EXEC SQL CONTEXT USE :CONTEXT-AREA1 END-EXEC EXEC SQL SELECT ENAME, SAL INTO :PEMP-NAME1, :PSAL-VALUE1:ISAL1 FROM EMP WHERE EMPNO = :PEMPNO END-EXEC IF ISAL1 < ZERO MOVE ZERO TO PSAL-VALUE1 END-IF MOVE PEMPNO TO DEMPNO MOVE PSAL-VALUE1 TO DSAL-VALUE DISPLAY "FOR EMP ", DEMPNO, " NAME ", PEMP-NAME1-ARR(1:PEMP-NAME1-LEN), " THE CURRENT SALARY IS ", DSAL-VALUE EXIT PROGRAM. *--------------------------------------------------------------- * THERE HAS BEEN AN ERROR WHEN SELECTING FROM THE EMP TABLE *--------------------------------------------------------------- SELECT-ERROR SECTION. EXEC SQL WHENEVER SQLERROR CONTINUE END-EXEC DISPLAY "HIT AN ORACLE ERROR SELECTING EMPNO 7566" DISPLAY "SQLCODE = ", SQLCODE DISPLAY "ERROR TEXT ", SQLERRMC(1:SQLERRML) GOBACK EXIT SECTION.
ファイルthread-2.pco
の内容は次のとおりです。
* This is Thread 2. The program will select, then update, * increment, and then commit the salary. It uses the passed-in * context upon which a connection has previously been established. * Precompile with THREADS=YES. * $SET REENTRANT MF IDENTIFICATION DIVISION. PROGRAM-ID. THREAD-2. ENVIRONMENT DIVISION. DATA DIVISION. WORKING-STORAGE SECTION. 01 PEMPNO PIC S9(4) COMP EXTERNAL. LOCAL-STORAGE SECTION. 01 DEMPNO PIC Z(4) VALUE ZERO. 01 PEMP-NAME2 PIC X(15) VARYING VALUE SPACES. 01 PSAL-VALUE2 PIC S9(7)V99 COMP-3 VALUE 100. 01 ISAL2 PIC S9(4) COMP VALUE ZERO. 01 DSAL-VALUE PIC +(7).99 VALUE ZERO. EXEC SQL INCLUDE SQLCA END-EXEC. LINKAGE SECTION. 01 CONTEXT-AREA2 SQL-CONTEXT. *--------------------------------------------------------------- * USING THE PASSED IN CONTEXT AREA, FIRST SELECT TO GET INITIAL * VALUES, INCREMENT THE SALARY, UPDATE AND COMMIT. *--------------------------------------------------------------- PROCEDURE DIVISION USING CONTEXT-AREA2. MAIN SECTION. EXEC SQL WHENEVER SQLERROR GOTO UPDATE-ERROR END-EXEC EXEC SQL CONTEXT USE :CONTEXT-AREA2 END-EXEC EXEC SQL SELECT ENAME, SAL INTO :PEMP-NAME2, :PSAL-VALUE2:ISAL2 FROM EMP WHERE EMPNO = :PEMPNO END-EXEC ADD 10 TO PSAL-VALUE2 EXEC SQL UPDATE EMP SET SAL = :PSAL-VALUE2 WHERE EMPNO = :PEMPNO END-EXEC MOVE PEMPNO TO DEMPNO MOVE PSAL-VALUE2 TO DSAL-VALUE DISPLAY "FOR EMP ", DEMPNO, " NAME ", PEMP-NAME2-ARR(1:PEMP-NAME2-LEN), " THE UPDATED SALARY IS ", DSAL-VALUE * THIS COMMIT IS REQUIRED, OTHERWISE THE DATABASE * WILL BLOCK SINCE THE UPDATES ARE TO THE SAME ROW EXEC SQL COMMIT WORK END-EXEC EXIT PROGRAM. *--------------------------------------------------------------- * THERE HAS BEEN AN ERROR WHEN UPDATING THE SAL IN THE EMP TABLE *--------------------------------------------------------------- UPDATE-ERROR SECTION. EXEC SQL WHENEVER SQLERROR CONTINUE END-EXEC DISPLAY "HIT AN ORACLE ERROR UPDATING EMPNO 7566" DISPLAY "SQLCODE = ", SQLCODE DISPLAY "ERROR TEXT ", SQLERRMC(1:SQLERRML) GOBACK EXIT SECTION.
ファイルoracon.pco
の内容は次のとおりです。
* This program allocates SQLLIB runtime contexts, stores * a pointer to the context in the variable which was * passed in from the main program through the linkage section, * and establishes a connection on the allocated context. * * This program is written for Merant MicroFocus COBOL and uses * vendor-specific directives and functionality. Precompile * with THREADS=YES. * $SET REENTRANT MF IDENTIFICATION DIVISION. PROGRAM-ID. ORACON. ENVIRONMENT DIVISION. DATA DIVISION. WORKING-STORAGE SECTION. 01 LOGON-STRING PIC X(40) VALUE SPACES. EXEC SQL INCLUDE SQLCA END-EXEC. LINKAGE SECTION. 01 CONTEXT SQL-CONTEXT. PROCEDURE DIVISION USING CONTEXT. MAIN SECTION. *----------------------------------------------------------------- * ALLOCATE CONTEXT AREAS ESTABLISH CONNECTION WITH EACH AREA. *----------------------------------------------------------------- ORACLE-CONNECTION SECTION. MOVE "SCOTT/TIGER" TO LOGON-STRING EXEC SQL CONTEXT ALLOCATE :CONTEXT END-EXEC IF SQLCODE NOT = ZERO DISPLAY 'ERROR ALLOCATING CONTEXT ' '- ABORTING : ' SQLERRMC GOBACK ELSE DISPLAY 'CONTEXT ALLOCATED' END-IF EXEC SQL CONTEXT USE :CONTEXT END-EXEC EXEC SQL CONNECT :LOGON-STRING END-EXEC IF SQLCODE NOT = ZERO DISPLAY 'ERROR CONNECTING SECOND THREAD TO THE DATABASE ' '- ABORT TEST : ' SQLERRMC GOBACK ELSE DISPLAY 'CONNECTION ESTABLISHED' END-IF EXIT SECTION.