Share via


SQLSetPos による行セットの行の更新

SQLSetPos の更新操作により、データ ソースは、バインドされた列ごとにアプリケーション バッファー内のデータを使用して、テーブルの 1 つ以上の選択された行を更新します (長さ/インジケーター バッファーの値が SQL_COLUMN_IGNORE ではない場合)。 バインドされていない列は更新されません。

SQLSetPos で行を更新するために、アプリケーションは次の処理を行います。

  1. 行セット バッファーに新しいデータ値を配置します。 SQLSetPos を使用して長いデータを送信する方法については、「長いデータと SQLSetPos と SQLBulkOperations」を参照してください。

  2. 必要に応じて、各列の長さ/インジケーター バッファーの値を設定します。 これは、文字列バッファーにバインドされた列のデータまたは SQL_NTS のバイト長、バイナリ バッファーにバインドされた列のデータのバイト長、および NULL に設定する列の SQL_NULL_DATA です。

  3. SQL_COLUMN_IGNORE に更新しない列の長さ/インジケーター バッファーの値を設定します。 アプリケーションはこの手順をスキップして既存のデータを再送信できますが、これは非効率的であり、読み取られたときに切り捨てられた値をデータ ソースに送信するリスクがあります。

  4. 操作を SQL_UPDATE に設定し、RowNumber を更新する行の数に設定して SQLSetPos を呼び出します。 RowNumber が 0 の場合は、行セット内のすべての行は更新されます。

SQLSetPos が戻った後、現在の行は更新された行に設定されます。

行セットのすべての行を更新する場合 (RowNumber が 0 に等しい場合)、アプリケーションでは、行操作配列の対応する要素 (SQL_ATTR_ROW_OPERATION_PTR ステートメント属性が指します) を SQL_ROW_IGNORE に設定することで、特定の行の更新を無効にすることができます。 行操作配列は、サイズと要素数が行ステータス配列 (SQL_ATTR_ROW_STATUS_PTR ステートメント属性によって示されます) に対応します。 正常にフェッチされ、行セットから削除されていない結果セット内の行のみを更新するために、アプリケーションは、行セットをフェッチした関数の行状態配列を行操作配列として SQLSetPos に使用します。

更新プログラムとしてデータ ソースに送信されるすべての行について、アプリケーション バッファーには有効な行データが必要です。 フェッチによってアプリケーション バッファーが設定され、行の状態配列が維持されている場合は、これら各行位置の行の状態値が SQL_ROW_DELETED、SQL_ROW_ERROR、または SQL_ROW_NOROW であってはなりません。

たとえば、次のコードを使用すると、ユーザーは Customers テーブルをスクロールし、新しい行を更新、削除、または追加できます。 SQLSetPos を呼び出して新しい行を更新または追加する前に、新しいデータを行セット バッファーに配置します。 新しい行を保持するために、行セット バッファーの末尾に追加の行が割り当てられます。これにより、新しい行のデータがバッファーに配置されるときに、既存のデータが上書きされるのを防ぐことができます。

#define UPDATE_ROW   100  
#define DELETE_ROW   101  
#define ADD_ROW      102  
  
SQLUINTEGER    CustIDArray[11];  
SQLCHAR        NameArray[11][51], AddressArray[11][51],   
               PhoneArray[11][11];  
SQLINTEGER     CustIDIndArray[11], NameLenOrIndArray[11],   
               AddressLenOrIndArray[11],  
               PhoneLenOrIndArray[11];  
SQLUSMALLINT   RowStatusArray[10], Action, RowNum;  
SQLRETURN      rc;  
SQLHSTMT       hstmt;  
  
// Set the SQL_ATTR_ROW_BIND_TYPE statement attribute to use column-wise   
// binding. 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.  
SQLSetStmtAttr(hstmt, SQL_ATTR_CURSOR_TYPE, SQL_CURSOR_KEYSET_DRIVEN, 0);  
SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_BIND_TYPE, SQL_BIND_BY_COLUMN, 0);  
SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, 10, 0);  
SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_STATUS_PTR, RowStatusArray, 0);  
  
// Bind arrays to the CustID, Name, Address, and Phone columns.  
SQLBindCol(hstmt, 1, SQL_C_ULONG, CustIDArray, 0, CustIDIndArray);  
SQLBindCol(hstmt, 2, SQL_C_CHAR, NameArray, sizeof(NameArray[0]), NameLenOrIndArray);  
SQLBindCol(hstmt, 3, SQL_C_CHAR, AddressArray, sizeof(AddressArray[0]),  
            AddressLenOrIndArray);  
SQLBindCol(hstmt, 4, SQL_C_CHAR, PhoneArray, sizeof(PhoneArray[0]),  
            PhoneLenOrIndArray);  
  
// Execute a statement to retrieve rows from the Customers table.  
SQLExecDirect(hstmt, "SELECT CustID, Name, Address, Phone FROM Customers", SQL_NTS);  
  
// Fetch and display the first 10 rows.  
rc = SQLFetchScroll(hstmt, SQL_FETCH_NEXT, 0);  
DisplayData(CustIDArray, CustIDIndArray, NameArray, NameLenOrIndArray, AddressArray,  
            AddressLenOrIndArray, PhoneArray, PhoneLenOrIndArray, RowStatusArray);  
  
// Call GetAction to get an action and a row number from the user.  
while (GetAction(&Action, &RowNum)) {  
   switch (Action) {  
  
      case SQL_FETCH_NEXT:  
      case SQL_FETCH_PRIOR:  
      case SQL_FETCH_FIRST:  
      case SQL_FETCH_LAST:  
      case SQL_FETCH_ABSOLUTE:  
      case SQL_FETCH_RELATIVE:  
         // Fetch and display the requested data.  
         SQLFetchScroll(hstmt, Action, RowNum);  
         DisplayData(CustIDArray, CustIDIndArray,  
                     NameArray, NameLenOrIndArray,  
                     AddressArray, AddressLenOrIndArray,  
                     PhoneArray, PhoneLenOrIndArray, RowStatusArray);  
         break;  
  
      case UPDATE_ROW:  
         // Place the new data in the rowset buffers and update the   
         // specified row.  
         GetNewData(&CustIDArray[RowNum - 1], &CustIDIndArray[RowNum - 1],  
                  NameArray[RowNum - 1], &NameLenOrIndArray[RowNum - 1],  
                  AddressArray[RowNum - 1], &AddressLenOrIndArray[RowNum - 1],  
                  PhoneArray[RowNum - 1], &PhoneLenOrIndArray[RowNum - 1]);  
         SQLSetPos(hstmt, RowNum, SQL_UPDATE, SQL_LOCK_NO_CHANGE);  
         break;  
  
      case DELETE_ROW:  
         // Delete the specified row.  
         SQLSetPos(hstmt, RowNum, SQL_DELETE, SQL_LOCK_NO_CHANGE);  
         break;  
  
      case ADD_ROW:  
         // Place the new data in the rowset buffers at index 10.   
         // This is an extra element for new rows so rowset data is   
         // not overwritten. Insert the new row. Row 11 corresponds   
         // to index 10.  
         GetNewData(&CustIDArray[10], &CustIDIndArray[10],  
                     NameArray[10], &NameLenOrIndArray[10],  
                     AddressArray[10], &AddressLenOrIndArray[10],  
                     PhoneArray[10], &PhoneLenOrIndArray[10]);  
         SQLSetPos(hstmt, 11, SQL_ADD, SQL_LOCK_NO_CHANGE);  
         break;  
   }  
}  
  
// Close the cursor.  
SQLCloseCursor(hstmt);