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
PQexec
ou une
des fonctions équivalentes. 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, d'autres commandes SQL peuvent être exécutées 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.
Les données supplémentaires sont disponibles 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 pour le moment
les formats par colonnes correspondent toujours au format complet).
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é placées dans la queue, zéro si elles n'ont
pas été placées dans la queue à cause de tampons pleins (cela n'arrivera
qu'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 à écrire et
ré-essayez).
L'application peut diviser le flux de données de COPY
dans des tampons de taille adéquate. Les limites des tampons 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
est passé en échec,
avec la chaîne pointée par errormsg
comme message d'erreur. (Mais ne pas supposer que ce message d'erreur précis
proviendra du serveur car le serveur pourrait avoir déjà échoué sur la commande
COPY
pour des raisons qui lui sont propres).
Le résultat est 1 si le message de terminaison a été envoyé ; ou en
mode non bloquant, cela peut seulement indiquer que le message de
terminaison a été correctement mis en file d'attente. (En mode non
bloquant, pour être certain que les données ont été correctement
envoyées, vous devriez ensuite attendre que le mode écriture soit
disponible puis appeler PQflush
, à répéter
jusqu'à ce que 0 soit renvoyé). Zéro indique que la fonction n'a
pas pu mettre en file d'attente le message de terminaison à cause d'une
file pleine ; ceci ne peut survenir qu'en mode non bloquant. (Dans ce
cas, attendez que le mode écriture soit disponible puis rappelez
à nouveau la fonction PQputCopyEnd
). Si
une erreur physique survient, -1 est renvoyé ; vous pouvez alors
appeler PQerrorMessage
pour avoir plus de
détails sur l'erreur.
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 au fonctionnement normal.
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, la valeur de retour est le
nombre d'octets de la donnée dans la ligne (et sera donc toujours 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 à
lire 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
a renvoyé -1, appelez
PQgetResult
pour obtenir le statut de résultat final de la commande
COPY
. On peut attendre la disponibilité de ce résultat comme
d'habitude. Puis, retournez aux opérations habituelles.
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 inadéquates 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é
lue 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 confond pas, par exemple,
la fin d'une longue ligne de données pour une ligne de terminaison).
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
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.
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 au serveur
qu'elle a terminé l'envoi des données du COPY
.
Bien que ceci fonctionne toujours, cette
méthode est obsolète 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ées 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. Elle devrait
indiquer soit le moment où 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 PQgetline
. Si ce n'est pas fait,
le serveur renverra un « out of sync » (perte de
synchronisation) au client. Au 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 NULL. 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 sont susceptibles de soumettre un
COPY
via PQexec
et supposent 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.