![]() |
|||||
|---|---|---|---|---|---|
Блочная выборка данных
Связывание столбцов, используемых с блочным курсоромПри использовании блочного курсора за один вызов функции может возвращаться несколько строк. Поэтому с каждым столбцом должна связываться не просто переменная соответствующего типа, а массив. Такой массив обычно называется буфером набора строк (rowset buffer).
Для выполнения любого типа связывания используется функция ODBC API SQLBindCol. При этом тип связывания определяется атрибутом SQL_ATTR_ROW_BIND_TYPE. В случае использования блочного курсора со связыванием по строке или по столбцу, функции SQLBindCol в качестве параметра вместо адреса простой переменной передается адрес массива. Связывание по столбцуПри использовании связывания по столбцу с каждым столбцом может быть связано от одного до трех массивов: первый массив - для извлекаемых значений, второй - для длины / индикатора буферов, третий - для индикатора буферов (если индикаторы и длина хранятся по отдельности). Каждый массив должен содержать число элементов, равное числу строк в извлекаемом наборе строк. #define ROW_ARRAY_SIZE 10 // Кол-во строк // в наборе строк SQLUINTEGER ID1Array[ROW_ARRAY_SIZE], NumRowsFetched; SQLCHAR SalArray[ROW_ARRAY_SIZE][11], StatusArray[ROW_ARRAY_SIZE][7]; SQLINTEGER ID1IndArray[ROW_ARRAY_SIZE], SalLenOrIndArray[ROW_ARRAY_SIZE], StatusLenOrIndArray[ROW_ARRAY_SIZE]; SQLUSMALLINT RowStatusArray[ROW_ARRAY_SIZE], i; SQLRETURN rc; SQLHSTMT hstmt; // Устанавливаем атрибут оператора // SQL_ATTR_ROW_BIND_TYPE для использования связывания // по столбцам SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_BIND_TYPE, SQL_BIND_BY_COLUMN, 0); // Размер набора строк задаем атрибутом оператора // SQL_ATTR_ROW_ARRAY_SIZE SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, ROW_ARRAY_SIZE, 0); // Устанавливаем атрибут оператора // SQL_ATTR_ROW_STATUS_PTR для определения массива // состояний строк SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_STATUS_PTR, RowStatusArray, 0); // Устанавливаем атрибут оператора // SQL_ATTR_ROWS_FETCHED_PTR для указания на // cRowsFetched SQLSetStmtAttr(hstmt, SQL_ATTR_ROWS_FETCHED_PTR, &NumRowsFetched, 0); // Связываем массивы со столбцами ID1, Sal и Status SQLBindCol(hstmt, 1, SQL_C_ULONG, ID1Array, 0, ID1IndArray); SQLBindCol(hstmt, 2, SQL_C_CHAR, SalArray, sizeof(SalArray[0]), SalLenOrIndArray); SQLBindCol(hstmt, 3, SQL_C_CHAR, StatusArray, sizeof(StatusArray[0]), StatusLenOrIndArray); // Выполняем SQL-оператор SELECT для создания // результирующего набора SQLExecDirect(hstmt, "SELECT ID1, Sal, Status FROM TBL1", SQL_NTS); // Выполняем блочную выборку из результирующего набора // В переменной NumRowsFetched возвращается число // в действительности выбранных строк while ((rc = SQLFetchScroll(hstmt,SQL_FETCH_NEXT,0)) != SQL_NO_DATA) {
for (i = 0; i < NumRowsFetched; i++) {
// Отображаем только успешно извлеченные строки (если // код ответа (rc) равен SQL_SUCCESS_WITH_INFO или // SQL_ERROR, то строку не выводим.) if ((RowStatusArray[i] == SQL_ROW_SUCCESS) || (RowStatusArray[i] == SQL_ROW_SUCCESS_WITH_INFO)) {
if (ID1IndArray[i] == SQL_NULL_DATA) printf(" NULL ");
else printf("%d\t", ID1Array[i]);
if (SalLenOrIndArray[i] == SQL_NULL_DATA) printf(" NULL ");
else printf("%s\t", SalArray[i]);
if (StatusLenOrIndArray[i] == SQL_NULL_DATA) printf(" NULL\n");
else printf("%s\n", StatusArray[i]);
} } } // Закрываем курсор SQLCloseCursor(hstmt); Связывание по строкамПри использовании связывания по строкам определяется структура, содержащая от одного до трех элементов для каждого столбца извлекаемых данных. Первый элемент предназначается для извлекаемых данных, второй - для длины / индикатора буфера, третий - для индикатора буфера при раздельном сохранении значений длины и индикатора (что определяется дескрипторами полей SQL_DESC_INDICATOR_PTR и SQL_DESC_OCTET_LENGTH_PTR). Адрес = Адрес_связывания + ((Номер_строки - 1) * Размер_структуры) На следующем рисунке приведена схема связывания по строкам. #define ROW_ARRAY_SIZE 10 // Определяем структуру TBL_INFO и создаем массив // структур, содержащий 10 элементов typedef struct {
SQLUINTEGER ID1; // Для значения 1 столбца SQLINTEGER ID1Ind; // Для длины/индикатора SQLCHAR Sal[11]; // Для значения 2 столбца SQLINTEGER SalLenOrInd; SQLCHAR Status[7]; // Для значения 3 столбца SQLINTEGER StatusLenOrInd; } ORDERINFO; TBL_INFO TBL_Array[ROW_ARRAY_SIZE]; // Массив структур SQLUINTEGER NumRowsFetched; SQLUSMALLINT RowStatusArray[ROW_ARRAY_SIZE], i; SQLRETURN rc; SQLHSTMT hstmt; // Определяем размер структуры, используя атрибут //оператора SQL_ATTR_ROW_BIND_TYPE, и одновременно // устанавливаем тип связывания по строкам SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_BIND_TYPE, sizeof(TBL_INFO), 0); // Используя атрибут оператора SQL_ATTR_ROW_ARRAY_SIZE // устанавливаем количество строк в извлекаемом наборе // строк SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, ROW_ARRAY_SIZE, 0); // Используя атрибут оператора SQL_ATTR_ROW_STATUS_PTR // определяем массив состояния строк SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_STATUS_PTR, RowStatusArray, 0); // Устанавливаем атрибут оператора // SQL_ATTR_ROWS_FETCHED_PTR для указания на // NumRowsFetched SQLSetStmtAttr(hstmt, SQL_ATTR_ROWS_FETCHED_PTR, &NumRowsFetched, 0); // Связываем поля структуры первого элемента массива // со столбцами ID1, Sal и Status SQLBindCol(hstmt, 1, SQL_C_ULONG, &TBL_Array[0].ID1, 0, &TBL_Array[0].ID1Ind); SQLBindCol(hstmt, 2, SQL_C_CHAR, TBL_Array[0].Sal, sizeof(TBL_Array[0].Sal), &TBL_Array[0].SalLenOrInd); SQLBindCol(hstmt, 3, SQL_C_CHAR, TBL_Array[0].Status, sizeof(TBL_Array[0].Status), &TBL_Array[0].StatusLenOrInd); // Выполняем SQL-оператор SELECT для формирования // результирующего набора SQLExecDirect(hstmt, "SELECT ID1, Sal, Status FROM TBL1", SQL_NTS); // Используя блочный курсор, извлекаем установленное //число строк while ((rc = SQLFetchScroll(hstmt,SQL_FETCH_NEXT,0)) != SQL_NO_DATA) {
// Переменная NumRowsFetched содержит число // в действительности извлеченных строк for (i = 0; i < NumRowsFetched; i++) {
if (RowStatusArray[i] == SQL_ROW_SUCCESS|| RowStatusArray[i] == SQL_ROW_SUCCESS_WITH_INFO) {
if (TBL_Array[i].ID1Ind == SQL_NULL_DATA) std::cout<<" NULL "; else std::cout<< TBL_Array[i].ID1; if (TBL_Array[i].SalLenOrInd == SQL_NULL_DATA) std::cout<< " NULL "; else std::cout<< TBL_Array[i].Sal; if (TBL_Array[i].StatusLenOrInd == SQL_NULL_DATA) std::cout<< " NULL\n"; else std::cout<< TBL_Array[i].Status; } } } // Закрываем курсор SQLCloseCursor(hstmt); |
|||||
С вопросами и предложениями можно обращаться по nicivas@bk.ru. 2009 г. |
|||||