다음을 통해 공유


비동기 실행(알림 방법)

ODBC를 사용하면 연결 및 문 작업을 비동기식으로 실행할 수 있습니다. 애플리케이션 스레드는 비동기 모드에서 ODBC 함수를 호출할 수 있으며 작업이 완료되기 전에 함수가 반환되어 애플리케이션 스레드가 다른 작업을 수행할 수 있습니다. Windows 7 SDK에서 비동기 문 또는 연결 작업의 경우 애플리케이션은 폴링 방법을 사용하여 비동기 작업이 완료되었음을 확인했습니다. 자세한 내용은 비동기 실행(폴링 방법)을 참조하세요. Windows 8 SDK부터 알림 방법을 사용하여 비동기 작업이 완료되었는지 확인할 수 있습니다.

폴링 메서드에서 애플리케이션은 작업의 상태 필요할 때마다 비동기 함수를 호출해야 합니다. 알림 방법은 콜백과 유사하며 ADO.NET 대기합니다. 그러나 ODBC는 Win32 이벤트를 알림 개체로 사용합니다.

ODBC 커서 라이브러리 및 ODBC 비동기 알림은 동시에 사용할 수 없습니다. 두 특성을 모두 설정하면 SQLSTATE S1119 오류가 반환됩니다(커서 라이브러리 및 비동기 알림을 동시에 사용할 수 없음).

드라이버 개발자에 대한 정보는 비동기 함수 완료 알림을 참조하세요.

참고 항목

알림 메서드는 커서 라이브러리에서 지원되지 않습니다. 애플리케이션은 알림 방법을 사용할 때 SQLSet커넥트Attr을 통해 커서 라이브러리를 사용하도록 설정하려고 하면 오류 메시지를 받습니다.

개요

ODBC 함수가 비동기 모드에서 호출되면 반환 코드 SQL_STILL_EXECUTING 사용하여 컨트롤이 호출 애플리케이션에 즉시 반환됩니다. 애플리케이션은 SQL_STILL_EXECUTING 이외의 함수를 반환할 때까지 함수를 반복적으로 폴링해야 합니다. 폴링 루프는 CPU 사용률을 증가시켜 많은 비동기 시나리오에서 성능이 저하됩니다.

알림 모델을 사용할 때마다 폴링 모델을 사용할 수 없습니다. 애플리케이션은 원래 함수를 다시 호출하면 안 됩니다. SQLCompleteAsync 함수를 호출하여 비동기 작업을 완료합니다. 비동기 작업이 완료되기 전에 애플리케이션이 원래 함수를 다시 호출하는 경우 호출은 SQLSTATE IM017을 사용하여 SQL_ERROR 반환합니다(폴링은 비동기 알림 모드에서 비활성화됨).

알림 모델을 사용하는 경우 애플리케이션은 SQLCancel 또는 SQLCancelHandle을 호출하여 문 또는 연결 작업을 취소할 수 있습니다. 취소 요청이 성공하면 ODBC는 SQL_SUCCESS 반환합니다. 이 메시지는 함수가 실제로 취소되었음을 나타내지 않습니다. 취소 요청이 처리되었음을 나타냅니다. 함수가 실제로 취소되는지 여부는 드라이버 종속 및 데이터 원본에 종속됩니다. 작업이 취소되면 드라이버 관리자는 여전히 이벤트에 신호를 보내게 됩니다. 드라이버 관리자는 반환 코드 버퍼의 SQL_ERROR 반환하고 상태는 취소에 성공했음을 나타내기 위해 SQLSTATE HY008(작업 취소됨)입니다. 함수가 정상적인 처리를 완료하면 드라이버 관리자가 SQL_SUCCESS 또는 SQL_SUCCESS_WITH_INFO 반환합니다.

아래쪽 동작

완료 시 이 알림을 지원하는 ODBC 드라이버 관리자 버전은 ODBC 3.81입니다.

애플리케이션 ODBC 버전 드라이버 관리자 버전 드라이버 버전 동작
모든 ODBC 버전의 새 애플리케이션 ODBC 3.81 ODBC 3.80 드라이버 드라이버가 이 기능을 지원하는 경우 애플리케이션에서 이 기능을 사용할 수 있습니다. 그렇지 않으면 드라이버 관리자가 오류가 발생합니다.
모든 ODBC 버전의 새 애플리케이션 ODBC 3.81 ODBC 3.80 이전 드라이버 드라이버가 이 기능을 지원하지 않는 경우 드라이버 관리자에서 오류가 발생합니다.
모든 ODBC 버전의 새 애플리케이션 ODBC 3.81 이전 모두 애플리케이션에서 이 기능을 사용하는 경우 이전 드라이버 관리자는 새 특성을 드라이버별 특성으로 간주하고 드라이버가 오류를 발생시켜야 합니다. 새 드라이버 관리자는 이러한 특성을 드라이버에 전달하지 않습니다.

애플리케이션은 이 기능을 사용하기 전에 드라이버 관리자 버전을 검사 합니다. 그렇지 않으면 잘못 작성된 드라이버에서 오류가 발생하지 않고 드라이버 관리자 버전이 ODBC 3.81 이전인 경우 동작이 정의되지 않습니다.

사용 사례

이 섹션에서는 비동기 실행 및 폴링 메커니즘에 대한 사용 사례를 보여 줍니다.

여러 ODBC 원본의 데이터 통합

데이터 통합 애플리케이션은 여러 데이터 원본에서 데이터를 비동기적으로 가져옵니다. 일부 데이터는 원격 데이터 원본에서, 일부 데이터는 로컬 파일에서 가져옵니다. 비동기 작업이 완료될 때까지 애플리케이션을 계속할 수 없습니다.

작업이 완료되었는지 확인하기 위해 작업을 반복적으로 폴링하는 대신 애플리케이션은 이벤트 개체를 만들고 ODBC 연결 핸들 또는 ODBC 문 핸들과 연결할 수 있습니다. 그런 다음 애플리케이션은 운영 체제 동기화 API를 호출하여 하나의 이벤트 개체 또는 여러 이벤트 개체(ODBC 이벤트 및 기타 Windows 이벤트 모두)를 기다립니다. ODBC는 해당 ODBC 비동기 작업이 완료되면 이벤트 개체에 신호를 전송합니다.

Windows에서는 Win32 이벤트 개체가 사용되며 사용자에게 통합 프로그래밍 모델을 제공합니다. 다른 플랫폼의 드라이버 관리자는 해당 플랫폼과 관련된 이벤트 개체 구현을 사용할 수 있습니다.

다음 코드 샘플에서는 연결 및 문 비동기 알림의 사용을 보여 줍니다.

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

드라이버가 비동기 알림을 지원하는지 확인

ODBC 애플리케이션은 ODBC 드라이버가 SQLGetInfo를 호출하여 비동기 알림을 지원하는지 여부를 확인할 수 있습니다. 따라서 ODBC 드라이버 관리자는 SQL_ASYNC_NOTIFICATION 사용하여 드라이버의 SQLGetInfo를 호출합니다.

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 핸들과 연결

애플리케이션은 해당 Win32 함수를 사용하여 Win32 이벤트 개체를 만듭니다. 애플리케이션은 하나의 Win32 이벤트 핸들을 하나의 ODBC 연결 핸들 또는 하나의 ODBC 문 핸들과 연결할 수 있습니다.

커넥트ion 특성은 SQL_ATTR_ASYNC_DBC_FUNCTION_ENABLE SQL_ATTR_ASYNC_DBC_EVENT ODBC가 비동기 모드에서 실행되는지 여부와 ODBC가 연결 핸들에 알림 모드를 사용하도록 설정할지 여부를 결정합니다. 문 특성 SQL_ATTR_ASYNC_ENABLE 및 SQL_ATTR_ASYNC_STMT_EVENT ODBC가 비동기 모드에서 실행되는지 여부와 ODBC가 문 핸들에 알림 모드를 사용하도록 설정하는지 여부를 결정합니다.

SQL_ATTR_ASYNC_ENABLE 또는 SQL_ATTR_ASYNC_DBC_FUNCTION_ENABLE SQL_ATTR_ASYNC_STMT_EVENT 또는 SQL_ATTR_ASYNC_DBC_EVENT 모드
Enable null이 아닌 경우 비동기 알림
Enable null 비동기 폴링
사용 안 함 any 동기

애플리케이션은 비동기 작업 모드를 일시적으로 사용하지 않도록 설정할 수 있습니다. ODBC는 연결 수준 비동기 작업을 사용하지 않도록 설정한 경우 SQL_ATTR_ASYNC_DBC_EVENT 값을 무시합니다. 문 수준 비동기 작업을 사용하지 않도록 설정하면 ODBC는 SQL_ATTR_ASYNC_STMT_EVENT 값을 무시합니다.

SQLSetStmtAttr 및 SQLSet커넥트Attr동기 호출

  • SQLSet커넥트Attr은 비동기 작업을 지원하지만 SQL_ATTR_ASYNC_DBC_EVENT 설정하기 위한 SQLSet커넥트Attr 호출은 항상 동기적입니다.

  • SQLSetStmtAttr 은 비동기 실행을 지원하지 않습니다.

오류 발생 시나리오
연결하기 전에 SQLSet커넥트Attr이 호출되면 드라이버 관리자는 사용할 드라이버를 확인할 수 없습니다. 따라서 드라이버 관리자는 SQLSet커넥트Attr에 대한 성공을 반환하지만 특성은 드라이버에서 설정할 준비가 되지 않을 수 있습니다. 드라이버 관리자는 애플리케이션이 연결 함수를 호출할 때 이러한 특성을 설정합니다. 드라이버가 비동기 작업을 지원하지 않으므로 드라이버 관리자에서 오류가 발생할 수 있습니다.

연결 특성 상속
일반적으로 연결 문은 연결 특성을 상속합니다. 그러나 SQL_ATTR_ASYNC_DBC_EVENT 특성은 상속할 수 없으며 연결 작업에만 영향을 줍니다.

이벤트 핸들을 ODBC 연결 핸들과 연결하기 위해 ODBC 애플리케이션은 ODBC API SQLSet커넥트Attr을 호출하고 SQL_ATTR_ASYNC_DBC_EVENT 특성으로 지정하고 이벤트 핸들을 특성 값으로 지정합니다. SQL_ATTR_ASYNC_DBC_EVENT 새 ODBC 특성은 SQL_IS_POINTER 형식입니다.

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

일반적으로 애플리케이션은 자동 재설정 이벤트 개체를 만듭니다. ODBC는 이벤트 개체를 다시 설정하지 않습니다. 애플리케이션은 비동기 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 드라이버에서 설정되지 않는 드라이버 관리자 전용 특성입니다.

SQL_ATTR_ASYNC_DBC_EVENT 기본값은 NULL입니다. 드라이버가 비동기 알림을 지원하지 않는 경우 SQL_ATTR_ASYNC_DBC_EVENT 가져오거나 설정하면 SQLSTATE HY092(잘못된 특성/옵션 식별자)를 사용하여 SQL_ERROR 반환됩니다.

ODBC 연결 핸들에 설정된 마지막 SQL_ATTR_ASYNC_DBC_EVENT 값이 NULL이 아니고 애플리케이션이 SQL_ASYNC_DBC_ENABLE_ON 특성 SQL_ATTR_ASYNC_DBC_FUNCTION_ENABLE 설정하여 비동기 모드를 사용하도록 설정한 경우 비동기 모드를 지원하는 ODBC 연결 함수를 호출하면 완료 알림이 표시됩니다. ODBC 연결 핸들에 설정된 마지막 SQL_ATTR_ASYNC_DBC_EVENT 값이 NULL인 경우 ODBC는 비동기 모드 사용 여부에 관계없이 애플리케이션에 알림을 보내지 않습니다.

애플리케이션은 특성 SQL_ATTR_ASYNC_DBC_FUNCTION_ENABLE 설정하기 전이나 후에 SQL_ATTR_ASYNC_DBC_EVENT 설정할 수 있습니다.

애플리케이션은 연결 함수(SQL커넥트, SQLBrowse커넥트 또는 SQLDriver커넥트)를 호출하기 전에 ODBC 연결 핸들에서 SQL_ATTR_ASYNC_DBC_EVENT 특성을 설정할 수 있습니다. ODBC 드라이버 관리자는 애플리케이션에서 사용할 ODBC 드라이버를 모르기 때문에 SQL_SUCCESS 반환합니다. 애플리케이션이 연결 함수를 호출할 때 ODBC 드라이버 관리자는 드라이버가 비동기 알림을 지원하는지 여부를 검사. 드라이버가 비동기 알림을 지원하지 않는 경우 ODBC 드라이버 관리자는 SQLSTATE S1_118 SQL_ERROR 반환합니다(드라이버는 비동기 알림을 지원하지 않음). 드라이버가 비동기 알림을 지원하는 경우 ODBC 드라이버 관리자는 드라이버를 호출하고 해당 특성을 SQL_ATTR_ASYNC_DBC_NOTIFICATION_CALLBACK 설정하고 SQL_ATTR_ASYNC_DBC_NOTIFICATION_CONTEXT.

마찬가지로 애플리케이션은 ODBC 문 핸들에서 SQLSetStmtAttr를 호출하고 문 수준 비동기 알림을 사용하거나 사용하지 않도록 설정하는 SQL_ATTR_ASYNC_STMT_EVENT 특성을 지정합니다. 연결이 설정된 후 문 함수가 항상 호출되므로 SQLSetStmtAttr 는 해당 드라이버가 비동기 작업을 지원하지 않거나 드라이버가 비동기 작업을 지원하지만 비동기 알림을 지원하지 않는 경우 즉시 SQLSTATE S1_118 사용하여 SQL_ERROR 반환합니다(드라이버는 비동기 알림을 지원하지 않음).

SQLRETURN retcode;  
retcode = SQLSetStmtAttr ( hSTMT,  
                           SQL_ATTR_ASYNC_STMT_EVENT, // Attribute name   
                           (SQLPOINTER) hEvent,       // Win32 Event handle  
                           SQL_IS_POINTER);           // length Indicator  

NULL로 설정할 수 있는 SQL_ATTR_ASYNC_STMT_EVENT 드라이버에서 설정되지 않는 드라이버 관리자 전용 특성입니다.

SQL_ATTR_ASYNC_STMT_EVENT 기본값은 NULL입니다. 드라이버가 비동기 알림을 지원하지 않는 경우 SQL_ATTR_ASYNC_ STMT_EVENT 특성을 가져오거나 설정하면 SQLSTATE HY092(잘못된 특성/옵션 식별자)를 사용하여 SQL_ERROR 반환됩니다.

애플리케이션은 동일한 이벤트 핸들을 둘 이상의 ODBC 핸들과 연결해서는 안 됩니다. 그렇지 않으면 동일한 이벤트 핸들을 공유하는 두 개의 핸들에서 두 개의 비동기 ODBC 함수 호출이 완료되면 하나의 알림이 손실됩니다. 연결 핸들에서 동일한 이벤트 핸들을 상속하는 문 핸들을 방지하기 위해 애플리케이션이 연결 핸들에서 SQL_ATTR_ASYNC_STMT_EVENT 설정하는 경우 ODBC는 SQLSTATE IM016을 사용하여 SQL_ERROR 반환합니다(문 특성을 연결 핸들로 설정할 수 없음).

비동기 ODBC 함수 호출

비동기 알림을 사용하도록 설정하고 비동기 작업을 시작한 후 애플리케이션은 모든 ODBC 함수를 호출할 수 있습니다. 함수가 비동기 작업을 지원하는 함수 집합에 속하는 경우 함수의 실패 여부와 관계없이 작업이 완료될 때 애플리케이션이 완료 알림을 받습니다. 유일한 예외는 애플리케이션이 잘못된 연결 또는 문 핸들을 사용하여 ODBC 함수를 호출한다는 것입니다. 이 경우 ODBC는 이벤트 핸들을 가져와서 신호 상태로 설정하지 않습니다.

애플리케이션은 해당 ODBC 핸들에서 비동기 작업을 시작하기 전에 연결된 이벤트 개체가 신호가 없는 상태인지 확인해야 합니다. ODBC는 이벤트 개체를 다시 설정하지 않습니다.

ODBC에서 알림 받기

애플리케이션 스레드는 WaitForSingleObject를 호출하여 하나의 이벤트 핸들을 기다리거나 WaitForMultipleObjects를 호출하여 이벤트 핸들 배열을 대기하고 하나 또는 모든 이벤트 개체가 신호를 수신하거나 제한 시간 간격이 경과할 때까지 일시 중단될 수 있습니다.

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