Блочная выборка данных
Связывание столбцов, используемых с блочным курсором
При использовании блочного курсора за один вызов функции может возвращаться несколько строк. Поэтому с каждым столбцом должна связываться не просто переменная соответствующего типа, а массив. Такой массив обычно называется буфером набора строк (rowset buffer).
Возможно два типа связывания:
- связывание по столбцу (column-wise binding), при котором с каждым столбцом связывается отдельный массив (структура данных, содержащая элементы одного типа);
- связывание по строке (row-wise binding), при котором с каждой строкой связывается отдельный массив (структура данных, типы элементов которой соответствуют типам столбцов строки набора данных).
Для выполнения любого типа связывания используется функция ODBC API SQLBindCol. При этом тип связывания определяется атрибутом SQL_ATTR_ROW_BIND_TYPE. В случае использования блочного курсора со связыванием по строке или по столбцу, функции SQLBindCol в качестве параметра вместо адреса простой переменной передается адрес массива.
Связывание по столбцу
При использовании связывания по столбцу с каждым столбцом может быть связано от одного до трех массивов: первый массив - для извлекаемых значений, второй - для длины / индикатора буферов, третий - для индикатора буферов (если индикаторы и длина хранятся по отдельности). Каждый массив должен содержать число элементов, равное числу строк в извлекаемом наборе строк.
Хранятся ли по отдельности индикаторы и значения длины, определяется установкой дескрипторов полей SQL_DESC_INDICATOR_PTR и SQL_DESC_OCTET_LENGTH_PTR.
На следующем рисунке приведена схема связывания по столбцам.
Следующий пример иллюстрирует применение связывания по столбцам для набора строк, состоящего из трех столбцов:
#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);