Asynchroniczne wykonywanie (metoda powiadomienia)
Funkcja ODBC umożliwia asynchroniczne wykonywanie operacji połączenia i instrukcji. Wątek aplikacji może wywołać funkcję ODBC w trybie asynchronicznym, a funkcja może powrócić przed zakończeniem operacji, umożliwiając wątkowi aplikacji wykonywanie innych zadań. W zestawie SDK systemu Windows 7 w przypadku asynchronicznych instrukcji lub operacji połączenia aplikacja ustaliła, że operacja asynchroniczna została ukończona przy użyciu metody sondowania. Aby uzyskać więcej informacji, zobacz Asynchroniczne wykonywanie (metoda sondowania). Począwszy od zestawu SDK systemu Windows 8, można określić, że operacja asynchroniczna została ukończona przy użyciu metody powiadamiania.
W metodzie sondowania aplikacje muszą wywoływać funkcję asynchroniczną za każdym razem, gdy potrzebują one stanu operacji. Metoda powiadomienia jest podobna do wywołania zwrotnego i oczekiwania w ADO.NET. OdBC używa jednak zdarzeń Win32 jako obiektu powiadomienia.
Nie można jednocześnie używać biblioteki kursorów ODBC i powiadomienia asynchronicznego ODBC. Ustawienie obu atrybutów spowoduje zwrócenie błędu z parametrem SQLSTATE S1119 (nie można jednocześnie włączyć biblioteki kursorów i powiadomienia asynchronicznego).
Aby uzyskać informacje dla programistów sterowników, zobacz Powiadomienie o zakończeniu funkcji asynchronicznej.
Notatka
Metoda powiadamiania nie jest obsługiwana w bibliotece kursorów. Jeśli aplikacja podejmie próbę włączenia biblioteki kursorów za pośrednictwem metody SQLSetConnectAttr, zostanie wyświetlony komunikat o błędzie.
Przegląd
Gdy funkcja ODBC jest wywoływana w trybie asynchronicznym, kontrolka jest zwracana do aplikacji wywołującej natychmiast z kodem zwrotnym SQL_STILL_EXECUTING. Aplikacja musi wielokrotnie sondować funkcję, dopóki nie zwróci czegoś innego niż SQL_STILL_EXECUTING. Pętla sondowania zwiększa wykorzystanie procesora, powodując niski poziom wydajności w wielu scenariuszach asynchronicznych.
Za każdym razem, gdy jest używany model powiadomień, model sondowania jest wyłączony. Aplikacje nie powinny ponownie wywoływać oryginalnej funkcji. Wywołaj funkcję SQLCompleteAsync, aby ukończyć operację asynchroniczną. Jeśli aplikacja ponownie wywołuje oryginalną funkcję przed zakończeniem operacji asynchronicznej, wywołanie zwróci SQL_ERROR z SQLSTATE IM017 (odpytywanie jest wyłączone w trybie powiadomień asynchronicznych).
W przypadku korzystania z modelu powiadomień aplikacja może wywołać SQLCancel lub SQLCancelHandle, aby anulować instrukcję lub operację połączenia. Jeśli żądanie anulowania zakończy się pomyślnie, funkcja ODBC zwróci SQL_SUCCESS. Ten komunikat nie wskazuje, że funkcja została rzeczywiście anulowana; wskazuje, że żądanie anulowania zostało przetworzone. Czy funkcja jest rzeczywiście anulowana, jest zależna od sterownika i źródła danych. Po anulowaniu operacji menedżer sterownika wciąż będzie sygnalizował zdarzenie. Menedżer sterowników zwraca SQL_ERROR w buforze kodu zwrotnego, a stan to SQLSTATE HY008 (operacja anulowana), aby wskazać, że anulowanie zakończyło się pomyślnie. Jeśli funkcja zakończyła normalne przetwarzanie, Menedżer sterowników zwraca SQL_SUCCESS lub SQL_SUCCESS_WITH_INFO.
Zachowanie obniżania poziomu
Wersja menedżera sterowników ODBC obsługująca to powiadomienie po zakończeniu to ODBC 3.81.
Wersja ODBC aplikacji | Wersja menedżera sterowników | Wersja sterownika | Zachowanie |
---|---|---|---|
Nowa aplikacja dowolnej wersji ODBC | ODBC 3.81 | Sterownik ODBC 3.80 | Aplikacja może użyć tej funkcji, jeśli sterownik obsługuje tę funkcję, w przeciwnym razie menedżer sterowników zgłosi błąd. |
Nowa aplikacja dowolnej wersji ODBC | ODBC 3.81 | Sterownik pre-ODBC 3.80 | Menedżer sterowników wyświetli błąd, jeśli sterownik nie obsługuje tej funkcji. |
Nowa aplikacja dowolnej wersji ODBC | Pre-ODBC 3.81 | Jakikolwiek | Gdy aplikacja używa tej funkcji, stary menedżer sterowników będzie traktować nowe atrybuty jako atrybuty specyficzne dla sterownika, a sterownik powinien zgłosić błąd. Nowy menedżer sterowników nie przekaże tych atrybutów do sterownika. |
Aplikacja powinna sprawdzić wersję menedżera sterowników przed użyciem tej funkcji. W przeciwnym razie, jeśli nieprawidłowo napisany sterownik nie powoduje błędu, a wersja menedżera sterowników jest sprzed ODBC 3.81, zachowanie jest niezdefiniowane.
Przypadki użycia
W tej sekcji przedstawiono przypadki użycia wykonywania asynchronicznego i mechanizmu sondowania.
Integrowanie danych z wielu źródeł ODBC
Aplikacja integracji danych asynchronicznie pobiera dane z wielu źródeł danych. Niektóre dane pochodzą ze zdalnych źródeł danych, a niektóre dane pochodzą z plików lokalnych. Aplikacja nie może kontynuować, dopóki nie zostaną ukończone operacje asynchroniczne.
Zamiast sprawdzać stan operacji w celu określenia, czy została ukończona, aplikacja może utworzyć obiekt zdarzenia i powiązać go z uchwytem połączenia ODBC lub uchwytem instrukcji ODBC. Następnie aplikacja wywołuje interfejsy API synchronizacji systemu operacyjnego, aby czekać na jeden obiekt zdarzenia lub wiele obiektów zdarzeń (zarówno zdarzeń ODBC, jak i innych zdarzeń systemu Windows). OdBC zasygnalizuje obiekt zdarzenia po zakończeniu odpowiedniej operacji asynchronicznej ODBC.
W systemie Windows zostaną użyte obiekty zdarzeń Win32, które zapewnią użytkownikowi ujednolicony model programowania. Menedżerowie sterowników na innych platformach mogą używać implementacji obiektu zdarzenia specyficznego dla tych platform.
Przykładowy kod poniżej demonstruje użycie asynchronicznego powiadomienia dla połączenia i instrukcji.
// This function opens NUMBER_OPERATIONS connections and executes one query on statement of each connection.
// Asynchronous Notification is used
#define NUMBER_OPERATIONS 5
int AsyncNotificationSample(void)
{
RETCODE rc;
SQLHENV hEnv = NULL;
SQLHDBC arhDbc[NUMBER_OPERATIONS] = {NULL};
SQLHSTMT arhStmt[NUMBER_OPERATIONS] = {NULL};
HANDLE arhDBCEvent[NUMBER_OPERATIONS] = {NULL};
RETCODE arrcDBC[NUMBER_OPERATIONS] = {0};
HANDLE arhSTMTEvent[NUMBER_OPERATIONS] = {NULL};
RETCODE arrcSTMT[NUMBER_OPERATIONS] = {0};
rc = SQLAllocHandle(SQL_HANDLE_ENV, NULL, &hEnv);
if ( !SQL_SUCCEEDED(rc) ) goto Cleanup;
rc = SQLSetEnvAttr(hEnv,
SQL_ATTR_ODBC_VERSION,
(SQLPOINTER) SQL_OV_ODBC3_80,
SQL_IS_INTEGER);
if ( !SQL_SUCCEEDED(rc) ) goto Cleanup;
// Connection operations begin here
// Alloc NUMBER_OPERATIONS connection handles
for (int i=0; i<NUMBER_OPERATIONS; i++)
{
rc = SQLAllocHandle(SQL_HANDLE_DBC, hEnv, &arhDbc[i]);
if ( !SQL_SUCCEEDED(rc) ) goto Cleanup;
}
// Enable DBC Async on all connection handles
for (int i=0; i<NUMBER_OPERATIONS; i++)
{
rc= SQLSetConnectAttr(arhDbc[i], SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE, (SQLPOINTER)SQL_ASYNC_DBC_ENABLE_ON, SQL_IS_INTEGER);
if ( !SQL_SUCCEEDED(rc) ) goto Cleanup;
}
// Application must create event objects
for (int i=0; i<NUMBER_OPERATIONS; i++)
{
arhDBCEvent[i] = CreateEvent(NULL, FALSE, FALSE, NULL); // Auto-reset, initial state is not-signaled
if (!arhDBCEvent[i]) goto Cleanup;
}
// Enable notification on all connection handles
// Event
for (int i=0; i<NUMBER_OPERATIONS; i++)
{
rc= SQLSetConnectAttr(arhDbc[i], SQL_ATTR_ASYNC_DBC_EVENT, arhDBCEvent[i], SQL_IS_POINTER);
if ( !SQL_SUCCEEDED(rc) ) goto Cleanup;
}
// Initiate connect establishing
for (int i=0; i<NUMBER_OPERATIONS; i++)
{
SQLDriverConnect(arhDbc[i], NULL, (SQLTCHAR*)TEXT("Driver={ODBC Driver 11 for SQL Server};SERVER=dp-srv-sql2k;DATABASE=pubs;UID=sa;PWD=XYZ;"), SQL_NTS, NULL, 0, NULL, SQL_DRIVER_NOPROMPT);
}
// Can do some other staff before calling WaitForMultipleObjects
WaitForMultipleObjects(NUMBER_OPERATIONS, arhDBCEvent, TRUE, INFINITE); // Wait All
// Complete connect API calls
for (int i=0; i<NUMBER_OPERATIONS; i++)
{
SQLCompleteAsync(SQL_HANDLE_DBC, arhDbc[i], & arrcDBC[i]);
}
BOOL fFail = FALSE; // Whether some connection opening fails.
for (int i=0; i<NUMBER_OPERATIONS; i++)
{
if ( !SQL_SUCCEEDED(arrcDBC[i]) )
fFail = TRUE;
}
// If some SQLDriverConnect() fail, clean up.
if (fFail)
{
for (int i=0; i<NUMBER_OPERATIONS; i++)
{
if (SQL_SUCCEEDED(arrcDBC[i]) )
{
SQLDisconnect(arhDbc[i]); // This is also async
}
else
{
SetEvent(arhDBCEvent[i]); // Previous SQLDriverConnect() failed. No need to call SQLDisconnect().
}
}
WaitForMultipleObjects(NUMBER_OPERATIONS, arhDBCEvent, TRUE, INFINITE);
for (int i=0; i<NUMBER_OPERATIONS; i++)
{
if (SQL_SUCCEEDED(arrcDBC[i]) )
{
SQLCompleteAsync(SQL_HANDLE_DBC, arhDbc[i], &arrcDBC[i]);; // To Complete
}
}
goto Cleanup;
}
// Statement Operations begin here
// Alloc statement handle
for (int i=0; i<NUMBER_OPERATIONS; i++)
{
rc = SQLAllocHandle(SQL_HANDLE_STMT, arhDbc[i], &arhStmt[i]);
if ( !SQL_SUCCEEDED(rc) ) goto Cleanup;
}
// Enable STMT Async on all statement handles
for (int i=0; i<NUMBER_OPERATIONS; i++)
{
rc = SQLSetStmtAttr(arhStmt[i], SQL_ATTR_ASYNC_ENABLE, (SQLPOINTER)SQL_ASYNC_ENABLE_ON, SQL_IS_INTEGER);
if ( !SQL_SUCCEEDED(rc) ) goto Cleanup;
}
// Create event objects
for (int i=0; i<NUMBER_OPERATIONS; i++)
{
arhSTMTEvent[i] = CreateEvent(NULL, FALSE, FALSE, NULL); // Auto-reset, initial state is not-signaled
if (!arhSTMTEvent[i]) goto Cleanup;
}
// Enable notification on all statement handles
// Event
for (int i=0; i<NUMBER_OPERATIONS; i++)
{
rc= SQLSetStmtAttr(arhStmt[i], SQL_ATTR_ASYNC_STMT_EVENT, arhSTMTEvent[i], SQL_IS_POINTER);
if ( !SQL_SUCCEEDED(rc) ) goto Cleanup;
}
// Initiate SQLExecDirect() calls
for (int i=0; i<NUMBER_OPERATIONS; i++)
{
SQLExecDirect(arhStmt[i], (SQLTCHAR*)TEXT("select au_lname, au_fname from authors"), SQL_NTS);
}
// Can do some other staff before calling WaitForMultipleObjects
WaitForMultipleObjects(NUMBER_OPERATIONS, arhSTMTEvent, TRUE, INFINITE); // Wait All
// Now, call SQLCompleteAsync to complete the operation and get return code
for (int i=0; i<NUMBER_OPERATIONS; i++)
{
SQLCompleteAsync(SQL_HANDLE_STMT, arhStmt[i], &arrcSTMT[i]);
}
// Check return values
for (int i=0; i<NUMBER_OPERATIONS; i++)
{
if ( !SQL_SUCCEEDED(arrcSTMT[i]) ) goto Cleanup;
}
for (int i=0; i<NUMBER_OPERATIONS; i++)
{
//Do some binding jobs here, set SQL_ATTR_ROW_ARRAY_SIZE
}
// Now, initiate fetching
for (int i=0; i<NUMBER_OPERATIONS; i++)
{
SQLFetch(arhStmt[i]);
}
// Can do some other staff before calling WaitForMultipleObjects
WaitForMultipleObjects(NUMBER_OPERATIONS, arhSTMTEvent, TRUE, INFINITE);
// Now, to complete the operations and get return code
for (int i=0; i<NUMBER_OPERATIONS; i++)
{
SQLCompleteAsync(SQL_HANDLE_STMT, arhStmt[i], &arrcSTMT[i]);
}
// Check return code
for (int i=0; i<NUMBER_OPERATIONS; i++)
{
if ( !SQL_SUCCEEDED(arrcSTMT[i]) ) goto Cleanup;
}
// USE fetched data here!!
Cleanup:
for (int i=0; i<NUMBER_OPERATIONS; i++)
{
if (arhStmt[NUMBER_OPERATIONS])
{
SQLFreeHandle(SQL_HANDLE_STMT, arhStmt[i]);
arhStmt[i] = NULL;
}
}
for (int i=0; i<NUMBER_OPERATIONS; i++)
{
if (arhSTMTEvent[i])
{
CloseHandle(arhSTMTEvent[i]);
arhSTMTEvent[i] = NULL;
}
}
for (int i=0; i<NUMBER_OPERATIONS; i++)
{
if (arhDbc[i])
{
SQLFreeHandle(SQL_HANDLE_DBC, arhDbc[i]);
arhDbc[i] = NULL;
}
}
for (int i=0; i<NUMBER_OPERATIONS; i++)
{
if (arhDBCEvent[i])
{
CloseHandle(arhDBCEvent[i]);
arhDBCEvent[i] = NULL;
}
}
if (hEnv)
{
SQLFreeHandle(SQL_HANDLE_ENV, hEnv);
hEnv = NULL;
}
return 0;
}
Określanie, czy sterownik obsługuje powiadomienie asynchroniczne
Aplikacja ODBC może określić, czy sterownik ODBC obsługuje powiadomienia asynchroniczne, wywołując SQLGetInfo. Menedżer sterowników ODBC w związku z tym wywoła SQLGetInfo sterownika za pomocą SQL_ASYNC_NOTIFICATION.
SQLUINTEGER InfoValue;
SQLLEN cbInfoLength;
SQLRETURN retcode;
retcode = SQLGetInfo (hDbc,
SQL_ASYNC_NOTIFICATION,
&InfoValue,
sizeof(InfoValue),
NULL);
if (SQL_SUCCEEDED(retcode))
{
if (SQL_ASYNC_NOTIFICATION_CAPABLE == InfoValue)
{
// The driver supports asynchronous notification
}
else if (SQL_ASYNC_NOTIFICATION_NOT_CAPABLE == InfoValue)
{
// The driver does not support asynchronous notification
}
}
Kojarzenie uchwytu zdarzenia Win32 z uchwytem ODBC
Aplikacje są odpowiedzialne za tworzenie obiektów zdarzeń Win32 przy użyciu odpowiednich funkcji Win32. Aplikacja może skojarzyć jeden uchwyt zdarzenia Win32 z jednym uchwytem połączenia ODBC lub jednym uchwytem instrukcji ODBC.
Atrybuty połączenia SQL_ATTR_ASYNC_DBC_FUNCTION_ENABLE i SQL_ATTR_ASYNC_DBC_EVENT określają, czy ODBC działa w trybie asynchronicznym oraz czy ODBC włącza tryb powiadomień dla uchwytu połączenia. Atrybuty instrukcji SQL_ATTR_ASYNC_ENABLE i SQL_ATTR_ASYNC_STMT_EVENT określają, czy funkcja ODBC jest wykonywana w trybie asynchronicznym i czy funkcja ODBC włącza tryb powiadomień dla uchwytu instrukcji.
SQL_ATTR_ASYNC_ENABLE lub SQL_ATTR_ASYNC_DBC_FUNCTION_ENABLE | SQL_ATTR_ASYNC_STMT_EVENT lub SQL_ATTR_ASYNC_DBC_EVENT | Tryb |
---|---|---|
Włącz | bez wartości null | Powiadomienie asynchroniczne |
Włącz | null | Sondowanie asynchroniczne |
Wyłącz | jakikolwiek | Synchroniczny |
Aplikacja może tymczasowo wyłączyć tryb operacji asynchronicznej. OdBC ignoruje wartości SQL_ATTR_ASYNC_DBC_EVENT, jeśli operacja asynchroniczna na poziomie połączenia jest wyłączona. OdBC ignoruje wartości SQL_ATTR_ASYNC_STMT_EVENT, jeśli operacja asynchroniczna na poziomie instrukcji jest wyłączona.
Synchroniczne wywołanie SQLSetStmtAttr i SQLSetConnectAttr
SQLSetConnectAttr obsługuje operacje asynchroniczne, ale wywołanie SQLSetConnectAttr ustawiania SQL_ATTR_ASYNC_DBC_EVENT jest zawsze synchroniczne.
SQLSetStmtAttr nie obsługuje asynchronicznego wykonywania.
Scenariusz błędu
Po wywołaniu SQLSetConnectAttr przed nawiązaniem połączenia menedżer sterowników nie może określić, który sterownik ma być używany. W związku z tym menedżer sterowników zwraca powodzenie dla SQLSetConnectAttr, ale atrybut może nie być gotowy do ustawienia w sterowniku. Menedżer sterowników ustawi te atrybuty, gdy aplikacja wywołuje funkcję połączenia. Menedżer sterowników może wystąpić z błędem, ponieważ sterownik nie obsługuje operacji asynchronicznych.
Dziedziczenie atrybutów połączenia
Zazwyczaj deklaracje połączenia dziedziczą atrybuty połączenia. Jednak atrybut SQL_ATTR_ASYNC_DBC_EVENT nie jest dziedziczony i ma wpływ tylko na operacje połączenia.
Aby skojarzyć uchwyt zdarzenia z uchwytem połączenia ODBC, aplikacja ODBC wywołuje funkcję interfejsu API ODBC SQLSetConnectAttr i określa SQL_ATTR_ASYNC_DBC_EVENT jako atrybut oraz uchwyt zdarzenia jako wartość atrybutu. Nowy atrybut ODBC SQL_ATTR_ASYNC_DBC_EVENT jest typu SQL_IS_POINTER.
HANDLE hEvent;
hEvent = CreateEvent(
NULL, // default security attributes
FALSE, // auto-reset event
FALSE, // initial state is non-signaled
NULL // no name
);
Zazwyczaj aplikacje tworzą obiekty zdarzeń z automatycznym resetem. OdBC nie spowoduje zresetowania obiektu zdarzenia. Aplikacje muszą upewnić się, że obiekt nie jest w stanie sygnałowym przed wywołaniem żadnej asynchronicznej funkcji ODBC.
SQLRETURN retcode;
retcode = SQLSetConnectAttr ( hDBC,
SQL_ATTR_ASYNC_DBC_EVENT, // Attribute name
(SQLPOINTER) hEvent, // Win32 Event handle
SQL_IS_POINTER); // Length Indicator
SQL_ATTR_ASYNC_DBC_EVENT jest atrybutem tylko menedżera sterowników, który nie zostanie ustawiony w sterowniku.
Wartość domyślna SQL_ATTR_ASYNC_DBC_EVENT ma wartość NULL. Jeśli sterownik nie obsługuje powiadomienia asynchronicznego, pobranie lub ustawienie SQL_ATTR_ASYNC_DBC_EVENT zwróci SQL_ERROR z parametrem SQLSTATE HY092 (nieprawidłowy atrybut/identyfikator opcji).
Jeśli ostatnia wartość SQL_ATTR_ASYNC_DBC_EVENT ustawiona na dojściu połączenia ODBC nie ma wartości NULL oraz tryb asynchroniczny został włączony przez aplikację poprzez ustawienie atrybutu SQL_ATTR_ASYNC_DBC_FUNCTION_ENABLE z SQL_ASYNC_DBC_ENABLE_ON, to wywołanie dowolnej funkcji połączenia ODBC obsługującej tryb asynchroniczny spowoduje otrzymanie powiadomienia o ukończeniu. Jeśli ostatnia wartość SQL_ATTR_ASYNC_DBC_EVENT ustawiona na dojściu połączenia ODBC ma wartość NULL, odBC nie wyśle aplikacji żadnego powiadomienia, niezależnie od tego, czy tryb asynchroniczny jest włączony.
Aplikacja może ustawić SQL_ATTR_ASYNC_DBC_EVENT przed lub po ustawieniu SQL_ATTR_ASYNC_DBC_FUNCTION_ENABLE atrybutu.
Aplikacje mogą ustawić atrybut SQL_ATTR_ASYNC_DBC_EVENT na dojściu połączenia ODBC przed wywołaniem funkcji połączenia (SQLConnect, SQLBrowseConnectlub SQLDriverConnect). Ponieważ menedżer sterowników ODBC nie wie, który sterownik ODBC będzie używany przez aplikację, zwróci SQL_SUCCESS. Gdy aplikacja wywołuje funkcję połączenia, menedżer sterowników ODBC sprawdzi, czy sterownik obsługuje powiadomienia asynchroniczne. Jeśli sterownik nie obsługuje powiadamiania asynchronicznego, Menedżer sterownika ODBC zwróci SQL_ERROR z SQLSTATE S1_118 (sterownik nie obsługuje powiadamiania asynchronicznego). Jeśli sterownik obsługuje powiadomienie asynchroniczne, menedżer sterowników ODBC wywoła sterownik i ustawi odpowiednie atrybuty SQL_ATTR_ASYNC_DBC_NOTIFICATION_CALLBACK i SQL_ATTR_ASYNC_DBC_NOTIFICATION_CONTEXT.
Podobnie aplikacja wywołuje SQLSetStmtAttr na dojściu instrukcji ODBC i określa atrybut SQL_ATTR_ASYNC_STMT_EVENT, aby włączyć lub wyłączyć asynchroniczne powiadomienie na poziomie instrukcji. Ponieważ funkcja instrukcji SQL jest zawsze wywoływana po nawiązaniu połączenia, SQLSetStmtAttr natychmiast zwróci SQL_ERROR z kodem SQLSTATE S1_118 (sterownik nie obsługuje powiadomień asynchronicznych), jeśli odpowiedni sterownik nie obsługuje operacji asynchronicznych lub obsługuje operacje asynchroniczne, ale nie obsługuje powiadomień asynchronicznych.
SQLRETURN retcode;
retcode = SQLSetStmtAttr ( hSTMT,
SQL_ATTR_ASYNC_STMT_EVENT, // Attribute name
(SQLPOINTER) hEvent, // Win32 Event handle
SQL_IS_POINTER); // length Indicator
SQL_ATTR_ASYNC_STMT_EVENT, który można ustawić na wartość NULL, jest atrybutem tylko menedżera sterowników, który nie zostanie ustawiony w sterowniku.
Wartość domyślna SQL_ATTR_ASYNC_STMT_EVENT ma wartość NULL. Jeśli sterownik nie obsługuje powiadomienia asynchronicznego, pobranie lub ustawienie atrybutu SQL_ATTR_ASYNC_ STMT_EVENT zwróci SQL_ERROR z parametrem SQLSTATE HY092 (nieprawidłowy atrybut/identyfikator opcji).
Aplikacja nie powinna skojarzyć tego samego uchwytu zdarzeń z więcej niż jednym uchwytem ODBC. W przeciwnym razie jedno powiadomienie zostanie utracone, jeśli dwa asynchroniczne wywołania funkcji ODBC zostaną ukończone na dwóch uchwytach, które współużytkują tego samego uchwytu zdarzenia. Aby uniknąć sytuacji, w której obsługa instrukcji dziedziczy ten sam uchwyt zdarzeń z uchwytu połączenia, funkcja ODBC zwraca SQL_ERROR z SQLSTATE IM016 (Nie można ustawić atrybutu instrukcji dla uchwytu połączenia), jeśli aplikacja ustawia SQL_ATTR_ASYNC_STMT_EVENT dla uchwytu połączenia.
Wywoływanie asynchronicznych funkcji ODBC
Po włączeniu powiadomienia asynchronicznego i uruchomieniu operacji asynchronicznej aplikacja może wywołać dowolną funkcję ODBC. Jeśli funkcja należy do zestawu funkcji obsługujących operację asynchroniczną, aplikacja otrzyma powiadomienie o zakończeniu operacji, niezależnie od tego, czy funkcja zakończyła się niepowodzeniem, czy zakończyła się pomyślnie. Jedynym wyjątkiem jest sytuacja, gdy aplikacja wywołuje funkcję ODBC za pomocą nieprawidłowego uchwytu połączenia lub instrukcji. W takim przypadku ODBC nie otrzyma dojścia zdarzenia i ustawi go w stanie zasygnalizowanym.
Aplikacja musi upewnić się, że skojarzony obiekt zdarzenia jest w stanie niesygnalizowany przed rozpoczęciem operacji asynchronicznej na odpowiednim dojściu ODBC. OdBC nie spowoduje zresetowania obiektu zdarzenia.
Otrzymywanie powiadomień z ODBC
Wątek aplikacji może wywołać WaitForSingleObject, aby czekać na jednym dojściu zdarzenia lub wywołać WaitForMultipleObjects, aby czekać na tablicę dojść zdarzeń i być zawieszony do momentu, aż jeden lub wszystkie obiekty zdarzeń zostaną zasygnalizowane lub upłynie interwał limitu czasu.
DWORD dwStatus = WaitForSingleObject(
hEvent, // The event associated with the ODBC handle
5000 // timeout is 5000 millisecond
);
If (dwStatus == WAIT_TIMEOUT)
{
// time-out interval elapsed before all the events are signaled.
}
Else
{
// Call the corresponding Asynchronous ODBC API to complete all processing and retrieve the return code.
}