33.3. Interfaces de cliente #

33.3.1. Crear un objeto grande
33.3.2. Importar un objeto grande
33.3.3. Exportar un objeto grande
33.3.4. Abrir un objeto grande existente
33.3.5. Escribir datos en un objeto grande
33.3.6. Leer datos de un objeto grande
33.3.7. Desplazarse en un objeto grande (Seeking)
33.3.8. Obtener la posición de desplazamiento de un objeto grande
33.3.9. Truncar un objeto grande
33.3.10. Cerrar un descriptor de objeto grande
33.3.11. Eliminar un objeto grande

Esta sección describe las facilidades que proporciona la biblioteca de interfaz de cliente libpq de PostgreSQL para acceder a objetos grandes. La interfaz de objetos grandes de PostgreSQL se modela a partir de la interfaz del sistema de archivos de Unix, con análogos de open, read, write, lseek, etc.

Toda la manipulación de objetos grandes mediante estas funciones debe realizarse dentro de un bloque de transacción SQL, ya que los descriptores de archivo de objetos grandes solo son válidos durante la transacción. Las operaciones de escritura, incluyendo lo_open con el modo INV_WRITE, no se permiten en una transacción de solo lectura.

Si ocurre un error al ejecutar cualquiera de estas funciones, la función devolverá un valor de otro modo imposible, típicamente 0 o -1. Un mensaje que describe el error se almacena en el objeto de conexión y se puede recuperar con la PQerrorMessage .

Las aplicaciones cliente que utilizan estas funciones deben incluir el archivo de cabecera libpq/libpq-fs.h y enlazarse con la biblioteca libpq.

Las aplicaciones cliente no pueden usar estas funciones mientras una conexión libpq esté en modo pipeline.

33.3.1. Crear un objeto grande #

La función

Oid lo_create(PGconn *conn, Oid lobjId);

crea un nuevo objeto grande. El OID a asignar se puede especificar mediante lobjId; si es así, se produce un fallo si ese OID ya está en uso por algún objeto grande. Si lobjId es InvalidOid (cero), entonces lo_create asigna un OID no utilizado. El valor de retorno es el OID que se asignó al nuevo objeto grande, o InvalidOid (cero) en caso de fallo.

Un ejemplo:

inv_oid = lo_create(conn, desired_oid);

La función más antigua

Oid lo_creat(PGconn *conn, int mode);

también crea un nuevo objeto grande, siempre asignando un OID no utilizado. El valor de retorno es el OID que se asignó al nuevo objeto grande, o InvalidOid (cero) en caso de fallo.

En las versiones de PostgreSQL 8.1 y posteriores, el parámetro mode se ignora, por lo que lo_creat es exactamente equivalente a lo_create con un segundo argumento en cero. Sin embargo, hay pocas razones para usar lo_creat a menos que necesites trabajar con servidores anteriores a la versión 8.1. Para trabajar con un servidor tan antiguo, debes usar lo_creat y no lo_create, y debes configurar el mode en uno de los siguientes: INV_READ, INV_WRITE o INV_READ | INV_WRITE. (Estas constantes simbólicas se definen en el archivo de cabecera libpq/libpq-fs.h).

Un ejemplo:

inv_oid = lo_creat(conn, INV_READ|INV_WRITE);

33.3.2. Importar un objeto grande #

Para importar un archivo del sistema operativo como un objeto grande, llama a

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

filename especifica el nombre del archivo en el sistema operativo a importar como un objeto grande. El valor de retorno es el OID que se asignó al nuevo objeto grande, o InvalidOid (cero) en caso de fallo. Ten en cuenta que el archivo es leído por la biblioteca de la interfaz de cliente, no por el servidor; por lo tanto, debe existir en el sistema de archivos del cliente y ser legible por la aplicación cliente.

La función

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

también importa un nuevo objeto grande. El OID a asignar se puede especificar mediante lobjId; si es así, se produce un fallo si ese OID ya está en uso por algún objeto grande. Si lobjId es InvalidOid (cero), entonces lo_import_with_oid asigna un OID no utilizado (este es el mismo comportamiento que lo_import). El valor de retorno es el OID que se asignó al nuevo objeto grande, o InvalidOid (cero) en caso de fallo.

lo_import_with_oid es nueva a partir de PostgreSQL 8.4 y utiliza lo_create internamente, la cual es nueva en la versión 8.1; si esta función se ejecuta contra un servidor 8.0 o anterior, fallará y devolverá InvalidOid.

33.3.3. Exportar un objeto grande #

Para exportar un objeto grande a un archivo del sistema operativo, llama a

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

El argumento lobjId especifica el OID del objeto grande a exportar y el argumento filename especifica el nombre del archivo en el sistema operativo. Ten en cuenta que la biblioteca de interfaz de cliente escribe el archivo, no el servidor. Devuelve 1 en caso de éxito, y -1 en caso de fallo.

33.3.4. Abrir un objeto grande existente #

Para abrir un objeto grande existente para lectura o escritura, llama a

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

El argumento lobjId especifica el OID del objeto grande a abrir. Los bits de mode controlan si el objeto se abre para lectura (INV_READ), escritura (INV_WRITE) o ambos. (Estas constantes simbólicas se definen en el archivo de cabecera libpq/libpq-fs.h). lo_open devuelve un descriptor de objeto grande (no negativo) para su uso posterior en lo_read, lo_write, lo_lseek, lo_lseek64, lo_tell, lo_tell64, lo_truncate, lo_truncate64 y lo_close. El descriptor solo es válido durante la transacción actual. En caso de fallo, devuelve -1.

Actualmente, el servidor no distingue entre los modos INV_WRITE y INV_READ | INV_WRITE: se te permite leer del descriptor en cualquiera de los dos casos. Sin embargo, existe una diferencia significativa entre estos modos y el modo INV_READ solo: con INV_READ no puedes escribir en el descriptor, y los datos leídos del mismo reflejarán el contenido del objeto grande en el momento en que se tomó la captura (snapshot) de la transacción que estaba activa cuando se ejecutó lo_open, independientemente de las escrituras posteriores de esta u otras transacciones. La lectura de un descriptor abierto con INV_WRITE devuelve datos que reflejan todas las escrituras de otras transacciones confirmadas, así como las escrituras de la transacción actual. Esto es similar al comportamiento de los modos de transacción REPEATABLE READ frente a READ COMMITTED para los comandos comunes SQL SELECT.

lo_open fallará si el privilegio SELECT no está disponible para el objeto grande, o si se especifica INV_WRITE y el privilegio UPDATE no está disponible. (Antes de PostgreSQL 11, estas comprobaciones de privilegios se realizaban en la primera llamada de lectura o escritura real utilizando el descriptor). Estas comprobaciones de privilegios se pueden deshabilitar con el parámetro de configuración lo_compat_privileges.

Un ejemplo:

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

33.3.5. Escribir datos en un objeto grande #

La función

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

escribe len bytes desde buf (que debe ser de tamaño len) en el descriptor de objeto grande fd. El argumento fd debe haber sido devuelto por una llamada previa a lo_open. Se devuelve el número de bytes realmente escritos (en la implementación actual, esto siempre será igual a len a menos que haya un error). En caso de error, el valor de retorno es -1.

Aunque el parámetro len se declara como size_t, esta función rechazará valores de longitud mayores que INT_MAX. En la práctica, es mejor transferir datos en fragmentos de a lo sumo unos pocos megabytes de todos modos.

33.3.6. Leer datos de un objeto grande #

La función

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

lee hasta len bytes del descriptor de objeto grande fd y los almacena en buf (que debe ser de tamaño len). El argumento fd debe haber sido devuelto por una llamada previa a lo_open. Se devuelve el número de bytes realmente leídos; esto será menor que len si se alcanza primero el final del objeto grande. En caso de error, el valor de retorno es -1.

Aunque el parámetro len se declara como size_t, esta función rechazará valores de longitud mayores que INT_MAX. En la práctica, es mejor transferir datos en fragmentos de a lo sumo unos pocos megabytes de todos modos.

33.3.7. Desplazarse en un objeto grande (Seeking) #

Para cambiar la ubicación actual de lectura o escritura asociada con un descriptor de objeto grande, llama a

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

Esta función mueve el puntero de ubicación actual para el descriptor de objeto grande identificado por fd a la nueva ubicación especificada por offset. Los valores válidos para whence son SEEK_SET (desplazarse desde el inicio del objeto), SEEK_CUR (desplazarse desde la posición actual) y SEEK_END (desplazarse desde el final del objeto). El valor de retorno es el puntero a la nueva ubicación, o -1 en caso de error.

Cuando se trabaje con objetos grandes que puedan exceder los 2 GB de tamaño, utiliza en su lugar:

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

Esta función tiene el mismo comportamiento que lo_lseek, pero puede aceptar un offset mayor de 2 GB y/o entregar un resultado mayor de 2 GB. Ten en cuenta que lo_lseek fallará si el puntero de la nueva ubicación es mayor de 2 GB.

lo_lseek64 es nueva a partir de PostgreSQL 9.3. Si esta función se ejecuta contra una versión de servidor anterior, fallará y devolverá -1.

33.3.8. Obtener la posición de desplazamiento de un objeto grande #

Para obtener la ubicación actual de lectura o escritura de un descriptor de objeto grande, llama a

int lo_tell(PGconn *conn, int fd);

En caso de error, el valor de retorno es -1.

Cuando se trabaje con objetos grandes que puedan exceder los 2 GB de tamaño, utiliza en su lugar:

int64_t lo_tell64(PGconn *conn, int fd);

Esta función tiene el mismo comportamiento que lo_tell, pero puede entregar un resultado mayor de 2 GB. Ten en cuenta que lo_tell fallará si la ubicación actual de lectura/escritura es mayor de 2 GB.

lo_tell64 es nueva a partir de PostgreSQL 9.3. Si esta función se ejecuta contra una versión de servidor anterior, fallará y devolverá -1.

33.3.9. Truncar un objeto grande #

Para truncar un objeto grande a una longitud dada, llama a

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

Esta función trunca el descriptor de objeto grande fd a la longitud len. El argumento fd debe haber sido devuelto por una llamada previa a lo_open. Si len es mayor que la longitud actual del objeto grande, el objeto grande se extiende a la longitud especificada con bytes nulos ('\0'). En caso de éxito, lo_truncate devuelve cero. En caso de error, el valor de retorno es -1.

La ubicación de lectura/escritura asociada con el descriptor fd no cambia.

Although the len parameter is declared as size_t, lo_truncate will reject length values larger than INT_MAX.

Cuando se trabaje con objetos grandes que puedan exceder los 2 GB de tamaño, utiliza en su lugar:

int64_t lo_truncate64(PGconn *conn, int fd, int64_t len);

Esta función tiene el mismo comportamiento que lo_truncate, pero puede aceptar un valor len que exceda los 2 GB.

lo_truncate es nueva a partir de PostgreSQL 8.3; si esta función se ejecuta contra una versión de servidor anterior, fallará y devolverá -1.

lo_truncate64 es nueva a partir de PostgreSQL 9.3; si esta función se ejecuta contra una versión de servidor anterior, fallará y devolverá -1.

33.3.10. Cerrar un descriptor de objeto grande #

Un descriptor de objeto grande se puede cerrar llamando a

int lo_close(PGconn *conn, int fd);

donde fd es un descriptor de objeto grande devuelto por lo_open. En caso de éxito, lo_close devuelve cero. En caso de error, el valor de retorno es -1.

Cualquier descriptor de objeto grande que permanezca abierto al final de una transacción se cerrará automáticamente.