Exécution asynchrone (méthode d’interrogation)
Avant ODBC 3.8 et le Kit de développement logiciel (SDK) Windows 7, les opérations asynchrones n’ont été autorisées que sur les fonctions d’instruction. Pour plus d’informations, consultez les opérations d’instruction en cours d’exécution de manière asynchrone, plus loin dans cette rubrique.
ODBC 3.8 dans le Kit de développement logiciel (SDK) Windows 7 a introduit l’exécution asynchrone sur les opérations liées à la connexion. Pour plus d’informations, consultez la section Exécution asynchrone des opérations d’Connecter ion, plus loin dans cette rubrique.
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. À 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. Pour plus d’informations, consultez Exécution asynchrone (méthode de notification).
Par défaut, les pilotes exécutent des fonctions ODBC de manière synchrone ; autrement dit, l’application appelle une fonction et le pilote ne retourne pas le contrôle à l’application tant qu’elle n’a pas terminé d’exécuter la fonction. Toutefois, certaines fonctions peuvent être exécutées de manière asynchrone ; autrement dit, l’application appelle la fonction et le pilote, après un traitement minimal, retourne le contrôle à l’application. L’application peut ensuite appeler d’autres fonctions alors que la première fonction est toujours en cours d’exécution.
L’exécution asynchrone est prise en charge pour la plupart des fonctions qui sont largement exécutées sur la source de données, telles que les fonctions permettant d’établir des connexions, de préparer et d’exécuter des instructions SQL, de récupérer des métadonnées, d’extraire des données et de valider des transactions. Il est plus utile lorsque la tâche exécutée sur la source de données prend beaucoup de temps, comme un processus de connexion ou une requête complexe sur une base de données volumineuse.
Lorsque l’application exécute une fonction avec une instruction ou une connexion activée pour le traitement asynchrone, le pilote effectue une quantité minimale de traitement (par exemple, des arguments de case activée pour les erreurs), le traitement des mains vers la source de données et retourne le contrôle à l’application avec le code de retour SQL_STILL_EXECUTING. L’application effectue ensuite d’autres tâches. Pour déterminer quand la fonction asynchrone est terminée, l’application interroge le pilote à intervalles réguliers en appelant la fonction avec les mêmes arguments que celui utilisé à l’origine. Si la fonction est toujours en cours d’exécution, elle retourne SQL_STILL_EXECUTING ; s’il a terminé l’exécution, il retourne le code qu’il aurait retourné s’il était exécuté de manière synchrone, par exemple SQL_SUCCESS, SQL_ERROR ou SQL_NEED_DATA.
Si une fonction s’exécute de façon synchrone ou asynchrone est spécifique au pilote. Par exemple, supposons que les métadonnées du jeu de résultats sont mises en cache dans le pilote. Dans ce cas, il faut très peu de temps pour exécuter SQLDescribeCol et le pilote doit simplement exécuter la fonction plutôt que de retarder artificiellement l’exécution. En revanche, si le pilote doit récupérer les métadonnées de la source de données, il doit retourner le contrôle à l’application pendant qu’il effectue cette opération. Par conséquent, l’application doit pouvoir gérer un code de retour autre que SQL_STILL_EXECUTING lors de l’exécution d’une fonction de manière asynchrone.
Exécution asynchrone d’opérations d’instruction
Les fonctions d’instruction suivantes fonctionnent sur une source de données et peuvent s’exécuter de manière asynchrone :
SQLBulkOperations
SQLColAttribute
SQLColumnPrivileges
SQLColumns
SQLDescribeCol
SQLDescribeParam
SQLExecDirect
SQLExecute
SQLFetch
L’exécution d’instructions asynchrones est contrôlée par instruction ou par connexion, selon la source de données. Autrement dit, l’application spécifie qu’une fonction particulière doit être exécutée de manière asynchrone, mais que toute fonction exécutée sur une instruction particulière doit être exécutée de manière asynchrone. Pour savoir qui est pris en charge, une application appelle SQLGetInfo avec une option de SQL_ASYNC_MODE. SQL_AM_CONNECTION est retournée si l’exécution asynchrone au niveau de la connexion (pour un handle d’instruction) est prise en charge ; SQL_AM_STATEMENT si l’exécution asynchrone au niveau de l’instruction est prise en charge.
Pour spécifier que les fonctions exécutées avec une instruction particulière doivent être exécutées de manière asynchrone, l’application appelle SQLSetStmtAttr avec l’attribut SQL_ATTR_ASYNC_ENABLE et la définit sur SQL_ASYNC_ENABLE_ON. Si le traitement asynchrone au niveau de la connexion est pris en charge, l’attribut d’instruction SQL_ATTR_ASYNC_ENABLE est en lecture seule et sa valeur est identique à l’attribut de connexion de la connexion sur laquelle l’instruction a été allouée. Il est spécifique au pilote si la valeur de l’attribut d’instruction est définie au moment de l’allocation d’instruction ou une version ultérieure. Toute tentative de définition renvoie SQL_ERROR et SQLSTATE HYC00 (fonctionnalité facultative non implémentée).
Pour spécifier que les fonctions exécutées avec une connexion particulière doivent être exécutées de manière asynchrone, l’application appelle SQLSet Connecter Attr avec l’attribut SQL_ATTR_ASYNC_ENABLE et la définit sur SQL_ASYNC_ENABLE_ON. Tous les handles d’instruction futurs alloués sur la connexion seront activés pour l’exécution asynchrone ; il est défini par le pilote si les handles d’instruction existants seront activés par cette action. Si SQL_ATTR_ASYNC_ENABLE est défini sur SQL_ASYNC_ENABLE_OFF, toutes les instructions de la connexion sont en mode synchrone. Une erreur est retournée si l’exécution asynchrone est activée pendant qu’il existe une instruction active sur la connexion.
Pour déterminer le nombre maximal d’instructions simultanées actives en mode asynchrone que le pilote peut prendre en charge sur une connexion donnée, l’application appelle SQLGetInfo avec l’option SQL_MAX_ASYNC_CONCURRENT_STATEMENTS.
Le code suivant montre comment fonctionne le modèle d’interrogation :
SQLHSTMT hstmt1;
SQLRETURN rc;
// Specify that the statement is to be executed asynchronously.
SQLSetStmtAttr(hstmt1, SQL_ATTR_ASYNC_ENABLE, SQL_ASYNC_ENABLE_ON, 0);
// Execute a SELECT statement asynchronously.
while ((rc=SQLExecDirect(hstmt1,"SELECT * FROM Orders",SQL_NTS))==SQL_STILL_EXECUTING) {
// While the statement is still executing, do something else.
// Do not use hstmt1, because it is being used asynchronously.
}
// When the statement has finished executing, retrieve the results.
Lorsqu’une fonction s’exécute de façon asynchrone, l’application peut appeler des fonctions sur n’importe quelle autre instruction. L’application peut également appeler des fonctions sur n’importe quelle connexion, à l’exception de celle associée à l’instruction asynchrone. Mais l’application ne peut appeler que la fonction d’origine et les fonctions suivantes (avec le handle d’instruction ou sa connexion associée, handle d’environnement), après qu’une opération d’instruction retourne SQL_STILL_EXECUTING :
SQLCancelHandle (sur le handle d’instruction)
Si l’application appelle une autre fonction avec l’instruction asynchrone ou avec la connexion associée à cette instruction, la fonction retourne SQLSTATE HY010 (erreur de séquence de fonction), par exemple.
SQLHDBC hdbc1, hdbc2;
SQLHSTMT hstmt1, hstmt2, hstmt3;
SQLCHAR * SQLStatement = "SELECT * FROM Orders";
SQLUINTEGER InfoValue;
SQLRETURN rc;
SQLAllocHandle(SQL_HANDLE_STMT, hdbc1, &hstmt1);
SQLAllocHandle(SQL_HANDLE_STMT, hdbc1, &hstmt2);
SQLAllocHandle(SQL_HANDLE_STMT, hdbc2, &hstmt3);
// Specify that hstmt1 is to be executed asynchronously.
SQLSetStmtAttr(hstmt1, SQL_ATTR_ASYNC_ENABLE, SQL_ASYNC_ENABLE_ON, 0);
// Execute hstmt1 asynchronously.
while ((rc = SQLExecDirect(hstmt1, SQLStatement, SQL_NTS)) == SQL_STILL_EXECUTING) {
// The following calls return HY010 because the previous call to
// SQLExecDirect is still executing asynchronously on hstmt1. The
// first call uses hstmt1 and the second call uses hdbc1, on which
// hstmt1 is allocated.
SQLExecDirect(hstmt1, SQLStatement, SQL_NTS); // Error!
SQLGetInfo(hdbc1, SQL_UNION, (SQLPOINTER) &InfoValue, 0, NULL); // Error!
// The following calls do not return errors. They use a statement
// handle other than hstmt1 or a connection handle other than hdbc1.
SQLExecDirect(hstmt2, SQLStatement, SQL_NTS); // OK
SQLTables(hstmt3, NULL, 0, NULL, 0, NULL, 0, NULL, 0); // OK
SQLGetInfo(hdbc2, SQL_UNION, (SQLPOINTER) &InfoValue, 0, NULL); // OK
}
Lorsqu’une application appelle une fonction pour déterminer s’il est toujours en cours d’exécution asynchrone, elle doit utiliser le handle d’instruction d’origine. Cela est dû au fait que l’exécution asynchrone est suivie par instruction. L’application doit également fournir des valeurs valides pour les autres arguments ( les arguments d’origine le feront) pour obtenir l’erreur passée case activée ing dans le Gestionnaire de pilotes. Toutefois, après que le pilote case activée le handle d’instruction et détermine que l’instruction s’exécute de manière asynchrone, elle ignore tous les autres arguments.
Lorsqu’une fonction s’exécute de façon asynchrone, c’est-à-dire une fois qu’elle a retourné SQL_STILL_EXECUTING et avant qu’elle retourne un autre code, l’application peut l’annuler en appelant SQLCancel ou SQLCancelHandle avec le même handle d’instruction. Cela n’est pas garanti pour annuler l’exécution de la fonction. Par exemple, la fonction peut avoir déjà terminé. En outre, le code retourné par SQLCancel ou SQLCancelHandle indique uniquement si la tentative d’annulation de la fonction a réussi, et non si elle a effectivement annulé la fonction. Pour déterminer si la fonction a été annulée, l’application appelle à nouveau la fonction. Si la fonction a été annulée, elle retourne SQL_ERROR et SQLSTATE HY008 (Opération annulée). Si la fonction n’a pas été annulée, elle retourne un autre code, tel que SQL_SUCCESS, SQL_STILL_EXECUTING ou SQL_ERROR avec un autre SQLSTATE.
Pour désactiver l’exécution asynchrone d’une instruction particulière lorsque le pilote prend en charge le traitement asynchrone au niveau de l’instruction, l’application appelle SQLSetStmtAttr avec l’attribut SQL_ATTR_ASYNC_ENABLE et la définit sur SQL_ASYNC_ENABLE_OFF. Si le pilote prend en charge le traitement asynchrone au niveau de la connexion, l’application appelle SQLSet Connecter Attr pour définir SQL_ATTR_ASYNC_ENABLE sur SQL_ASYNC_ENABLE_OFF, ce qui désactive l’exécution asynchrone de toutes les instructions sur la connexion.
L’application doit traiter les enregistrements de diagnostic dans la boucle répétée de la fonction d’origine. Si SQLGetDiagField ou SQLGetDiagRec est appelé lorsqu’une fonction asynchrone est en cours d’exécution, elle retourne la liste actuelle des enregistrements de diagnostic. Chaque fois que l’appel de fonction d’origine est répété, il efface les enregistrements de diagnostic précédents.
Exécution asynchrone d’opérations d’Connecter ion
Avant ODBC 3.8, l’exécution asynchrone a été autorisée pour les opérations liées aux instructions telles que la préparation, l’exécution et l’extraction, ainsi que pour les opérations de métadonnées de catalogue. À compter d’ODBC 3.8, l’exécution asynchrone est également possible pour les opérations liées à la connexion, telles que la connexion, la déconnexion, la validation et la restauration.
Pour plus d’informations sur ODBC 3.8, consultez Nouveautés d’ODBC 3.8.
L’exécution asynchrone d’opérations de connexion est utile dans les scénarios suivants :
Lorsqu’un petit nombre de threads gère un grand nombre d’appareils avec des taux de données très élevés. Pour optimiser la réactivité et la scalabilité, il est souhaitable que toutes les opérations soient asynchrones.
Lorsque vous souhaitez chevaucher les opérations de base de données sur plusieurs connexions afin de réduire les temps de transfert écoulés.
Les appels ODBC asynchrones efficaces et la possibilité d’annuler les opérations de connexion permettent à l’application d’annuler toute opération lente sans avoir à attendre les délais d’expiration.
Les fonctions suivantes, qui fonctionnent sur les handles de connexion, peuvent désormais être exécutées de manière asynchrone :
Pour déterminer si un pilote prend en charge les opérations asynchrones sur ces fonctions, une application appelle SQLGetInfo avec SQL_ASYNC_DBC_FUNCTIONS. SQL_ASYNC_DBC_CAPABLE est retourné si les opérations asynchrones sont prises en charge. SQL_ASYNC_DBC_NOT_CAPABLE est retourné si les opérations asynchrones ne sont pas prises en charge.
Pour spécifier que les fonctions exécutées avec une connexion particulière doivent être exécutées de manière asynchrone, l’application appelle SQLSet Connecter Attr et définit l’attribut SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE sur SQL_ASYNC_DBC_ENABLE_ON. La définition d’un attribut de connexion avant d’établir une connexion s’exécute toujours de façon synchrone. En outre, l’opération définissant l’attribut de connexion SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE avec SQLSet Connecter Attr s’exécute toujours de façon synchrone.
Une application peut activer l’opération asynchrone avant d’établir une connexion. Étant donné que le Gestionnaire de pilotes ne peut pas déterminer le pilote à utiliser avant d’établir une connexion, le Gestionnaire de pilotes retourne toujours la réussite dans SQLSet Connecter Attr. Toutefois, il peut échouer à se connecter si le pilote ODBC ne prend pas en charge les opérations asynchrones.
En règle générale, il peut y avoir au plus une fonction en cours d’exécution asynchrone associée à un handle de connexion ou à un handle d’instruction particulier. Toutefois, un handle de connexion peut avoir plusieurs handles d’instruction associés. S’il n’existe aucune opération asynchrone s’exécutant sur le handle de connexion, un handle d’instruction associé peut exécuter une opération asynchrone. De même, vous pouvez avoir une opération asynchrone sur un handle de connexion s’il n’existe aucune opération asynchrone en cours sur un handle d’instruction associé. Une tentative d’exécution d’une opération asynchrone à l’aide d’un handle qui exécute actuellement une opération asynchrone retourne HY010, « Erreur de séquence de fonction ».
Si une opération de connexion retourne SQL_STILL_EXECUTING, une application peut uniquement appeler la fonction d’origine et les fonctions suivantes pour ce handle de connexion :
SQLCancelHandle (sur le handle de connexion)
SQLGetDiagField
SQLGetDiagRec
SQLAllocHandle (allocation d’ENV/DBC)
SQLAllocHandleStd (allocation d’ENV/DBC)
SQLGetEnvAttr
SQLGetConnectAttr
SQLDataSources
SQLDrivers
SQLGetInfo
SQLGetFunctions
L’application doit traiter les enregistrements de diagnostic dans la boucle répétée de la fonction d’origine. Si SQLGetDiagField ou SQLGetDiagRec est appelé lorsqu’une fonction asynchrone est en cours d’exécution, elle retourne la liste actuelle des enregistrements de diagnostic. Chaque fois que l’appel de fonction d’origine est répété, il efface les enregistrements de diagnostic précédents.
Si une connexion est ouverte ou fermée de façon asynchrone, l’opération est terminée lorsque l’application reçoit SQL_SUCCESS ou SQL_SUCCESS_WITH_INFO dans l’appel de fonction d’origine.
Une nouvelle fonction a été ajoutée à ODBC 3.8, SQLCancelHandle. Cette fonction annule les six fonctions de connexion (SQLBrowse Connecter, SQL Connecter, SQLDisconnect, SQLDriver Connecter, SQLEndTran et SQLSet Connecter Attr). Une application doit appeler SQLGetFunctions pour déterminer si le pilote prend en charge SQLCancelHandle. Comme avec SQLCancel, si SQLCancelHandle retourne la réussite, cela ne signifie pas que l’opération a été annulée. Une application doit appeler à nouveau la fonction d’origine pour déterminer si l’opération a été annulée. SQLCancelHandle vous permet d’annuler des opérations asynchrones sur les handles de connexion ou les handles d’instruction. L’utilisation de SQLCancelHandle pour annuler une opération sur un handle d’instruction est identique à l’appel de SQLCancel.
Il n’est pas nécessaire de prendre en charge les opérations de connexion SQLCancelHandle et asynchrones en même temps. Un pilote peut prendre en charge les opérations de connexion asynchrones, mais pas SQLCancelHandle, ou inversement.
Les opérations de connexion asynchrone et SQLCancelHandle peuvent également être utilisées par les applications ODBC 3.x et ODBC 2.x avec un pilote ODBC 3.8 et odbc 3.8 Driver Manager. Pour plus d’informations sur la façon d’activer une application plus ancienne pour utiliser de nouvelles fonctionnalités dans une version ODBC ultérieure, consultez La matrice de compatibilité.
Regroupement de connexions
Chaque fois que le regroupement de connexions est activé, les opérations asynchrones sont uniquement prises en charge pour établir une connexion (avec SQL Connecter et SQLDriver Connecter) et fermer une connexion avec SQLDisconnect. Toutefois, une application doit toujours être en mesure de gérer la valeur de retour SQL_STILL_EXECUTING à partir de SQL Connecter, SQLDriver Connecter et SQLDisconnect.
Lorsque le regroupement de connexions est activé, SQLEndTran et SQLSet Connecter Attr sont pris en charge pour les opérations asynchrones.
Exemples
R. Activer l’exécution asynchrone des fonctions de connexion
L’exemple suivant montre comment utiliser SQLSet Connecter Attr pour activer l’exécution asynchrone pour les fonctions liées à la connexion.
BOOL AsyncConnect (SQLHANDLE hdbc)
{
SQLRETURN r;
SQLHANDLE hdbc;
// Enable asynchronous execution of connection functions.
// This must be executed synchronously, that is r != SQL_STILL_EXECUTING
r = SQLSetConnectAttr(
hdbc,
SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE,
reinterpret_cast<SQLPOINTER> (SQL_ASYNC_DBC_ENABLE_ON),
0);
if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO)
{
return FALSE;
}
TCHAR szConnStrIn[256] = _T("DSN=AsyncDemo");
r = SQLDriverConnect(hdbc, NULL, (SQLTCHAR *) szConnStrIn, SQL_NTS, NULL, 0, NULL, SQL_DRIVER_NOPROMPT);
if (r == SQL_ERROR)
{
// Use SQLGetDiagRec to process the error.
// If SQLState is HY114, the driver does not support asynchronous execution.
return FALSE;
}
while (r == SQL_STILL_EXECUTING)
{
// Do something else.
// Check for completion, with the same set of arguments.
r = SQLDriverConnect(hdbc, NULL, (SQLTCHAR *) szConnStrIn, SQL_NTS, NULL, 0, NULL, SQL_DRIVER_NOPROMPT);
}
if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO)
{
return FALSE;
}
return TRUE;
}
B. Opérations de validation asynchrones
Cet exemple montre des opérations de validation asynchrones. Les opérations de restauration peuvent également être effectuées de cette façon.
BOOL AsyncCommit ()
{
SQLRETURN r;
// Assume that SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE is SQL_ASYNC_DBC_ENABLE_ON.
r = SQLEndTran(SQL_HANDLE_DBC, hdbc, SQL_COMMIT);
while (r == SQL_STILL_EXECUTING)
{
// Do something else.
// Check for completion with the same set of arguments.
r = SQLEndTran(SQL_HANDLE_DBC, hdbc, SQL_COMMIT);
}
if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO)
{
return FALSE;
}
return TRUE;
}