| Documentation PostgreSQL 8.0.25 | ||||
|---|---|---|---|---|
| Précédent | Arrière rapide | Chapitre 27. libpq - Bibliothèque C | Avance rapide | Suivant |
La fonction PQexec est adéquate pour soumettre des
commandes aux applications standards, synchrones. Néanmoins, il a quelques
déficiences pouvant être d'importance à certains utilisateurs :
PQexec attend que la commande se termine. L'application
pourrait avoir d'autres travaux à réaliser (comme le rafraichissement de
l'interface utilisateur), auquel cas il ne voudra pas être bloqué en attente
de la réponse.
Comme l'exécution de l'application cliente est suspendue en attendant le résultat, il est difficile pour l'application de décider qu'elle voudrait annuler la commande en cours (c'est possible avec un gestionnaire de signaux mais pas autrement).
PQexec ne peut renvoyer qu'une structure
PGresult. Si la chaîne de commande soumise contient
plusieurs commandes SQL, toutes les structures
PGresult sont annulées par
PQexec, sauf la dernière.
Les applications qui n'apprécient pas ces limitations peuvent utiliser à la
place les fonctions sous-jacentes à partir desquelles
PQexec est construit :
PQsendQuery et PQgetResult. Il existe
aussi PQsendQueryParams, PQsendPrepare
et PQsendQueryPrepared pouvant être utilisées avec
PQgetResult pour dupliquer les fonctionnalités de
respectivement PQexecParams, PQprepare et
PQexecPrepared.
PQsendQuery Soumet une commande au serveur sans attendre le(s) résultat(s). 1 est
renvoyé si la commande a été correctement envoyée et 0 dans le cas
contraire (auquel cas, utilisez la fonction PQerrorMessage
pour obtenir plus d'informations sur l'échec).
int PQsendQuery(PGconn *conn, const char *command);
Après un appel réussi à PQsendQuery, appelez
PQgetResult une ou plusieurs fois pour obtenir
les résultats. PQsendQuery pourrait être appelé
de nouveau (sur la même connexion) jusqu'à ce que
PQgetResult renvoie un pointeur nul,
indiquant que la commande a terminé.
PQsendQueryParamsSoumet une commande et des paramètres séparés au serveur sans attendre le(s) résultat(s).
int PQsendQueryParams(PGconn *conn,
const char *command,
int nParams,
const Oid *paramTypes,
const char * const *paramValues,
const int *paramLengths,
const int *paramFormats,
int resultFormat);
Ceci est équivalent à PQsendQuery sauf que les
paramètres de requêtes peuvent être spécifiés à partir de la chaîne de
requête. Les paramètres de la fonction sont gérés de façon identique à
PQexecParams. Comme
PQexecParams, cela ne fonctionnera pas
pour les connexions utilisant le protocole 2.0 et cela ne permettra
qu'une seule commande dans la chaîne de requête.
PQsendPrepareEnvoie une requête pour créer une instruction préparée avec les paramètres donnés et redonne la main sans attendre la fin de son exécution.
int PQsendPrepare(PGconn *conn,
const char *stmtName,
const char *query,
int nParams,
const Oid *paramTypes);
Ceci est la version asynchrone de PQprepare : elle
renvoie 1 si elle a été capable d'envoyer la requête, 0 sinon. Après un
appel terminé avec succès, appelez PQgetResult pour
déterminer si le serveur a créé avec succès l'instruction préparée. Les
paramètres de la fonction sont gérés de façon identique à
PQprepare. Comme PQprepare, cela ne
fonctionnera pas sur les connexions utilisant le protocole 2.0.
PQsendQueryPreparedEnvoie une requête pour exécuter une instruction préparée avec des paramètres donnés sans attendre le(s) résultat(s).
int PQsendQueryPrepared(PGconn *conn,
const char *stmtName,
int nParams,
const char * const *paramValues,
const int *paramLengths,
const int *paramFormats,
int resultFormat);
Ceci est similaire à PQsendQueryParams mais la
commande à exécuter est spécifiée en nommant une instruction
précédemment préparée au lieu de donner une chaîne contenant la
requête. Les paramètres de la fonction sont gérés de façon identique à
PQexecPrepared. Comme
PQexecPrepared, cela ne fonctionnera pas pour les
connexions utilisant le protocole 2.0.
PQgetResult Attend le prochain résultat d'un appel précédant à
PQsendQuery,
PQsendQueryParams,
PQsendPrepare ou
PQsendQueryPrepared, et le renvoie. Un pointeur
nul est renvoyé quand la commande est terminée et qu'il n'y aura plus
de résultats.
PGresult *PQgetResult(PGconn *conn);
PQgetResult doit être appelé de façon répété
jusqu'à ce qu'il retourne un pointeur nul indiquant que la commande
s'est terminée (si appelé à un moment où aucune commande n'est
active, PQgetResult renverra seulement un
pointeur nul à la fois). Chaque résultat non nul provenant de
PQgetResult devrait être traité en utilisant les
mêmes fonctions d'accès à PGresult que celles
précédemment décrites. N'oubliez pas de libérer chaque objet résultat
avec PQclear une fois que vous en avez terminé.
Notez que PQgetResult bloquera seulement si la
commande est active et que les données nécessaires en réponse n'ont
pas encore été lues par PQconsumeInput.
Utiliser PQsendQuery et PQgetResult
résout un des problèmes de PQexec : si une chaîne de
commande contient plusieurs commandes SQL, les résultats de
ces commandes peuvent être obtenus individuellement (ceci permet une simple
forme de traitement en parallèle : le client peut gérer les résultats
d'une commande alors que le serveur travaille sur d'autres requêtes de la même
chaîne de commandes). Néanmoins, appeler PQgetResult
causera toujours un blocage du client jusqu'à la fin de la prochaine commande
SQL. Ceci est évitable en utilisant proprement deux
fonctions supplémentaires :
PQconsumeInputSi l'entrée est disponible à partir du serveur, consommez-la.
int PQconsumeInput(PGconn *conn);
PQconsumeInput renvoie normalement 1 indiquant
<< aucune erreur >>, mais renvoie zéro s'il y a eu une erreur (auquel
cas PQerrorMessage peut être consulté). Notez que le
résultat ne dit pas si des données ont été récupérées en entrée. Après avoir
appelé PQconsumeInput, l'application devrait vérifier
PQisBusy et/ou PQnotifies pour voir
si leur état a changé.
PQconsumeInput pourrait être appelé même si l'application
n'est pas encore préparé à gérer un résultat ou une notification. La fonction
lira les données disponibles et les sauvegardera dans un tampon indiquant
ainsi qu'une lecture d'un select() est possible.
L'application peut donc utiliser PQconsumeInput pour
effacer la condition select() immédiatement, puis pour
examiner les résultats autant que possible.
PQisBusyRenvoie 1 si une commande est occupée, c'est-à-dire que
PQgetResult bloquerait en attendant une entrée. Un zéro
indiquerait que PQgetResult peut être appelé avec
l'assurance de ne pas être bloqué.
int PQisBusy(PGconn *conn);
PQisBusy ne tentera pas lui-même de lire les données à
partir du serveur ; du coup, PQconsumeInput doit être
appelé d'abord ou l'état occupé ne s'arrêtera jamais.
Une application typique de l'utilisation de ces fonctions aura une boucle
principale utilisant select() ou poll() pour
attendre toutes les conditions auxquelles il doit répondre. Une des conditions
sera la disponibilité des données à partir du serveur, ce qui signifie des données
lisibles pour select() sur le descripteur de
fichier identifié par PQsocket. Lorsque la boucle
principale détecte la disponibilité de données, il devrait appeler
PQconsumeInput pour lire l'en-tête. Il peut ensuite appeler
PQisBusy suivi par PQgetResult si
PQisBusy renvoie false (0). Il peut aussi appeler
PQnotifies pour détecter les messages NOTIFY
(voir la Section 27.7).
Un client qui utilise
PQsendQuery/PQgetResult peut aussi
tenter d'annuler une commande en cours de traitement par le
serveur ; voir la Section 27.5. Mais quelque soit la valeur
renvoyée par PQcancel, l'application doit continuer avec
la séquence normale de lecture du résultat en utilisant
PQgetResult. Une annulation réussie causera simplement une
fin plus rapide de la commande.
En utilisant les fonctions décrites ci-dessus, il est possible d'éviter le blocage pendant l'attente de données du serveur. Néanmoins, il est toujours possible que l'application se bloque en attendant l'envoi vers le serveur. C'est relativement peu fréquent mais cela peut arriver si de très longues commandes SQL ou données sont envoyées (c'est bien plus probable si l'application envoie des données via COPY IN). Pour empêcher cette possibilité et réussir des opérations de bases de données totalement non bloquantes, les fonctions supplémentaires suivantes pourraient être utilisées.
PQsetnonblockingInitialise le statut non bloquant de la connexion.
int PQsetnonblocking(PGconn *conn, int arg);
Initialise l'état de la connexion à non bloquant si arg vaut 1 et à bloquant si arg vaut 0. Renvoie 0 si OK, -1 en cas d'erreur.
Dans l'état non bloquant, les appels à
PQsendQuery,
PQputline, PQputnbytes
et PQendcopy ne bloqueront pas mais renverront à la
place une erreur s'ils ont besoin d'être de nouveau appelés.
Notez que PQexec n'honore pas le mode non
bloquant ; s'il est appelé, il agira d'une façon bloquante malgré tout.
PQisnonblockingRenvoie le statut bloquant de la connexion à la base de données.
int PQisnonblocking(const PGconn *conn);
Renvoie 1 si la connexion est en mode non bloquant, 1 dans le cas contraire.
PQflushTente de vider les données des queues de sortie du serveur. Renvoie 0 en cas de succès (ou si la queue d'envoi est vide), -1 en cas d'échec quelque soit la raison ou 1 s'il a été incapable d'envoyer encore toutes les données dans la queue d'envoi (ce cas arrive seulement si la connexion est non bloquante).
int PQflush(PGconn *conn);
Après avoir envoyé une commande ou des données dans une connexion non bloquante,
appelez PQflush. S'il renvoie 1, attendez que la socket
soit disponible en écriture et appelez-la de nouveau ; répétez cela jusqu'à
ce qu'il renvoie 0. Une fois que PQflush renvoie 0,
attendez que la socket soit disponible en lecture puis lisez la réponse comme
décrit ci-dessus.
| Précédent | Sommaire | Suivant |
| Fonctions de commandes d'exécution | Niveau supérieur | Annuler des requêtes en cours d'exécution |