Механизмы выборки данных
Обработка результирующего набора
Результирующий набор формируется в выделяемой области памяти. Для того чтобы использовать данные, записанные в результирующий набор, их следует извлечь из заданной области памяти в переменные используемого языка программирования.
Извлечение данных из результирующего набора в переменные может быть выполнено:
- вызовом функции SQLFetch или SQLFetchScroll ;
- вызовом функции SQLGetData.
Функции SQLFetch или SQLFetchScroll всегда выполняют продвижение курсора на следующую запись. При этом функция SQLFetch, реализует механизм "однонаправленного курсора", а функция SQLFetchScroll позволяет, в зависимости от используемого источника данных, реализовывать механизм "двунаправленного курсора" и механизм "прямой выборки".
Функции SQLFetch или SQLFetchScroll выполняют одновременное извлечение данных только в том случае, если поля результирующего набора предварительно были связаны с переменными вызовом функции SQLBindCol для каждого связываемого поля.
Функция SQLFetch имеет следующее формальное описание:
SQLRETURN SQLFetch(
SQLHSTMT StatementHandle);Параметр StatementHandle ([Input]) указывает дескриптор оператора.
Функция SQLGetData имеет следующее формальное описание:
SQLRETURN SQLGetData(
SQLHSTMT StatementHandle,
SQLUSMALLINT ColumnNumber,
SQLSMALLINT TargetType,
SQLPOINTER TargetValuePtr,
SQLINTEGER BufferLength,
SQLINTEGER * StrLen_or_IndPtr);Параметр StatementHandle ([Input]) указывает дескриптор оператора.
Параметр ColumnNumber ([Input]) указывает номер связываемого столбца результирующего набора (начиная с 1). По умолчанию столбец номер 0 является столбцом маркера строки, в том случае, если маркеры доступны.
Параметр TargetType ([Input]) определяет C-тип данных для буфера*TargetValuePtr в соответствии со следующей таблицей.
| Идентификатор C-типа | ODBC C typedef | Тип C |
|---|---|---|
| SQL_C_CHAR | SQLCHAR * | unsigned char * |
| SQL_C_SSHORT | SQLSMALLINT | Short int |
| SQL_C_USHORT | SQLUSMALLINT | unsigned short int |
| SQL_C_SLONG | SQLINTEGER | long int |
| SQL_C_ULONG | SQLUINTEGER | unsigned long int |
| SQL_C_FLOAT | SQLREAL | float |
| SQL_C_DOUBLE | SQLDOUBLE, SQLFLOAT | double |
| SQL_C_BIT | SQLCHAR | unsigned char |
| SQL_C_STINYINT | SQLSCHAR | Signed char |
| SQL_C_UTINYINT | SQLCHAR | unsigned char |
| SQL_C_SBIGINT | SQLBIGINT | _int64 |
| SQL_C_UBIGINT | SQLUBIGINT | unsigned _int64 |
| SQL_C_BINARY | SQLCHAR * | unsigned char * |
| SQL_C_BOOKMARK | BOOKMARK | unsigned long int |
| SQL_C_VARBOOKMARK | SQLCHAR * | unsigned char * |
| SQL_C_TYPE_DATE | SQL_DATE_STRUCT |
struct tagDATE_STRUCT {
SQLSMALLINT year;
SQLUSMALLINT month;
SQLUSMALLINT day;
} DATE_STRUCT; |
| SQL_C_TYPE_TIME | SQL_TIME_STRUCT |
struct tagTIME_STRUCT {
SQLUSMALLINT hour;
SQLUSMALLINT minute;
SQLUSMALLINT second;
} TIME_STRUCT; |
| SQL_C_TYPE_TIMESTAMP | SQL_TIMESTAMP_STRUCT |
struct tagTIMESTAMP_STRUCT {
SQLSMALLINT year;
SQLUSMALLINT month;
SQLUSMALLINT day;
SQLUSMALLINT hour;
SQLUSMALLINT minute;
SQLUSMALLINT second;
SQLUINTEGER fraction;
} TIMESTAMP_STRUCT; |
| SQL_C_NUMERIC | SQL_NUMERIC_STRUCT |
Struct tagSQL_NUMERIC_STRUCT {
SQLCHAR precision;
SQLSCHAR scale;
SQLCHAR sign[g];
SQLCHAR
val[SQL_MAX_NUMERIC_LEN];
} SQL_NUMERIC_STRUCT; |
| SQL_C_GUID | SQLGUID |
struct tagSQLGUID {
DWORD Data1;
WORD Data2;
WORD Data3;
BYTE Data4[8];
} SQLGUID; |
| Все интервальные C типы данных | SSQL_INTERVAL_STRUCT |
typedef struct tagSQL_INTERVAL_STRUCT
{
SQLINTERVAL interval_type;
SQLSMALLINT interval_sign;
union {
SQL_YEAR_MONTH_STRUCT year_month;
SQL_DAY_SECOND_STRUCT day_second;
} intval;
} SQL_INTERVAL_STRUCT;
typedef enum
{
SQL_IS_YEAR = 1,
SQL_IS_MONTH = 2,
SQL_IS_DAY = 3,
SQL_IS_HOUR = 4,
SQL_IS_MINUTE = 5,
SQL_IS_SECOND = 6,
SQL_IS_YEAR_TO_MONTH = 7,
SQL_IS_DAY_TO_HOUR = 8,
SQL_IS_DAY_TO_MINUTE = 9,
SQL_IS_DAY_TO_SECOND = 10,
SQL_IS_HOUR_TO_MINUTE = 11,
SQL_IS_HOUR_TO_SECOND = 12,
SQL_IS_MINUTE_TO_SECOND = 13
} SQLINTERVAL;
typedef struct tagSQL_YEAR_MONTH
{
SQLUINTEGER year;
SQLUINTEGER month;
} SQL_YEAR_MONTH_STRUCT;
typedef struct tagSQL_DAY_SECOND
{
SQLUINTEGER day;
SQLUINTEGER hour;
SQLUINTEGER minute;
SQLUINTEGER second;
SQLUINTEGER fraction;
} SQL_DAY_SECOND_STRUCT; |
Например:
SQLCHAR ValuePtr[50];
SQLINTEGER ValueLenOrInd;
SQLGetData(hstmt, 1, SQL_C_CHAR,
ValuePtr, sizeof(ValuePtr),
&ValueLenOrInd);В параметре TargetType также можно указывать идентификатор типа SQL_C_DEFAULT: в этом случае драйвер самостоятельно выбирает тип данных С, основываясь на типе данных поля источника данных.
Параметр TargetValuePtr ([Output]) определяет буфер, в который выполняется извлечение данных, а параметр ([Input]) определяет размер этого буфера в байтах. Для данных, имеющих фиксированную длину, таких как целочисленные значения, драйвер игнорирует значение параметра BufferLength.
Параметр StrLen_or_IndPtr ([Output]) определяет буфер, в котором возвращается размер данных или индикатор и может содержать следующие значения:
- размер данных в байтах;
- SQL_NO_TOTAL - индикатор, указывающий, что размер не может быть определен;
- SQL_NULL_DATA - индикатор, указывающий, что данные имеют значение NULL.
Следующий пример иллюстрирует применение механизма извлечения данных при помощи функции SQLGetData.
//OBDC_Connect.cpp
#include "stdafx.h"
#include "Test_ODBC_connect.h"
#include <iostream>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
CWinApp theApp; // Объявление объекта приложения
using namespace std;
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{ int nRetCode = 0;
if (!AfxWinInit(::GetModuleHandle(NULL), NULL,
::GetCommandLine(), 0))
{ _tprintf(_T("Ошибка инициализации MFC\n"));
nRetCode = 1;
}
else
{
std::cout<<"Begin"<<std::endl;
SQLHENV henv; // Дескриптор окружения
SQLHDBC hdbc; // Дескриптор соединения
SQLHSTMT hstmt; // Дескриптор оператора
SQLRETURN retcode; // Код возврата
/*Инициализация дескриптора окружения */
retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
std::cout<<"SQLAllocHandle создан успешно"<<std::endl;
/* Определение версии ODBC */
retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION,
(void*)SQL_OV_ODBC3, 0);
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
/* Инициализация дескриптора соединения */
retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
std::cout<<"SQLAllocHandle создан успешно "<<std::endl;
retcode = SQLConnect(hdbc, (SQLCHAR*) "MySQLDB", SQL_NTS,
(SQLCHAR*) "", SQL_NTS,
(SQLCHAR*) "", SQL_NTS);
if (retcode == SQL_SUCCESS ||
retcode == SQL_SUCCESS_WITH_INFO){
/* Инициализация дескриптора оператора */
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
SQLCHAR sqf3[50];
SQLINTEGER sqf1,sqf2,sbf1,sbf2,sbf3;
SQLCHAR selecttxt[] ="SELECT f1, f2, f3 FROM tbl1";
/* Создание результирующего набора */
retcode = SQLExecDirect(hstmt, selecttxt, SQL_NTS);
if (retcode == SQL_SUCCESS) {
while (TRUE) {
/* Выборка данных */
retcode = SQLFetch(hstmt);
if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) {
}
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){
/* Извлечение данных трех полей результирующего набора */
SQLGetData(hstmt, 1, SQL_C_ULONG, &sqf1, 0, &sbf1);
SQLGetData(hstmt, 2, SQL_C_ULONG, &sqf2, 0, &sbf2);
SQLGetData(hstmt, 3, SQL_C_CHAR, sqf3, 50, &sbf3);
/* Запись в поток вывода строк результирующего набора */
std::cout<< "1: "<<sqf1<<" 2: "<<sqf2<<" 3: "<< sqf3<<" "<<std::endl;
} else {
break;
}
}
}
/* Освобождение дескрипторов */
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
}
SQLDisconnect(hdbc);
}
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
}
}
SQLFreeHandle(SQL_HANDLE_ENV, henv);
}
return nRetCode;
}
}
//OBDC_Connect.h
#pragma once
#include "resource.h"
#ifndef _AFX_NOFORCE_LIBS
////////////////////////////////////////////////////////////////
// Win32 библиотеки
#pragma comment(lib, "odbc32.lib")
#pragma comment(lib, "odbccp32.lib")
#endif //!_AFX_NOFORCE_LIBS
#ifndef __SQL
#include <sql.h> // ядро
#endif
#ifndef __SQLEXT
#include <sqlext.h> // расширение
#endif