учебники, программирование, основы, введение в,

 

Именованные курсоры

Создание именованного курсора
Курсор, для которого определено имя, называется именованным курсором.
Ассоциировать имя курсора с активным дескриптором оператора можно вызовом функции SQLSetCursorName. В том случае, если эта функция не вызывается явным образом, драйвер при необходимости может генерировать имя курсора при выполнении SQL-оператора.
Функция SQLSetCursorName имеет следующее формальное описание:
SQLRETURN SQLSetCursorName(
SQLHSTMT      StatementHandle,
SQLCHAR *     CursorName,
SQLSMALLINT     NameLength);
Параметр StatementHandle ([Input]) указывает дескриптор оператора, а параметр CursorName ([Input]) задает назначаемое имя курсора. Отметим, что для эффективной обработки имя курсора не должно иметь лидирующих или завершающих пробелов.
Параметр NameLength ([Input]) определяет длину буфера *CursorName.
Следующий пример иллюстрирует применение функции SQLSetCursorName для получения имени курсора и выполнения затем позиционированного SQL-оператора UPDATE:
#define NAME_LEN 40
#define PHONE_LEN 12

SQLHSTMT     hstmtSelect;  // Дескриптор оператора
// (для оператора SELECT)
SQLHSTMT     hstmtUpdate;  // Дескриптор оператора
// (для оператора UPDATE)
SQLRETURN    retcode;
SQLHDBC      hdbc;
SQLCHAR      szName[NAME_LEN], szPhone[PHONE_LEN];
SQLINTEGER   cbName, cbPhone;

/* Создаем дескриптор оператора и определяем имя курсора */
SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmtSelect);
SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmtUpdate);
SQLSetCursorName(hstmtSelect, "C1", SQL_NTS);

/* Выполняем SQL-оператор SELECT для формирования результирующего набора
и связываем его столбцы с локальными буферами для извлечения данных */
SQLExecDirect(hstmtSelect,
"SELECT NAME, PHONE FROM Tbl1", SQL_NTS);
SQLBindCol(hstmtSelect, 1, SQL_C_CHAR,
szName, NAME_LEN, &cbName);
SQLBindCol(hstmtSelect, 2, SQL_C_CHAR,
szPhone, PHONE_LEN, &cbPhone);

/* Выбираем строки результирующего набора до тех пор,
пока не найдем строку "Иванов А." */
do
retcode = SQLFetch(hstmtSelect);
while ((retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) &&
(strcmp(szName, "Иванов А.") != 0));

/* Выполняем позиционированный UPDATE для текущей выбранной строки
именованного курсора */
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
SQLExecDirect(hstmtUpdate,
"UPDATE Tbl2 SET PHONE=\"1373737\"
WHERE CURRENT OF C1", SQL_NTS);
}
Для получения имени курсора, ассоциированного с конкретным дескриптором оператора, используется функция SQLGetCursorName, которая имеет следующее формальное описание:
SQLRETURN SQLGetCursorName(
SQLHSTMT     StatementHandle,
SQLCHAR *     CursorName,
SQLSMALLINT     BufferLength,
SQLSMALLINT *     NameLengthPtr);
Параметр StatementHandle ([Input]) указывает дескриптор оператора.
Имя курсора возвращается в буфере, определяемом параметром CursorName ([Output]).
Параметр BufferLength ([Input]) задает длину буфера *CursorName в байтах. Параметр NameLengthPtr ([Output]) определяет число байтов (включая ограничивающий 0-символ), которые занимает имя курсора. Если размер выделенного буфера меньше, чем требуется под имя курсора, то возвращаемое имя усекается.
В том случае, если в приложении функция SQLSetCursorName для задания имени курсора не вызывается, то драйвер автоматически генерирует имя курсора, начинающееся с префикса SQL_CUR.
Имя курсора в основном используется для позиционированного изменения или удаления, которое указывается в SQL-операторе фразой WHERE CURRENT OF имя_курсора.
Отметим, что в ODBC 2.x в том случае, если курсор не был открыт и ему не было назначено имя при вызове функции SQLSetCursorName, то инициировалась ошибка с кодом ответа SQLSTATE HY015 (Нет имени курсора). В версии ODBC 3.x вне зависимости от того, вызывалась ли функция SQLSetCursorName, драйвер всегда возвращает имя курсора.
Пока курсор не открыт, разрешено его переименование. Для этого достаточно вызвать функцию SQLSetCursorName.
Явно или неявно созданное имя курсора остается установленным до тех пор, пока не будет разрушен дескриптор оператора при вызове функции SQLFreeHandle с параметром HandleType, равным SQL_HANDLE_STMT.
Свойства курсора
Свойства курсора устанавливаются посредством атрибутов оператора. Для определения атрибутов оператора используется функция SQLSetStmtAttr, которая имеет следующее формальное описание:
SQLRETURN SQLSetStmtAttr(
SQLHSTMT     StatementHandle,
SQLINTEGER     Attribute,
SQLPOINTER     ValuePtr,
SQLINTEGER     StringLength);
Параметр StatementHandle ([Input]) указывает дескриптор оператора, для которого устанавливается значение атрибута оператора. Параметр Attribute ([Input]) определяет атрибут, значение которого задается параметром ValuePtr ([Input]). В зависимости от типа устанавливаемого атрибута параметр ValuePtr может быть: 32-битовым беззнаковым целым значением; указателем на null-ограниченную строку символов или двоичный буфер; значением, определяемым драйвером.
Параметр StringLength ([Input]) в зависимости от типа параметра может: игнорироваться (для целочисленных значений); указывать длину строки или быть равным SQL_NTS для null-ограниченных строк; быть равным результату макроса SQL_LEN_BINARY_ATTR(length) для указателя на двоичный буфер; для ValuePtr, который является указателем на значение, отличное от null-ограниченной строки или двоичного буфера, параметр должен быть равен SQL_IS_POINTER; для значений фиксированной длины параметр может быть равен SQL_IS_INTEGER или SQL_IS_UINTEGER.

Асинхронное выполнение функций
По умолчанию ODBC-драйверы применяют синхронное выполнение функций, когда приложение ожидает завершения выполнения функции. При асинхронном выполнении функций ODBC-драйвер возвращает управление приложению до окончательного завершения выполнения функции. В этом случае приложение продолжает выполняться дальше и имеет возможность синхронного или асинхронного вызова других функций.
В зависимости от используемого источника данных асинхронное выполнение осуществляется на основе оператора или соединения. Режим асинхронного выполнения можно определить при вызове функции SQLGetInfo с параметром, равным SQL_ASYNC_MODE: для асинхронного выполнения уровня соединения возвращается значение SQL_AM_CONNECTION, а для асинхронного выполнения уровня оператора - значение SQL_AM_STATEMENT.
Для определения того, что функция будет выполняться асинхронно на уровне оператора, следует вызовом функции SQLSetStmtAttr установить значение атрибута SQL_ATTR_ASYNC_ENABLE равным SQL_ASYNC_ENABLE_ON. Для определения асинхронного выполнения на уровне соединения следует вызовом функции SQLSetConnectAttr устанавливать значение атрибута соединения SQL_ATTR_ASYNC_ENABLE равным SQL_ASYNC_ENABLE_ON. При использовании асинхронного режима уровня соединения все операторы, ассоциируемые с данным соединением, могут выполняться в асинхронном режиме.
Количество максимально допустимых параллельно и асинхронно выполняемых операторов для конкретного драйвера определяется вызовом функции SQLGetInfo с параметром, равным SQL_MAX_ASYNC_CONCURRENT_STATEMENTS.
При асинхронном выполнении функции до завершения ее выполнения каждый повторный вызов этой функции с теми же параметрами возвращает код ответа SQL_STILL_EXECUTING. Так, повторяя вызовы через некоторый интервал времени, можно определять момент, когда будет завершено асинхронное выполнение функции.
Например:
SQLHSTMT  hstmt1;         // Дескриптор оператора
SQLRETURN rc;

// Устанавливаем режим асинхронного выполнения
SQLSetStmtAttr(hstmt1, SQL_ATTR_ASYNC_ENABLE,
SQL_ASYNC_ENABLE_ON, 0);
// Выполняем асинхронно оператор SELECT
while ((rc=SQLExecDirect(hstmt1,
"SELECT * FROM TBL1",SQL_NTS)) ==
SQL_STILL_EXECUTING)
{
// Действия, осуществляемые во время асинхронного
// выполнения оператора SELECT (нельзя использовать
// дескриптор hstmt1)
}
// Асинхронное выполнение завершено
Во время асинхронного выполнения оператора приложение может осуществлять синхронный или асинхронный вызов функций для других дескрипторов оператора. Для самого дескриптора оператора в период асинхронного выполнения может осуществляться только повторный вызов выполняемой функции или функций SQLCancel (прерывание вызова), SQLGetDiagField и SQLGetDiagRec (но только заголовки полей).
Для соединения, ассоциированного с асинхронно выполняемым оператором, возможен вызов следующих функций: SQLAllocHandle (для размещения дескриптора оператора), SQLGetDiagField, SQLGetDiagRec, SQLGetFunctions.
Пример:
SQLHDBC       hdbc1, hdbc2;  // Дескрипторы соединения
SQLHSTMT      hstmt1, hstmt2, hstmt3;
SQLCHAR *     SQLStatement = "SELECT * FROM TBL1";
SQLUINTEGER   InfoValue;
SQLRETURN     rc;
// Создание дескрипторов операторов
SQLAllocHandle(SQL_HANDLE_STMT, hdbc1, &hstmt1);
SQLAllocHandle(SQL_HANDLE_STMT, hdbc1, &hstmt2);
SQLAllocHandle(SQL_HANDLE_STMT, hdbc2, &hstmt3);
// Устанавливаем для hstmt1 режим асинхронного
// выполнения
SQLSetStmtAttr(hstmt1, SQL_ATTR_ASYNC_ENABLE,
SQL_ASYNC_ENABLE_ON, 0);
// Асинхронное выполнение для дескриптора hstmt1
while ((rc = SQLExecDirect(hstmt1, SQLStatement,
SQL_NTS)) == SQL_STILL_EXECUTING) {
// Следующий вызов вернет код ответа HY010,
// т.к. дескриптор оператора hstmt1 пока " занят",
// а второй вызов использует дескриптор hdbc1, в
// котором размещен дескриптор оператора hstmt1
SQLExecDirect(hstmt1, SQLStatement, SQL_NTS);     
SQLGetInfo(hdbc1, SQL_UNION,
(SQLPOINTER) &InfoValue,
0, NULL);   // Ошибка с кодом HY010
// Следующие операторы будут выполнены без ошибки,
// т.к для hdbc1 применяются дескрипторы оператора,
//не используемые асинхронно в настоящий момент
SQLExecDirect(hstmt2, SQLStatement, SQL_NTS);
SQLTables(hstmt3,NULL,0,NULL,0,NULL,0,NULL,0);  
SQLGetInfo(hdbc2, SQL_UNION,
(SQLPOINTER) &InfoValue, 0, NULL);  
}
Для отключения режима асинхронного выполнения операторов следует вызвать функцию SQLSetStmtAttr со значением атрибута SQL_ATTR_ASYNC_ENABLE, равным SQL_ASYNC_ENABLE_OFF (для уровня оператора) или функцию SQLSetConnectAttr со значением атрибута SQL_ATTR_ASYNC_ENABLE, равным SQL_ASYNC_ENABLE_OFF (для уровня соединения).
При вызове функции SQLGetDiagField, применяемой для получения диагностической информации, с дескриптором оператора, используемого асинхронно, возвращаются следующие значения:

  • поля SQL_DIAG_CURSOR_ROW_COUNT, SQL_DIAG_DYNAMIC_FUNCTION, SQL_DIAG_DYNAMIC_FUNCTION_CODE, SQL_DIAG_ROW_COUNT возвращают неопределенное значение;
  • поле SQL_DIAG_NUMBER возвращает значение 0;
  • поле SQL_DIAG_RETURNCODE возвращает значение SQL_STILL_EXECUTING;
  • все поля записи возвращают SQL_NO_DATA.

Следующий пример иллюстрирует процесс получения диагностической информации:
SQLCHAR       SqlState[6], SQLStmt[100], Msg[SQL_MAX_MESSAGE_LENGTH];
SQLINTEGER    NativeError;
SQLSMALLINT   i, MsgLen;
SQLRETURN     rc1, rc2;
SQLHSTMT      hstmt;
// В SQLStmt содержится SQL-оператор
// Выполнение оператора и получение информации
// о возникающих ошибках или предупреждениях
rc1 = SQLExecDirect(hstmt, SQLStmt, SQL_NTS);
if ((rc1 == SQL_SUCCESS_WITH_INFO) ||
(rc1 == SQL_ERROR)) {
// Получение записей об ошибках
i = 1;
while ((rc2 = SQLGetDiagRec(SQL_HANDLE_STMT,
hstmt, i, SqlState,
&NativeError,
Msg, sizeof(Msg),
&MsgLen)) != SQL_NO_DATA) {
cout<< SqlState<<" "
<<NativeError<<" "
<<Msg<<" "
<<MsgLen;
i++;
}
}

if ((rc1 == SQL_SUCCESS) ||
(rc1 == SQL_SUCCESS_WITH_INFO)) {
// Оператор выполнен успешно
}

 

 
На главную | Содержание | < Назад....Вперёд >
С вопросами и предложениями можно обращаться по nicivas@bk.ru. 2013 г.Яндекс.Метрика