|
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
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, надо сделать следующее:
Большинство прикладных программ использует некоторое изменение этих шагов. 3.2 Настройка MyODBC DSNИсточник данных идентифицирует путь для данных, который может включать
сетевую библиотеку, сервер, базу данных и другие атрибуты. В нашем случае
источник данных представляет собой путь к базе данных
Чтобы добавлять и конфигурировать источники данных, используйте
Чтобы открыть
Чтобы добавить источник данных в Windows:
Теперь нажмите Driver Options: Вы можете также видеть кнопку
Обратите внимание, что параметры Чтобы изменить источник данных в Windows:
Когда Вы закончите изменять информацию в этом диалоговом окне,
Чтобы настроить источник данных в Unix: В ; ; 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 в секции
Параметр
Если Вы хотите иметь много параметров, Вы должны сложить вышеупомянутые числа. Например, установка опции в 12 (4+8) дает Вам отладку без ограничений на размеры пакета. По умолчанию MYODBC3.DLL компилируется для оптимальной
эффективности. Если Вы хотите отладить 3.4 Связь с сервером MySQLПрикладная программа может быть связана с любом числом источников данных и драйверов. Они могут быть вариантами того же самого драйвера и ряда источников данных или несколькими подключениями с тем же самым драйвером и источником данных. Прикладная программа должна сделать следующее, чтобы соединиться с сервером MySQL через MyODBC:
3.4.1 Распределение дескриптора средыПрежде, чем прикладная программа сможет использовать любую функцию ODBC, надо инициализировать ODBC-связь с помощью интерфейса и сопоставить с ней дескриптор среды. Он обеспечивает доступ к глобальной информации типа имеющих силу дескрипторов подключения и активных дескрипторов подключения. Чтобы распределить правильный дескриптор среды, прикладная программа:
Если прикладная программа связана через Driver Manager, то это обращение
загружает Driver Manager. Он не вызывает Если прикладная программа связана непосредственно с драйвером, то это обращение загружает драйвер, и уже драйвер формирует информацию среды и возвращает распределенную структуру обратно прикладной программе. 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 при использовании следующих элементов:
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 или с драйвером, она должна распределить дескриптор подключения, следующим образом:
Если прикладная программа связана через 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). Имеются две различных функции для этого:
3.4.5.1 Соединение через SQLConnectSQLConnect самая простая функция подключения. Требует имя источника данных и принимает факультативные user ID и пароль. Прикладная программа передает следующую информацию драйверу через SQLConnect:
Обратите внимание, что, если Вы уже определили имя пользователя и пароль в параметрах 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 Связь через SQLDriverConnectSQLDriverConnect используется, чтобы соединиться с сервером, используя строку подключения. Можно использовать SQLDriverConnect вместо SQLConnect по следующим причинам:
Строка подключения может состоять из одного или большего количества параметров 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 поможет это устроить:
3.5.3.1 Подготовленное выполнениеПодготовленное выполнение представляет собой эффективный способ выполнить инструкцию больше одного раза. Инструкция сначала компилируется в план доступа. План доступа затем будет выполнен столько раз, сколько понадобится. Подготовленное выполнение более предпочтительно, если прикладная программа: Подготовленное выполнение главным образом достигнуто через MyODBC API SQLPrepare и SQLExecute. Подготовленная инструкция выполняется быстрее, чем неприготовленная инструкция или прямое выполнение потому, что драйвер компилирует инструкцию, строит для нее план доступа и возвращает идентификатор плана доступа обратно прикладной программе. Драйвер минимизирует затраты времени на обработку инструкции, поскольку он не должен каждый раз строить план доступа. Уменьшается и трафик. Чтобы подготовить и выполнить инструкцию, прикладная программа: Пример: этот пример объясняет, как прикладная программа может использовать подготовленное выполнение. Выборка готовит инструкцию 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 анализируется каждый раз, когда выполняется. Чтобы выполнить инструкцию непосредственно, прикладная программа выполняет следующий набор действий:
Пример: 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, он должен быть установлен в одно из следующих значений прежде, чем инструкция выполнена:
Расположения параметров, заданные через 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 или BlobMySQL определяет данные long как любые символьные или двоичные данные, превышающие некий размер, обычно 254 символа. Не всегда реально сохранить в памяти целиком элемент длинных данных. Пример: здоровенный текстовый документ (например, эта книга в типографском формате PostScript) или растровая картинка. А поскольку такие данные не могут быть сохранены в одиночном буфере, прикладная программа посылает их драйверу по частям через SQLPutData, когда инструкция выполнена. Обратите внимание, что прикладная программа может фактически посылать любой тип данных во времени выполнения с помощью SQLPutData, хотя только символьные и двоичные данные могут быть представлены частями. Однако, если данные достаточно маленькие, чтобы разместиться в одиночном буфере, не имеется вообще никакой причины использовать SQLPutData. Намного проще позволять драйверу получать данные из буфера напрямую. Когда Вы должны ввести большие количества данных в столбец long varchar или в long varbinary, Вы можете использовать ODBC-функции SQLPutData и SQLParamData, чтобы ввести данные в меньших сегментах. Данные обеспечены в сегментах через SQLPutData, а SQLParamData используется, чтобы проверить требуют ли параметры данных. Чтобы посылать длинные данные во время выполнения в сегментах, прикладная программа выполняет следующие действия:
3.5.4 Освобождение операторного дескриптораПеред выполнением новой инструкции SQL, прикладная программа должна убедиться, что текущие операторные параметры настройки соответствующие. Они включают операторные атрибуты, связанные параметры и наборы результатов. Вообще, параметры и наборы результатов для старой инструкции SQL должны быть освобождены (вызовом SQLFreeStmt с опцией SQL_RESET_PARAMS или SQL_UNBIND). Когда прикладная программа закончила использовать инструкцию, она вызывает SQLFreeHandle с опцией SQL_HANDLE_STMT или SQLFreeStmt с опцией SQL_DROP, чтобы освободить инструкцию. Вызов SQLDisconnect автоматически освобождает все инструкции для данного подключения. Функция SQLFreeStmt имеет четыре опции:
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 Выборки данныхЧтобы получить строку данных из набора результатов, прикладная программа:
Данные, выбранные из сервера 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 три типа скроллируемых курсоров, используя которые прикладная программа может двигаться в наборе результатов:
Чтобы работать с динамическим курсором, надо проверить опцию "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 выбрать.
Обратите внимание, что при использовании типа курсора "только вперед", прикладная программа может только продвигаться на SQL_FETCH_NEXT в то время, как при использовании статических и/или динамических типов можно переходить в любое желательное расположение. 3.7.4 Позиционные модификации и удалениеПрикладные программы могут модифицировать или удалять желательные строки в наборе результатов, используя следующий набор обращений ODBC:
Чтобы использовать позиционное удаление или модификацию, прикладная программа должна:
Синтаксис этих инструкций: 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
Здесь 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, прикладная программа делает следующее:
После завершения SQLSetPos текущей строкой будет модифицируемая строка. Прикладная программа может проверять общее количество строк, на которые воздействует инструкция update, вызывая SQLRowCount и статус обновления через атрибут SQL_ATTR_ROW_STATUS_PTR. Удаление строк: После завершения SQLSetPos, удаленная строка становится текущей, и состояние равно SQL_ROW_DELETED. Строка не может использоваться в любых дальнейших позиционных операциях. 3.8 Функции каталогаСервер MySQL поддерживает синтаксис SHOW SQL, чтобы обеспечить информацию относительно баз данных, таблиц, столбцов или состояния сервера. Прикладные программы ODBC могут получать метаинформацию относительно сервера, используя следующие функции каталога:
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. Пример:
Вы можете попробовать сделать то же самое с 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, введенных пользователем. Коды возврата:
Когда происходит ошибка в прикладной программе, то есть когда функция возвратит SQL_ERROR или SQL_SUCCESS_WITH_INFO, прикладная программа может запрашивать диагностическую информацию, вызывая функции SQLGetDiagRec или SQLGetDiagField из драйвера. В MyODBC 2.50 прикладная программа может использовать SQLError для выполнения этой работы. При использовании драйвера MyODBC 3.51, прикладная программа может запрашивать большее количество диагностических записей, используя SQLGetDiagField. Применение SQLGetDiagRec и SQLGetDiagField: Прикладные программы получают индивидуальные диагностические поля, вызывая 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);
}
}
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
CITForum © 1997–2025