Обновление строк в наборе строк с помощью SQLSetPos

Операция обновления SQLSetPos делает источник данных обновлением одной или нескольких выбранных строк таблицы, используя данные в буферах приложения для каждого связанного столбца (если значение в буфере длины или индикатора не SQL_COLUMN_IGNORE). Столбцы, которые не привязаны, не будут обновляться.

Чтобы обновить строки с помощью SQLSetPos, приложение выполняет следующие действия.

  1. Помещает новые значения данных в буферы набора строк. Сведения о том, как отправлять длинные данные с помощью SQLSetPos, см. в разделе Long Data and SQLSetPos и SQLBulkOperations.

  2. Задает значение в буфере длины или индикатора каждого столбца по мере необходимости. Это длина байтов данных или SQL_NTS столбцов, привязанных к строковым буферам, длина байтов данных для столбцов, привязанных к двоичным буферам, и SQL_NULL_DATA для всех столбцов, которые должны иметь значение NULL.

  3. Задает значение в буфере длины или индикатора этих столбцов, которые не обновляются до SQL_COLUMN_IGNORE. Хотя приложение может пропустить этот шаг и повторно отправить существующие данные, это неэффективно и риск отправки значений в источник данных, которые были усечены при чтении.

  4. Вызывает SQLSetPos с набором операций для SQL_UPDATE и RowNumber , заданных для обновления строки. Если 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.

Например, следующий код позволяет пользователю прокручивать таблицу "Клиенты" и обновлять, удалять или добавлять новые строки. Он помещает новые данные в буферы набора строк перед вызовом 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);