Основы проектирования приложений баз данных

       

Асинхронное выполнение функций


По умолчанию 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)) { // Оператор выполнен успешно }


Содержание раздела