rowset カーソルを使用した SQL ステートメントの実行

rowset カーソルを使用して、複数行 FETCH ステートメント、位置付け UPDATE ステートメント、および位置付け DELETE ステートメントを実行できます。

このタスクについて

rowset カーソルを使用するときは、以下の静的 SQL ステートメントを実行できます。
  • 列値の行セットを以下のいずれかのデータ域にコピーする、 複数行 FETCH ステートメント。
    • プログラムで宣言されるホスト変数配列
    • ストレージ・アドレスが、 取り出される列の属性とともに SQL 記述子域 (SQLDA) に入れられる、 動的割り振り配列
  • いずれかの形式の複数行 FETCH ステートメントの後に、 次のステートメントを出すことができます。
    • 現在行セットでの位置付け UPDATE ステートメント
    • 現在行セットでの位置付け DELETE ステートメント

行セット位置付け FETCH ステートメントを使用する予定の場合は、DECLARE CURSOR ステートメント の WITH ROWSET POSITIONING 文節を使用する必要があります。

次の例は、プログラムで宣言されているホスト変数配列に 20 行を検索する FETCH ステートメントを示しています。

EXEC SQL
  FETCH NEXT ROWSET FROM C1  
  FOR 20 ROWS 
  INTO :HVA-EMPNO, :HVA-LASTNAME, :HVA-SALARY :INDA-SALARY
END-EXEC.

プログラムが ROWSET キーワードを指定した FETCH ステートメントを実行すると、 カーソルは、結果表の行セットの位置に置かれます。 この行セットを、現在行セット と呼びます。 それぞれのホスト変数配列の次元は、検索行数以上でなければなりません。

従業員表から取り出す列値の配列に必要なストレージを、 動的に割り振るものとします。 以下のことを行う必要があります。

  1. SQLDA 構造、および SQLDA を参照する変数を宣言する。
  2. SQLDA、および列値に必要な配列を動的に割り振る。
  3. 取り出す列値の SQLDA 内のフィールドを設定する。
  4. カーソルを開く。
  5. 行をフェッチする。

最初に、SQLDA 構造を宣言する必要があります。 次の SQL INCLUDE ステートメントは、 標準の SQLDA 宣言を要求します。

EXEC SQL INCLUDE SQLDA;

プログラムは、SQLDA 構造を参照する変数、SQLDA 内の SQLVAR 構造、 ならびに DECIMAL 列を取り出す場合は精度および位取り用の DECLEN 構造も 宣言する必要があります。 C プログラムの場合、コードは次のようになります。

struct sqlda *sqldaptr;
struct sqlvar *varptr;
struct DECLEN {
   unsigned char precision;
   unsigned char scale; 
   };

取り出す列値の SQLDA にフィールドを設定するには、SQLDA 構造にストレージを 動的に割り振っておく必要があります。 C プログラムの場合、コードは次のようになります。

sqldaptr = (struct sqlda *) malloc (3 * 44 + 16);

SQLDA のサイズは SQLN * 44 + 16 です。 ここで、SQLN フィールドの値は出力列の数です。

FETCH ステートメントの SQLDA 構造には、フィールドを設定する必要があります。 列 EMPNO、LASTNAME、および SALARY を取り出すものとします。 これらの列に SQLDA フィールドを設定する C コードは、 次のようになります。

strcpy(sqldaptr->sqldaid,"SQLDA");
sqldaptr->sqldabc = 148;      /* number bytes of storage allocated for the SQLDA */
sqldaptr->sqln = 3;                              /* number of SQLVAR occurrences */
sqldaptr->sqld = 3;
varptr = (struct sqlvar *) (&(sqldaptr->sqlvar[0]));    /* Point to first SQLVAR */
varptr->sqltype = 452;                                      /* data type CHAR(6) */
varptr->sqllen = 6;
varptr->sqldata = (char *) hva1;
varptr->sqlind = (short *) inda1;
varptr->sqlname.length = 8;
memcpy(varptr->sqlname.data, "\x00\x00\x00\x00\x00\x01\x00\x14",varptr->sqlname.length);
varptr = (struct sqlvar *) (&(sqldaptr->sqlvar[0]) + 1); /* Point to next SQLVAR */
varptr->sqltype = 448;                                  /* data type VARCHAR(15) */
varptr->sqllen = 15;
varptr->sqldata = (char *) hva2;
varptr->sqlind = (short *) inda2;
varptr->sqlname.length = 8;
memcpy(varptr->sqlname.data, "\x00\x00\x00\x00\x00\x01\x00\x14",varptr->sqlname.length);
varptr = (struct sqlvar *) (&(sqldaptr->sqlvar[0]) + 2); /* Point to next SQLVAR */
varptr->sqltype = 485;                                 /* data type DECIMAL(9,2) */
((struct DECLEN *) &(varptr->sqllen))->precision = 9;
((struct DECLEN *) &(varptr->sqllen))->scale = 2;
varptr->sqldata = (char *) hva3;
varptr->sqlind = (short *) inda3;
varptr->sqlname.length = 8;
memcpy(varptr->sqlname.data, "\x00\x00\x00\x00\x00\x01\x00\x14",varptr->sqlname.length);

SQLDA 構造には、以下のフィールドがあります。

  • SQLDABC は、SQLDA に割り振るストレージのバイト数を示します。 ストレージには、16 バイトのヘッダーと、 各 SQLVAR フィールドの 44 バイトが含まれます。 値は、この例の場合、SQLN x 44 + 16、または 148 です。
  • SQLN は、SQLVAR オカレンスの数 (または出力列の数) です。
  • SQLD は、 FETCH ステートメントの処理時に Db2に使われる SQLDA 内の変数です。
  • 各SQLVAR オカレンスは、結果表内の列の値が戻されるホスト変数配列またはバッファーを記述します。 各 SQLVAR 内では、次のようになります。
    • SQLTYPE は列のデータ・タイプを示します。
    • SQLLEN は列の長さを示します。 データ・タイプが DECIMAL の場合、 そのフィールドには、PRECISION と SCALE の 2 つの部分が入ります。
    • SQLDATA は、列値の配列の最初のエレメントを指します。 この例の場合、プログラムは、動的変数配列 hva1、hva2、および hva3、 ならびにその標識配列 inda1、inda2、 および inda3 を割り振るものとします。
    • SQLIND は、列の標識値の配列の最初のエレメントを指します。 SQLTYPE が奇数の場合、この属性は必要です。 (SQLTYPE が奇数の場合は、列に NULL 値を使用できます。)
    • SQLNAME には、LENGTH と DATA の 2 つの部分があります。 LENGTH は 8です。 DATA フィールドの最初2 バイトは X'0000'です。 DATA フィールドのバイト 5 と 6 は、変数が配列であるか、または FOR n ROWS 値であるかを示すフラグです。 バイト 7 と 8 は、配列のディメンションを表す 2 バイトの 2 進整数です。

カーソルをオープンできるのは、 出力 SQLDA ですべてのフィールドが設定された後のみです。

EXEC SQL OPEN C1;

OPEN ステートメントの後、 プログラムは次の行セットをフェッチします。

EXEC SQL 
  FETCH NEXT ROWSET FROM C1 
  FOR 20 ROWS
  USING DESCRIPTOR :*sqldaptr; 

FETCH ステートメントの USING 文節は、検索される列を示す SQLDA を指します。

プログラムが FETCH ステートメントを実行して現在行セットを確立した後は、 次のいずれかの文節に位置付け UPDATE ステートメントを使用できます。

  • WHERE CURRENT OF を使用して、現在行セットのすべての行を変更する
  • FOR ROW n OF ROWSET を使用して、現在行セット内の行 n を変更する

WHERE CURRENT OF 文節を使用する位置付け UPDATE ステートメントの例を、 以下に示します。

EXEC SQL
  UPDATE DSN8C10.EMP 
    SET SALARY = 50000
    WHERE CURRENT OF C1
END-EXEC.

UPDATE ステートメントが実行されるとき、 カーソルは、結果表の行または行セット上になければなりません。 カーソルが行に位置付けられている場合、その行が更新されます。 カーソルが行セット上にあるときは、 その行セットのすべての行が更新されます。

FOR ROW n OF ROWSET 文節を使用する位置付け UPDATE ステートメントの例を、 以下に示します。

EXEC SQL
  UPDATE DSN8C10.EMP 
    SET SALARY = 50000
    FOR CURSOR C1 FOR ROW 5 OF ROWSET
END-EXEC.

UPDATE ステートメントが実行されるとき、 カーソルは、結果表の行セット上になければなりません。 現在行セット上の指定された行 (この例では、行 5) が 更新されます。

プログラムが FETCH ステートメントを実行して現在行セットを確立した後は、 次のいずれかの文節に位置付け DELETE ステートメントを使用できます。

  • WHERE CURRENT OF を使用して、現在行セットのすべての行を削除する
  • FOR ROW n OF ROWSET を使用して、現在行セット内の行 n を削除する

WHERE CURRENT OF 文節を使用する位置付け DELETE ステートメントの例を、 以下に示します。

EXEC SQL
  DELETE FROM DSN8C10.EMP 
    WHERE CURRENT OF C1
END-EXEC.

DELETE ステートメントが実行されるとき、 カーソルは、結果表の行または行セット上になければなりません。 カーソルが行に位置付けられている場合、その行が削除され、その結果表の次の行の前にカーソルが位置付けられます。 カーソルが行セット上にある場合は、行セットのすべての行が削除され、 カーソルは、その結果表の次の行セットの前に位置付けられます。

FOR ROW n OF ROWSET 文節を使用する位置付け DELETE ステートメントの例を、 以下に示します。

EXEC SQL
  DELETE FROM DSN8C10.EMP 
    FOR CURSOR C1 FOR ROW 5 OF ROWSET
END-EXEC.

DELETE ステートメントが実行されるとき、 カーソルは、結果表の行セット上になければなりません。 現在行セット上の指定された行が削除され、 カーソルはその行セットの位置に残ります。 削除された行 (この例では、行セットの行 5) は、 取り出しも更新もできません。