SQLExtendedFetch() - 行の配列のフェッチ

SQLExtendedFetch() は、 SQLFetch() の機能を拡張したものであり、 バインドされた列ごとに、行セット配列を返します。 SQL_ATTR_ROWSET_SIZE ステートメント属性の値によって、SQLExtendedFetch() が 戻す行セットのサイズが決まります。

SQLExtendedFetch() の ODBC 仕様

表 1. SQLExtendedFetch() 仕様
ODBC 仕様レベル X/Open CLI CAE 仕様 ISO CLI 仕様
1.0 (「使用すべきでない」) いいえ いいえ

構文

31 ビット・アプリケーションの場合、次の構文を使用します。

SQLRETURN SQLExtendedFetch  (SQLHSTMT           hstmt,
                             SQLUSMALLINT       fFetchType,
                             SQLINTEGER             irow,
                             SQLUINTEGER  FAR   *pcrow,
                             SQLUSMALLINT FAR   *rgfRowStatus);

64 ビット・アプリケーションの場合、次の構文を使用します。

SQLRETURN SQLExtendedFetch  (SQLHSTMT           hstmt,
                             SQLUSMALLINT       fFetchType,
                             SQLLEN             irow,
                             SQLULEN      FAR   *pcrow,
                             SQLUSMALLINT FAR   *rgfRowStatus);

関数引数

次の表は、この関数のそれぞれの引数ごとに、 データ・タイプ、用途、および説明を示しています。

表 2. SQLExtendedFetch() 引数
データ・タイプ 引数 使用 説明
SQLHSTMT hstmt input 配列データを取り出すステートメント・ハンドルを指定します。
SQLUSMALLINT fFetchType input フェッチの方向とタイプを指定します。 Db2 ODBC はフェッチ方向 SQL_FETCH_NEXT (前方スクロール・カーソル方向) のみをサポートします。 常に、次のデータ配列 (行セット) が取り出されます。
SQLINTEGER (31ビット) または SQLLEN (64ビット) 1 irow input 将来の利用のために予約済み。 この引数には、任意の整数を使用します。
SQLUINTEGER *(31ビット) または SQLULEN * (64ビット )2 pcrow 出力 実際にフェッチされた行数を戻します。 処理中にエラーが起こると、引数 pcrow は、エラーが発生した行の 前の行 (行セット内) の順序を表す位置を指します。 最初の行を取り出す際にエラーが起こった場合は、引数 pcrow は値 0 を指します。
SQLUSMALLINT * rgfRowStatus 出力 状況値の配列を戻します。 このエレメント数は、行セットの行数 (SQL_ROWSET_SIZE 属性で定義) と等しくなければなりません。 フェッチされたそれぞれの行ごとに、状況値が戻されます。
  • SQL_ROW_SUCCESS

フェッチされた行数が状況配列のエレメント数より少ない (すなわち、行セットのサイズより小さい) 場合、残りの状況エレメントは SQL_ROW_NOROW に設定されます。

Db2 ODBC は、フェッチの開始以降に行が更新または削除されたかどうかを検出できません。 このため、以下の ODBC 定義の状況値は報告されません。
  • SQL_ROW_DELETED
  • SQL_ROW_UPDATED
注:
  1. 64 ビット・アプリケーションの場合、以前のバージョンの Db2 で使用されていたデータ・タイプ SQLINTEGER は、引き続き有効です。 ただし、アプリケーションのポータビリティーを最大限に引き出すために、SQLLEN の使用をお勧めします。
  2. 64 ビット・アプリケーションの場合、以前のバージョンの Db2 で使用されていたデータ・タイプ SQLUINTEGER は、引き続き有効です。 ただし、アプリケーションのポータビリティーを最大限に引き出すために、SQLULEN の使用をお勧めします。

使用法

SQLExtendedFetch() は、複数の行を 1 セットにして配列フェッチを行います。 アプリケーションは、SQL_ROWSET_SIZE 属性を用いて SQLSetStmtAttr() を呼び出すことによって、配列のサイズを指定します。

結果を取り出す際、SQLExtendedFetch()SQLFetch() を一緒に使用することはできません。

最初に SQLExtendedFetch() を呼び出す前に、カーソルは最初の行の前に位置付けられます。 SQLExtendedFetch() の呼び出し後、取り出されたばかりの行セット内の最後の行エレメントに対応する、結果セット内にある行にカーソルが位置付けられます。

データ行を一度に 1 行ずつフェッチするには、SQLExtendedFetch() ではなく SQLFetch() を呼び出す 必要があります。

rgfRowStatus 配列出力バッファーのエレメント数は、行セット内の 行数 (SQL_ROWSET_SIZE ステートメント属性で定義) と等しくする必要があります。 フェッチされた行数が状況配列内のエレメント数より少ない場合、 残りの状況エレメントが設定されて SQL_ROW_NOROW になっています。

SQLBindCol() 関数を使用してバインドされた結果セット内の任意のカラムについて、 Db2 ODBC は必要に応じてバインドされたカラムのデータを変換し、それらのカラムにバインドされた場所に保存します。 結果セットは、 列方向または行方向にバインドすることができます。

列方向のバインド: 結果セットを列方向にバインドするには、アプリケーションで SQL_BIND_TYPE ステートメント属性 に SQL_BIND_BY_COLUMN を指定します。 (これはデフォルト値です。) その後、アプリケーションは SQLBindCol() 関数を呼び出します。 LOB 列値をファイルにバインドするために、アプリケーションは SQLBindFileToCol() 関数を呼び出すことができます。

アプリケーションが SQLExtendedFetch() を呼び出すと、 バッファーの先頭に最初の行のデータが保管されます。 後続の各データ行は、 cbValueMax 引数で指定したバイト数のオフセットで保存されます。 SQLBindCol() 電話。 ただし、関連する C バッファー・タイプが固定幅 (SQL_C_LONG など) の場合は、 直前の行のデータからその固定長に対応した相対位置に保管されます。

バインドされた各列について、各要素に返すことができるバイト数は、 pcbValue 引数が持つ配列バッファに格納されます。 SQLBindCol() 指定します。 バインドされた列の最初の行に対応して戻すのに使用可能なバイト数は、バッファーの先頭に保管されます。 後続の各行に対応して戻すのに使用可能なバイト数は、以下に示す C 関数が戻す値に等しい 相対位置に保管されます。
sizeof(SQLINTEGER)
特定の行の列のデータがnullの場合、 pcbValue 引数の配列内の関連要素は SQLBindCol() 指す先は SQL_NULL_DATA に設定されます。

行方向のバインド: アプリケーションはまず最初に、SQL_BIND_TYPE 属性を 指定して SQLSetStmtAttr() を呼び出す必要があります。この場合、その引数 vParam には、 取り出されたデータの単一行と、各列のデータ値ごとの関連データ長を保持可能な構造サイズ に設定します。

各バインドされた列について、データの最初の行は rgbValue 引数で指定されたアドレスに格納されます。 SQLBindCol()。 後続の各データ行は、 vParam 引数で指定したバイト数に等しいオフセットで区切られます。 SQLSetStmtAttr() 前の行のデータから。

各バインドされた列について、最初の行に返すことができるバイト数は、 pcbValue 引数で指定されたアドレスに格納されます。 SQLBindCol()。 後続の各値は、 vParam 引数で指定したバイト数に等しいオフセットで区切られます。 SQLBindCol()

エラー処理: SQLExtendedFetch() は SQLFetch() と同じ方法で以下の例外を伴ってエラーを戻します。
  • 行セット内の特別な行に適用する警告が起きた場合、SQLExtendedFetch() は、行状況配列の対応する項目を SQL_ROW_SUCCESS_WITH_INFO ではなく、SQL_ROW_SUCCESS に設定します。
  • 行セット内のすべての行にエラーが発生した場合、SQLExtendedFetch() は、SQL_ERROR ではなく SQL_SUCCESS_WITH_INFO を戻します。
  • 個々の行に適用する状況レコードの各グループで、SQLExtendedFetch() によって戻される最初の状況レコードに SQLSTATE 01S01 (行内のエラー) が含まれます。 SQLExtendedFetch() が追加の SQLSTATE を戻せない場合、SQLSTATE 01S01 のみが戻されます。

エンコード方式の処理: 初期化ファイルのCURRENTAPPENSCHキーワードと fCType 引数 SQLBindCol() または SQLGetData() 結果セット内の文字またはグラフィック データのエンコード スキームを決定します。

戻りコード

SQLExtendedFetch() は、呼び出された後、次のいずれかの値を戻します。
  • SQL_SUCCESS
  • SQL_SUCCESS_WITH_INFO
  • SQL_ERROR
  • SQL_INVALID_HANDLE
  • SQL_NO_DATA_FOUND

診断

次の表は、この関数が生成する各 SQLSTATE 値ごとに、 その記述と説明を一覧で記載してあります。

表 3. SQLExtendedFetch() SQLSTATE
SQLSTATE 説明 説明
01 0 04 データが切り捨てられました。 1つ以上のカラムに対して返されるデータは切り捨てられます。(SQLExtendedFetch() は、このSQLSTATEに対してSQL_SUCCESS_WITH_INFOを返します。)
01S0 1 行にエラーがあります。 1つ以上の行の取得中にエラーが発生しました。(SQLExtendedFetch() は、このSQLSTATEに対してSQL_SUCCESS_WITH_INFOを返します。)
07002 列数が多すぎます。 次の 1 つ以上の理由に該当した場合に、この SQLSTATE が戻されます。
  • 1 つ以上の列のバインドで指定された列番号が、結果セットの列数より大きい値です。
  • アプリケーションは、 SQLSetColAttributes() を使用して、結果セットの記述子情報を Db2 ODBC に通知しますが、結果セット内のすべてのカラムについてこの情報を提供するわけではありません。
0700 6 無効な変換です。 データ値は、 fCType 引数で指定されたデータ型に意味のある方法で変換できません。 SQLBindCol() 指定します。
08S01 通信リンク障害が発生しました。 関数が完了する前に、アプリケーションとデータ・ソース間の 通信リンクで障害が発生しました。
2 20 02 無効な出力または標識バッファーが指定されました。 pcbValue 引数は SQLBindCol() NULL ポインターを指定し、対応する列の値は NULL です。 この関数は、SQL_NULL_DATA を報告できません。
22008 無効な日付時刻形式または日付時刻フィールドがオーバーフローです。 次の 1 つ以上の理由に該当した場合に、この SQLSTATE が戻されます。
  • 文字ストリングから日時形式への変換が指示されましたが、 指定されたストリング表示または値が無効であるか、あるいは日付の値が無効です。
  • 日付、時刻、またはタイム・スタンプの値が、指定されたデータ・タイプ の構文に準拠していません。
  • 日時フィールドでオーバーフローが起こりました。

    例: 日付またはタイム・スタンプの算術計算の結果が日付の有効範囲から外れているか、 あるいは、バインドされた変数が小さすぎて日付/時刻値を割り当てることができません。

22012 ゼロによる除算は無効です。 除数ゼロでの割り算となる算術式からの値が戻されました。
22018 割り当てにエラーがありました。 次の 1 つ以上の理由に該当した場合に、この SQLSTATE が戻されます。
  • 戻された値は、バインドされた列のデータ・タイプと互換性がありません。
  • 返された LOB ロケーター値は、バインドされた列のデータ・タイプと互換性がありませんでした。
24000 カーソルの状態が無効です。 ステートメント・ハンドルで実行された SQL ステートメントは 照会ではありません。
580 04 予想外のシステム障害が発生しました。 リカバリー不能なシステム・エラーです。
HY001 メモリーの割り振りが失敗しました。 DB2 ODBC は、関数の実行または完了をサポートするのに必要なメモリーを割り振ることができません。
HY010 関数のシーケンス・エラーです。 次の 1 つ以上の理由に該当した場合に、この SQLSTATE が戻されます。
  • SQLExtendedFetch() が、SQLFetch() 呼び出しの後、 かつ SQLFreeStmt() (引数 fOption を SQL_CLOSE に設定) 呼び出しの前に、ステートメント・ハンドル で呼び出されました。
  • この関数は、ステートメント・ハンドルで SQLPrepare() または SQLExecDirect() を呼び出す 前に、呼び出されました。
  • この関数は、実行時データの操作時に呼び出されました。 (すなわち、SQLParamData() または SQLPutData() 関数を使用するプロシージャー実行中に関数が呼び出されました。)
HY013 予期しない、メモリーのハンドル・エラーです。 DB2 ODBC は、関数の実行または完了をサポートするのに必要なメモリーにアクセスすることができません。
HY019 数値が範囲外です。 次の 1 つ以上の理由に該当した場合に、この SQLSTATE が戻されます。
  • 1 つ以上の列に対応して戻された数値 (数値またはストリングとして) が原因で、 割り当て時もしくは中間結果の計算時に、数値の整数部分が切り捨てられました。
  • 除数ゼロでの割り算となる算術式からの値が戻されました。
HY106 フェッチ・タイプが範囲外です。 引数 fFetchType に指定された値は認識されません。
HYC0 0 ドライバーは使用できません。 次の 1 つ以上の理由に該当した場合に、この SQLSTATE が戻されます。
  • Db2 ODBC または、データソースが、 SQLBindCol() のfCTypeArgument と対応するカラムのSQLデータ型が要求する変換をサポートしていない。
  • Db2 ODBC がサポートしていない列データ型に対して、 SQLBindCol() への呼び出しが行われます。
  • 指定されたフェッチ・タイプは認識されますが、サポートされていません。

この関数は ODBC 3.0では推奨されませんが、この関数は Db2 ODBCでは非推奨ではありません。 しかし、ODBC アプリケーションでは、SQLExtendedFetch() ではなく、SQLFetchScroll() をご使用ください。

次の例は、 SQLExtendedFetch() を使用して配列のフェッチを実行するアプリケーションを示しています。
図1: 配列フェッチを行うアプリケーション
/* ... */
    "SELECT deptnumb, deptname, id, name FROM staff, org \
                     WHERE dept=deptnumb AND job = 'Mgr'";
    /* Column-wise */
    SQLINTEGER      deptnumb[ROWSET_SIZE];
    SQLCHAR         deptname[ROWSET_SIZE][15];
    SQLINTEGER      deptname_l[ROWSET_SIZE];
    SQLSMALLINT     id[ROWSET_SIZE];
    SQLCHAR         name[ROWSET_SIZE][10];
    SQLINTEGER      name_l[ROWSET_SIZE];
    /* Row-wise (Includes buffer for both column data and length) */
    struct {
        SQLINTEGER      deptnumb_l; /* length */
        SQLINTEGER      deptnumb; /* value  */
        SQLINTEGER      deptname_l;
        SQLCHAR         deptname[15];
        SQLINTEGER      id_l;
        SQLSMALLINT     id;
        SQLINTEGER      name_l;
        SQLCHAR         name[10];
    }               R[ROWSET_SIZE];
    SQLUSMALLINT    Row_Stat[ROWSET_SIZE];
    SQLUINTEGER     pcrow;
    int             i;
/* ... */
    /*********************************************/
    /* Column-wise binding                       */
    /*********************************************/
    rc = SQLAllocHandle( SQL_HANDLE_STMT, hdbc, &hstmt);
    rc = SQLSetStmtAttr(hstmt, SQL_ATTR_ROWSET_SIZE, (void*) ROWSET_SIZE, 0);
    rc = SQLExecDirect(hstmt, stmt, SQL_NTS);
    rc = SQLBindCol(hstmt, 1, SQL_C_LONG, (SQLPOINTER) deptnumb, 0, NULL);
    rc = SQLBindCol(hstmt, 2, SQL_C_CHAR, (SQLPOINTER) deptname,
                    15, deptname_l);
    rc = SQLBindCol(hstmt, 3, SQL_C_SSHORT, (SQLPOINTER) id, 0, NULL);
    rc = SQLBindCol(hstmt, 4, SQL_C_CHAR, (SQLPOINTER) name, 10, name_l);
    /* Fetch ROWSET_SIZE rows ast a time, and display */
    printf("\nDEPTNUMB DEPTNAME         ID       NAME\n");
    printf("-------- -------------- -------- ---------\n");
    while ((rc = SQLExtendedFetch(hstmt, SQL_FETCH_NEXT, 0, 
            &pcrow, Row_Stat)) == SQL_SUCCESS) {
        for (i = 0; i < pcrow; i++) {
            printf("%8ld %-14s %8ld %-9s\n", deptnumb[i], deptname[i],
                   id[i], name[i]);
        }
        if (pcrow < ROWSET_SIZE)
            break;
    }                           /* endwhile */
    if (rc != SQL_NO_DATA_FOUND && rc != SQL_SUCCESS)
        CHECK_HANDLE(SQL_HANDLE_STMT, hstmt, rc);
    rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
     /*********************************************/
    /* Row-wise binding               */
    /*********************************************/
    rc = SQLAllocHandle( SQL_HANDLE_STMT, hdbc, &hstmt);
    CHECK_HANDLE(SQL_HANDLE_STMT, hstmt, rc);
    /* Set maximum number of rows to receive with each extended fetch */
    rc = SQLSetStmtAttr(hstmt, SQL_ATTR_ROWSET_SIZE, (void*) ROWSET_SIZE, 0);
    CHECK_HANDLE(SQL_HANDLE_STMT, hstmt, rc);
    /*
     * Set vparam to size of one row, used as offset for each bindcol
     * rgbValue
     */
    /* ie. &(R[0].deptnumb) + vparam = &(R[1].deptnum) */
    rc = SQLSetStmtAttr(hstmt, SQL_ATTR_BIND_TYPE, 
                         (void*) (sizeof(R) / ROWSET_SIZE), 0);
    rc = SQLExecDirect(hstmt, stmt, SQL_NTS);
    rc = SQLBindCol(hstmt, 1, SQL_C_LONG, (SQLPOINTER) &R[0].deptnumb, 0,
                    &R[0].deptnumb_l);
    rc = SQLBindCol(hstmt, 2, SQL_C_CHAR, (SQLPOINTER) R[0].deptname, 15,
                    &R[0].deptname_l);
    rc = SQLBindCol(hstmt, 3, SQL_C_SSHORT, (SQLPOINTER) &R[0].id, 0,
                    &R[0].id_l);
    rc = SQLBindCol(hstmt, 4, SQL_C_CHAR, (SQLPOINTER) R[0].name, 10, &R[0].name_l);
    /* Fetch ROWSET_SIZE rows at a time, and display */
    printf("\nDEPTNUMB DEPTNAME         ID       NAME\n");
    printf("-------- -------------- -------- ---------\n");
    while ((rc = SQLExtendedFetch(hstmt, SQL_FETCH_NEXT, 0, &pcrow, Row_Stat))
           == SQL_SUCCESS) {
        for (i = 0; i < pcrow; i++) {
            printf("%8ld %-14s %8ld %-9s\n", R[i].deptnumb, R[i].deptname,
                R[i].id, R[i].name);
        }
        if (pcrow < ROWSET_SIZE)
            break;
    }                           /* endwhile */
    if (rc != SQL_NO_DATA_FOUND && rc != SQL_SUCCESS)
        CHECK_HANDLE(SQL_HANDLE_STMT, hstmt, rc);
    /* Free handles, commit, exit */
/* ... */