Hitachi

ノンストップデータベース HiRDB Version 10 UAP開発ガイド


4.8.1 配列を使用したFETCH機能

〈この項の構成〉

(1) 概要

FETCH文で,INTO句に配列型の埋込み変数を指定するか,又はBY句の埋込み変数に検索行数を指定すると,検索結果を一度に複数行取得できます。HiRDBクライアントからHiRDBシステムにアクセスし,大量のデータを検索する場合に有効です。ブロック転送機能とは異なり,複数行の検索結果を取得することをプログラム内で明示的に記述します。

(2) 使用方法

(a) 静的に実行する場合

FETCH文のINTO句に指定した埋込み変数と標識変数を,すべて配列型の変数にしてください。一括して検索する行数は,指定した埋込み変数の最小配列要素数となります。

(b) 動的に実行する場合

次に示す手順で実行してください。

  1. PREPARE文でSELECT文を前処理します。

  2. DESCRIBE文で前処理したSELECT文のSQL記述領域の情報を取得します。

  3. SQL記述領域のSQLDATAに,各データの受け取り領域を設定してください。また,可変長データ型の場合は,1要素のサイズをSQLSYSに設定してください。

  4. FETCH文のUSING DESCRIPTOR句にSQL記述領域を指定し,かつBY句に埋込み変数を指定してください。一括して検索する行数は,BY句に指定した埋込み変数で指定します。

(3) 注意事項

  1. 配列を使用したFETCH機能で指定するカーソルは,配列を使用したFETCH機能専用のカーソルとなります。そのカーソルを使用した場合,ブロック転送機能は無効となります。また,そのカーソルを指定して通常のFETCHを実行する場合でも,注意事項4.が適用されます。同一モジュール(プリプロセス単位)で,配列を使用したFETCH機能と通常のFETCHを使用する場合,それぞれ異なるカーソルを使用してください。

  2. 配列を使用したFETCH機能では,通常のFETCHとは異なり,検索の途中で取得する行がなくなってNOT FOUNDが発生しても,その直前の行まではデータが取得されているので注意が必要です。同様に,エラーが発生した場合も,エラーが発生した行までのデータは取得されています。

  3. 動的に実行する場合,BY句の埋込み変数に受け取り領域以上の行数を指定すると,UAP側の領域を破壊するおそれがあります。

  4. 次のどれかに該当する場合,配列を使用したFETCH機能は利用できません。

    • BLOB型の選択式が問合せ指定にある場合

    • 問合せ指定にBINARY型の選択式があり,かつBINARY型の選択式受け取り領域の1要素分の定義長が4の倍数でない場合

    • 定義長が32,001バイト以上のBINARY型の選択式を含む検索で,HiRDBサーバ,又はHiRDBクライアントライブラリのバージョンのどちらかが07-00以前の場合

(4) 使用例

配列を使用したFETCH機能のコーディング例について説明します。

例1:

FETCH文形式3を使用します。対象となる表はSCODE(CHAR(4)),SNAME(VARCHAR(17)),COL(NCHAR(1)),TANKA(INTEGER),及びZSURYO(INTEGER)で構成されているものとします。

  long sel_cnt;
  long data_cnt;
  short i;
  char work[17];
 
  /* 配列型の埋込み変数の宣言 */
  EXEC SQL BEGIN DECLARE SECTION;
      char    xscode[50][5];
      SQL  TYPE  IS  VARCHAR(17)  xsname[50];
      char    xcol[50][3];
      long    xtanka[50];
      long    xzsuryo[50];
  EXEC SQL END DECLARE SECTION;
 
  EXEC SQL
      DECLARE CR3 CURSOR FOR
         SELECT SCODE,SNAME,COL,TANKA,ZSURYO
         FROM ZAIKO;
 
  EXEC SQL WHENEVER SQLERROR GOTO FIN;
 
  EXEC SQL OPEN CR3;
 
  /*  見出し */
 
  printf("    *****  在庫表 リスト  *****\n\n");
  printf("    商品コード  商品名            色  単価      現在庫量\n");
  printf("    ----        ----------------  --  --------  --------\n");
 
  EXEC SQL WHENEVER SQLERROR GOTO OWARI;
  EXEC SQL WHENEVER NOT FOUND GOTO OWARI;
 
  /* FETCH */
  sel_cnt = 0;
  for(;;){
      EXEC SQL
          FETCH CR3 INTO :xscode,:xsname,:xcol,:xtanka,:xzsuryo;
      /* SQLERRD2にはこのカーソルで検索したトータル行数を格納 */
      data_cnt = SQLERRD2 - sel_cnt;       /* 取得した行数を求める */
      for(i=0; i < data_cnt; i++){
          memcpy(work, xsname[i].str, xsname[i].len);
          work[xsname[i].len] = ‘\0’;
          printf("    %4s      %-16s  %2s  %8d  %8d\n",
                  xscode[i], work, xcol[i], xtanka[i], xzsuryo[i]);
      }  
      sel_cnt = SQLERRD2;
  }
 
OWARI:
/*                                                                 */
/* エラー発生時,及びNOT FOUND発生時でも,データが読み込まれて    */
/* いるため,残りのデータを表示する                                */
/*                                                                 */
  if(sel_cnt  !=  SQLERRD2 ){
      data_cnt = SQLERRD2 - sel_cnt;
      for(i=0; i < data_cnt; i++){
          memcpy(work, xsname[i].str, xsname[i].len);
          work[xsname[i].len] = ‘\0’;
          printf("    %4s      %-16s  %2s  %8d  %8d\n",
                  xscode[i], work, xcol[i], xtanka[i], xzsuryo[i]);
      }
  } 
FIN:  
  EXEC SQL WHENEVER SQLERROR CONTINUE;
  EXEC SQL CLOSE CR3;
  EXEC SQL COMMIT;
例2:

FETCH文形式2を使用します。対象となる表はSCODE(CHAR(4)),SNAME(VARCHAR(17)),COL(NCHAR(1)),TANKA(INTEGER),及びZSURYO(INTEGER)で構成されているものとします。

#include <pdbsqlda.h>              /* ユーザ定義のSQLDAを        */
                                   /* 使用するためにincludeする。*/
 
  long sel_cnt;
  long data_cnt;
  short i;
  char work[17];
 
  /* ユーザ定義SQLDAの宣言 */
  PDUSRSQLDA(5)  xsqlda;
 
  /* 配列型の埋込み変数の宣言 */
  EXEC SQL BEGIN DECLARE SECTION;
      char    xscode[50][5];
      SQL  TYPE  IS  VARCHAR(17)  xsname[50];
      char    xcol[50][3];
      long    xtanka[50];
      long    xzsuryo[50];
      short    arry_num;
  EXEC SQL END DECLARE SECTION;
 
  EXEC SQL WHENEVER SQLERROR GOTO FIN;
 
  /* 検索SQLの前処理実行 */
  EXEC SQL PREPARE SEL1 FROM
         ‘SELECT * FROM ZAIKO’ ;
 
  /* 検索SQLの出力情報取得 */
  PDSQLN(xsqlda) = 5 ;      /* SQLVAR数を設定 */
  EXEC SQL DESCRIBE SEL1 INTO :xsqlda ;
 
  EXEC SQL
      DECLARE CR3 CURSOR FOR SEL1 ;
 
  EXEC SQL OPEN CR3;
 
  /*  SQLVARの設定:本来であれば,I/O領域をSQLDAから動的に確保した */
  /*  方がよいが,例題のため省略する                                 */
  /*  SQLLEN,SQLXDIM,SQLSYSはDESCRIBE時に設定される値を使用する。  */
  /* SCODE列情報設定 */
  PDSQLDATA(xsqlda, 0) = (void *)xscode ;    /* アドレス設定 */
  PDSQLIND(xsqlda, 0) = NULL ;               /* 標識変数NULLクリア */
  PDSQLCOD(xsqlda, 0) = PDSQL_CHAR ;         /* データコード設定 */
  /* SNAME列情報設定 */
  PDSQLDATA(xsqlda, 1) = (void *) xsname;    /* アドレス設定 */
  PDSQLIND(xsqlda, 1) = NULL ;               /* 標識変数NULLクリア */
  PDSQLCOD(xsqlda, 1) = PDSQL_VARCHAR ;      /* データコード設定 */
  PDSQLSYS(xsqlda, 1) = sizeof(xsname[0]) ;  /* 可変長なのでSQLSYSを*/
                                             /* 設定                 */
  /* COL列情報設定 */
  PDSQLDATA(xsqlda, 2) = (void *) xcol;      /* アドレス設定 */
  PDSQLIND(xsqlda, 2) = NULL ;               /* 標識変数NULLクリア */
  PDSQLCOD(xsqlda, 2) = PDSQL_NCHAR ;        /* データコード設定 */
  /* TANKA列情報設定 */
  PDSQLDATA(xsqlda, 3) = (void *) xtanka;    /* アドレス設定 */
  PDSQLIND(xsqlda, 3) = NULL ;               /* 標識変数NULLクリア */
  PDSQLCOD(xsqlda, 3) = PDSQL_INTEGER ;      /* データコード設定 */
  /* GSURYO列情報設定 */
  PDSQLDATA(xsqlda, 4) = (void *) xzsuryo;   /* アドレス設定 */
  PDSQLIND(xsqlda, 4) = NULL ;               /* 標識変数NULLクリア */
  PDSQLCOD(xsqlda, 4) = PDSQL_ INTEGER;      /* データコード設定 */
 
  /*  見出し */
 
  printf("    *****  在庫表 リスト  *****\n\n");
  printf("    商品コード  商品名            色  単価      現在庫量\n");
  printf("    ----        ----------------  --  --------  --------\n");
 
  EXEC SQL WHENEVER SQLERROR GOTO OWARI;
  EXEC SQL WHENEVER NOT FOUND GOTO OWARI;
 
  /* FETCH */
  sel_cnt = 0;
  for(;;){
      arry_num = 50 ;
      EXEC SQL
          FETCH CR3 USING DESCRIPTOR :xsqlda BY :arry_num ROWS ;
      /* SQLERRD2にはこのカーソルで検索したトータル行数を格納 */
      data_cnt = SQLERRD2 - sel_cnt;       /* 取得した行数を求める */
      for(i=0; i < data_cnt; i++){
          memcpy(work, xsname[i].str, xsname[i].len);
          work[xsname[i].len] = ‘\0’;
          printf("    %4s      %-16s  %2s  %8d  %8d\n",
                  xscode[i], work, xcol[i], xtanka[i], xzsuryo [i]);
      }  
      sel_cnt = SQLERRD2;
  }
 
OWARI:
/*                                                              */
/* エラー発生時,及びNOT FOUND発生時でも,データが読み込まれて */
/* いるため,残りのデータを表示する                             */
/*                                                              */
  if(sel_cnt  !=  SQLERRD2 ){
      data_cnt = SQLERRD2 - sel_cnt;
      for(i=0; i < data_cnt; i++){
          memcpy(work, xsname[i].str, xsname[i].len);
          work[xsname[i].len] = ‘\0’;
          printf("    %4s      %-16s  %2s  %8d  %8d\n",
                  xscode[i], work, xcol[i], xtanka[i], xzsuryo [i]);
      }
  } 
FIN:  
  EXEC SQL WHENEVER SQLERROR CONTINUE;
  EXEC SQL CLOSE CR3;
  EXEC SQL COMMIT;
例3:

FETCH文形式3を使用します。対象となる表はXCODE(INTEGER),及びROW_DATA(BINARY(3002))で構成されているものとします。

  long sel_cnt;
  long data_cnt;
  short i;
 
  /* 配列型の埋込み変数の宣言 */
  EXEC SQL BEGIN DECLARE SECTION;
      long    xcode[50];
      /* BINARY型の配列を使用したFETCHを行う場合は,    */
      /* 領域長を4の倍数で定義すること                   */
      SQL  TYPE  IS  BINARY(3004)  xrow_data[50];
  EXEC SQL END DECLARE SECTION;
 
  EXEC SQL
      DECLARE CR3 CURSOR FOR
         SELECT * FROM T_BINARY;
 
  EXEC SQL WHENEVER SQLERROR GOTO FIN;
 
  EXEC SQL OPEN CR3;
 
  /*  見出し */
 
  printf("    *****  バイナリデータ表  *****\n\n");
 
  EXEC SQL WHENEVER SQLERROR GOTO OWARI;
  EXEC SQL WHENEVER NOT FOUND GOTO OWARI;
 
  /* FETCH */
  sel_cnt = 0;
  for(;;){
 
      EXEC SQL
          FETCH CR3 INTO : xcode,: xrow_data;
      /* SQLERRD2にはこのカーソルで検索したトータル行数を格納 */
      data_cnt = SQLERRD2 - sel_cnt;       /* 取得した行数を求める */
      for(i=0; i < data_cnt; i++){
          printf("    CODE=%8d\n",xcode[i]);
          printf("    DATA_LENGTH=%d\n", xrow_data [i].len);
          /* BINARYデータ部の表示は例題のため行わない。   */
          /* xrow_data[i].strを各UAP固有の形式に変換すること */
      }  
      sel_cnt = SQLERRD2;
  }
 
OWARI:
/*                                                              */
/* エラー発生時,及びNOT FOUND発生時でも,データが読み込まれて */
/* いるため,残りのデータを表示する                             */
/*                                                              */
  if(sel_cnt  !=  SQLERRD2 ){
      data_cnt = SQLERRD2 - sel_cnt;
      for(i=0; i < data_cnt; i++){
          printf("    CODE=%8d\n",xcode[i]);
          printf("    DATA_LENGTH=%d\n", xrow_data [i].len);
          /* BINARYデータ部の表示は例題のため行わない。   */
          /* xrow_data[i].strを各UAP固有の形式に変換すること */
      }
  } 
FIN:  
  EXEC SQL WHENEVER SQLERROR CONTINUE;
  EXEC SQL CLOSE CR3;
  EXEC SQL COMMIT;
例4:

FETCH文形式2を使用します。対象となる表はXCODE(INTEGER),及びROW_DATA(BINARY(3002))で構成されているものとします。

#include <pdbsqlda.h>       /* ユーザ定義のSQLDAを使用するために */
                            /* includeする。                      */
 
  long sel_cnt;
  long data_cnt;
  short i;
 
  /* ユーザ定義SQLDAの宣言 */
  PDUSRSQLDA(2)  xsqlda;
 
  /* 配列型の埋込み変数の宣言 */
  EXEC SQL BEGIN DECLARE SECTION;
      long    xcode[50];
      /* BINARY型の配列を使用したFETCHを行う場合は,    */
      /* 領域長を4の倍数で定義すること                   */
      SQL  TYPE  IS  BINARY(3004)  xrow_data[50];
      short    arry_num;
  EXEC SQL END DECLARE SECTION;
 
  EXEC SQL WHENEVER SQLERROR GOTO FIN;
 
  /* 検索SQLの前処理実行 */
  EXEC SQL PREPARE SEL1 FROM
         ‘SELECT * FROM T_BINARY ;
 
  /* 検索SQLの出力情報取得 */
  PDSQLN(xsqlda) = 2 ;      /* SQLVAR数を設定 */
  EXEC SQL DESCRIBE SEL1 INTO :xsqlda ;
 
  EXEC SQL
      DECLARE CR3 CURSOR FOR SEL1 ;
 
  EXEC SQL OPEN CR3;
 
  /*  SQLVARの設定:本来であれば,I/O領域をSQLDAから動的に確保した*/
  /*  方がよいが,例題のため省略する                                */
  /*  SQLLEN,SQLXDIM,SQLSYSはDESCRIBE時に設定される値を使用する。 */
  /* XCODE列情報設定 */
  PDSQLDATA(xsqlda, 0) = (void *)xcode ;    /* アドレス設定 */
  PDSQLIND(xsqlda, 0) = NULL ;              /* 標識変数NULLクリア */
  PDSQLCOD(xsqlda, 0) = PDSQL_INTEGER ;     /* データコード設定 */
  /* R_DATA列情報設定 */
  PDSQLDATA(xsqlda, 1) = (void *) xrow_data; /* アドレス設定 */
  PDSQLIND(xsqlda, 1) = NULL ;               /* 標識変数NULLクリア */
  PDSQLCOD (xsqlda, 1) = PDSQL_BINARY ;      /* データコード設定*/
  PDSQLLEN (xsqlda, 1) = 3004 ;              /* 定義長が4の倍数で */
                                             /* ないため再設定する */
 
  /*  見出し */
 
  printf("    *****  バイナリデータ表  *****\n\n");
 
  EXEC SQL WHENEVER SQLERROR GOTO OWARI;
  EXEC SQL WHENEVER NOT FOUND GOTO OWARI;
 
  /* FETCH */
  sel_cnt = 0;
  for(;;){
      arry_num = 50 ;
      EXEC SQL
          FETCH CR3 USING DESCRIPTOR :xsqlda BY :arry_num ROWS ;
      /* SQLERRD2にはこのカーソルで検索したトータル行数を格納 */
      data_cnt = SQLERRD2 - sel_cnt;       /* 取得した行数を求める */
      for(i=0; i < data_cnt; i++){
          printf("    CODE=%8d\n",xcode[i]);
          printf("    DATA_LENGTH=%d\n", xrow_data [i].len);
          /* BINARYデータ部の表示は例題のため行わない。   */
          /* xrow_data[i].strを各UAP固有の形式に変換すること */
      }  
      sel_cnt = SQLERRD2;
  }
 
OWARI:
/*                                                              */
/* エラー発生時,及びNOT FOUND発生時でも,データが読み込まれて */
/* いるため,残りのデータを表示する                              */
/*                                                               */
  if(sel_cnt  !=  SQLERRD2 ){
      data_cnt = SQLERRD2 - sel_cnt;
      for(i=0; i < data_cnt; i++){
          printf("    CODE=%8d\n",xcode[i]);
          printf("    DATA_LENGTH=%d\n", xrow_data [i].len);
          /* BINARYデータ部の表示は例題のため行わない。   */
          /* xrow_data[i].strを各UAP固有の形式に変換すること */
      }
  } 
FIN:  
  EXEC SQL WHENEVER SQLERROR CONTINUE;
  EXEC SQL CLOSE CR3;
  EXEC SQL COMMIT;