32.3. Interfaces client

Cette section décrit les possibilités de la bibliothèque d'interface client libpq de PostgreSQL™ permettant d'accéder aux « Large Objects ». L'interface des « Large Objects » de PostgreSQL™ est modelé d'après l'interface des systèmes de fichiers d'Unix avec des analogies pour les appels open, read, write, lseek, etc.

Toutes les manipulations de « Large Objects » utilisant ces fonctions doivent prendre place dans un bloc de transaction SQL car les descripteurs de fichiers des « Large Objects » sont seulement valides pour la durée d'une transaction.

Si une erreur survient lors de l'exécution de ces fonctions, la fonction renverra une valeur autrement impossible, typiquement 0 or -1. Un message décrivant l'erreur est stocké dans l'objet de connexion et peut être récupéré avec la fonction PQerrorMessage.

Les applications clientes qui utilisent ces fonctions doivent inclure le fichier d'en-tête libpq/libpq-fs.h et établir un lien avec la bibliothèque libpq.

32.3.1. Créer un objet large

La fonction

Oid lo_creat(PGconn *conn, int mode);
    

crée un nouvel objet large. La valeur de retour est un OID assigné au nouvel objet large ou InvalidOid (zéro) en cas d'erreur. mode est inutilisée et ignorée sur PostgreSQL™ 8.1 ; néanmoins, pour la compatibilité avec les anciennes versions, il est préférable de l'initialiser à INV_READ, INV_WRITE, ou INV_READ | INV_WRITE (ces constantes symboliques sont définies dans le fichier d'en-tête libpq/libpq-fs.h).

Un exemple :

inv_oid = lo_creat(conn, INV_READ|INV_WRITE);
    

La fonction

Oid lo_create(PGconn *conn, Oid lobjId);
    

crée aussi un nouvel objet large. L'OID à affecter peut être spécifié par lobjId ; dans ce cas, un échec survient si l'OID est déjà utilisé pour un autre objet large. Si lobjId vaut InvalidOid (zero), alors lo_create affecte un OID inutilisé (ceci est le même comportement que lo_creat). La valeur de retour est l'OID qui a été affecté au nouvel objet large ou InvalidOid (zero) en cas d'échec.

lo_create est nouveau depuis PostgreSQL™ 8.1 ; si cette fonction est utilisée à partir d'un serveur d'une version plus ancienne, elle échouera et renverra InvalidOid.

Un exemple :

inv_oid = lo_create(conn, desired_oid);
    

32.3.2. Importer un objet large

Pour importer un fichier du système d'exploitation en tant qu'objet large, appelez

Oid lo_import(PGconn *conn, const char *filename);
    

filename spécifie le nom du fichier à importer comme objet large. Le code de retour est l'OID assigné au nouvel objet large ou InvalidOid (zero) en cas d'échec. Notez que le fichier est lu par la bibliothèque d'interface du client, pas par le serveur. Donc il doit exister dans le système de fichier du client et lisible par l'application du client.

La fonction

Oid lo_import_with_oid(PGconn *conn, const char *filename, Oid lobjId);
    

importe aussi un nouvel « large object ». L'OID à affecter peut être indiqué par lobjId ; dans ce cas, un échec survient si l'OID est déjà utilisé pour un autre « large object ». Si lobjId vaut InvalidOid (zéro) alors lo_import_with_oid affecte un OID inutilisé (et donc obtient ainsi le même comportement que lo_import). La valeur de retour est l'OID qui a été affecté au nouveau « large object » ou InvalidOid (zéro) en cas d'échec.

lo_import_with_oid est une nouveauté de PostgreSQL™ 8.4, et utilise en interne lo_create qui était une nouveauté de la 8.1 ; si cette fonction est exécutée sur un serveur en 8.0 voire une version précédente, elle échouera et renverra InvalidOid.

32.3.3. Exporter un objet large

Pour exporter un objet large en tant que fichier du système d'exploitation, appelez

int lo_export(PGconn *conn, Oid lobjId, const char *filename);
    

L'argument lobjId spécifie l'OID de l'objet large à exporter et l'argument filename spécifie le nom du fichier. Notez que le fichier est écrit par la bibliothèque d'interface du client, pas par le serveur. Renvoie 1 en cas de succès, -1 en cas d'échec.

32.3.4. Ouvrir un objet large existant

Pour ouvrir un objet large existant pour lire ou écrire, appelez

int lo_open(PGconn *conn, Oid lobjId, int mode);
    

L'argument lobjId spécifie l'OID de l'objet large à ouvrir. Les bits mode contrôlent si l'objet est ouvert en lecture (INV_READ), écriture (INV_WRITE) ou les deux (ces constantes symboliques sont définies dans le fichier d'en-tête libpq/libpq-fs.h). lo_open renvoie un descripteur (positif) d'objet large pour une utilisation future avec lo_read, lo_write, lo_lseek, lo_lseek64, lo_tell, lo_tell64, lo_truncate, lo_truncate64 et lo_close. Le descripteur est uniquement valide pour la durée de la transaction en cours. En cas d'échec, -1 est renvoyé.

Actuellement, le serveur ne fait pas de distinction entre les modes INV_WRITE et INV_READ | INV_WRITE : vous êtes autorisé à lire à partir du descripteur dans les deux cas. Néanmoins, il existe une différence significative entre ces modes et INV_READ seul : avec INV_READ, vous ne pouvez pas écrire sur le descripteur et la donnée lue à partir de ce dernier, reflètera le contenu de l'objet large au moment où lo_open a été exécuté dans la transaction active, quelques soient les possibles écritures par cette transaction ou par d'autres. Lire à partir d'un descripteur ouvert avec INV_WRITE renvoie des données reflétant toutes les écritures des autres transactions validées ainsi que les écritures de la transaction en cours. Ceci est similaire à la différence de comportement entre les modes de transaction REPEATABLE READ et READ COMMITTED pour les requêtes SQL SELECT.

Un exemple :

inv_fd = lo_open(conn, inv_oid, INV_READ|INV_WRITE);
    

32.3.5. Écrire des données dans un objet large

La fonction

int lo_write(PGconn *conn, int fd, const char *buf, size_t len);
    

écrit len octets à partir de buf (qui doit avoir len comme taille) dans le descripteur fd du « Large Object ». L'argument fd doit avoir été renvoyé par un appel précédent à lo_open. Le nombre d'octets réellement écrit est renvoyé (dans l'implémentation actuelle, c'est toujours égal à len sauf en cas d'erreur). Dans le cas d'une erreur, la valeur de retour est -1.

Bien que le paramètre len est déclaré size_t, cette fonction rejettera les valeurs plus grandes que INT_MAX. En pratique, il est préférable de transférer les données en plusieurs parties d'au plus quelques méga-octets.

32.3.6. Lire des données à partir d'un objet large

La fonction

int lo_read(PGconn *conn, int fd, char *buf, size_t len);
    

lit jusqu'à len octets à partir du descripteur de fichier fd dans buf (qui doit avoir pour taille len). L'argument fd doit avoir été renvoyé par un appel précédent à lo_open. Le nombre d'octets réellement lus est renvoyé. Cela sera plus petit que len si la fin du « Large Object » est atteint avant. Dans le cas d'une erreur, la valeur de retour est -1.

Bien que le paramètre len est déclaré size_t, cette fonction rejettera les valeurs plus grandes que INT_MAX. En pratique, il est préférable de transférer les données en plusieurs parties d'au plus quelques méga-octets.

32.3.7. Recherche dans un objet large

Pour modifier l'emplacement courant de lecture ou écriture associé au descripteur d'un objet large, on utilise

int lo_lseek(PGconn *conn, int fd, int offset, int whence);
    

Cette fonction déplace le pointeur d'emplacement courant pour le descripteur de l'objet large identifié par fd au nouvel emplacement spécifié avec le décalage (offset). Les valeurs valides pour whence sont SEEK_SET (rechercher depuis le début de l'objet), SEEK_CUR (rechercher depuis la position courante) et SEEK_END (rechercher depuis la fin de l'objet). Le code de retour est le nouvel emplacement du pointeur ou -1 en cas d'erreur.

When dealing with large objects that might exceed 2GB in size, instead use

pg_int64 lo_lseek64(PGconn *conn, int fd, pg_int64 offset, int whence);
    

This function has the same behavior as lo_lseek, but it can accept an offset larger than 2GB and/or deliver a result larger than 2GB. Note that lo_lseek will fail if the new location pointer would be greater than 2GB.

lo_lseek64 is new as of PostgreSQL™ 9.3. If this function is run against an older server version, it will fail and return -1.

32.3.8. Obtenir la position de recherche d'un objet large

Pour obtenir la position actuelle de lecture ou écriture d'un descripteur d'objet large, appelez

int lo_tell(PGconn *conn, int fd);
    

S'il n'y a pas d'erreur, la valeur renvoyée est -1.

Lors de la gestion de « Large Objects » qui pourraient dépasser 2 Go, utilisez à la place

pg_int64 lo_tell64(PGconn *conn, int fd);
    

Cette fonction a le même comportement que lo_tell mais elle peut gérer des objets de plus de 2 Go. Notez que lo_tell échouera si l'emplacement de lecture/écrire va au-delà des 2 Go.

lo_tell64 est disponible depuis la version 9.3 de PostgreSQL™. Si cette fonction est utilisée sur une ancienne version, elle échouera et renverra -1.

32.3.9. Tronquer un Objet Large

Pour tronquer un objet large avec une longueur donnée, on utilise

int lo_truncate(PGcon *conn, int fd, size_t len);
    

Cette fonction tronque le « Large Object » décrit par fd avec la longueur len. L'argument fd doit avoir été renvoyé par un appel précédent à lo_open. Si la valeur du paramètre len est plus grand que la longueur actuelle du « Large Object », ce dernier est étendu à la longueur spécifié avec des octets nuls ('\0'). En cas de succès, lo_truncate renvoit 0. En cas d'erreur, il renvoit -1.

L'emplacement de lecture/écriture associé avec le descripteur fd n'est pas modifié.

Bien que le paramètre len est déclaré size_t, lo_truncate rejettera toute longueur supérieure à INT_MAX.

Lors de la gestion de « Large Objects » qui pourraient dépasser 2 Go, utilisez à la place

int lo_truncate64(PGcon *conn, int fd, pg_int64 len);
    

Cette fonction a le même comportement que lo_truncate mais elle peut accepter une valeur supérieure à 2 Go pour le paramètre len.

lo_truncate est une nouveauté de PostgreSQL™ 8.3; si cette fonction est également exécuté sur un version plus ancienne du serveur, elle échouera et retournera -1.

lo_truncate64 est disponible depuis la version 9.3 de PostgreSQL™. Si cette fonction est utilisée sur une ancienne version, elle échouera et renverra -1.

32.3.10. Fermer un descripteur d'objet large

Un descripteur d'objet large peut être fermé en appelant

int lo_close(PGconn *conn, int fd);
    

fd est un descripteur d'objet large renvoyé par lo_open. En cas de succès, lo_close renvoie zéro. -1 en cas d'échec.

Tous les descripteurs d'objets larges restant ouverts à la fin d'une transaction seront automatiquement fermés.

32.3.11. Supprimer un objet large

Pour supprimer un objet large de la base de données, on utilise

int lo_unlink(PGconn *conn, Oid lobjId);
    

L'argument lobjId spécifie l'OID de l'objet large à supprimer. En cas d'erreur, le code de retour est -1.