29.8. Fonctions associées avec la commande COPY
Dans PostgreSQL™, la commande
COPY
a des options pour
lire ou écrire à partir de la connexion réseau utilisée par
libpq. Les fonctions décrites dans
cette section autorisent les applications à prendre avantage de cette
capacité en apportant ou en consommant les données copiées.
Le traitement complet est le suivant. L'application lance tout
d'abord la commande SQL
COPY
via PQexec ou une des fonctions équivalents. La réponse à
ceci (s'il n'y a pas d'erreur dans la commande) sera un objet
PGresult avec un code de retour
PGRES_COPY_OUT ou PGRES_COPY_IN (suivant la direction spécifiée pour la
copie). L'application devrait alors utiliser les fonctions de cette
section pour recevoir ou transmettre des lignes de données. Quand le
transfert de données est terminé, un autre objet PGresult est renvoyé pour indiquer le succès ou
l'échec du transfert. Son statut sera PGRES_COMMAND_OK en cas de succès et PGRES_FATAL_ERROR si un problème a été rencontré. À ce
point, toute autre commande SQL pourrait être exécutée via PQexec (il n'est pas possible d'exécuter d'autres
commandes SQL en utilisant la même connexion tant que l'opération
COPY
est en cours).
Si une commande
COPY
est lancée via PQexec dans une chaîne qui
pourrait contenir d'autres commandes supplémentaires, l'application
doit continuer à récupérer les résultats via PQgetResult après avoir terminé la séquence
COPY
. C'est seulement
quand PQgetResult renvoie NULL que vous pouvez être certain que la chaîne de
commandes PQexec est terminée et qu'il est
possible de lancer d'autres commandes.
Les fonctions de cette section devraient seulement être exécutées
pour obtenir un statut de résultat PGRES_COPY_OUT ou PGRES_COPY_IN à partir de PQexec ou PQgetResult.
Un objet PGresult gérant un de ces
statuts comporte quelques données supplémentaires sur l'opération
COPY
qui commence. La
données supplémentaire est disponible en utilisant les fonctions qui
sont aussi utilisées en relation avec les résultats de requêtes :
-
PQnfields
-
Renvoie le nombre de colonnes (champs) à copier.
-
PQbinaryTuples
-
0 indique que le format de copie complet est textuel (lignes
séparées par des retours chariots, colonnes séparées par des
caractères de séparation, etc). 1 indique que le format de
copie complet est binaire. Voir COPY pour plus d'informations.
-
PQfformat
-
Renvoie le code de format (0 pour le texte, 1 pour le binaire)
associé avec chaque colonne de l'opération de copie. Les codes
de format par colonne seront toujours zéro si le format de
copie complet est textuel mais le format binaire supporte à la
fois des colonnes textuelles et des colonnes binaires
(néanmoins, avec l'implémentation actuelle de
COPY
, seules les colonnes
binaires apparaissent dans une copie binaire donc les formats
par colonnes correspondent toujours au format complet
actuellement).
Note
Ces valeurs de données supplémentaires sont seulement disponibles
en utilisant le protocole 3.0. Lors de l'utilisation du protocole
2.0, toutes ces fonctions renvoient 0.
29.8.1. Fonctions d'envoi de données pour COPY
Ces fonctions sont utilisées pour envoyer des données lors d'un
COPY FROM STDIN. Elles échoueront si elles
sont appelées alors que la connexion ne se trouve pas dans l'état
COPY_IN.
-
PQputCopyData
-
Envoie des données au serveur pendant un état COPY_IN.
int PQputCopyData(PGconn *conn,
const char *buffer,
int nbytes);
Transmet les données de
COPY
dans le tampon
spécifié (
buffer
), sur
nbytes
octets, au
serveur. Le résultat vaut 1 si les données ont été envoyées,
zéro si elles n'ont pas été envoyées car la tentative
pourrait bloquer (ce cas n'est possible que lors d'une
connexion en mode non bloquant) ou -1 si une erreur s'est
produite (utilisez PQerrorMessage
pour récupérer des détails si la valeur de retour vaut -1. Si
la valeur vaut zéro, attendez qu'il soit prêt en écriture et
ré-essayez).
L'application pourrait diviser le flux de données de
COPY
dans des
chargements de tampon de taille convenable. Les limites n'ont
pas de signification sémantique lors de l'envoi. Le contenu
du flux de données doit correspondre au format de données
attendu par la commande
COPY
; voir COPY pour des détails.
-
PQputCopyEnd
-
Envoie une indication de fin de transfert au serveur lors de
l'état COPY_IN.
int PQputCopyEnd(PGconn *conn,
const char *errormsg);
Termine l'opération COPY_IN avec
succès si
errormsg
est
NULL. Si
errormsg
n'est pas NULL alors
COPY
échoue, la chaîne
pointée par
errormsg
étant utilisée comme message d'erreur (néanmoins, vous ne
devriez pas supposer que ce message d'erreur précis reviendra
du serveur car le serveur pourrait avoir déjà échouée sur la
commande
COPY
pour des raisons qui lui sont propres). Notez aussi que
l'option forçant l'échec ne fonctionnera pas lors de
l'utilisation de connexions avec un protocole pre-3.0.
Le résultat est 1 si la donnée de fin a été envoyée, zéro si
elle ne l'a pas été car cette tentative serait bloquante (ce
cas est uniquement possible si la connexion est dans un mode
non bloquant) ou -1 si une erreur est survenue (utilisez
PQerrorMessage pour récupérer les
détails si le code de retour est -1. Si la valeur vaut zéro,
attendez que le serveur soit prêt en écriture et ré-essayez
de nouveau).
Après un appel réussi à PQputCopyEnd, appelez PQgetResult pour obtenir le statut de
résultat final de la commande
COPY
. Vous pouvez attendre
que le résultat soit disponible de la même façon. Puis,
retournez aux opérations normales.
29.8.2. Fonctions de réception des données de COPY
Ces fonctions sont utilisées pour recevoir des données lors d'un
COPY TO STDOUT. Elles échoueront si elles
sont appelées alors que la connexion n'est pas dans l'état
COPY_OUT
-
PQgetCopyData
-
Reçoit des données à partir du serveur lors d'un état
COPY_OUT.
int PQgetCopyData(PGconn *conn,
char **buffer,
int async);
Tente d'obtenir une autre ligne de données du serveur lors
d'une opération
COPY
. Les données ne sont
renvoyées qu'une ligne à la fois ; si seulement une ligne
partielle est disponible, elle n'est pas renvoyée. Le retour
d'une ligne avec succès implique l'allocation d'une portion
de mémoire pour contenir les données. Le paramètre
buffer
ne doit pas être
NULL.
*buffer
est initialisé pour pointer
vers la mémoire allouée ou vers NULL au cas où aucun tampon n'est renvoyé. Un
tampon résultat non NULL devra
être libéré en utilisant PQfreemem
lorsqu'il ne sera plus utile.
Lorsqu'une ligne est renvoyée avec succès, le code de retour
est le nombre d'octets de la donnée dans la ligne (et sera
donc supérieur à zéro). La chaîne renvoyée est toujours
terminée par un octet nul bien que ce ne soit utile que pour
les
COPY
textuels. Un résultat zéro indique que la commande
COPY
est
toujours en cours mais qu'aucune ligne n'est encore
disponible (ceci est seulement possible lorsque
async
est vrai). Un résultat -1
indique que
COPY
a terminé. Un résultat
-2 indique qu'une erreur est survenue (consultez PQerrorMessage pour en connaître la raison).
Lorsque
async
est vraie
(différent de zéro), PQgetCopyData
ne bloquera pas en attente d'entrée ; il renverra zéro si
COPY
est
toujours en cours mais qu'aucune ligne n'est encore
disponible (dans ce cas, attendez qu'il soit prêt en lecture
puis appelez PQconsumeInput avant
d'appeler PQgetCopyData de
nouveau). Quand
async
est
faux (zéro), PQgetCopyData bloquera
tant que les données ne seront pas disponibles ou tant que
l'opération n'aura pas terminée.
Après que PQgetCopyData ait renvoyé
-1, appelez PQgetResult pour
obtenir le statut de résultat final de la commande
COPY
. Vous
pourriez attendre la disponibilité de ce résultat comme
d'habitude. Puis, retournez aux opérations habituelles.
29.8.3. Fonctions obsolètes pour COPY
Ces fonctions représentent d'anciennes méthodes de gestion de
COPY
. Bien qu'elles
fonctionnent toujours, elles sont obsolètes à cause de leur pauvre
gestion des erreurs, des méthodes non convenables de détection
d'une fin de transmission, et du manque de support des transferts
binaires et des transferts non bloquants.
-
PQgetline
-
Lit une ligne de caractères terminée par un retour chariot
(transmis par le serveur) dans un tampon de taille
length
.
int PQgetline(PGconn *conn,
char *buffer,
int length);
Cette fonction copie jusqu'à
length
-1 caractères dans le tampon
et convertit le retour chariot en un octet nul. PQgetline renvoie EOF à la fin de l'entrée, 0 si la ligne
entière a été lu et 1 si le tampon est complet mais que le
retour chariot à la fin n'a pas encore été lu.
Notez que l'application doit vérifier si un retour chariot
est constitué de deux caractères \.,
ce qui indique que le serveur a terminé l'envoi des résultats
de la commande
COPY
. Si l'application peut
recevoir des lignes de plus de
length
-1 caractères, une attention
toute particulière est nécessaire pour s'assurer qu'elle
reconnaisse la ligne \. correctement
(et ne la confond pas, par exemple, avec la fin d'une longue
ligne de données).
-
PQgetlineAsync
-
Lit une ligne de données
COPY
(transmise par le
serveur) dans un tampon sans blocage.
int PQgetlineAsync(PGconn *conn,
char *buffer,
int bufsize);
Cette fonction est similaire à PQgetline mais elle peut être utilisée par
des applications qui doivent lire les données de
COPY
de façon asynchrone,
c'est-à-dire sans blocage. Après avoir lancé la commande
COPY
et obtenu
une réponse PGRES_COPY_OUT,
l'application devrait appeler PQconsumeInput et PQgetlineAsync jusqu'à ce que le signal de
fin des données ne soit détecté.
Contrairement à PQgetline, cette
fonction prend la responsabilité de détecter la fin de
données.
À chaque appel, PQgetlineAsync
renverra des données si une ligne de données complète est
disponible dans le tampon d'entrée de libpq. Sinon, aucune ligne n'est
renvoyée jusqu'à l'arrivée du reste de la ligne. La fonction
renvoie -1 si le marqueur de fin de copie des données a été
reconnu, 0 si aucune donnée n'est disponible ou un nombre
positif indiquant le nombre d'octets renvoyés. Si -1 est
renvoyé, l'appelant doit ensuite appeler PQendcopy puis retourner aux traitements
habituels.
Les données renvoyées ne seront pas étendues au delà de la
limite de la ligne. Si possible, une ligne complète sera
retournée en une fois. Mais si le tampon offert par
l'appelant est trop petit pour contenir une ligne envoyée par
le serveur, alors une ligne de données partielle sera
renvoyée. Avec des données textuelles, ceci peut être détecté
en testant si le dernier octet renvoyé est \n ou non (dans un
COPY
binaire, l'analyse
réelle du format de données
COPY
sera nécessaire pour
faire la détermination équivalente). La chaîne renvoyée n'est
pas terminée par un octet nul (si vous voulez ajouter un
octet nul de terminaison, assurez-vous de passer un
bufsize
inférieur de 1
par rapport à l'espace réellement disponible).
-
PQputline
-
Envoie une chaîne terminée par un octet nul au serveur.
Renvoie 0 si tout va bien et EOF
s'il est incapable d'envoyer la chaîne.
int PQputline(PGconn *conn,
const char *string);
Le flux de données de
COPY
envoyé par une série
d'appels à PQputline a le même
format que celui renvoyé par PQgetlineAsync, sauf que les applications ne
sont pas obligées d'envoyer exactement une ligne de données
par appel à PQputline ; il est
correct d'envoyer une ligne partielle ou plusieurs lignes par
appel.
Note
Avant le protocole 3.0 de PostgreSQL™, il était
nécessaire pour l'application d'envoyer explicitement les
deux caractères \. comme ligne
finale pour indiquer qu'il a terminé l'envoi des données
du
COPY
data. Bien que ceci fonctionne toujours, cette méthode
est abandonnée et la signification spéciale de \. pourrait être supprimée dans une
prochaine version. Il est suffisant d'appeler PQendcopy après avoir envoyé les vraies
données.
-
PQputnbytes
-
Envoie une chaîne non terminée par un octet nul au serveur.
Renvoie 0 si tout va bien et EOF
s'il n'a pas été capable d'envoyer la chaîne.
int PQputnbytes(PGconn *conn,
const char *buffer,
int nbytes);
C'est exactement comme PQputline
sauf que le tampon de donnée n'a pas besoin d'être terminé
avec un octet nul car le nombre d'octets envoyés est spécifié
directement. Utilisez cette procédure pour envoyer des
données binaires.
-
PQendcopy
-
Se synchronise avec le serveur.
int PQendcopy(PGconn *conn);
Cette fonction attend que le serveur ait terminé la copie. Il
devrait soit indiquer quand la dernière chaîne a été envoyée
au serveur en utilisant PQputline
soit le moment où la dernière chaîne a été reçue du serveur
en utilisant PGgetline. Si ce n'est
pas fait, le serveur renverra un « out of sync » (perte de synchronisation)
au client. Suivant le retour de cette fonction, le serveur
est prêt à recevoir la prochaine commande SQL. Le code de
retour 0 indique un succès complet et est différent de zéro
dans le cas contraire (utilisez PQerrorMessage pour récupérer des détails sur
l'échec).
Lors de l'utilisation de PQgetResult, l'application devrait répondre à
un résultat PGRES_COPY_OUT en
exécutant PQgetline de façon
répétée, suivi par un PQendcopy une
fois la ligne de terminaison aperçue. Il devrait ensuite
retourner à la boucle PQgetResult
jusqu'à ce que PQgetResult renvoie
un pointeur nul. De façon similaire, un résultat PGRES_COPY_IN est traité par une série
d'appels à PQputline suivis par un
PQendcopy, ensuite retour à la
boucle PQgetResult. Cet arrangement
vous assurera qu'une commande
COPY
intégrée dans une
série de commandes SQL
sera exécutée correctement.
Les anciennes applications soumettent un
COPY
via PQexec et assument que la transaction est
faite après un PQendcopy. Ceci
fonctionnera correctement seulement si
COPY
est la seule commande
SQL dans la chaîne de
commandes.
|