Logo Море(!) аналитической информации!
IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware
VPS/VDS серверы. 30 локаций на выбор

Серверы VPS/VDS с большим диском

Хорошие условия для реселлеров

4VPS.SU - VPS в 17-ти странах

2Gbit/s безлимит

Современное железо!

Бесплатный конструктор сайтов и Landing Page

Хостинг с DDoS защитой от 2.5$ + Бесплатный SSL и Домен

SSD VPS в Нидерландах под различные задачи от 2.6$

✅ Дешевый VPS-хостинг на AMD EPYC: 1vCore, 3GB DDR4, 15GB NVMe всего за €3,50!

🔥 Anti-DDoS защита 12 Тбит/с!

2004 г

MySQL: Руководство по ODBC и MyODBC. Версия 1.0. 20 апреля 2004 г.

Алексей Паутов,
Все о MySQL на русском: http://www.botik.ru/~rldp/mysql.htm, ftp://ftp.botik.ru/rented/rldp/www/pub
Russian LDP: http://www.botik.ru/~rldp, ftp://ftp.botik.ru/rented/rldp

содержание

3 Разработка прикладных программы, используя MyODBC

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

3.1 Базисные шаги прикладной программы MyODBC

В общем виде, чтобы работать с сервером MySQL из любой программы через ODBC/MyODBC, надо сделать следующее:

  • Настроить MyODBC DSN
  • Подключиться к серверу MySQL
  • Провести инициализацию
  • Выполнить команды SQL
  • Получить результаты
  • Обработать транзакции
  • Отсоединиться от сервера

Большинство прикладных программ использует некоторое изменение этих шагов.

3.2 Настройка MyODBC DSN

Источник данных идентифицирует путь для данных, который может включать сетевую библиотеку, сервер, базу данных и другие атрибуты. В нашем случае источник данных представляет собой путь к базе данных MySQL. Чтобы соединиться с источником данных, Driver Manager проверяет системный реестр Windows для получения специфической информации подключения.

ODBC Driver Manager и MyODBC Drivers использует вход системного реестра, созданный ODBC Data Source Administrator . Этот вход содержит информацию относительно каждого источника данных и связанного с ним драйвера. Прежде, чем Вы сможете соединяться с источником данных, информация о подключении должна быть добавлена к системному реестру.

Чтобы добавлять и конфигурировать источники данных, используйте ODBC Data Source Administrator. ODBC Administrator модифицирует информацию о подключениях к источникам данных. Поскольку Вы добавляете источники данных, ODBC Administrator модифицирует информацию системного реестра для них.

Чтобы открыть ODBC Administrator из Control Panel:

  • Нажмите Start, укажите на Settings и щелкните Control Panel .
  • На системах под Microsoft Windows 2000 дважды щелкните по Administrative Tools, а затем дважды щелкните по Data Sources (ODBC). На компьютерах под предыдущими версиями Microsoft Windows дважды щелкните по 32-bit ODBC или по ODBC.

Чтобы добавить источник данных в Windows:

  1. Откройте ODBC Data Source Administrator.
  2. В диалоговом окне ODBC Data Source Administrator нажмите Add. Откроется диалоговое окно Create New Data Source.
  3. Выберите там MySQL ODBC 3.51 Driver и нажмите на Finish. Появится диалоговое окно MySQL ODBC 3.51 Driver - DSN Configuration.
  4. В окне Data Source Name впечатайте имя источника данных, к которому Вы хотите обращаться. Это может быть любое имеющее силу имя, которое понравилось.
  5. В окне Description введите описание необходимое для DSN.
  6. В окне Host or Server Name (or IP) напечатайте имя сервера MySQL, к которому Вы хотите обращаться. По умолчанию это local host.
  7. В окне Database Name укажите имя MySQL базы данных, которая будет применяться как заданная по умолчанию база данных.
  8. В окне User задайте имя пользователя базы данных (user ID).
  9. В окне Password надо задать пароль.
  10. В окне Port напечатайте номер порта, если это не значение по умолчанию 3306.
  11. В окне SQL Command Вы можете вводить факультативную команду SQL, которую серверу надлежит выполнить сразу после установления подключения.

Теперь нажмите OK, чтобы добавить этот источник данных. Обратите внимание: при щелчке на OK диалоговое окно Data Sources dialog, и ODBC Administrator модифицирует информацию системного реестра. Имя пользователя и строка подключения станут заданными по умолчанию значениями подключения для этого источника данных. Вы можете также проверить, достаточны ли Ваши параметры настройки, чтобы соединиться с сервером, используя кнопку Test Data Source. Эта возможность появилась только начиная с MyODBC 3.51.

Driver Options: Вы можете также видеть кнопку Options, которая отобразит диалог дополнительных параметров, которые управляют поведением драйвера.

Обратите внимание, что параметры Driver Trace Options будут заблокированы (нарисованы серым цветом) при использовании обычной версии DLL.

Чтобы изменить источник данных в Windows:

  1. Откройте окно ODBC Data Source Administrator . Выберите соответствующую вкладку DSN.
  2. Выберите источник данных MySQL, который Вы хотите изменить, а затем нажмите modify и щелкните по Configure. Откроется диалоговое окно MySQL ODBC 3.51 Driver - DSN Configuration.
  3. Измените соответствующие поля источника данных, а затем нажмите OK.

Когда Вы закончите изменять информацию в этом диалоговом окне, ODBC Administrator модифицирует информацию системного реестра.

Чтобы настроить источник данных в Unix:

В Unix Вы можете конфигурировать DSN-входы непосредственно в файле ODBC.INI. Имеется пример файла odbc.ini с myodbc как DSN-имя для MyODBC 2.50 и myodbc3 для MyODBC 3.51 Drivers:

  ;
  ;  odbc.ini configuration for MyODBC and MyODBC 3.51 Drivers
  ;
  [ODBC Data Sources]
  myodbc  = MySQL ODBC 2.50 Driver DSN
  myodbc3 = MySQL ODBC 3.51 Driver DSNа

  [myodbc]
  Driver      = /usr/local/lib/libmyodbc.so
  Description = MySQL ODBC 2.50 Driver DSN
  SERVER      = localhost
  PORT        =
  USER        = root
  Password    =
  Database    = test
  OPTION      = 3
  SOCKET      =

  [myodbc3]
  Driver      = /usr/local/lib/libmyodbc3.so
  Description = MySQL ODBC 3.51 Driver DSN
  SERVER      = localhost
  PORT        =
  USER        = root
  Password    =
  Database    = test
  OPTION      = 3
  SOCKET      =

  [Default]
  Driver      = /usr/local/lib/libmyodbc3.so
  Description = MySQL ODBC 3.51 Driver DSN
  SERVER      = localhost
  PORT        =
  USER        = root
  Password    =
  Database    = test
  OPTION      = 3
  SOCKET      =

Обратите внимание: если Вы используете unixODBC, то Вы можете использовать следующие инструментальные средства чтобы настроить DSN:

3.3 Параметры подключения

Можно определять следующие параметры для MyODBC или для MyODBC 3.51 в секции [Data Source Name] файла ODBC.INI или через параметр InConnectionString в вызове SQLDriverConnect().

Параметр Значение по умолчанию Комментарий
user ODBC (в Windows) Имя пользователя для связи с MySQL.
server localhost Имя сервера MySQL.
database База данных по умолчанию
option 0 Целое число, которым Вы можете определять как должен работать MyODBC 3.51. Описано чуть ниже.
port 3306 Порт TCP/IP, чтобы использовать, если server не равен localhost.
stmt Инструкция, которая будет выполнена, когда установлено подключение к MySQL.
password Пароль для комбинации server user.
socket Сокет или именованный канал Windows для связи.

Параметр OPTION используется, чтобы сообщить MyODBC 3.51, что пользователь не на 100% совместим с ODBC. Следующие параметры перечислены в том же самом порядке, в каком они появляются в MyODBC 3.51:

Бит Описание
1 Пользователь не может обрабатывать ситуацию, когда MyODBC возвращает реальную ширину столбца.
2 Пользователь не может обрабатывать ситуацию, когда MySQL возвращает истинное число обработанных строк. Если этот параметр установлен, MySQL вернет число найденных строк. Нужно иметь MySQL 3.21.14 или более новый, чтобы это работало.
4 Создать протокол трассировки в файле c:\myodbc.log (/tmp/myodbc.log). Это аналогично указанию MYSQL_DEBUG=d:t:O,c::\myodbc.log в AUTOEXEC.BAT.
8 Не устанавливать ограничений пакета для результатов и параметров.
16 -Не запрашивать ничего, даже если драйвер хочет запросить.
32 Включить или отключить поддержку динамического курсора. Это не работает в MyODBC 2.50.
64 Игнорировать использование имени базы данных в формате database.table.column.
128 Использование экспериментальных курсоров ODBC manager.
256 Отключить использование расширенной (экспериментальной) выборки.
512 Дополнить поля типа CHAR до полной длины столбца.
1024 SQLDescribeCol() возвратит полностью квалифицированные имена столбцов.
2048 Использовать сжатый протокол клиент-сервер.
4096 Сервер должен игнорировать пробел между именем функции и '(' (нужно для Power Builder). Это делает все ключевые слова именами функций!
8192 Соединиться через именованный канал с сервером mysqld под NT.
16384 Менять столбцы типа LONGLONG на столбцы INT (некоторые прикладные программы не могут корректно обрабатывать LONGLONG).
32768 Вернуть user как Table_qualifier и Table_owner из SQLTables.
65536 Читать параметры из групп client и odbc в файле my.cnf
131072 Добавить некоторые дополнительные проверки безопасности (вроде бы не очень и надо, но...).
262144 Выключить использование транзакций
524288 Включить регистрацию запросов в файле c:\myodbc.sql (/tmp/myodbc.sql). Доступно только в режиме отладки в специальной версии драйвера.

Если Вы хотите иметь много параметров, Вы должны сложить вышеупомянутые числа. Например, установка опции в 12 (4+8) дает Вам отладку без ограничений на размеры пакета.

По умолчанию MYODBC3.DLL компилируется для оптимальной эффективности. Если Вы хотите отладить MyODBC 3.51 (например, чтобы получить трассировку), используйте MYODBCD3.DLL вместо стандартного файла MYODBC3.DLL.

3.4 Связь с сервером MySQL

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

  • Распределите дескриптор среды
  • Установите версию ODBC
  • Распределите дескриптор подключения
  • Установите факультативные атрибуты подключения перед подключением
  • Создайте подключение к серверу
  • Установите факультативные атрибуты подключения после подключением

3.4.1 Распределение дескриптора среды

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

Чтобы распределить правильный дескриптор среды, прикладная программа:

  1. Объявляет переменную типа SQLHENV. Например, прикладная программа могла бы использовать объявление:
    SQLHENV henv;
    
  2. Вызывает SQLAllocHandle (в MyODBC 2.50 называется SQLAllocEnv) и передает адрес этой переменной и опции SQL_HANDLE_ENV как:
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv) или
    SQLAllocEnv(&henv)
    

Если прикладная программа связана через Driver Manager, то это обращение загружает Driver Manager. Он не вызывает SQLAllocHandle в драйвере потому, что пока не знает, который драйвер вызвать. Это откладывает вызов SQLAllocHandle в драйвере до получения вызовов из прикладной программы, чтобы соединиться с источником данных: тогда-то будет однозначно ясно, какой драйвер нужен.

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

3.4.2 Установка версии ODBC

Если Вы используете драйвер MyODBC 2.50, то Вы можете игнорировать этот раздел. Прежде, чем прикладная программа создаст соединение, необходимо установить атрибут SQL_ATTR_ODBC_VERSION среды, используя SQLSetEnvAttr:

SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, 0);

Этот атрибут заявляет, что прикладная программа следует спецификациям ODBC 2.x или ODBC 3.x при использовании следующих элементов:

  • SQLSTATE: Много значений SQLSTATE различны в ODBC 2.x и ODBC 3.x. Для получения списка кодов SQLSTATE, возвращаемых драйвером MyODBC 3.51 обратитесь к разделу " Коды ошибок MyODBC".
  • Типы Date, Time и Timestamp: следующая таблица показывает идентификаторы типов для данных date, time и timestamp в ODBC 2.x и в ODBC 3.x.
ODBC 2.X ODBC 3.X
Идентификаторы типов в SQL
SQL_DATE SQL_TYPE_DATE
SQL_TIME SQL_TYPE_TIME
SQL_TIMESTAMP SQL_TYPE_TIMESTAMP
Идентификаторы типов в C
SQL_C_DATE SQL_C_TYPE_DATE
SQL_C_TIME SQL_C_TYPE_TIME
SQL_C_TIMESTAMP SQL_C_TYPE_TIMESTAMP

MyODBC 3.51 контролирует версию спецификации ODBC, для которой прикладная программа написана и отвечает соответственно. Например, если прикладная программа следует версии ODBC 2.x и вызывает SQLExecute до вызова SQLPrepare, драйвер вернет: SQLSTATE S1010 (Function sequence error). Если прикладная программа поддерживает спецификацию ODBC 3.x, то это возвращает: SQLSTATE HY010 (Function sequence error).

3.4.3 Распределение дескриптора подключения

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

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

  • Прикладная программа объявляет переменную типа SQLHDBC.
  • Она затем вызывает SQLAllocHandle (или SQLAllocConnect для версии MyODBC 2.50) и передает адрес этой переменной, дескриптор среды, чтобы распределить подключение, и опцию SQL_HANDLE_DBC. Например:
    SQLHDBC hdbc;
    SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc); или
    SQLAllocConnect(henv, &hdbc);
    

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

3.4.4 Установка атрибутов соединения (подключения)

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

Атрибуты подключения установлены с помощью SQLSetConnectAttr, а их текущие параметры настройки могут быть получены с помощью SQLGetConnectAttr. Для прикладных программ драйвера MyODBC 2.50 Вы можете использовать SQLSetConnectOption и SQLGetConnectOption.

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

Атрибуты, которые определяют, использовать ли библиотеку курсоров ODBC (SQL_ATTR_ODBC_CURSORS) и сетевой размер пакета (SQL_ATTR_PACKET_SIZE), должны быть установлены прежде, чем соединение создано потому что, библиотека курсоров ODBC находится между Driver Manager и драйвером, а следовательно должно быть загружена перед драйвером. Подробный перечень атрибутов подключения, поддерживаемых драйверами MyODBC, есть в разделе "4.5.1 SQLSetConnectAttr".

3.4.5 Установление подключения, использующего MyODBC

После распределения среды и дескрипторов подключения и установки факультативных атрибутов подключения, прикладная программа готова соединиться с сервером MySQL или драйвером MyODBC (через Driver Manager). Имеются две различных функции для этого:

  • SQLConnect и
  • SQLDriverConnect
3.4.5.1 Соединение через SQLConnect

SQLConnect самая простая функция подключения. Требует имя источника данных и принимает факультативные user ID и пароль. Прикладная программа передает следующую информацию драйверу через SQLConnect:

DSN: имя источника данных.
UID: имя пользователя для связи с сервером (опционально).
PWD: соответствующий пароль (опционально).

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

Когда из прикладной программы вызван SQLConnect, Driver Manager использует имя источника данных, чтобы прочитать имя драйвера DLL из соответствующего раздела файла ODBC.INI или из системного реестра. Это затем загружает драйвер DLL и передает ему параметры SQLConnect. Если драйвер нуждается в дополнительной информации, чтобы соединиться с источником данных, он читает эту информацию из того же самого раздела файла ODBC.INI.

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

Пример: следующий пример распределяет необходимую среду, дескриптор подключения и соединяется с сервером MySQL, используя DSN myodbc3.

SQLHENV    henv;
SQLHDBC    hdbc;
SQLHSTMT   hstmt;
SQLRETURN  retcode;

/* Allocate environment handle */
retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
{
   /* Set the ODBC version environment attribute to version 3 */
   retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION,
                           (SQLPOINTER)SQL_OV_ODBC3, 0);
   if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
   {
      /* Allocate connection handle */
      retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
      if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
      {
         /* Connect to data source myodbc3 */
         retcode = SQLConnect(hdbc, (SQLCHAR*) "myodbc3", SQL_NTS,
                              (SQLCHAR*) "myuser", SQL_NTS,
                              (SQLCHAR*) "mypassword", SQL_NTS);
         if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
         {
            /* Set auto commit to ON */
            retcode = SQLSetConnectAttr(hdbc, SQL_ATTR_AUTO_COMMIT,
                                        SQL_AUTOCOMMIT_ON,0);
            printf("\n autocommit returned :%d", redcode);
            /* Allocate statement handle */
            retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
         if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
            {
               /* Process data */
                  ;
                  ;
                  ;
               /* Free stattemt handle */
               SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
            }
            /* Disconnect from the server */
            SQLDisconnect(hdbc);
         }
         /* Close the connection handle */
         SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
      }
   }
   /* Close the environment handle */
   SQLFreeHandle(SQL_HANDLE_ENV, henv);

3.4.5.2 Связь через SQLDriverConnect

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

  • Позволить прикладной программе использовать специфическую для драйвера информацию подключения.
  • Чтобы драйвер запрашивал пользователя относительно информации подключения.
  • Соединяться без определения источника данных (DSN less connection).

Строка подключения может состоять из одного или большего количества параметров MyODBC подключения, отделяемых точкой с запятой (;). Если драйвер должен запрашивать пользователя относительно информации подключения, то он отображает диалог подключения.

3.4.5.3 Строка подключения для SQLDriverConnect

Используя myodbc3 как MySQL ODBC 3.51 DSN:

ConnectionString = "DSN=myodbc3"

DSN Less Connection:

ConnectionString = "DRIVER={MySQL ODBC 3.51 Driver}; SERVER=localhost;\
                    DATABASE=test; USER=monty; PASSWORD=monty;\
                    OPTION=4;"
3.4.6 Получение информации о драйвере и источнике данных

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

  • SQLGetInfo: возвращает общую информацию относительно драйвера и источника данных, связанного с подключением. Например, какие инструкции SQL прикладная программа выполнит? Прикладная программа использует скроллируемые курсоры? Транзакции? Процедуры? Длинные данные?
  • SQLGetTypeInfo: возвращает информацию относительно типов данных, поддерживаемых сервером. Драйвер возвращает информацию в форме набора результатов SQL. Типы данных предназначены для использования в инструкциях Data Definition Language (DDL).
  • SQLGetFunctions: возвращает информацию относительно того, поддерживает ли драйвер специфическую функцию ODBC. Прикладная программа может всегда использовать эту функцию, чтобы проверить, поддерживает ли драйвер некий API или нет.

    Пример: получает имя драйвера и версию, имя и версию сервера и соглашения SQL, поддерживаемые драйвером.

    SQLHDBC     hdbc;
    SQLRETURN   retcode;
    SQLCHAR     strValue[50];
    SQLINTEGER  nValue;
    SQLSMALLINT pcbValue;
    
    /* Connect to the server */
    retcode = SQLConnect (..)
    if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
    {
       /* get the driver name */
       retcode = SQLGetInfo(hdbc, SQL_DRIVER_NAME,
                            strValue, 50, &pcbValue);
       if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
       {
          printf("driver name:%s",strValue);
       }
       /* get the driver version */
       retcode = SQLGetInfo(hdbc, SQL_DRIVER_VER, 
    	           strValue, 50, &pcbValue);
       if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
       {
          printf("driver version:%s",strValue);
       }
       /* get the server name */
       retcode = SQLGetInfo(hdbc, SQL_DBMS_NAME, 
    	           strValue, 50, &pcbValue);
       if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
       {
          printf("server name:%s",strValue);
       }
       /* get the SQL conformance*/
       retcode = SQLGetInfo(hdbc, SQL_SQL_CONFORMANCE,
                            &nValue, 0, &pcbValue);
       if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
       {
          printf("SQL Conformance:%d",nValue);
       }
    }
    
    3.4.7 Прерывание соединения

    Когда прикладная программа закончила использовать сервер MySQL, она должна в обязательном порядке закрыть подключение и освободить все предварительно распределенные дескрипторы. Чтобы завершать подключение из MyODBC нужно:

    • Вызвать SQLDisconnect, чтобы закрыть подключение. Если имеются любые открытые операторные дескрипторы на этом подключении, то драйвер внутренне освобождает все открытые инструкции для этого подключения. Прикладная программа может затем использовать дескриптор подключения, чтобы повторно соединиться с тем же самым источником данных или присоединиться к другому источнику данных, если дескриптор подключения не был освобожден.
    • Вызвать SQLFreeHandle с опцией SQL_HANDLE_DBC, чтобы освободить подключение и все ресурсы, связанные с дескриптором.
    • Вызвать SQLFreeHandle с опцией SQL_HANDLE_ENV, чтобы освободить среду и все ресурсы, связанные с дескриптором.

    Обратите внимание, если Вы используете драйвер MyODBC 2.50, Вы должны использовать SQLFreeConnect и SQLFreeEnv, чтобы освободить дескрипторы подключения и среды соответственно.

    3.5 Выполнение команд SQL

    Ну ладно, подключение установлено, а дальше-то что? Надо работать с сервером, для этого все и затевалось. Работа эта происходит на базе обмена командами SQL и их результатами. Вот это самое сложное. Прикладная программа может представлять на рассмотрение любую инструкцию SQL, поддерживаемую сервером MySQL. ODBC-программы выполняют почти весь доступ к базе данных, выполняя инструкции SQL. Общая последовательность событий:

    • Распределите операторный дескриптор
    • Установите факультативные операторные атрибуты,
    • Выполните инструкцию,
    • Соберите все результаты и наконец
    • Освободите операторный дескриптор.
    3.5.1 Распределение операторного дескриптора

    Операторный дескриптор обеспечивает доступ к операторной информации, типа сообщений об ошибках, имени курсора и информации состояния для обработки инструкции SQL. Прежде, чем прикладная программа сможет представлять на рассмотрение серверу инструкцию SQL, она должна распределить операторный дескриптор, используя SQLAllocHandle (или SQLAllocStmt в MyODBC 2.50):

    • Прикладная программа объявляет переменную типа HSTMT. Это затем вызывает SQLAllocHandle и передает адрес этой переменной, дескриптор подключения, чтобы распределить инструкцию, и опцию SQL_HANDLE_STMT:
      SQLHSTMT hstmt;
      SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt) или
      SQLAllocStmt(hdbc, &hstmt)
      
    • Driver Manager распределяет структуру, чтобы сохранить информацию относительно инструкции и вызывает SQLAllocHandle в драйвере с опцией SQL_HANDLE_STMT.
    • Драйвер распределяет собственную структуру, чтобы сохранить информацию относительно инструкции и возвращает дескриптор инструкции драйвера назад в Driver Manager. С другой стороны, если Вы компонуете программу непосредственно с драйвером, то именно сам драйвер распределяет операторную структуру и возвращает ее адрес обратно прикладной программе.
    • Driver Manager возвращает дескриптор инструкции прикладной программе.

    Драйвер идентифицирует, которую инструкцию надо использовать при вызове функций ODBC через дескриптор инструкции.

    3.5.2 Установка операторных атрибутов

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

    Операторные атрибуты могут быть установлены с помощью SQLSetStmtAttr, а их актуальные параметры настройки можно узнать через вызов SQLGetStmtAttr (SQLSetStmtOption и SQLGetConnectOption соответственно для MyODBC 2.50). Поскольку решительно все операторные атрибуты имеют значения по умолчанию, прикладная программа не обязана их менять, можно оставить все как есть.

    3.5.3 Передача на рассмотрение инструкций SQL

    MyODBC позволяет прикладной программе представлять на рассмотрение инструкции SQL двумя различными способами:

    • Подготовленное выполнение
    • Прямое выполнение

  • 3.5.3.1 Подготовленное выполнение

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

    Подготовленное выполнение более предпочтительно, если прикладная программа:

    • Выполняет инструкцию больше одного раза, меняя значения параметра.
    • Нуждается в информации относительно инструкции SQL или набора результатов до выполнения.

    Подготовленное выполнение главным образом достигнуто через MyODBC API SQLPrepare и SQLExecute. Подготовленная инструкция выполняется быстрее, чем неприготовленная инструкция или прямое выполнение потому, что драйвер компилирует инструкцию, строит для нее план доступа и возвращает идентификатор плана доступа обратно прикладной программе. Драйвер минимизирует затраты времени на обработку инструкции, поскольку он не должен каждый раз строить план доступа. Уменьшается и трафик.

    Чтобы подготовить и выполнить инструкцию, прикладная программа:

    • Вызывает SQLPrepare и передает строку, содержащую инструкцию SQL.
    • Устанавливает значения любых операторных параметров.
    • Вызывает SQLExecute и делает любую дополнительную обработку, которая является необходимой, типа выборки данных.
    • По мере надобности повторяет 2 и 3 шаги.
    • Когда вызвана SQLPrepare, драйвер изменяет инструкцию SQL, чтобы использовать синтаксис MySQL без того, чтобы анализировать инструкцию. Это включает замену управляющих последовательностей. Но драйвер не возвращает никаких синтаксических и семантических ошибок.
    • При вызове SQLExecute драйвер:
      • Получает текущий параметр, оценивает и преобразует его по мере необходимости.
      • Посылает идентификатор плана доступа и преобразованные значения параметров на сервер MySQL.
      • Возвращает любые ошибки. Это ошибки, возникшие во время выполнения программы, типа SQLSTATE 24000 (Invalid cursor state), а также синтаксические и семантические ошибки, если они есть.

    Пример: этот пример объясняет, как прикладная программа может использовать подготовленное выполнение. Выборка готовит инструкцию INSERT и вставляет 100 строк данных, заменяя буферные значения.

    SQLHSTMT hstmt;
    SQLRETURN retcode;
    retcode = SQLPrepare(hstmt, "INSERT INTO EMP(ID,NAME) VALUES(?,?)", 
                         SQL_NTS);
    if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
    {
     SQLINTEGER id;
     SQLCHAR name[30];
     /* do the binding for parameter 1, id */
     retcode = SQLBindParameter(hstmt,1,SQL_PARAM_INPUT, SQL_C_LONG,
                                SQL_INTEGER, 0,0, &id, 0, NULL);
     if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
     {
        /* Now do the bindings for parameter 2, name */
        retcode = SQLBindParameter(hstmt,1,SQL_PARAM_INPUT, SQL_C_CHAR,
                                   SQL_VARCHAR, 0,0, name, 
                                   sizeof(name),NULL);
        if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
        {
           /* Now insert data by changing id and name buffer values */
           for (id=1; id <= 100; id++)
           {
             /* Set name as Сmysql1Т, Сmysql2ТЕ */
             sprintf(name,Фmysql%dФ,id);
             retcode = SQLExecute(hstmt);
           }
        }
     }
    /* Free param buffer resources */
    retcode = SQLFreeStmt(hstmt, SQL_REST_PARAMS);
    }
      
    3.5.3.2 Прямое выполнение

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

    SQLCHAR *statement;
    
    // Build an SQL statement.
    printf("enter the SQL statement:");
    scanf("%s",&statement);
    
    // Execute the statement.
    SQLExecDirect (hstmt, statement, SQL_NTS);
        

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

    • Инструкция нужна однократно.
    • Прикладная программа не нуждается в информации относительно набора результатов до выполнения.

    Основной недостаток использования прямого выполнения: инструкция SQL анализируется каждый раз, когда выполняется.

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

    • Устанавливает значения любых параметров.
    • Вызывает SQLExecDirect и передает строку, содержащую инструкцию SQL.
    • При вызове SQLExecDirect драйвер:
      • Изменяет инструкцию SQL, чтобы использовать синтаксис MySQL без того, чтобы анализировать инструкцию. Это включает замену всеъ управляющих последовательностей языка.
      • Получает актуальный параметр, оценивает его и изменяет инструкцию SQL, меняя маркеры параметра на данные с соответствующими преобразованиями.
      • Посылает измененную инструкцию SQL MySQL для выполнения.
      • Возвращает любые ошибки. Они включают диагностику выполнения, например, SQLSTATE 24000 (Invalid cursor state), синтаксические ошибки, типа SQLSTATE 42000 (Syntax error or access violation) и семантические ошибки, вроде SQLSTATE 42S02 (Base table or view not found).

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

    SQLHSTMT hstmt;
    SQLRETURN retcode;
    
    /* create table as "my_test" with integer and text field */
    retcode = SQLExecDirect(hstmt, "CREATE TABLE my_test(id int,
                            name text", SQL_NTS);
    if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
    {
       printf("table created successfully..");
       /* insert 2 rows of data to the table Сmy_testТ */
       retcode = SQLExecDirect(hstmt, 
                               "INSERT INTO my_test VALUES(10,'mysql')",
                               SQL_NTS);
       if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
       {
          printf("row 1 inserted successfully..");
       }
       retcode = SQLExecDirect(hstmt,
                               "INSERT INTO my_test VALUES(20,'monty')",
                               SQL_NTS);
       if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
       {
          printf("row 2 inserted successfully..");
       }
       /* Now update the second row by changing id from 20 to 100 */
       retcode = SQLExecDirect(hstmt, "UPDATE my_test SET id=100
                               WHERE name='monty', SQL_NTS);
       if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
       {
         SQLINTEGER rowcount;
         printf("row updated successfully..");
         /* Get total number of rows affected by the update statement*/
         retcode=SQLRowCount(hstmt, &rowcount);
         printf("total rows affected by the updated statement:%d",
                 rowcount);
       }
       /* Now delete the newly updated row */
       retcode = SQLExecDirect(hstmt, "DELETE FROM my_test WHERE id=100",
                               SQL_NTS);
       if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
       {
          SQLINTEGER rowcount;
          printf("row deleted successfully..");
          /* Get total number of rows affected by the delete statement*/
          retcode=SQLRowCount(hstmt, &rowcount);
          printf("total rows affected by the delete statement:%d",
                  rowcount);
       }
    }
    /* now drop the table Сmy_testТ */
    retcode = SQLExecDirect(hstmt,"DROP TABLE my_test", SQL_NTS);
    if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
    {
       printf(Уtable dropped successfully);
    }
        
    3.5.3.3 Операторные параметры

    Параметром является переменная в инструкции SQL. Инструкция SQL может содержать маркеры параметров ("?"), которые указывают значения, которые драйвер получает из прикладной программы во время выполнения.

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

    INSERT INTO EMPLOYEE (NAME.AGE) VALUES (?,?)
          

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

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

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

    Когда инструкция выполнена, драйвер просто получает актуальное значение переменной. Это особенно полезно, когда подготовленная инструкция выполнена больше, чем однажды: прикладная программа устанавливает новые значения для некоторых или всех переменных, каждый раз, когда инструкция выполнена.

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

    • Длина данных в байтах в связанной переменной. Драйвер проверяет эту длину только, если переменная символьная или двоичная (ValueType равен SQL_C_CHAR или SQL_C_BINARY).
    • SQL_NTS. Данные являются строкой с нулевым символом в конце.
    • SQL_NULL_DATA. Значение данных равно NULL, и драйвер игнорирует значение связанной переменной.
    • SQL_DATA_AT_EXEC или результат макрокоманды SQL_LEN_DATA_AT_EXEC. Значение параметра должно быть послано с SQLPutData.

    Расположения параметров, заданные через SQLBindParameter, останутся привязанными к маркерам параметра до вызова SQLFreeStmt из прикладной программы с опцией SQL_RESET_PARAMS или SQL_DROP. Прикладная программа может связать новое место в памяти с маркером параметра в любое время, вызывая SQLBindParameter. Пример:

    SQLUINTEGER   id;
    SQLINTEGER    idInd;
    
    // Prepare a statement to insert id
    SQLPrepare(hstmt, "INSERT INTO my_table VALUES(?)", SQL_NTS);
    
    // Bind id to the parameter for the id column
    SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_ULONG,
                     SQL_LONG, 0, 0, &id, 0, &idInd);
    
    // Repeatedly execute the statement, to insert 100 rows of data
    for (id=1; id <= 100; id++)
    {
      SQLExecute(hstmt);
    }
          
    3.5.3.4 Передача данных Long или Blob

    MySQL определяет данные long как любые символьные или двоичные данные, превышающие некий размер, обычно 254 символа. Не всегда реально сохранить в памяти целиком элемент длинных данных. Пример: здоровенный текстовый документ (например, эта книга в типографском формате PostScript) или растровая картинка. А поскольку такие данные не могут быть сохранены в одиночном буфере, прикладная программа посылает их драйверу по частям через SQLPutData, когда инструкция выполнена.

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

    Когда Вы должны ввести большие количества данных в столбец long varchar или в long varbinary, Вы можете использовать ODBC-функции SQLPutData и SQLParamData, чтобы ввести данные в меньших сегментах. Данные обеспечены в сегментах через SQLPutData, а SQLParamData используется, чтобы проверить требуют ли параметры данных.

    Чтобы посылать длинные данные во время выполнения в сегментах, прикладная программа выполняет следующие действия:

    • Готовит SQL-инструкцию с маркерами параметра там, где будут данные long или blob. Используется SQLPrepare.
    • Устанавливает параметр pcbValue в функции SQLBindParameter в значение SQL_DATA_AT_EXEC или SQL_LEN_DATA_AT_EXEC. Это позволяет драйверу узнать, что Вы будете обеспечивать значения для этого параметра во время выполнения, используя SQLPutData.
    • Выполняет команду SQL. Если инструкция уже подготовлена, выполняется подготовленная инструкция, используя SQLExecute или SQLExecDirect. Если имеются любые параметры, которые должны получить данные во времени выполнения, то драйвер возвращает SQL_NEED_DATA.
    • Вызывает SQLParamData в ответ на возврат значения SQL_NEED_DATA. Если длинные данные должны быть посланы, SQLParamData вернет SQL_NEED_DATA. В буфере, указанном параметром ValuePtrPtr, драйвер возвращает значение, которое идентифицирует параметр ожидания данных при выполнении. Если имеется больше, чем один такой параметр, прикладная программа должна использовать это значение, чтобы определить, который параметр ожидается. Заметьте, что данные могут быть запрошены драйвером в любом порядке.
    • Вызывает SQLPutData:, чтобы послать данные параметра драйверу. Если данные параметра не вписываются в одиночный буфер, что часто имеет место с длинными данными, вызовы SQLPutData из прикладной программы будут повторяться для передачи последующих порций данных.
    • Вызывает SQLParamData: если код возврата равен SQL_NEED_DATA, следующий параметр, который ожидает данные во время выполнения, готов их получить, и Вы должны вернуться к шагу 4. Если код возврата равен SQL_SUCCESS или хотя бы SQL_SUCCESS_WITH_INFO, все данные для всех параметров, ожидающих данных во время выполнения, посланы, и инструкция SQL завершила выполнение.
    3.5.4 Освобождение операторного дескриптора

    Перед выполнением новой инструкции SQL, прикладная программа должна убедиться, что текущие операторные параметры настройки соответствующие. Они включают операторные атрибуты, связанные параметры и наборы результатов. Вообще, параметры и наборы результатов для старой инструкции SQL должны быть освобождены (вызовом SQLFreeStmt с опцией SQL_RESET_PARAMS или SQL_UNBIND).

    Когда прикладная программа закончила использовать инструкцию, она вызывает SQLFreeHandle с опцией SQL_HANDLE_STMT или SQLFreeStmt с опцией SQL_DROP, чтобы освободить инструкцию. Вызов SQLDisconnect автоматически освобождает все инструкции для данного подключения.

    Функция SQLFreeStmt имеет четыре опции:

    Опция Что она делает
    SQL_CLOSE Закрывает курсор, если он существует, и отбрасывает ждущие обработки результаты. Прикладная программа может использовать операторный дескриптор позже.
    SQL_DROP Закрывает курсор, если он существует, отбрасывает ждущие обработки результаты и освобождает все ресурсы, связанные с операторным дескриптором.
    SQL_UNBIND Освобождает все буфера возвратов, связанные SQLBindCol с операторным дескриптором.
    SQL_RESET_PARAMS Освобождает все буфера параметров, запрошенные SQLBindParameter для операторного дескриптора.
    3.6 Получение результатов

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

    3.6.1 Как узнать, создан ли набор результатов или нет?

    В большинстве случаев, когда прикладная программа не уверена, относительно того, вернула ли специфическая инструкция набор результатов, она должна вызвать SQLNumResultCols, чтобы определить число столбцов в наборе результатов. Если это 0, инструкция не создала набор результатов.

    Прикладная программа может вызывать SQLNumResultCols в любой момент после того, как инструкция подготовлена или выполнена. Обратите внимание, что если Вы вызываете SQLNumResultCols на подготовленной, но не выполненной инструкции, прикладная программа теряет в эффективности, поскольку драйвер внутренне выполняет подготовленную инструкцию, чтобы вернуть информацию обратно прикладной программе.

    ОБРАТИТЕ ВНИМАНИЕ, для инструкций типа INSERT, UPDATE или DELETE вызов SQLRowCount из прикладной программы вернет число строк, на которые воздействует инструкция. Для других инструкций SQL драйвер возвращает любой набор результатов, и код возврата SQLExecute или SQLExecDirect обычно единственный источник информации относительно того, была ли инструкция успешно выполнена.

    3.6.2 Получение набора результатов

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

    SQLDescribeCol и SQLColAttribute (SQLColAttributes в случае MyODBC 2.50) используются, чтобы получить набор метаданных. Различие между этими двумя функциями в том, что SQLDescribeCol всегда возвращает те же самые пять частей информации (имя столбца, тип данных, точность, масштаб и допустимость null), а вот SQLColAttribute возвращает часть информации, запрошенную прикладной программой. Однако, SQLColAttribute может возвращать намного более богатый набор метаданных, включая чувствительность столбца к регистру, размер отображения, возможность поиска и тому подобное.

    3.6.3 Выборки данных

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

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

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

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

    Переменная остается связанной со столбцом до тех пор, пока столбец не будет отвязан явно вызовом SQLBindCol с указателем null в качестве адреса переменной, или пока не вызвана функция SQLFreeStmt с опцией SQL_UNBIND.

    3.7 Операции с курсором

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

    MyODBC поддерживает работу с двумя типами курсоров, а именно с блочным и со скроллируемым.

    3.7.1 Блочный курсор: выборка нескольких строк данных

    Прикладная программа может выбирать много строк данных, используя одну инструкцию выборки через блочный курсор. Строки, возвращенные в одиночной выборке с блочным курсором, названы rowset. Важно не путать rowset с набором результатов. Набор результатов поддерживается сервером MySQL, в то время как rowset поддерживается драйвером в буферах прикладных программ. В то время как набор результатов фиксирован, rowset меняет позицию и удовлетворяет каждый раз новому набору строк. Прикладная программа устанавливает размер rowset, используя SQLSetStmtAttr с опцией SQL_ATTR_ROW_ARRAY_SIZE.

    3.7.2 Типы курсоров

    MyODBC 3.51 три типа скроллируемых курсоров, используя которые прикладная программа может двигаться в наборе результатов:

    • Только вперед
    • Статический
    • Динамический (только для MyODBC 3.51.01 и выше)

    Чтобы работать с динамическим курсором, надо проверить опцию "Enable Dynamic Cursor Type" в настройках DSN или передать в строке подключения параметр OPTION=32.

    Прикладная программа может устанавливать тип курсора через SQLSetStmtAttr (или SQLSetStmtOption в драйвере MyODBC 2.50) с опцией SQL_ATTR_CURSOR_TYPE. По умолчанию драйвер неявно использует курсор типа "только вперед".

    Применяя курсор типа "только вперед", прикладная программа может идти только вперед в наборе результатов и не может вернуться назад. В статическом типе курсора прикладная программа может продвигаться вперед, назад или вообще к любому желательному расположению в наборе результатов.

    3.7.3 Скроллинг набора результатов

    При использовании скроллируемых курсоров, прикладные программы вызывают SQLFetchScroll (или SQLExtendedFetch для MyODBC 2.50), чтобы установить курсор и строки выборок. SQLFetchScroll поддерживает как относительную (следующая строка, предыдущая строка и переход на n строк), так и абсолютную (первая строка, последняя строка и строка n) прокрутку (скроллинг). Параметры FetchOrientation и FetchOffset в вызове функции SQLFetchScroll определяют, который rowset выбрать.

    FetchOrientation Значение
    SQL_FETCH_NEXT Вернет следующий rowset. Это эквивалентно вызову SQLFetch. SQLFetchScroll игнорирует значение FetchOffset.
    SQL_FETCH_PRIOR Вернет предшествующий rowset. SQLFetchScroll игнорирует значение FetchOffset.
    SQL_FETCH_FIRST Вернет первый rowset в наборе результатов. SQLFetchScroll игнорирует значение FetchOffset.
    SQL_FETCH_LAST Вернет последний полный rowset в наборе результатов. SQLFetchScroll игнорирует значение FetchOffset.
    SQL_FETCH_ABSOLUTE Вернет rowset, начинающийся в строке FetchOffset.
    SQL_FETCH_RELATIVE Вернет FetchOffset строк от начала текущего rowset.

    Обратите внимание, что при использовании типа курсора "только вперед", прикладная программа может только продвигаться на SQL_FETCH_NEXT в то время, как при использовании статических и/или динамических типов можно переходить в любое желательное расположение.

    3.7.4 Позиционные модификации и удаление

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

    • Вызовом SQLSetPos
    • Выполнением позиционных команд SQL, используя SQLExecute или SQLExecDirect.

    Чтобы использовать позиционное удаление или модификацию, прикладная программа должна:

    • Установить имя курсора, вызывая SQLSetCursorName. Если прикладная программа не установила имя курсора явно, то драйвер возвращает заданное по умолчанию имя курсора.
    • Открыть набор результатов инструкцией SELECT.
    • Установить курсор в строку, которую нужно модифицировать или удалить. Прикладная программа может делать это, вызывая SQLFetchScroll (или SQLExtendedFetch в случае MyODBC 2.50), чтобы получить rowset, содержащий требуемую строку, и вызывая SQLSetPos с SQL_POSITION, чтобы установить курсор в эту строку в рамках rowset.
    • Получить имя курсора, вызывая SQLGetCursorName. Обратите внимание, что, если прикладная программа не устанавливает имя курсора явно перед открытием набора результатов в том же самом операторном дескрипторе через вызов функции SQLSetCursorName, драйвер возвращает заданное по умолчанию имя курсора.
    • Прикладная программа выполняет позиционную инструкцию на другом операторном дескрипторе, чем тот, который используется набором результатов.

    Синтаксис этих инструкций:

    UPDATE table-name SET column-identifier = {expression | NULL}
                      [, column-identifier = {expression | NULL}]...
                      WHERE CURRENT OF cursor-name
    DELETE FROM table-name WHERE CURRENT OF cursor-name
          

    Здесь cursor-name задает имя курсора, возвращенное SQLGetCursorName.
    Пример:

    HSTMT  hstmtSelect;
    HSTMT  hstmtUpdate;
    UCHAR  szLname[NAME_LEN],szFname[NAME_LEN],cursorName[10];
    SWORD  cursorLen;
    SDWORD cbName;
    
    /* Allocate the statement handles */
    retcode = SQLAllocStmt(hdbc, &hstmtSelect);
    retcode = SQLAllocStmt(hdbc, &hstmtUpdate);
    
    /* SELECT the result set and bind its columns to local storage  */
    retcode = SQLExecDirect(hstmtSelect, 
                            "SELECT lname,fname FROM EMP", SQL_NTS);
    retcode = SQLBindCol(hstmtSelect, 
                            1, SQL_C_CHAR, szLname, NAME_LEN,
                         &cbLname);
    retcode = SQLBindCol(hstmtSelect, 2, SQL_C_CHAR, szFname, NAME_LEN,
                         &cbFname);
    
    /* get the cursor name */
    retcode = SQLGetCursorName(hstmtSelect, cursorName, 
                               10, &cursorLen);
    
    /* Position to third row in the result set */
    retcode = SQLFetchScroll(hstmtSelect,SQL_FETCH_ABSOLUTE, 3);
    if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO));
    
    /* Perform a positioned update */
    sprintf(updsql, 
            "UPDATE EMP SET fname = 'monty' WHERE CURRENT OF %s",
            cursorName);
    retcode = SQLExecDirect(hstmtUpdate, updsql, SQL_NTS);
          
    3.7.5 Использование SQLSetPos

    Прикладные программы могут модифицировать или удалять любую строку в текущем (актуальном) rowset, используя SQLSetPos. Это удобный вариант для построения и выполнения инструкции SQL.

    SQLSetPos функционирует на текущем (актуальном) rowset и может использоваться только после обращения к SQLFetchScroll или SQLExtendedFetch. Прикладная программа определяет номер строки, которую надо модифицировать, удалить или вставить, и драйвер получает новые данные для этой строки из буферов rowset. SQLSetPos может также использоваться, чтобы обозначить определенную строку как текущую или обновить специфическую строку в rowset из источника данных.

    Размер Rowset может быть установлен обращением к SQLSetStmtAttr с опцией SQL_ATTR_ROW_ARRAY_SIZE.

    Первая строка в rowset имеет номер 1. Параметр RowNumber в SQLSetPos должен идентифицировать строку в rowset. В смысле, значение должно быть в диапазоне между 1 и числом строк, которые были выбраны в последний раз (что может быть меньше, чем размер rowset). Маленькая хитрость: если RowNumber равен 0, операция будет применяться к каждой строке в rowset.

    Модификация строк в rowset:
    Операция SQLSetPos с параметром SQL_UPDATE предписыает серверу модифицировать одну или более выбранных строк таблицы, используя данные в буферах прикладных программ для каждого связанного столбца.

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

    • Помещает новые значения данных в буфера rowset.
    • Устанавливает значение в буфере длин каждого столбца по мере необходимости. Это байт длины данных или SQL_NTS для столбцов, связанных со строковыми буферами, или SQL_NULL_DATA для любых столбцов, которые будут установлены в NULL.
    • Вызывает SQLSetPos с параметром Operation установленным в SQL_UPDATE и RowNumber равным числу строк для обновления. Маленькая хитрость: если RowNumber равен 0, операция будет применяться к каждой строке в rowset.

    После завершения SQLSetPos текущей строкой будет модифицируемая строка. Прикладная программа может проверять общее количество строк, на которые воздействует инструкция update, вызывая SQLRowCount и статус обновления через атрибут SQL_ATTR_ROW_STATUS_PTR.

    Удаление строк:
    Параметр SQL_DELETE в SQLSetPos предписывает серверу удалить одну или несколько строк в таблице. Чтобы удалить строки с помощью SQLSetPos, программа вызывает SQLSetPos с параметром Operation, установленным в SQL_DELETE и RowNumber равным числу удаляемых строк. Осторожно: если RowNumber равен 0, будут удалены все строки.

    После завершения SQLSetPos, удаленная строка становится текущей, и состояние равно SQL_ROW_DELETED. Строка не может использоваться в любых дальнейших позиционных операциях.

    3.8 Функции каталога

    Сервер MySQL поддерживает синтаксис SHOW SQL, чтобы обеспечить информацию относительно баз данных, таблиц, столбцов или состояния сервера. Прикладные программы ODBC могут получать метаинформацию относительно сервера, используя следующие функции каталога:

    Функция Описание
    SQLTables Возвращает список каталогов (баз данных), таблиц или типы таблиц.
    SQLColumns Возвращает список столбцов в одной или нескольких таблицах.
    SQLStatistics Возвращает список статистики относительно одной таблицы. Также возвращает список индексов, связанных с этой таблицей.
    SQLSpecialColumns Возвращает список столбцов, который уникально идентифицирует строку в одной таблице. Также возвращает список столбцов, которые автоматически модифицируются в этой таблице.
    SQLPrimaryKeys Возвращает список столбцов, которые составляют первичный ключ в одной таблице.
    SQLForeignKeys Возвращает список внешних ключей в одной таблице или список внешних ключей в других таблицах, которые обращаются к ней.
    SQLTablePrivileges Возвращает список привилегий, связанных с таблицей или несколькими таблицами сразу.
    SQLColumnPrivileges Возвращает список привилегий, связанных с одним или несколькими столбцами только в одной таблице.
    SQLGetTypeInfo Возвращает список типов данных SQL, поддерживаемых сервером. Эти типы данных используются в командах CREATE TABLE и ALTER TABLE.
    3.9 Управление транзакциями

    Транзакция представляет собой последовательность инструкций SQL, которые формируют логический модуль. Каждая инструкция SQL в транзакции выполняет часть задачи, и все они необходимы для выполнения некоего задания. Только когда все инструкции SQL в транзакции выполнены успешно, задачу можно обрабатывать как завершенную. Имеется общее управление потоком данных в транзакции:

    • Звауск транзакции
    • Выполнение транзакции
    • Завершение или отмена транзакции

    По умолчанию MyODBC/MySQL работает в режиме autocommit. Это означает, что как только Вы выполняете инструкцию SQL, MySQL сохранит данные на диске: механизм транзакций выключен. Если Вы используете транзакционно-безопасные таблицы (например, BDB или InnoDB), Вы можете перевести MySQL в режим не-autocommit с командой SQL:

    SET AUTOCOMMIT=0
          

    Через MyODBC Вы можете устанавливать AUTOCOMMIT в ON или в OFF, используя SQLSetConnectAttr (или SQLSetConnectOption в MyODBC 2.50) с атрибутом SQL_ATTR_AUTOCOMMIT. После этого Вы должны использовать SQLEndTran (или SQLTransact в MyODBC 2.50) для завершения транзакции или ее отмены (если Вы хотите игнорировать изменения, которые Вы сделали, начиная с начала Вашей транзакции), используя опции SQL_COMMIT или SQL_ROLLBACK.

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

    • Создает таблицу типа BDB или типа InnoDB.
    • Выключает режим AUTOCOMMIT.
    • Вставляет строку данных и завершает транзакцию.
    • Вставляет вторую строку данных и отменяет эту транзакцию.
    • Теперь Вы должны видеть только одну (первую) строку данных в таблице.

    Вы можете попробовать сделать то же самое с InnoDB, меняя тип таблицы.

    SQLHDBC hdbc;
    SQLHSTMT hstmt;
    
    /* Set AUTOCOMMIT to OFF */
    SQLSetConnectOption(hdbc,SQL_AUTOCOMMIT,SQL_AUTOCOMMIT_OFF);
    
    /* CREATE TABLE t_tran of TYPE BDB */
    SQLExecDirect(hstmt,"drop table if exists t_tran",SQL_NTS);
    SQLTransact(NULL,hdbc,SQL_COMMIT);
    SQLExecDirect(hstmt,"create table t_tran(col1 int, col2 varchar(30))
                  TYPE= BDB",SQL_NTS);
    SQLTransact(NULL,hdbc,SQL_COMMIT);
    
    /* INSERT A ROW OF DATA */
    SQLExecDirect(hstmt,"insert into t_tran values(10,'venu')",SQL_NTS);
    
    /* Now, commit the insert */
    SQLTransact(NULL,hdbc,SQL_COMMIT);
    
    /* Again INSERT second row of data */
    SQLExecDirect(hstmt,"insert into t_tran values(20,'mysql')",SQL_NTS);
    
    /* Rollback the previous INSERT */
    SQLTransact(NULL,hdbc,SQL_ROLLBACK);
    
    /* Now FETCH bac and check whether it has one row or not. */
    SQLFreeStmt(hstmt,SQL_CLOSE);
    SQLExecDirect(hstmt,"select * from t_tran",SQL_NTS);
    SQLFetch(hstmt);
    assert(SQLFetch(hstmt) == SQL_NO_DATA_FOUND);
    SQLFreeStmt(hstmt,SQL_CLOSE);
          

    Обратите внимание, что если Вы используете драйвер MyODBC 3.51, замените SQLSetConnectOption на SQLSetConnectAttr, а SQLTransact на SQLEndTran.

    3.10 Получение диагностической информации

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

    Коды возврата:
    каждая функция в ODBC возвращает код, известный как код возврата. Следующее представляет собой различные коды возврата, возвращаемые MyODBC.

    Код возврата Описание
    SQL_SUCCESS Все в порядке.
    SQL_SUCCESS_WITH_INFO Все в порядке, но некоторая информация возвращается в качетсве предупреждения. Прикладная программа может вызывать SQLGetDiagRec (или SQLError для MyODBC 2.50) или SQLGetDiagField, чтобы получить дополнительную информацию.
    SQL_ERROR Ошибка: функция провалилась. Прикладная программа может вызывать SQLGetDiagRec (или SQLError для MyODBC 2.50) или SQLGetDiagField, чтобы получить дополнительную информацию.
    SQL_NO_DATA Данные не могут быть получены (конец набора?).
    SQL_NO_DATA_FOUND Это синоним для SQL_NO_DATA в случае MyODBC 2.50.
    SQL_INVALID_HANDLE Недопустимый дескриптор был обнаружен. Это указывает на ошибку программирования.
    SQL_NEED_DATA Драйвер указывает, что прикладная программа должна послать значения данных в качестве параметра времени выполнения.

    Когда происходит ошибка в прикладной программе, то есть когда функция возвратит SQL_ERROR или SQL_SUCCESS_WITH_INFO, прикладная программа может запрашивать диагностическую информацию, вызывая функции SQLGetDiagRec или SQLGetDiagField из драйвера. В MyODBC 2.50 прикладная программа может использовать SQLError для выполнения этой работы. При использовании драйвера MyODBC 3.51, прикладная программа может запрашивать большее количество диагностических записей, используя SQLGetDiagField.

    Применение SQLGetDiagRec и SQLGetDiagField:
    Как описано в предыдущем разделе, прикладные программы вызывают SQLGetDiagRec или SQLGetDiagField, чтобы получить диагностическую информацию в случае драйвера MyODBC 3.51. Эти функции принимают среду, подключение, инструкцию или дескриптор и возвращают диагностику из функции, которая последней использовала этот дескриптор.

    Прикладные программы получают индивидуальные диагностические поля, вызывая SQLGetDiagField и определяя поле, которое надо получить. Некоторые поля не имеют никакого значения для определенных типов дескрипторов.

    Прикладные программы получают и SQLSTATE, местный код ошибки и диагностическое сообщение в одном обращении, вызывая SQLGetDiagRec.

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

    SQLCHAR      SqlState[6],
    SQLCHAR      ErrorMsg[SQL_MAX_MESSAGE_LENGTH];
    SQLINTEGER   NativeError;
    SQLSMALLINT  MsgLen;
    SQLRETURN    sql_return, diag_return;
    SQLHSTMT     hstmt;
    
    // Drop a non-existing table
    sql_return=SQLExecDirect(hstmt, "DROP TABLE NON_EXISTANT_TABLES^&*",
                             SQL_NTS);
    if (sql_return == SQL_SUCCESS_WITH_INFO || sql_return == SQL_ERROR)
    {
       // Get the diag information.
       Diag_return = SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, 1, SqlState,
                     &NativeError, ErrorMsg, sizeof(ErrorMsg),
                     &MsgLen);
       if (diag_return != SQL_NO_DATA)
       {
          DisplayError(SqlState,NativeError,Msg,MsgLen);
       }
    }
          

содержание       назад       вперед

VPS в России, Европе и США

Бесплатная поддержка и администрирование

Оплата российскими и международными картами

🔥 VPS до 5.7 ГГц под любые задачи с AntiDDoS в 7 локациях

💸 Гифткод CITFORUM (250р на баланс) и попробуйте уже сейчас!

🛒 Скидка 15% на первый платеж (в течение 24ч)

Скидка до 20% на услуги дата-центра. Аренда серверной стойки. Colocation от 1U!

Миграция в облако #SotelCloud. Виртуальный сервер в облаке. Выбрать конфигурацию на сайте!

Виртуальная АТС для вашего бизнеса. Приветственные бонусы для новых клиентов!

Виртуальные VPS серверы в РФ и ЕС

Dedicated серверы в РФ и ЕС

По промокоду CITFORUM скидка 30% на заказ VPS\VDS

Новости мира IT:

Архив новостей

IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware

Информация для рекламодателей PR-акции, размещение рекламы — adv@citforum.ru,
тел. +7 495 7861149
Пресс-релизы — pr@citforum.ru
Обратная связь
Информация для авторов
Rambler's Top100 TopList This Web server launched on February 24, 1997
Copyright © 1997-2000 CIT, © 2001-2019 CIT Forum
Внимание! Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав. Подробнее...