アプリケーション開発の手引き

例: LOB 式の評価の据え置き

ターゲットの宛先に LOB 式の指定を行うまで、LOB 値のバイトの移動はありません。これは、ストリング関数および演算子と共に使用される LOB 値のロケーターが、指定されるまで評価が延期される式を作成できるということを意味します。これは、LOB 式の評価の据え置き と呼ばれます。

この例では、特別な再開 (empno = '000130') が、 EMP_RESUME という再開の表の中でシークされます。 Department Information という再開のセクションは、複写および切り抜きされ、再開の最後に追加されます。そして、この新規の再開は EMP_RESUME という表に挿入されます。この表中の元の再開は、未変更のままです。

ロケーターは、元の再開から実際にバイトの移動または複写を行わずに、新規の再開をアセンブルおよび検査することを許可します。最終的な割り当て、つまり INSERT ステートメントまで、バイトの移動は行われません。これはまた、サーバーにおいてのみ行われます。

評価を据え置くと、DB2 が LOB I/O のパフォーマンスを向上させる場合があります。これは、LOB 関数最適化プログラムが LOB 式を代替式に変形させようとするために起こります。これらの代替式は同じ結果を出しますが、ディスク I/O が少なくて済みます。

要約すると、以下の場合に LOB ロケーターはプログラミング・シナリオの数に観念的に適合します。

  1. かなり大きな LOB のごく一部のみをクライアント・プログラムに移動する場合。
  2. LOB 全体がアプリケーションのメモリーに収まらない場合。
  3. プログラムに LOB 式からの一時的な LOB 値が必要であるが、その結果を保管する必要はない場合。
  4. (LOB 式の評価を据え置くことにより) パフォーマンスを重視する場合。

LOBEVAL プログラム例の作動方法

  1. ホスト変数を宣言する。 BEGIN DECLARE SECTION および END DECLARE SECTION ステートメントは、ホスト変数宣言を区切ります。ホスト変数には、SQL ステートメントで参照される際に、接頭部としてコロン (:) が付けられます。 CLOB LOCATOR ホスト変数が宣言されます。
  2. ホスト変数 LOCATOR に LOB 値を取り出す。 CURSOR および FETCH ルーチンを使用して、データベース中の LOB フィールドの場所をホスト変数のロケーターに与えます。
  3. LOCATORS を使用して LOB データを操作する。次に続く 5 つの SQL ステートメントは、 LOB フィールドに含まれている実データを移動せずに LOB データを操作します。これは、LOB LOCATORS を使用して行います。
  4. LOB データがターゲット宛先に移動する。ターゲット宛先に割り当てられた LOB の評価は、この SQL ステートメントまで延期されます。この LOB ステートメントの評価は据え置かれます。
  5. LOB LOCATORS を解放する。この例で使用されている LOB LOCATORS が解放され、ロケーターをその前の値から解放します。

CHECKERR マクロ / 関数は、プログラム外部にあるエラー検査ユーティリティーです。エラー検査ユーティリティーの所在は、ご使用のプログラム言語により異なります。

C
DB2 API を呼び出す C プログラムの場合、 utilapi.c 内の sqlInfoPrint 関数は、 utilapi.h 内の API_SQL_CHECK として再定義されます。 C 組み込み SQL プログラムの場合、 utilemb.sqc 内の sqlInfoPrint 関数は、 utilemb.h 内の EMB_SQL_CHECK として再定義されます。

COBOL
CHECKERRcheckerr.cbl. という名前の外部プログラムです。

このエラー検査ユーティリティーのソース・コードについては、 プログラム例での GET ERROR MESSAGE の使用を参照してください。

C の例: LOBEVAL.SQC

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "utilemb.h"
EXEC SQL INCLUDE SQLCA;
int main(int argc, char *argv[]) {
   EXEC SQL BEGIN DECLARE SECTION; (1)
      char userid[9];
      char passwd[19];
      sqlint32        hv_start_deptinfo;
      sqlint32        hv_start_educ;
      sqlint32        hv_return_code;
      SQL TYPE IS CLOB(5K) hv_new_section_buffer;
      SQL TYPE IS CLOB_LOCATOR hv_doc_locator1;
      SQL TYPE IS CLOB_LOCATOR hv_doc_locator2;
      SQL TYPE IS CLOB_LOCATOR hv_doc_locator3;
   EXEC SQL END DECLARE SECTION;
   printf( "Sample C program: LOBEVAL\n" );
   if (argc == 1) {
      EXEC SQL CONNECT TO sample;
	  EMB_SQL_CHECK("CONNECT TO SAMPLE");
   }
   else if (argc == 3) { 
      strcpy (userid, argv[1]);
      strcpy (passwd, argv[2]);
      EXEC SQL CONNECT TO sample USER :userid USING :passwd;
      EMB_SQL_CHECK("CONNECT TO SAMPLE");
   }
   else {
      printf ("\nUSAGE: lobeval [userid passwd]\n\n");
      return 1;
   } /* endif */
   
   /* delete any instance of "A00130" from
     previous executions of this sample */
   EXEC SQL DELETE FROM emp_resume WHERE empno = 'A00130';
   /* Use a single row select to get the document */
   EXEC SQL SELECT resume INTO :hv_doc_locator1 FROM emp_resume
      WHERE empno = '000130' AND resume_format = 'ascii';  (2)
   EMB_SQL_CHECK("SELECT");
   /* Use the POSSTR function to locate the start of
      sections "Department Information" & "Education" */
   EXEC SQL VALUES (POSSTR(:hv_doc_locator1, 'Department Information'))
      INTO :hv_start_deptinfo; (3)
   EMB_SQL_CHECK("VALUES1");
   EXEC SQL VALUES (POSSTR(:hv_doc_locator1, 'Education'))
      INTO :hv_start_educ;
   EMB_SQL_CHECK("VALUES2");
   /* Replace Department Information Section with nothing */
   EXEC SQL VALUES (SUBSTR(:hv_doc_locator1, 1, :hv_start_deptinfo -1)
      || SUBSTR (:hv_doc_locator1, :hv_start_educ))
      INTO :hv_doc_locator2;
   EMB_SQL_CHECK("VALUES3");
   /* Move Department Information Section into the hv_new_section_buffer */
   EXEC SQL VALUES (SUBSTR(:hv_doc_locator1, :hv_start_deptinfo,
      :hv_start_educ -:hv_start_deptinfo)) INTO :hv_new_section_buffer;
   EMB_SQL_CHECK("VALUES4");
   /* Append our new section to the end (assume it has been filled in)
      Effectively, this just moves the Department Information to the bottom
      of the resume. */
   EXEC SQL VALUES (:hv_doc_locator2 || :hv_new_section_buffer) INTO
      :hv_doc_locator3;
   EMB_SQL_CHECK("VALUES5");
   /* Store this resume section in the table. This is where the LOB value
      bytes really move */
   EXEC SQL INSERT INTO emp_resume VALUES ('A00130', 'ascii',
      :hv_doc_locator3);  (4)
   EMB_SQL_CHECK("INSERT");
   printf ("LOBEVAL completed\n");
   /* free the locators */  (5)
   EXEC SQL FREE LOCATOR :hv_doc_locator1, :hv_doc_locator2, : hv_doc_locator3;
   EMB_SQL_CHECK("FREE LOCATOR");
   EXEC SQL CONNECT RESET;
   EMB_SQL_CHECK("CONNECT RESET");
   return 0;
}
/* end of program : LOBEVAL.SQC */

COBOL の例: LOBEVAL.SQB

       Identification Division.
       Program-ID. "lobeval".
       Data Division.
       Working-Storage Section.
           copy "sqlenv.cbl".
           copy "sql.cbl".
           copy "sqlca.cbl".
           EXEC SQL BEGIN DECLARE SECTION END-EXEC.                     (1)
       01 userid            pic x(8).
       01 passwd.
         49 passwd-length   pic s9(4) comp-5 value 0.
         49 passwd-name     pic x(18).
       01 hv-start-deptinfo pic s9(9) comp-5.
       01 hv-start-educ     pic s9(9) comp-5.
       01 hv-return-code    pic s9(9) comp-5.
       01 hv-new-section-buffer USAGE IS SQL TYPE IS CLOB(5K).
       01 hv-doc-locator1   USAGE IS SQL TYPE IS CLOB-LOCATOR.
       01 hv-doc-locator2   USAGE IS SQL TYPE IS CLOB-LOCATOR.
       01 hv-doc-locator3   USAGE IS SQL TYPE IS CLOB-LOCATOR.
           EXEC SQL END DECLARE SECTION END-EXEC.
       77 errloc          pic x(80).
       Procedure Division.
       Main Section.
           display "Sample COBOL program: LOBEVAL".
      * Get database connection information.
           display "Enter your user id (default none): " 
                with no advancing.
           accept userid.
           if userid = spaces
             EXEC SQL CONNECT TO sample END-EXEC
           else
             display "Enter your password : " with no advancing
             accept passwd-name.
      * Passwords in a CONNECT statement must be entered in a VARCHAR
      * format with the length of the input string.
           inspect passwd-name tallying passwd-length for characters
              before initial " ".
           EXEC SQL CONNECT TO sample USER :userid USING :passwd
               END-EXEC.
           move "CONNECT TO" to errloc.
           call "checkerr" using SQLCA errloc.
      * Delete any instance of "A00130" from previous executions
           EXEC SQL DELETE FROM emp_resume
                    WHERE empno = 'A00130' END-EXEC.
      * use a single row select to get the document
           EXEC SQL SELECT resume INTO :hv-doc-locator1                 (2)
                    FROM emp_resume
                    WHERE empno = '000130'
                    AND resume_format = 'ascii' END-EXEC.
           move "SELECT" to errloc.
           call "checkerr" using SQLCA errloc.
      * use the POSSTR function to locate the start of sections
      * "Department Information" & "Education"
           EXEC SQL VALUES (POSSTR(:hv-doc-locator1,
                    'Department Information'))
                    INTO :hv-start-deptinfo END-EXEC.                   (3)
           move "VALUES1" to errloc.
           call "checkerr" using SQLCA errloc.
           EXEC SQL VALUES (POSSTR(:hv-doc-locator1,
                    'Education')) INTO :hv-start-educ END-EXEC.
           move "VALUES2" to errloc.
           call "checkerr" using SQLCA errloc.
      * replace Department Information section with nothing
           EXEC SQL VALUES (SUBSTR(:hv-doc-locator1, 1,
                    :hv-start-deptinfo - 1) ||
                    SUBSTR(:hv-doc-locator1, :hv-start-educ))
                    INTO :hv-doc-locator2 END-EXEC.
           move "VALUES3" to errloc.
           call "checkerr" using SQLCA errloc.
      * move Department Information section into hv-new-section-buffer
           EXEC SQL VALUES (SUBSTR(:hv-doc-locator1,
                    :hv-start-deptinfo,
                    :hv-start-educ - :hv-start-deptinfo))
                    INTO :hv-new-section-buffer END-EXEC.
           move "VALUES4" to errloc.
           call "checkerr" using SQLCA errloc.
      * Append the new section to the end (assume it has been filled)
      * Effectively, this just moves the Dept Info to the bottom of
      * the resume.
           EXEC SQL VALUES (:hv-doc-locator2 ||
                    :hv-new-section-buffer)
                    INTO :hv-doc-locator3 END-EXEC.
           move "VALUES5" to errloc.
           call "checkerr" using SQLCA errloc.
      * Store this resume in the table.
      * This is where the LOB value bytes really move.
           EXEC SQL INSERT INTO emp_resume                              (4)
                    VALUES ('A00130', 'ascii', :hv-doc-locator3)
                    END-EXEC.
           move "INSERT" to errloc.
           call "checkerr" using SQLCA errloc.
           display "LOBEVAL completed".
           EXEC SQL FREE LOCATOR :hv-doc-locator1, :hv-doc-locator2,    (5)
                    :hv-doc-locator3 END-EXEC.
           move "FREE LOCATOR" to errloc.
           call "checkerr" using SQLCA errloc.
           EXEC SQL CONNECT RESET END-EXEC.
           move "CONNECT RESET" to errloc.
           call "checkerr" using SQLCA errloc.
       End-Prog.
           stop run.

標識変数および LOB ロケーター

アプリケーション・プログラムの通常のホスト変数については、ホスト変数に NULL 値を指定すると、その値が NULL であると示す標識変数に負の値が指定されます。しかし LOB ロケーターの場合は、標識変数の意味が少し異なります。ロケーターのホスト変数自体は決して NULL にはならないので、負標識の変数値が、LOB ロケーターにより表される LOB 値は NULL であることを示します。 NULL 情報は、標識変数値を使用するクライアントに対してローカルに保たれます。サーバーは、有効なロケーターを持つ NULL 値をトラックしません。


[ ページのトップ | 前ページ | 次ページ | 目次 | 索引 ]