Какая функция odbc распределяет память для заданного идентификатора окружения

Обновлено: 04.07.2024

ODBC мониторинг соответствует типу элемента данных Монитор баз данных в веб-интерфейсе Zabbix.

Zabbix может выполнять запросы к любой базе данных, которая поддерживается ODBC. Чтобы это сделать, Zabbix не подключается напрямую к базам данных, он использует интерфейс ODBC и драйвера установленные в ODBC. Эта функция позволяет мониторить различные базы данных с различными целями с большей эффективностью - например, проверка специфичных запросов к базе данных, статистика использования и прочее. Zabbix поддерживает unixODBC, которая наиболее часто используются в реализациях ODBC API с открытым исходным кодом.

Установка unixODBC

Установка unixODBC на системы на базе RedHat/Fedora с использованием менеджера пакетов yum:

Установка unixODBC на системы на базе SUSE с использованием менеджера пакетов zypper:

Пакет unixODBC-devel требуется для компиляции Zabbix с поддержкой unixODBC.

Установка драйверов unixODBC

Установка MySQL драйвера на системы на базе SUSE с использованием менеджера пакетов zypper:

Настройка unixODBC

Настройка ODBC выполняется редактированием файлов odbcinst.ini и odbc.ini. Для проверки размещения этих файлов введите:

odbcinst.ini используется для перечисления установленных драйверов баз данных ODBC:

Атрибут Описание
mysql Имя драйвера базы данных.
Description Описание драйвера базы данных.
Driver Размещение библиотеки драйвера базы данных.

odbc.ini используется для определения источников данных:

Атрибут Описание
test Имя источника данных (DSN).
Description Описание источника данных.
Driver Имя драйвера базы данных - как указано в odbcinst.ini
Server IP/DNS сервера базы данных.
User Пользователь базы данных для подключения.
Password Пароль к базе данных.
Port Порт подключения к базе данных.
Database Имя базы данных.

Для проверки работает ли соединение ODBC корректно, подключение к базе данных необходимо протестировать. Для этого можно воспользоваться утилитой isql (включена в пакет unixODBC):

Компиляция Zabbix с поддержкой ODBC

Для включения поддержки ODBC, Zabbix должен быть скомпилирован со следующим флагом:

Смотрите более подробную информацию о установке Zabbix из исходных кодов.

Настройка элемента данных в веб-интерфейсе Zabbix

Настройка элемента данных для мониторинга базы данных.


Все обязательные поля ввода отмечены красной звёздочкой.

Специально для элементов данных мониторинга баз данных вы должны указать:

Тип Выберите здесь Монитор баз данных.
Ключ Введите db.odbc.select[уникальное_описание,имя_источника_данных]
Уникальное описание будет служить идентификатором элемента данных в триггерах и тому подобном.
Имя источника данных (DSN) должно быть указано как в настройках odbc.ini.
Имя пользователя Введите имя пользователя для доступа к базе данных (опционально, если пользователь указан в odbc.ini)
Пароль Введите пароль пользователя для доступа к базе данных (опционально, если пароль указан в odbc.ini)
SQL запрос Введите необходимый SQL запрос
Тип информации Очень важно знать какой тип информации будет возвращаться указанным запросом, то есть выберите корректный тип информации здесь. С некорректным типом информации элемент данных станет неподдерживаемым.

Важные замечания

Zabbix не ограничивает время выполнения запроса. Пользователь вправе выбирать запросы, которые могут быть выполнены в разумное время. Значение параметра Timeout с Zabbix сервера используется как время ожидания подключения ODBC (обратите внимание, в зависимости от драйвера ODBC время ожидания подключения может быть проигнорировано). Если запрос возвращает более чем одну колонку, будет прочитана только первая колонка. Если запрос возвращает более чем одну строку, будет прочитана только первая строка. Команда SQL не должна включать в себя переводы строк.

  Возможные возвращаемые значения SQLAllocHandle могут быть:

 

SQL_SUCCESSФункция завершена успешно
SQL_SUCCESS_WITH_INFOФункция завершена успешно, но с предупреждением
SQL_ERRORФункция потерпела неудачу.
SQL_INVALID_HANDLEИдентификатор переданный функции, недействителен

  Выполнилась ли функция успешно или потерпела неудачу, вы можете получить подробную информацию относительно этого, вызывая SQLGetDiagRec или SQLGetDiagField . Они играют ту же самую роль, что и GetLastError в Win32 API.

invoke SQLAllocHandle, SQL_HANDLE_ENV, SQL_HANDLE_NULL, addr hEnv

ВЫБОР ВЕРСИИ ODBC

  После выделения памяти для идентификатора окружения вы должны установить атрибут окружения, SQL_ATTR_ODBC_VERSION , в соответствующее значение. Установка значения атрибута окружения делается, вызовом SQLSetEnvAttr . К настоящему времени вы должны знать, что имеются также функции SQLSetConnectAttr и SQLSetStmtAttr . SQLSetEnvAttr определена как:

  • EnvironmentHandle. Содержит идентификатор окружения, атрибут которого вы хотите установить.
  • Attribute. Константа, которая представляет атрибут, который выхотите установить. Для нашей цели, это - SQL_ATTR_ODBC_VERSION . Вы можете искать полный списокв MSDN.
  • ValuePtr. Значение этого параметра зависит от атрибута, который вы хотите установить. Если атрибут - 32-разрядное значение, этот параметр обрабатывается как значение, которое вы хотите установить. Если атрибут - текстовая строка или двоичный буфер, то это интерпретируется как указатель на строку или буфер. Если вы определяете SQL_ATTR_ODBC_VERSION , то имеются два возможных значения, которые вы можете использовать: SQL_OV_ODBC3 и SQL_OV_ODBC2 , для ODBC версий 3.x и 2.x соответственно.
  • StringLength. Размер значения, указанного ValuePtr . Если значение - строка или двоичный буфер, этот параметр должен быть действителен. Если атрибут, который вы хотите установить - dword, этот параметр игнорируется. С тех пор как SQL_ATTR_ODBC_VERSION атрибут содержит значение dword, вы можете передавать NULL как этот параметр.

  Список возможных возвращаемых значений идентичен SQLAllocHandle.

invoke SQLAllocHandle, SQL_HANDLE_ENV, SQL_HANDLE_NULL, addr hEnv invoke SQLSetEnvAttr, hEnv, SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3, NULL

ВЫДЕЛЕНИЕ ПАМЯТИ ДЛЯ ИДЕНТИФИКАТОРА ПОДКЛЮЧЕНИЯ

  Этот шаг подобен выделению памяти для ид. окружения, вы также вызываете SQLAllocHandle , но передаёте другое значение параметра.

invoke SQLAllocHandle, SQL_HANDLE_ENV, SQL_HANDLE_NULL, addr hEnv invoke SQLSetEnvAttr, hEnv, SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3, NULL invoke SQLAllocHandle, SQL_HANDLE_DBC, hEnv, addr hConn

УСТАНОВКА СВЯЗИ

  Теперь мы готовы сделать попытку фактического подключения к источнику данных через выбранный ODBC драйвер. Имеются фактически три функции ODBC, которые мы можем использовать, чтобы достичь этой цели. Они предлагают различную степень "выбора", который вы можете сделать.

 

SQLConnectЯдроЭто - самая простая функция. Требуется только DSN (название источника Данных) и необязательное название пользователя и пароль. Она не предлагает интерфейса GUI типа подсказки пользователю в виде диалого окна для получения дополнительной информации. Вы должны использовать эту функцию, если вы уже имеете DSN для заданной базы данных.
SQLDriverConnectЯдроЭта функция предлагает более широкий спектр услуг чем SQLConnect. Вы можете соединяться с источником данных, который не определен в системной информации, то есть без DNS. Кроме того, вы можете определить, отобразит ли эта функция диалоговое окно, запрашивающее пользователя для получения дополнительной информации. Например, если вы опустили имя файла базы данных, она будет инструктировать ODBC драйвер об отображении диалогового окна, запрашивающего пользователя выбрать базу данных, для соединения с ней.
SQLBrowseConnectУровень 1Эта функция предлагает перечисление источников данных во время выполнения. Она обеспечивает более гибкий интерфейс в сравнении с SQLDriverConnect, потому что вы можете вызывать SQLBrowseConnect неско раз последовательно, каждый раз запрашивая пользователя для получения более конкретной информации, пока наконец вы не получите рабочую строку подключения.

  Я буду исследовать сначала SQLConnect. Чтобы использовать SQLConnect, вы должны знать кое-что относительно DSN. DSN расшифровывается как Название Источника Данных, т.е. это строка, которая уникально идентифицирует источник данных. DSN идентифицирует строение данных, которое содержит информацию о том, как соединиться с удельным источником данных. Информация включает и то, какой ODBC-драйвер использовать и с какой базой данных соединиться. Вы создаете, изменяете и удаляете DSN, используя 32-разрядного ODBC Администратора в панели управления.

  SQLConnect имеет следующий синтаксис:

  • ConnectionHandle. Идентификатор подключения который вы хотите использовать.
  • pDSN. Указатель на DSN-строку.
  • DSNLength. Длина DSN-строки.
  • pUserName. Указатель на строку содержащую имя пользователя.
  • NameLength. Длинна строки содержащей имя пользователя.
  • pPassword. Указатель на строку содержащую пароль ассоциированный с данным именем пользователя.
  • PasswordLength. Длина пароля

  По минимуму, SQLConnect требует идентификатор соединения, DSN и их длинну: имя пользователя и пароль необязательны, если источник данных не требует их. Список возможных возвращаемых значений идентичен таковому SQLAllocHandle. Предположим мы имеем DSN называемый "Продажи" в нашей системе, и мы хотим соединиться с ним. Мы можем сделать это следующим образом:

  Один из недостатоков SQLConnect - то, что, вы должны создать DSN прежде, чем сможете соединяться с источником данных. SQLDriverConnect предлагает более гибкий вариант. Она имеет следующий синтаксис:

  • ConnectionHandle. Идентификатор соединения.
  • hWnd. Дескриптор вашего окна. Если вы передадите NULL как параметр, драйвер не будет запрашивать пользователя для получения дополнительной информации (если необходимо).
  • pInConnectString.Указатель на строку подключения. Это - ASCIIZ строка, которая отформатирована, согласно специфике ODBC драйвера, с которым вы хотите соединиться. Она описывает название драйвера и источника данных а так же некоторые дополнительные параметры. Полное описание строки подключения можно найти в MSDN. Здесь я не буду углублятся в подробности.
  • InStringLength. Длина строки соединения.
  • pOutConnectString. Указатель на буфер, который будет заполнен законченной строкой подключения. Размер этого буфера должен быть по крайней мере 1,024 байта. Это может звучать запутывающе. Если строка подключения, которую вы передаёте функции, не закончена, то в этом случае, ODBC драйвер может запрашивать пользователя для получения дополнительной информации. ODBC драйвер в этом случае создает законченную строку подключения из всей располагаемой информации и помещает её в буфер. Даже если строка подключения, которую вы составили, была функциональна, этот буфер будет заполнен большим количеством атрибутов. Цель этого параметра - сохранить законченную строку подключения для будущего подключения.
  • OutBufferSize. Размер буфера, указанного pOutConnectString.
  • pOutConnectStringLength. Указатель на dword переменную, которая получит фактическую длину законченной строки подключения, возвращенной ODBC драйвером.
  • DriverCompletion. Флаг, который определяет запросит ли ODBC менеджер/драйвер пользователя для получения дополнительной информации. Однако, флаг зависит от того, передаёте ли вы дескриптор окна hWnd параметру SQLDriverConnect. Если вы не делали этого, ODBC менеджер/драйвер не будет запрашивать пользователя, даже если этот флаг инструктирует об этом.
SQL_DRIVER_PROMPTODBC драйвер запрашивает пользователя относительно информации. Эта информация используется для создания строки подключения.
SQL_DRIVER_COMPLETE
SQL_DRIVER_COMPLETE_REQUIRED
ODBC драйвер запросит пользователя только, если строка подключения, составленная в вашей программе не закончена.
SQL_DRIVER_NOPROMPTODBC драйвер не будет запрашивать пользователя для получения дополнительной информации.
invoke SQLDriverConnect, hConn, hWnd, addr strConnect, sizeof strConnect, addr buffer, sizeof buffer, addr OutBufferLength, SQL_DRIVER_COMPLETE

РАЗЪЕДИНЕНИЕ С ИСТОЧНИКОМ ДАННЫХ

  После того, как подключение сделано успешно, вы можете создать одну или большее количество инструкций и сделать запрос источнику данных. Я буду исследовать эту часть на следующей консультации. Пока, давайте предположим, что вы уже отработали с источником данных, и должны разъединится с ним, вызывая SQLDisconnect. Эта функция проста (Это отражение грубой и грустной действительности о том, что разрушение - намного проще чем конструкция или созидание). Требуется только один параметр, маркер подключения.

УДАЛЕНИЕ ИДЕНТИФИКАТОРОВ ПОДКЛЮЧЕНИЯ И СРЕДЫ

  После успешного разъединения вы можете уничтожить идентификаторы подключения и среды, вызывая SQLFreeHandle. Это - новая функция, вводимая в ODBC 3.x., она заменяет SQLFreeConnect, SQLFreeEnvи SQLFreeStmt. SQLFreeHandle имеет следующий синтаксис:

Первым шагом при реализации доступа к источнику данных посредством ODBC API без применения пула соединений является создание дескриптора окружения. После выделения памяти под дескриптор окружения приложение должно вызвать функцию SQLSetEnvAttr для задания значения атрибуту дескриптора окружения SQL_ATTR_ODBC_VERSION . Если не установить номер версии ODBC API , то при создании дескриптора соединения функция SQLAllocHandle вернет код ответа SQLSTATE равным HY010, что соответствует коду произошедшей ошибки.

После создания дескриптора окружения создаются дескрипторы соединений. Каждый дескриптор соединения формируется вызовом функции SQLAllocHandle с типом дескриптора, равным SQL_HANDLE_DBC . Драйвер выделяет память для хранения информации о соединении и возвращает значение дескриптора соединения. Далее для реального соединения с источником данных вызывается функция SQLConnect или функция SQLDriverConnect.

Для выполнения SQL-операторов создаются дескрипторы операторов. Они позволяют получить доступ к информации о выполненном операторе, имени курсора и атрибутах. Дескриптор оператора формируется вызовом функции SQLAllocHandle со значением типа дескриптора, равным SQL_HANDLE_STMT .

При создании дескриптора оператора драйвер автоматически создает еще четыре дескриптора и записывает указатели на них в атрибуты дескриптора оператора SQL_ATTR_APP_ROW_DESC , SQL_ATTR_APP_PARAM_DESC , SQL_ATTR_IMP_ROW_DESC и SQL_ATTR_IMP_PARAM_DESC . Эти четыре дескриптора называются неявно размещаемыми дескрипторами.

Для явного размещения дескриптора приложения следует вызвать функцию SQLAllocHandle со значением типа дескриптора, равным SQL_HANDLE_DESC . При этом формируется дескриптор , называемый явно размещаемым дескриптором.

Приложение может указать драйверу использовать явно размещенный дескриптор приложения вместо автоматически созданного для данного дескриптора оператора. Для этого следует вызвать функцию SQLSetStmtAttr с атрибутом SQL_ATTR_APP_ROW_DESC или SQL_ATTR_APP_PARAM_DESC .

Явно размещаемые дескрипторы также ассоциируются с дескриптором соединения: они остаются доступны только до тех пор, пока приложение имеет соединение с базой данных. Поскольку явно размещаемые дескрипторы ассоциируются с дескриптором соединения, то приложение может ассоциировать такие дескрипторы с несколькими дескрипторами операторов для данного соединения. Неявно размещаемый дескриптор приложения не может быть ассоциирован более чем с одним дескриптором оператора.

Если явно размещаемый дескриптор освобождается, то дескриптору оператора опять назначается неявно размещаемый дескриптор .

На следующей схеме отображена последовательность действий приложения-клиента для реализации доступа к источнику данных.

Аббревиатура ODBC является сокращением для Open DataBase Connectivity, что можно перевести как «открытый интерфейс доступа к базам данных». Этот интерфейс представляет собой набор функций, которые можно использовать для доступа к любой реляционной СУБД, поддерживающей SQL. На уровне операционной системы ODBC реализуется в виде группы DLL-библиотек, состоящей из драйверов отдельных баз данных (ODBC-драйверов) и так называемого менеджера драйверов , выполняющего роль прослойки между приложением-клиентом и ODBC-драйвером; именно наличие такой прослойки и обеспечивает независимость приложения от конкретного сервера БД.

Последняя версия ODBC, выпущенная в 1997 году, имеет номер 3.51; как показывает практика, для решения большинства типичных задач бывает достаточно версий 2.x, выходивших в период с 1993 по 1995 год. Заметим, что Microsoft официально прекратила развитие ODBC, предлагая в качестве замены технологию ADO (Active Data Objects), которая представляет собой ни что иное, как построенную на базе COM оболочку ядра ODBC.

В основе ODBC лежат следующие четыре понятия:

  1. statement (оператор) — содержит произвольную инструкцию SQL и, возможно, результат ее выполнения; каждый оператор идентифицируется дескриптором, имеющим тип HSTMT , используя этот дескриптор можно получить доступ к состоянию оператора и результату его выполнения;
  2. connection (соединение) — представляет собой канал обмена данными между приложением-клиентом и сервером БД; идентифицируется дескриптором, имеющим тип HDBC ; с каждым таким соединением могут быть связаны один или несколько операторов;
  3. environment (окружение) — глобальный контекст, в котором выполняется доступ к данным; идентифицируется дескриптором, имеющим тип HENV , и может содержать дескрипторы одного или нескольких соединений;
  4. data source (источник данных) — собственно база данных, с которой работает приложение.

Примечание: фактический тип переменных, объявленных как SQLTCHAR , зависит от того, определен ли при компиляции макрос UNICODE.

Рассмотрим основные шаги, которые необходимо предпринять при разработке приложения, использующего механизм ODBC для обращения к базам данных.

1. Создание .dsn файла

Этот файл определяет формат базы данных и ее физическое расположение, а также параметры работы с этой БД ее ODBC-драйвера. Он является обычным текстовым файлом в формате Windows .INI и может быть создан либо вручную, либо с помощью Control Panel . Под Windows 95/98 соответствующий значок называется ODBC Data Sources (32-bit) , а под Windows 2000 он «скрывается» в папке Administrative Tools под именем Data Sources (ODBC) .

Примечание: готовое приложение должно поставляться вместе с .dsn файлом или уметь корректно генерировать его при необходимости, что предпочтительнее.

2. Создание дескриптора окружения

Для этого используется функция

В переменную по адресу phenv будет записан созданный дескриптор окружения. Пример использования:

3. Установление соединения

Вначале необходимо создать дескриптор соединения с помощью функции

Через параметр henv передается дескриптор окружения, в контексте которого будет выполняться соединение. Созданный дескриптор соединения будет записан в переменную по адресу phdbc . Пример использования:

При необходимости, после создания дескриптора назначаются характеристики устанавливаемого соединения. Для этого используется функция

Через параметр hdbc передается дескриптор соединения; параметр swOption должен содержать идентификатор характеристики, а параметр sdwValue — назначаемое ей значение. Например, для того, чтобы драйвер БД самостоятельно обслуживал результаты выполнения операторов, используется вызов

Последним шагом является собственно установление соединения, выполняемое с помощью функции

4. Выполнение оператора SQL

Вначале необходимо создать дескриптор оператора с помощью функции

Через параметр hdbc необходимо передать дескриптор соединения, с которым будет ассоциирован данный оператор. Созданный дескриптор оператора будет записан в переменную по адресу phstmt .

Для выполнения оператора можно использовать функцию

Через параметр hstmt передается дескриптор оператора, а через параметр pStmtText — текст оператора на SQL. Параметр sdwStmtLen должен содержать длину этого текста; для строк, завершающихся двоичным нулем, указывается значение SQL_NTS.

Частным случаем оператора SQL является SQL-запрос, пример выполнения которого приведен ниже:

В результате выполнения SQL-запроса в памяти создается таблица, называемая в терминах ODBC курсором , которая содержит все отобранные данные. Работа с данными этой таблицы рассматривается ниже.

5. Получение информации о результатах выполнения оператора

Для получения количества колонок (полей) в результирующей таблице используется функция

В переменную по адресу pswNumCols будет записано количество колонок в таблице, являющейся результатом выполнения оператора hstmt . Естественно, что вызов этой функции необходим только в том случае, когда количество результирующих колонок заранее не известно.

Для получения атрибутов заданной колонки можно воспользоваться функцией

hstmt Дескриптор оператора. uwColNumber Порядковый номер столбца, начиная с 1. uwAttrID Идентификатор запрашиваемого атрибута. Можно задавать одно из следующих значений: SQL_COLUMN_NAME имя колонки (поля) в БД; SQL_COLUMN_LENGTH размер данных в колонке (размер поля) в символах; SQL_COLUMN_TYPE тип данных в колонке (тип поля). pCharAttr Адрес буфера, в который будет записано значение атрибута, если этот атрибут строковый (например, SQL_COLUMN_NAME). swMaxCharAttr Размер буфера, адресуемого параметром pCharAttr . pswCharAttrLen Адрес переменной, в которую будет записана реальная длина строки, скопированной по адресу pCharAttr . pNumAttr Адрес переменной, в которую будет записано значение атрибута, если этот атрибут числовой (например, SQL_COLUMN_LENGTH). Как правило, такая переменная должна иметь тип SDWORD .

При получении значений строковых атрибутов параметр pNumAttr можно задавать равным NULL, а при получении значений числовых атрибутов можно задавать нулевыми параметры pCharAttr , swMaxCharAttr и pswCharAttrLen .

ODBC предусматривает следующие типы полей:

6. Доступ к результатам выполнения оператора

Результаты выполнения любого оператора SQL ассоциируются с его дескриптором и приложение не имеет к ним непосредственного доступа. Чтобы получить значения полей в результирующей таблице необходимо предварительно связать с каждой из интересующих нас колонок переменную соответствующего типа. В терминах ODBC эта операция называется binding и выполняется с помощью функции

hstmt Дескриптор оператора. uwColNumber Порядковый номер колонки, начиная с 1. swColType Тип данных в колонке. Бывает, что его приходится подбирать опытным путем. pDest Адрес буфера, в который будет записываться значение поля. sdwDestSize Размер буфера, адресуемого параметром pDest , в байтах. psdwInd Адрес переменной, в которую будет записываться информация о результатах получения данных.

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

После связывания всех необходимых колонок выполняется построчное чтение данных. В терминах ODBC эта операция называется fetching и выполняется с помощью функции

Через параметр hstmt передается дескриптор оператора. Каждый вызов этой функции записывает в переменные, связанные с колонками, значения соответствующих полей текущей записи, после чего делает текущей следующую запись. Функция должна циклически вызываться до тех пор, пока не будет достигнут конец результирующей таблицы (то есть, пока она возвращает значение SQL_SUCCESS или SQL_SUCCESS_WITH_INFO). Для проверки возвращаемого значения можно воспользоваться макросом

и организовать, например, следующий цикл:

7. Освобождение системных ресурсов

После завершения работы с базой данных необходимо «удалить» каждый созданный оператор с помощью функции

Через параметр hstmt передается дескриптор удаляемого оператора, а через параметр uwOption — характер удаления. Для полного освобождения системных ресурсов, занятых оператором и результатами его выполнения, необходимо сделать два последовательных вызова:

После удаления всех операторов необходимо разорвать соединение с сервером БД вызовом функции

и удалить дескриптор этого соединения с помощью функции

В обоих случаях, через параметр hdbc передается дескриптор разрываемого соединения.

Последним шагом является удаление дескриптора окружения, выполняемое при помощи функции

которой через параметр henv нужно передать подлежащий удалению дескриптор.

Заметим, что операция установления соединения с базой данных является наиболее длительной из всех, поэтому для обеспечения максимального быстродействия приложения-клиента целесообразно выполнять ее один раз (при запуске) и разрывать это соединение только перед завершением работы приложения.

В первую очередь необходимо сделать курсор, создаваемый функцией SQLExecDirect , статическим (по умолчанию он обеспечивает возможность только однократного последовательного прохода по всем строкам выборки). Для решения этой задачи можно использовать функцию

Она позволяет для оператора hstmt назначить значение атрибута с идентификатором uwOption равным udwValue . В нашем случае необходимо в качестве идентификатора атрибута указать значение SQL_CURSOR_TYPE (тип курсора), а в качестве назначаемого значения этого атрибута — SQL_CURSOR_STATIC (статический курсор).

Начиная с ODBC версии 3.0 можно также воспользоваться функцией

Параметр hstmt , как и в предыдущем случае, определяет оператор, заданный атрибут которого необходимо изменить. Идентификатор изменяемого атрибута передается через параметр sdwAttr и в нашем случае должен быть задан равным SQL_ATTR_CURSOR_TYPE. Назначаемое значение необходимо передать через параметр pValue , причем для строковых атрибутов он должен содержать адрес строки ( SQLCHAR* ), а для числовых — величину типа UDWORD . Еще раз подчеркнем, что в последнем случае необходимо передать значение атрибута, приведенное к типу void* . Для создания статического курсора, как и в предыдущем случае, используется значение SQL_CURSOR_STATIC. Через параметр sdwStrLen необходимо передать длину строки, адресуемой параметром pValue ; для числовых атрибутов значение этого параметра игнорируется и может быть задано равным нулю.

После изменения типа курсора можно обычным образом выполнить оператор с помощью функции SQLExecDirect , рассмотренной выше.

Для перемещения по строкам статического курсора можно воспользоваться универсальной функцией

Через параметр hstmt передается дескриптор оператора, параметр swType задает тип перемещения, а параметр sdwOffset — требуемое смещение в результирующей таблице (курсоре). Возможные значения последнего параметра зависят от типа перемещения и приведены ниже:

swType sdwOffset
значениеописание
SQL_FETCH_FIRST перемещение к первой строке игнорируется
SQL_FETCH_LAST перемещение к последней строке игнорируется
SQL_FETCH_NEXT перемещение к следующей строке игнорируется
SQL_FETCH_PRIOR перемещение к предыдущей строке игнорируется
SQL_FETCH_ABSOLUTE перемещение к строке с номером sdwOffset номер строки
SQL_FETCH_RELATIVE перемещение на sdwOffset строк от текущей смещение

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

Поскольку нумерация строк начинается с 1, то можно переместиться на последнюю строку и получить ее номер, который и будет соответствовать искомому значению. Для получения номера текущей строки можно воспользоваться функцией

Она позволяет для оператора hstmt получить значение атрибута с идентификатором uwOption . В нашем случае в качестве идентификатора необходимо указать значение SQL_ROW_NUMBER (номер строки). Через параметр pValue необходимо передать адрес переменной, в которую будет записано значение атрибута; при получении номера текущей строки эта переменная должна иметь тип SDWORD .

Начиная с ODBC версии 3.0 для получения атрибута оператора можно использовать функцию

Параметр hstmt , как и в предыдущем случае, определяет оператор, для которого требуется получить значение атрибута. Идентификатор атрибута необходимо передать через параметр sdwAttr , в нашем случае он задается равным SQL_ATTR_ROW_NUMBER. Через параметр pValue передается адрес переменной, в которую будет записано значение атрибута. Параметр sdwSize должен содержать размер буфера, адресуемого pValue ; для числовых атрибутов этот параметр игнорируется, а для строк в кодировке Unicode он должен быть четным числом. И наконец, через параметр psdwStrLen передается адрес переменной, в которую будет записана длина возвращенной строки; для числовых атрибутов его можно задавать равным NULL.

Примером получения количества строк в результирующей таблице может служить следующий код:

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

Если проверка возвращаемого значения какой-либо функции ODBC макросом SQL_SUCCEEDED дает ложный результат, то для получения подробной информации о возникшей ошибке необходимо сразу же вызвать функцию

Все, что необходимо начинающему и опытному программисту

Стандарт ODBC

ODBC — это стандарт, описывающий систему интерфейсов, с помощью которых прикладные программы могут обращаться к базам данных и обрабатывать их независимым от СУБД способом. ODBC предоставляет интерфейсы для доступа к реляционным базам данных и базам данных с табличной организацией. Широкое распространение стандарт получил благодаря поддержке Майкрософт.

На рис. 3.19 схематично изображена архитектура ODBC.


Рис. 3.19. Архитектура ODBC

Как видно из рисунка, приложение обращается к диспетчеру драйверов, а диспетчер, в свою очередь, обращается к источнику данных и производит с ними какие-либо действия. Источник данных — это база данных, приложение, операционная система пли даже некая аппаратная платформа. Приложение инициирует запросы на установление соединения с источником данных, на выполнение каких-либо действий с базой данных.

Стандарт ODBC предоставляет разработчику набор интерфейсов для выполнения каждого из этих запросов и регламентирует стандартные коды ошибок, которые будут возвращены приложению в случае неудачного выполнения запроса.

Диспетчер драйверов (driver manager) служит связующим звеном между приложениями и драйверами СУБД. Когда приложение инициирует соединение с базой данных, диспетчер определяет тип СУБД и загружает соответствующий драйвер в память (или использует ранее загруженный). Диспетчер драйверов обрабатывает запросы на инициализацию соединения и контролирует формат запросов и порядок их поступления от приложения. Диспетчер драйвера является частью Windows.

Драйвер (driver) обрабатывает запросы, поступающие от приложения, преобразует их в набор команд API СУБД и, таким образом, производит какие-либо действия с базой данных. Драйвер отвечает за то, чтобы стандартные команды ODBC выполнялись корректно. В некоторых случаях источит; данных не поддерживает некоторые функции, таким образом, их приходится выполнять драйверу. Если источник имеет полную поддержку SQL, то драйвер всего лишь передает запрос на обработку и получает результаты. На драйвере также лежит функция приведения кодов ошибок, поступающих от источника, к стандартным, определенным в ODBC.

Определяют два типа драйверов — одноуровневые и многоуровневые. Одноуровневые обрабатывают вызовы ODBC и операторы SQL. Многоуровневые обрабатывают только вызовы ODBC, оставляя СУБД осуществлять обработку SQL-запросов.

Уровни соответствия

Уровень соответствия ODBC (ODBC conformance level) описывает то, какие возможности и функции доступны через API (интерфейс прикладных программ) драйвера, API драйвера содержит набор функций, которые может вызывать приложение для обращения к интерфейсам источника данных. Различают несколько уровней соответствия ODBC, обеспечивающих разные наборы возможностей:

Базовый уровень (Core API):

• соединение с источником данных;
• подготовка и выполнение SQL-запросов;
• получение результирующего набора данных;
• фиксация и откат транзакций;
• получение информации об ошибках.

Первый уровень (Level I API):

• соответствие ODBC на базовом уровне;
• получение информации о параметрах, возможностях и функциях драйвера;
• соединение с источниками данных, содержащих информацию, специфичную для драйвера;
• получение информации из каталога.

Второй уровень (Level 2 API):

• соответствие ODBC па первом и базовом уровнях;
• обзор возможных соединений и источников данных;
• использование диалекта SQL данной СУБД;
• вызов библиотеки преобразований;
• обработка двунаправленных курсоров.

Если какой-либо драйвер не поддерживает требуемый приложению уровень, то программист может реализовать нужные функции самостоятельно, обрабатывая данные, получаемые из источника соответствующим образом.

Уровни соответствия SQL определяют, какие SQL-операторы, выражения и типы данных доступны драйверу на данном уровне. Стандартом определены три уровня соответствия SQL.

Минимальный синтаксис (Minimum SQL grammar):

• CREATE TABLE, DROP TABLE;
• оператор SELECT (без вложенных подзапросов);
• INSERT, UPDATE, DELETE;
• простые выражения (сравнения, арифметические операции);
• типы данных CHAR, VARCHAR, LONGCHAR.

Базовый синтаксис (Core SQL grammar):

• минимальный синтаксис;
• ALTER TABLE, TREATE INDEX, DROP INDEX;
. CREATE VIEW, DROP VIEW;
• GRANT, REVOKE;
• полный синтаксис оператора SELECT;
• встроенные функции SUM, COUNT, MAX, MIN, AVG.

Расширенный синтаксис (Extended SQL grammar):

• базовый синтаксис;
• UPDATE и DELETE с использованием позиции курсора;
• скалярные функции SUBSTRING и ABS;
• переменные даты, времени и временная метка;
• пакетная обработка операторов SQL;
• хранимые процедуры.

Приложение может вызвать драйвер и определить, какой уровень соответствия SQL он поддерживает,

Драйверы ODBC могут поддерживать многопоточность (multithreaded driver), то есть с одним драйвером могут одновременно работать несколько приложении в синхронном режиме, л нося какие-либо изменения в источник данных. В случае, если драйвер не является многопоточным, он работает только в асинхронном режиме.

Читайте также: