Exécution asynchrone (méthode de notification)

ODBC autorise l’exécution asynchrone des opérations de connexion et d’instruction. Un thread d’application peut appeler une fonction ODBC en mode asynchrone et la fonction peut retourner avant la fin de l’opération, ce qui permet au thread d’application d’effectuer d’autres tâches. Dans le Kit de développement logiciel (SDK) Windows 7, pour les opérations d’instruction ou de connexion asynchrones, une application a déterminé que l’opération asynchrone était terminée à l’aide de la méthode d’interrogation. Pour plus d’informations, consultez Exécution asynchrone (méthode d’interrogation). À compter du Kit de développement logiciel (SDK) Windows 8, vous pouvez déterminer qu’une opération asynchrone est terminée à l’aide de la méthode de notification.

Dans la méthode d’interrogation, les applications doivent appeler la fonction asynchrone chaque fois qu’elle souhaite l’état de l’opération. La méthode de notification est similaire au rappel et à attendre dans ADO.NET. ODBC utilise toutefois les événements Win32 comme objet de notification.

La bibliothèque de curseurs ODBC et la notification asynchrone ODBC ne peuvent pas être utilisées en même temps. La définition des deux attributs retourne une erreur avec SQLSTATE S1119 (la bibliothèque de curseurs et la notification asynchrone ne peuvent pas être activées en même temps).

Consultez notification de fin de fonction asynchrone pour plus d’informations pour les développeurs de pilotes.

Remarque

La méthode de notification n’est pas prise en charge avec la bibliothèque de curseurs. Une application reçoit un message d’erreur s’il tente d’activer la bibliothèque de curseurs via SQLSet Connecter Attr, lorsque la méthode de notification est activée.

Vue d’ensemble

Lorsqu’une fonction ODBC est appelée en mode asynchrone, le contrôle est retourné immédiatement à l’application appelante avec le code de retour SQL_STILL_EXECUTING. L’application doit interroger à plusieurs reprises la fonction jusqu’à ce qu’elle retourne quelque chose d’autre que SQL_STILL_EXECUTING. La boucle d’interrogation augmente l’utilisation du processeur, ce qui entraîne des performances médiocres dans de nombreux scénarios asynchrones.

Chaque fois que le modèle de notification est utilisé, le modèle d’interrogation est désactivé. Les applications ne doivent pas appeler à nouveau la fonction d’origine. Appelez la fonction SQLCompleteAsync pour terminer l’opération asynchrone. Si une application appelle à nouveau la fonction d’origine avant la fin de l’opération asynchrone, l’appel retourne SQL_ERROR avec SQLSTATE IM017 (l’interrogation est désactivée en mode de notification asynchrone).

Lorsque vous utilisez le modèle de notification, l’application peut appeler SQLCancel ou SQLCancelHandle pour annuler une instruction ou une opération de connexion. Si la demande d’annulation réussit, ODBC retourne SQL_SUCCESS. Ce message n’indique pas que la fonction a été réellement annulée ; elle indique que la demande d’annulation a été traitée. Indique si la fonction est réellement annulée dépend du pilote et dépend de la source de données. Lorsqu’une opération est annulée, le Gestionnaire de pilotes signale toujours l’événement. Le Gestionnaire de pilotes retourne SQL_ERROR dans la mémoire tampon de code de retour et l’état est SQLSTATE HY008 (Opération annulée) pour indiquer que l’annulation a réussi. Si la fonction a terminé son traitement normal, le Gestionnaire de pilotes retourne SQL_SUCCESS ou SQL_SUCCESS_WITH_INFO.

Comportement de niveau inférieur

La version du Gestionnaire de pilotes ODBC prenant en charge cette notification est ODBC 3.81.

Version ODBC de l’application Version du Gestionnaire de pilotes Version du pilote Comportement
Nouvelle application de n’importe quelle version ODBC ODBC 3.81 Pilote ODBC 3.80 L’application peut utiliser cette fonctionnalité si le pilote prend en charge cette fonctionnalité ; sinon, le Gestionnaire de pilotes s’affiche.
Nouvelle application de n’importe quelle version ODBC ODBC 3.81 Pilote pré-ODBC 3.80 Le Gestionnaire de pilotes s’affiche si le pilote ne prend pas en charge cette fonctionnalité.
Nouvelle application de n’importe quelle version ODBC Pré-ODBC 3.81 Tout Lorsque l’application utilise cette fonctionnalité, un ancien Gestionnaire de pilotes considère les nouveaux attributs comme des attributs spécifiques au pilote, et le pilote doit se tromper. Un nouveau gestionnaire de pilotes ne transmet pas ces attributs au pilote.

Une application doit case activée la version du Gestionnaire de pilotes avant d’utiliser cette fonctionnalité. Sinon, si un pilote mal écrit ne s’affiche pas et que la version du Gestionnaire de pilotes est antérieure à ODBC 3.81, le comportement n’est pas défini.

Cas d'utilisation

Cette section présente les cas d’usage pour l’exécution asynchrone et le mécanisme d’interrogation.

Intégrer des données à partir de plusieurs sources ODBC

Une application d’intégration de données extrait de manière asynchrone des données à partir de plusieurs sources de données. Certaines données proviennent de sources de données distantes et certaines données proviennent de fichiers locaux. L’application ne peut pas continuer tant que les opérations asynchrones ne sont pas terminées.

Au lieu d’interroger à plusieurs reprises une opération pour déterminer s’il est terminé, l’application peut créer un objet d’événement et l’associer à un handle de connexion ODBC ou à un handle d’instruction ODBC. L’application appelle ensuite des API de synchronisation du système d’exploitation pour attendre sur un objet d’événement ou de nombreux objets d’événements (événements ODBC et autres événements Windows). ODBC signale l’objet d’événement lorsque l’opération asynchrone ODBC correspondante est terminée.

Sur Windows, les objets d’événement Win32 sont utilisés et fournissent à l’utilisateur un modèle de programmation unifié. Les gestionnaires de pilotes sur d’autres plateformes peuvent utiliser l’implémentation d’objet d’événement spécifique à ces plateformes.

L’exemple de code suivant illustre l’utilisation de la notification asynchrone de connexion et d’instruction :

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

Déterminer si un pilote prend en charge la notification asynchrone

Une application ODBC peut déterminer si un pilote ODBC prend en charge la notification asynchrone en appelant SQLGetInfo. Le Gestionnaire de pilotes ODBC appellera par conséquent SQLGetInfo du pilote avec 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  
      }  
}  

Association d’un handle d’événements Win32 à un handle ODBC

Les applications sont responsables de la création d’objets d’événements Win32 à l’aide des fonctions Win32 correspondantes. Une application peut associer un handle d’événement Win32 à un handle de connexion ODBC ou un handle d’instruction ODBC.

les attributs Connecter ion SQL_ATTR_ASYNC_DBC_FUNCTION_ENABLE et SQL_ATTR_ASYNC_DBC_EVENT déterminer si ODBC s’exécute en mode asynchrone et si ODBC active le mode de notification pour un handle de connexion. Les attributs d’instruction SQL_ATTR_ASYNC_ENABLE et SQL_ATTR_ASYNC_STMT_EVENT déterminent si ODBC s’exécute en mode asynchrone et si ODBC active le mode de notification pour un handle d’instruction.

SQL_ATTR_ASYNC_ENABLE ou SQL_ATTR_ASYNC_DBC_FUNCTION_ENABLE SQL_ATTR_ASYNC_STMT_EVENT ou SQL_ATTR_ASYNC_DBC_EVENT Mode
Activer non null Notification asynchrone
Activer null Interrogation asynchrone
Désactiver n'importe laquelle Synchrone

Une application peut désactiver temporellement le mode d’opération asynchrone. ODBC ignore les valeurs de SQL_ATTR_ASYNC_DBC_EVENT si l’opération asynchrone au niveau de la connexion est désactivée. ODBC ignore les valeurs de SQL_ATTR_ASYNC_STMT_EVENT si l’opération asynchrone au niveau de l’instruction est désactivée.

Appel synchrone de SQLSetStmtAttr et SQLSet Connecter Attr

  • SQLSet Connecter Attr prend en charge les opérations asynchrones, mais l’appel de SQLSet Connecter Attr pour définir SQL_ATTR_ASYNC_DBC_EVENT est toujours synchrone.

  • SQLSetStmtAttr ne prend pas en charge l’exécution asynchrone.

Scénario d’erreur
Lorsque SQLSet Connecter Attr est appelé avant d’établir une connexion, le Gestionnaire de pilotes ne peut pas déterminer le pilote à utiliser. Par conséquent, le Gestionnaire de pilotes retourne la réussite pour SQLSet Connecter Attr, mais l’attribut peut ne pas être prêt à être défini dans le pilote. Le Gestionnaire de pilotes définit ces attributs lorsque l’application appelle une fonction de connexion. Le Gestionnaire de pilotes peut générer des erreurs, car le pilote ne prend pas en charge les opérations asynchrones.

Héritage des attributs de connexion
En règle générale, les instructions d’une connexion héritent des attributs de connexion. Toutefois, l’attribut SQL_ATTR_ASYNC_DBC_EVENT n’est pas hériter et affecte uniquement les opérations de connexion.

Pour associer un handle d’événement à un handle de connexion ODBC, une application ODBC appelle SQLSet de l’API ODBC Connecter Attr et spécifie SQL_ATTR_ASYNC_DBC_EVENT comme attribut et le handle d’événement comme valeur d’attribut. Le nouvel attribut ODBC SQL_ATTR_ASYNC_DBC_EVENT est de 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  
            );  

En règle générale, les applications créent des objets d’événements de réinitialisation automatique. ODBC ne réinitialise pas l’objet d’événement. Les applications doivent s’assurer que l’objet n’est pas à l’état signalé avant d’appeler une fonction ODBC asynchrone.

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 est un attribut Driver Manager uniquement qui ne sera pas défini dans le pilote.

La valeur par défaut de SQL_ATTR_ASYNC_DBC_EVENT est NULL. Si le pilote ne prend pas en charge la notification asynchrone, l’obtention ou le paramètre SQL_ATTR_ASYNC_DBC_EVENT retourne SQL_ERROR avec SQLSTATE HY092 (identificateur d’attribut/option non valide).

Si la dernière valeur SQL_ATTR_ASYNC_DBC_EVENT définie sur un handle de connexion ODBC n’est pas NULL et que l’application a activé le mode asynchrone en définissant l’attribut SQL_ATTR_ASYNC_DBC_FUNCTION_ENABLE avec SQL_ASYNC_DBC_ENABLE_ON, l’appel d’une fonction de connexion ODBC prenant en charge le mode asynchrone reçoit une notification d’achèvement. Si la dernière valeur SQL_ATTR_ASYNC_DBC_EVENT définie sur un handle de connexion ODBC a la valeur NULL, ODBC n’envoie aucune notification à l’application, quel que soit le mode asynchrone activé.

Une application peut définir SQL_ATTR_ASYNC_DBC_EVENT avant ou après la définition de l’attribut SQL_ATTR_ASYNC_DBC_FUNCTION_ENABLE.

Les applications peuvent définir l’attribut SQL_ATTR_ASYNC_DBC_EVENT sur un handle de connexion ODBC avant d’appeler une fonction de connexion (SQL Connecter, SQLBrowse Connecter ou SQLDriver Connecter). Étant donné que le Gestionnaire de pilotes ODBC ne sait pas quel pilote ODBC l’application utilisera, il retourne SQL_SUCCESS. Lorsque l’application appelle une fonction de connexion, odbc Driver Manager case activée si le pilote prend en charge la notification asynchrone. Si le pilote ne prend pas en charge la notification asynchrone, odbc Driver Manager retourne SQL_ERROR avec SQLSTATE S1_118 (Driver ne prend pas en charge la notification asynchrone). Si le pilote prend en charge la notification asynchrone, odbc Driver Manager appelle le pilote et définit les attributs correspondants SQL_ATTR_ASYNC_DBC_NOTIFICATION_CALLBACK et SQL_ATTR_ASYNC_DBC_NOTIFICATION_CONTEXT.

De même, une application appelle SQLSetStmtAttr sur un handle d’instruction ODBC et spécifie l’attribut SQL_ATTR_ASYNC_STMT_EVENT pour activer ou désactiver la notification asynchrone au niveau de l’instruction. Étant donné qu’une fonction d’instruction est toujours appelée une fois la connexion établie, SQLSetStmtAttr retourne SQL_ERROR avec SQLSTATE S1_118 (Driver ne prend pas en charge la notification asynchrone) immédiatement si le pilote correspondant ne prend pas en charge les opérations asynchrones ou que le pilote prend en charge l’opération asynchrone, mais ne prend pas en charge la notification asynchrone.

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, qui peut être défini sur NULL, est un attribut Driver Manager uniquement qui ne sera pas défini dans le pilote.

La valeur par défaut de SQL_ATTR_ASYNC_STMT_EVENT est NULL. Si le pilote ne prend pas en charge la notification asynchrone, l’obtention ou la définition de l’attribut SQL_ATTR_ASYNC_ STMT_EVENT retourne SQL_ERROR avec SQLSTATE HY092 (identificateur d’attribut/d’option non valide).

Une application ne doit pas associer le même handle d’événements à plusieurs handles ODBC. Sinon, une notification est perdue si deux appels de fonction ODBC asynchrones se terminent sur deux handles qui partagent le même handle d’événement. Pour éviter qu’un handle d’instruction hérite du même handle d’événement du handle de connexion, ODBC retourne SQL_ERROR avec SQLSTATE IM016 (Impossible de définir l’attribut d’instruction en handle de connexion) si une application définit SQL_ATTR_ASYNC_STMT_EVENT sur un handle de connexion.

Appel de fonctions ODBC asynchrones

Après avoir activé la notification asynchrone et démarré une opération asynchrone, l’application peut appeler n’importe quelle fonction ODBC. Si la fonction appartient à l’ensemble de fonctions qui prennent en charge l’opération asynchrone, l’application reçoit une notification d’achèvement une fois l’opération terminée, que la fonction ait échoué ou réussi. La seule exception est que l’application appelle une fonction ODBC avec un handle de connexion ou d’instruction non valide. Dans ce cas, ODBC n’obtient pas le handle d’événement et le définit sur l’état signalé.

L’application doit s’assurer que l’objet d’événement associé est dans un état non signalé avant de démarrer une opération asynchrone sur le handle ODBC correspondant. ODBC ne réinitialise pas l’objet d’événement.

Obtention d’une notification à partir d’ODBC

Un thread d’application peut appeler WaitForSingleObject pour attendre sur un handle d’événement ou appeler WaitForMultipleObjects pour attendre sur un tableau de handles d’événements et être suspendu jusqu’à ce que l’un ou l’ensemble des objets d’événement deviennent signalés ou que l’intervalle de délai d’attente s’écoule.

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