非同期実行 (通知方法)Asynchronous Execution (Notification Method)

ODBC を使用すると、接続およびステートメント操作を非同期に実行できます。ODBC allows asynchronous execution of connection and statement operations. アプリケーションスレッドは、非同期モードで ODBC 関数を呼び出すことができます。また、関数は、操作が完了する前にを返すことができます。これにより、アプリケーションスレッドで他のタスクを実行できるようになります。An application thread can call an ODBC function in asynchronous mode and the function can return before the operation is complete, allowing the application thread to perform other tasks. Windows 7 SDK で、非同期ステートメントまたは接続操作の場合、アプリケーションは、ポーリングメソッドを使用して非同期操作が完了したと判断しました。In the Windows 7 SDK, for asynchronous statement or connection operations, an application determined that the asynchronous operation was complete using the polling method. 詳細については、「非同期実行 (ポーリングメソッド)」を参照してください。For more information, see Asynchronous Execution (Polling Method). Windows 8 SDK 以降では、通知メソッドを使用して非同期操作が完了したことを確認できます。Beginning in the Windows 8 SDK, you can determine that an asynchronous operation is complete using the notification method.

ポーリングメソッドでは、アプリケーションは、操作の状態を要求するたびに非同期関数を呼び出す必要があります。In the polling method, applications need to call the asynchronous function each time it wants the status of the operation. 通知方法は、コールバックと ADO.NET での待機に似ています。The notification method is similar to callback and wait in ADO.NET. ただし、ODBC では、通知オブジェクトとして Win32 イベントが使用されます。ODBC, however, uses Win32 events as the notification object.

ODBC カーソルライブラリと ODBC 非同期通知は同時に使用できません。The ODBC Cursor Library and ODBC asynchronous notification cannot be used at the same time. 両方の属性を設定すると、SQLSTATE S1119 (カーソルライブラリと非同期通知を同時に有効にすることはできません) でエラーが返されます。Setting both attributes will return an error with SQLSTATE S1119 (Cursor Library and Asynchronous Notification cannot be enabled at the same time).

ドライバー開発者向けの情報については、「非同期関数の完了通知」を参照してください。See Notification of Asynchronous Function Completion for information for driver developers.

注意

通知方法は、カーソルライブラリではサポートされていません。The notification method is not supported with cursor library. 通知方法が有効になっている場合、SQLSetConnectAttr 経由でカーソルライブラリを有効にしようとすると、アプリケーションでエラーメッセージが表示されます。An application will receive error message if it attempts to enable cursor library via SQLSetConnectAttr, when the notification method is enabled.

概要Overview

ODBC 関数が非同期モードで呼び出されると、呼び出し元のアプリケーションにコントロールが返されます。その際、SQL_STILL_EXECUTING のリターンコードが直ちに返されます。When an ODBC function is called in asynchronous mode, the control is returned to the calling application immediately with the return code SQL_STILL_EXECUTING. アプリケーションは、SQL_STILL_EXECUTING 以外のものを返すまで、関数を繰り返しポーリングする必要があります。The application must repeatedly poll the function until it returns something other than SQL_STILL_EXECUTING. ポーリングループが原因で CPU 使用率が増加し、多くの非同期シナリオでパフォーマンスが低下します。The polling loop increases CPU utilization, causing poor performance in many asynchronous scenarios.

通知モデルが使用されるたびに、ポーリングモデルは無効になります。Whenever the notification model is used, the polling model is disabled. アプリケーションでは、元の関数を再度呼び出すことはできません。Applications should not call the original function again. Sqlcompleteasync 関数を呼び出して、非同期操作を完了します。Call SQLCompleteAsync Function to complete the asynchronous operation. 非同期操作が完了する前にアプリケーションが元の関数を再び呼び出した場合、呼び出しは SQLSTATE IM017 (非同期通知モードではポーリングが無効) の SQL_ERROR を返します。If an application calls the original function again before the asynchronous operation is complete, the call will return SQL_ERROR with SQLSTATE IM017 (Polling is disabled in Asynchronous Notification Mode).

通知モデルを使用する場合、アプリケーションはSQLCancelまたはsqlcancelhandleを呼び出して、ステートメントまたは接続操作を取り消すことができます。When using the notification model, the application can call SQLCancel or SQLCancelHandle to cancel a statement or connection operation. キャンセル要求が成功すると、ODBC は SQL_SUCCESS を返します。If the cancel request is successful, ODBC will return SQL_SUCCESS. このメッセージは、関数が実際にキャンセルされたことを示すものではありません。これは、キャンセル要求が処理されたことを示します。This message does not indicate that the function was actually canceled; it indicates that the cancel request was processed. 関数が実際に取り消されたかどうかは、ドライバーに依存し、データソースに依存します。Whether the function is actually canceled is driver-dependent and data source-dependent. 操作が取り消されると、ドライバーマネージャーは引き続きイベントを通知します。When an operation is canceled, the Driver Manager will still signal the event. ドライバーマネージャーはリターンコードバッファーに SQL_ERROR を返し、キャンセルが成功したことを示す状態は SQLSTATE HY008 (操作が取り消されました) になります。The Driver Manager returns SQL_ERROR in the return code buffer and the state is SQLSTATE HY008 (Operation canceled) to indicate the cancelation is successful. 関数が通常の処理を完了した場合、ドライバーマネージャーは SQL_SUCCESS または SQL_SUCCESS_WITH_INFO を返します。If the function completed its normal processing, the Driver Manager returns SQL_SUCCESS or SQL_SUCCESS_WITH_INFO.

ダウンレベルの動作Downlevel Behavior

この通知をサポートしている ODBC ドライバーマネージャーのバージョンは、ODBC 3.81 です。The ODBC Driver Manager version supporting this notification on complete is ODBC 3.81.

Application ODBC のバージョンApplication ODBC Version ドライバーマネージャーのバージョンDriver Manager Version ドライバーのバージョンDriver Version 動作Behavior
任意の ODBC バージョンの新しいアプリケーションNew application of any ODBC version ODBC 3.81ODBC 3.81 ODBC 3.80 ドライバーODBC 3.80 Driver ドライバーがこの機能をサポートしている場合、アプリケーションはこの機能を使用できます。それ以外の場合は、ドライバーマネージャーによってエラーが発生します。Application can use this feature if the driver supports this feature, otherwise the Driver Manager will error out.
任意の ODBC バージョンの新しいアプリケーションNew application of any ODBC version ODBC 3.81ODBC 3.81 ODBC 前3.80 ドライバーPre-ODBC 3.80 Driver ドライバーがこの機能をサポートしていない場合は、ドライバーマネージャーでエラーが発生します。The Driver Manager will error out if the driver does not support this feature.
任意の ODBC バージョンの新しいアプリケーションNew application of any ODBC version ODBC 前3.81Pre-ODBC 3.81 AnyAny アプリケーションでこの機能を使用すると、古いドライバーマネージャーによって新しい属性がドライバー固有の属性として考慮され、ドライバーでエラーが発生します。新しいドライバーマネージャーは、これらの属性をドライバーに渡しません。When the application uses this feature, an old Driver Manager will regard the new attributes as driver-specific attributes, and the driver should error out. A new Driver Manager will not pass these attributes to the driver.

アプリケーションでは、この機能を使用する前に、ドライバーマネージャーのバージョンを確認する必要があります。An application should check the Driver Manager version before using this feature. それ以外の場合、適切に記述されていないドライバーがエラーになり、ドライバーマネージャーのバージョンが ODBC 3.81 より前の場合、動作は未定義になります。Otherwise, if a poorly written driver does not error out and the Driver Manager version is pre ODBC 3.81, behavior is undefined.

Use Cases

ここでは、非同期実行のユースケースとポーリング機構について説明します。This section shows use cases for asynchronous execution and the polling mechanism.

複数の ODBC ソースからのデータを統合するIntegrate Data from Multiple ODBC Sources

データ統合アプリケーションは、複数のデータソースから非同期的にデータをフェッチします。A data integration application asynchronously fetches data from multiple data sources. 一部のデータは、リモートデータソースからのものであり、一部のデータはローカルファイルからのものです。Some of the data are from remote data sources and some data are from local files. 非同期操作が完了するまで、アプリケーションは続行できません。The application cannot continue until the asynchronous operations are completed.

操作を繰り返しポーリングして、完了しているかどうかを判断するのではなく、アプリケーションでイベントオブジェクトを作成し、ODBC 接続ハンドルまたは ODBC ステートメントハンドルに関連付けることができます。Instead of repeatedly polling an operation to determine if it is complete, the application can create an event object and associate it with an ODBC connection handle or an ODBC statement handle. 次に、アプリケーションは、オペレーティングシステムの同期 Api を呼び出して、1つまたは複数のイベントオブジェクト (ODBC イベントとその他の Windows イベントの両方) を待機します。The application then calls operating system synchronization APIs to wait on one event object or many event objects (both ODBC events and other Windows events). ODBC は、対応する ODBC 非同期操作が完了するとイベントオブジェクトを通知します。ODBC will signal the event object when the corresponding ODBC asynchronous operation is completed.

Windows では、Win32 イベントオブジェクトが使用され、ユーザーは統一されたプログラミングモデルを提供します。On Windows, Win32 event objects will be used and that will provide the user a unified programming model. 他のプラットフォームのドライバーマネージャーは、これらのプラットフォームに固有のイベントオブジェクトの実装を使用できます。Driver Managers on other platforms can use the event object implementation specific to those platforms.

次のコードサンプルは、接続とステートメントの非同期通知の使用方法を示しています。The following code sample demonstrates the use of connection and statement asynchronous notification:

// 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 openning 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;  
}  
  

ドライバーが非同期通知をサポートしているかどうかを確認するDetermining if a Driver Supports Asynchronous Notification

Odbc アプリケーションは、 SQLGetInfoを呼び出すことによって、odbc ドライバーが非同期通知をサポートしているかどうかを判断できます。An ODBC application can determine if an ODBC driver supports asynchronous notification by calling SQLGetInfo. その結果、ODBC ドライバーマネージャーは、SQL_ASYNC_NOTIFICATION でドライバーのSQLGetInfoを呼び出します。The ODBC Driver Manager will consequently call the SQLGetInfo of the driver with 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  
      }  
}  

Win32 イベントハンドルと ODBC ハンドルの関連付けAssociating a Win32 Event Handle with an ODBC Handle

アプリケーションは、対応する Win32 関数を使用して Win32 イベントオブジェクトを作成します。Applications are responsible for creating Win32 event objects using the corresponding Win32 functions. アプリケーションでは、1つの Win32 イベントハンドルを1つの ODBC 接続ハンドルまたは1つの ODBC ステートメントハンドルに関連付けることができます。An application can associate one Win32 event handle with one ODBC connection handle or one ODBC statement handle.

接続属性 SQL_ATTR_ASYNC_DBC_FUNCTION_ENABLE および SQL_ATTR_ASYNC_DBC_EVENT ODBC が非同期モードで実行されるかどうか、および ODBC が接続ハンドルの通知モードを有効にするかどうかを決定します。Connection attributes SQL_ATTR_ASYNC_DBC_FUNCTION_ENABLE and SQL_ATTR_ASYNC_DBC_EVENT determine whether ODBC executes in asynchronous mode and whether ODBC enables notification mode for a connection handle. ステートメント属性 SQL_ATTR_ASYNC_ENABLE および SQL_ATTR_ASYNC_STMT_EVENT ODBC が非同期モードで実行されるかどうか、および ODBC がステートメントハンドルの通知モードを有効にするかどうかを決定します。Statement attributes SQL_ATTR_ASYNC_ENABLE and SQL_ATTR_ASYNC_STMT_EVENT determine whether ODBC executes in asynchronous mode and whether ODBC enables notification mode for a statement handle.

SQL_ATTR_ASYNC_ENABLE または SQL_ATTR_ASYNC_DBC_FUNCTION_ENABLESQL_ATTR_ASYNC_ENABLE or SQL_ATTR_ASYNC_DBC_FUNCTION_ENABLE SQL_ATTR_ASYNC_STMT_EVENT または SQL_ATTR_ASYNC_DBC_EVENTSQL_ATTR_ASYNC_STMT_EVENT or SQL_ATTR_ASYNC_DBC_EVENT モードMode
有効化Enable null 以外non-null 非同期通知Asynchronous Notification
有効化Enable nullnull 非同期ポーリングAsynchronous Polling
DisableDisable anyany 同期Synchronous

アプリケーションでは、非同期操作モードを一時的にに無効にすることができます。An application can temporally disable asynchronous operation mode. 接続レベルの非同期操作が無効になっている場合、ODBC は SQL_ATTR_ASYNC_DBC_EVENT の値を無視します。ODBC ignores values of SQL_ATTR_ASYNC_DBC_EVENT if the connection level asynchronous operation is disabled. ステートメントレベルの非同期操作が無効になっている場合、ODBC は SQL_ATTR_ASYNC_STMT_EVENT の値を無視します。ODBC ignores values of SQL_ATTR_ASYNC_STMT_EVENT if the statement level asynchronous operation is disabled.

SQLSetStmtAttrSQLSetConnectAttrの同期呼び出しSynchronous call of SQLSetStmtAttr and SQLSetConnectAttr

  • SQLSetConnectAttrは非同期操作をサポートしますが、SQL_ATTR_ASYNC_DBC_EVENT 設定するSQLSetConnectAttrの呼び出しは常に同期です。SQLSetConnectAttr supports asynchronous operations but the invocation of SQLSetConnectAttr to set SQL_ATTR_ASYNC_DBC_EVENT is always synchronous.

  • SQLSetStmtAttrでは、非同期実行はサポートされていません。SQLSetStmtAttr does not support asynchronous execution.

エラー-出力シナリオError-out scenario
接続を作成する前にSQLSetConnectAttrを呼び出すと、ドライバーマネージャーは使用するドライバーを決定できません。When SQLSetConnectAttr is called before making a connection, the Driver Manager cannot determine which driver to use. そのため、ドライバーマネージャーはSQLSetConnectAttrの成功を返しますが、ドライバーで属性を設定する準備ができていない可能性があります。Therefore, the Driver Manager returns success for SQLSetConnectAttr but the attribute may not be ready to set in the driver. アプリケーションが接続関数を呼び出すと、ドライバーマネージャーによってこれらの属性が設定されます。The Driver Manager will set these attributes when the application calls a connection function. ドライバーで非同期操作がサポートされていないため、ドライバーマネージャーでエラーが発生することがあります。The Driver Manager may error-out because driver does not support asynchronous operations.

接続属性の継承Inheritance of connection attributes
通常、接続のステートメントは、接続属性を継承します。Usually, the statements of a connection will inherit the connection attributes. ただし、属性 SQL_ATTR_ASYNC_DBC_EVENT は継承できないため、接続操作にのみ影響します。However, the attribute SQL_ATTR_ASYNC_DBC_EVENT is not inheritable and only affects the connection operations.

Odbc アプリケーションでは、イベントハンドルを ODBC 接続ハンドルに関連付けるために、ODBC API SQLSetConnectAttrを呼び出し、属性およびイベントハンドルとして SQL_ATTR_ASYNC_DBC_EVENT を属性値として指定します。To associate an event handle with an ODBC connection handle, an ODBC application calls ODBC API SQLSetConnectAttr and specifies SQL_ATTR_ASYNC_DBC_EVENT as the attribute and the event handle as the attribute value. 新しい ODBC 属性 SQL_ATTR_ASYNC_DBC_EVENT は SQL_IS_POINTER 型です。The new ODBC attribute SQL_ATTR_ASYNC_DBC_EVENT is of type SQL_IS_POINTER.

HANDLE hEvent;  
hEvent = CreateEvent(   
            NULL,                // default security attributes  
            FALSE,               // auto-reset event  
            FALSE,               // initial state is non-signaled  
            NULL                 // no name  
            );  

通常、アプリケーションは自動リセットイベントオブジェクトを作成します。Usually, applications create auto-reset event objects. ODBC では、イベントオブジェクトはリセットされません。ODBC will not reset the event object. 非同期 ODBC 関数を呼び出す前に、アプリケーションでオブジェクトがシグナル状態になっていないことを確認する必要があります。Applications must make sure that the object is not in signaled state before calling any asynchronous ODBC function.

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 は、ドライバーでは設定されない、ドライバーマネージャーのみの属性です。SQL_ATTR_ASYNC_DBC_EVENT is a Driver Manager-only attribute that will not be set in the driver.

SQL_ATTR_ASYNC_DBC_EVENT の既定値は NULL です。The default value of SQL_ATTR_ASYNC_DBC_EVENT is NULL. ドライバーが非同期通知をサポートしていない場合、SQL_ATTR_ASYNC_DBC_EVENT の取得または設定では、SQLSTATE HY092 (無効な属性/オプション識別子) の SQL_ERROR が返されます。If the driver does not support asynchronous notification, getting or setting SQL_ATTR_ASYNC_DBC_EVENT will return SQL_ERROR with SQLSTATE HY092 (Invalid attribute/option identifier).

ODBC 接続ハンドルで設定された最後の SQL_ATTR_ASYNC_DBC_EVENT 値が NULL ではなく、アプリケーションが SQL_ASYNC_DBC_ENABLE_ON で属性 SQL_ATTR_ASYNC_DBC_FUNCTION_ENABLE を設定して非同期モードを有効にした場合、非同期モードをサポートする ODBC 接続関数を呼び出すと完了通知が返されます。If the last SQL_ATTR_ASYNC_DBC_EVENT value set on an ODBC connection handle is not NULL and the application enabled asynchronous mode by setting attribute SQL_ATTR_ASYNC_DBC_FUNCTION_ENABLE with SQL_ASYNC_DBC_ENABLE_ON, calling any ODBC connection function that supports asynchronous mode will get a completion notification. ODBC 接続ハンドルに設定されている最後の SQL_ATTR_ASYNC_DBC_EVENT 値が NULL の場合、非同期モードが有効かどうかに関係なく、ODBC はアプリケーションに通知を送信しません。If the last SQL_ATTR_ASYNC_DBC_EVENT value set on an ODBC connection handle is NULL, ODBC will not send the application any notification, regardless whether asynchronous mode is enabled.

アプリケーションでは、属性 SQL_ATTR_ASYNC_DBC_FUNCTION_ENABLE を設定する前または後に SQL_ATTR_ASYNC_DBC_EVENT を設定できます。An application can set SQL_ATTR_ASYNC_DBC_EVENT before or after setting the attribute SQL_ATTR_ASYNC_DBC_FUNCTION_ENABLE.

アプリケーションでは、接続関数 (SQLConnectSQLBrowseConnect、またはSQLDriverConnect) を呼び出す前に、ODBC 接続ハンドルの SQL_ATTR_ASYNC_DBC_EVENT 属性を設定できます。Applications can set the SQL_ATTR_ASYNC_DBC_EVENT attribute on an ODBC connection handle before calling a connection function (SQLConnect, SQLBrowseConnect, or SQLDriverConnect). ODBC ドライバーマネージャーでは、アプリケーションが使用する ODBC ドライバーが認識されないため、SQL_SUCCESS が返されます。Because the ODBC Driver Manager does not know which ODBC driver the application will use, it will return SQL_SUCCESS. アプリケーションが接続関数を呼び出すと、ODBC ドライバーマネージャーは、ドライバーが非同期通知をサポートしているかどうかを確認します。When the application calls a connection function, the ODBC Driver Manager will check whether the driver supports asynchronous notification. ドライバーが非同期通知をサポートしていない場合、ODBC ドライバーマネージャーは SQLSTATE S1_118 で SQL_ERROR を返します (ドライバーは非同期通知をサポートしていません)。If the driver does not support asynchronous notification, the ODBC Driver Manager will return SQL_ERROR with SQLSTATE S1_118 (Driver does not support asynchronous notification). ドライバーが非同期通知をサポートしている場合、ODBC ドライバーマネージャーはドライバーを呼び出し、対応する属性 SQL_ATTR_ASYNC_DBC_NOTIFICATION_CALLBACK および SQL_ATTR_ASYNC_DBC_NOTIFICATION_CONTEXT を設定します。If the driver supports asynchronous notification, the ODBC Driver Manager will call the driver and set the corresponding attributes SQL_ATTR_ASYNC_DBC_NOTIFICATION_CALLBACK and SQL_ATTR_ASYNC_DBC_NOTIFICATION_CONTEXT.

同様に、アプリケーションは ODBC ステートメントハンドルでSQLSetStmtAttrを呼び出し、ステートメントレベルの非同期通知を有効または無効にする SQL_ATTR_ASYNC_STMT_EVENT 属性を指定します。Similarly, an application calls SQLSetStmtAttr on an ODBC statement handle and specifies the SQL_ATTR_ASYNC_STMT_EVENT attribute to enable or disable statement level asynchronous notification. 接続が確立されると、ステートメント関数は常に呼び出されるため、 SQLSetStmtAttrは、対応するドライバーが非同期操作をサポートしていない場合、またはドライバーが非同期操作をサポートしているが非同期通知をサポートしていない場合に、SQLSTATE S1_118 (ドライバーは非同期通知をサポートしません) を使用して SQL_ERROR を返します。Because a statement function is always called after the connection is established, SQLSetStmtAttr will return SQL_ERROR with SQLSTATE S1_118 (Driver does not support asynchronous notification) immediately if the corresponding driver does not support asynchronous operations or the driver supports asynchronous operation but does not support asynchronous notification.

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 は、NULL に設定できますが、ドライバーマネージャーのみの属性であり、ドライバーでは設定されません。SQL_ATTR_ASYNC_STMT_EVENT, which can be set to NULL, is a Driver Manager-only attribute that will not be set in the driver.

SQL_ATTR_ASYNC_STMT_EVENT の既定値は NULL です。The default value of SQL_ATTR_ASYNC_STMT_EVENT is NULL. ドライバーが非同期通知をサポートしていない場合、SQL_ATTR_ASYNC_ STMT_EVENT 属性を取得または設定すると、SQLSTATE HY092 (無効な属性/オプション識別子) の SQL_ERROR が返されます。If the driver does not support asynchronous notification, getting or setting the SQL_ATTR_ASYNC_ STMT_EVENT attribute will return SQL_ERROR with SQLSTATE HY092 (Invalid attribute/option identifier).

アプリケーションでは、同じイベントハンドルを複数の ODBC ハンドルに関連付けることはできません。An application should not associate the same event handle with more than one ODBC handle. それ以外の場合、2つの非同期の ODBC 関数呼び出しが、同じイベントハンドルを共有する2つのハンドルで完了すると、1つの通知が失われます。Otherwise, one notification will be lost if two asynchronous ODBC function invocations complete on two handles that share the same event handle. 接続ハンドルから同じイベントハンドルを継承するステートメントハンドルを使用しないようにするには、アプリケーションが接続ハンドルに SQL_ATTR_ASYNC_STMT_EVENT を設定していると、ODBC は SQLSTATE IM016 (ステートメント属性を接続ハンドルに設定できません) で SQL_ERROR を返します。To avoid a statement handle inheriting the same event handle from the connection handle, ODBC returns SQL_ERROR with SQLSTATE IM016 (Cannot set statement attribute into connection handle) if an application sets SQL_ATTR_ASYNC_STMT_EVENT on a connection handle.

非同期 ODBC 関数の呼び出しCalling Asynchronous ODBC Functions

非同期通知を有効にし、非同期操作を開始した後、アプリケーションは任意の ODBC 関数を呼び出すことができます。After enabling asynchronous notification and starting an asynchronous operation, the application can call any ODBC function. 関数が非同期操作をサポートする関数のセットに属している場合、その関数が失敗したか成功したかに関係なく、操作が完了すると、アプリケーションは完了通知を受け取ります。If the function belongs to the set of functions that support asynchronous operation, the application will get a completion notification when the operation completes, regardless of whether the function failed or succeeded. 唯一の例外は、アプリケーションが ODBC 関数を無効な接続またはステートメントハンドルで呼び出すことです。The only exception is that the application calls an ODBC function with an invalid connection or statement handle. この場合、ODBC はイベントハンドルを取得せず、シグナル状態に設定します。In this case, ODBC will not get the event handle and set it to the signaled state.

アプリケーションは、対応する ODBC ハンドルで非同期操作を開始する前に、関連付けられているイベントオブジェクトがシグナル状態でないことを確認する必要があります。The application must ensure that the associated event object is in a non-signaled state before starting an asynchronous operation on the corresponding ODBC handle. ODBC では、イベントオブジェクトはリセットされません。ODBC will not reset the event object.

ODBC から通知を受け取るGetting Notification from ODBC

アプリケーションスレッドは、 WaitForSingleObjectを呼び出して1つのイベントハンドルを待機するか、またはWaitForMultipleObjectsを呼び出してイベントハンドルの配列を待機し、1つまたはすべてのイベントオブジェクトがシグナル状態になるか、タイムアウト間隔が経過するまで中断させることができます。An application thread can call WaitForSingleObject to wait on one event handle or call WaitForMultipleObjects to wait on an array of event handles and be suspended until one or all of the event objects become signaled or the time-out interval elapses.

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.  
}