行方向のバインド
行方向のバインドを使用する場合、アプリケーションは、データを返す列ごとに 1 つまたは 2 つ、場合によっては 3 つの要素を含む構造体を定義します。 最初の要素はデータ値を保持し、2 番目の要素は長さ/インジケーター バッファーを保持します。 インジケーターと長さの値は、SQL_DESC_INDICATOR_PTR フィールドと SQL_DESC_OCTET_LENGTH_PTR 記述子フィールドを異なる値に設定することで、個別のバッファーに格納できます。これが行われる場合、構造体には 3 番目の要素が含まれます。 その後、アプリケーションは行セット内の行と同じ数の要素を含む、これらの構造体の配列を割り当てます。
アプリケーションは、SQL_ATTR_ROW_BIND_TYPE ステートメント属性を使用して構造体のサイズをドライバーに宣言し、配列の最初の要素の各メンバーのアドレスをバインドします。 したがって、ドライバーは、特定の行と列のデータのアドレスを次のように計算できます。
Address = Bound Address + ((Row Number - 1) * Structure Size)
行は 1 から行セットのサイズまでの番号が付けられます。 (C の配列インデックスは 0 から始まるため、行番号から 1 つが減算されます。) 次の図は、行方向のバインドのしくみを示しています。 一般に、バインドされる列のみが構造体に含まれます。 構造体には、結果セット列に関係のないフィールドを含めることができます。 列は任意の順序で構造に配置できますが、わかりやすくするために順番に表示されます。
例えば、次のコードは、OrderID、SalesPerson、Status 列のデータと、SalesPerson 列と Status 列の長さ/インジケーターを返す要素を含む構造体を作成します。 これらの構造体を 10 個割り当て、OrderID、SalesPerson、Status 列にバインドします。
#define ROW_ARRAY_SIZE 10
// Define the ORDERINFO struct and allocate an array of 10 structs.
typedef struct {
SQLUINTEGER OrderID;
SQLINTEGER OrderIDInd;
SQLCHAR SalesPerson[11];
SQLINTEGER SalesPersonLenOrInd;
SQLCHAR Status[7];
SQLINTEGER StatusLenOrInd;
} ORDERINFO;
ORDERINFO OrderInfoArray[ROW_ARRAY_SIZE];
SQLULEN NumRowsFetched;
SQLUSMALLINT RowStatusArray[ROW_ARRAY_SIZE], i;
SQLRETURN rc;
SQLHSTMT hstmt;
// Specify the size of the structure with the SQL_ATTR_ROW_BIND_TYPE
// statement attribute. This also declares that row-wise binding will
// be used. Declare the rowset size with the SQL_ATTR_ROW_ARRAY_SIZE
// statement attribute. Set the SQL_ATTR_ROW_STATUS_PTR statement
// attribute to point to the row status array. Set the
// SQL_ATTR_ROWS_FETCHED_PTR statement attribute to point to
// NumRowsFetched.
SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_BIND_TYPE, sizeof(ORDERINFO), 0);
SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, ROW_ARRAY_SIZE, 0);
SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_STATUS_PTR, RowStatusArray, 0);
SQLSetStmtAttr(hstmt, SQL_ATTR_ROWS_FETCHED_PTR, &NumRowsFetched, 0);
// Bind elements of the first structure in the array to the OrderID,
// SalesPerson, and Status columns.
SQLBindCol(hstmt, 1, SQL_C_ULONG, &OrderInfoArray[0].OrderID, 0, &OrderInfoArray[0].OrderIDInd);
SQLBindCol(hstmt, 2, SQL_C_CHAR, OrderInfoArray[0].SalesPerson,
sizeof(OrderInfoArray[0].SalesPerson),
&OrderInfoArray[0].SalesPersonLenOrInd);
SQLBindCol(hstmt, 3, SQL_C_CHAR, OrderInfoArray[0].Status,
sizeof(OrderInfoArray[0].Status), &OrderInfoArray[0].StatusLenOrInd);
// Execute a statement to retrieve rows from the Orders table.
SQLExecDirect(hstmt, "SELECT OrderID, SalesPerson, Status FROM Orders", SQL_NTS);
// Fetch up to the rowset size number of rows at a time. Print the actual
// number of rows fetched; this number is returned in NumRowsFetched.
// Check the row status array to print only those rows successfully
// fetched. Code to check if rc equals SQL_SUCCESS_WITH_INFO or
// SQL_ERRORnot shown.
while ((rc = SQLFetchScroll(hstmt,SQL_FETCH_NEXT,0)) != SQL_NO_DATA) {
for (i = 0; i < NumRowsFetched; i++) {
if (RowStatusArray[i] == SQL_ROW_SUCCESS|| RowStatusArray[i] ==
SQL_ROW_SUCCESS_WITH_INFO) {
if (OrderInfoArray[i].OrderIDInd == SQL_NULL_DATA)
printf(" NULL ");
else
printf("%d\t", OrderInfoArray[i].OrderID);
if (OrderInfoArray[i].SalesPersonLenOrInd == SQL_NULL_DATA)
printf(" NULL ");
else
printf("%s\t", OrderInfoArray[i].SalesPerson);
if (OrderInfoArray[i].StatusLenOrInd == SQL_NULL_DATA)
printf(" NULL\n");
else
printf("%s\n", OrderInfoArray[i].Status);
}
}
}
// Close the cursor.
SQLCloseCursor(hstmt);