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.
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);
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);
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.
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.
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.
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);
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.
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.
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.
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.
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.
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.
Para eliminar un objeto grande de la base de datos, llama a
int lo_unlink(PGconn *conn, Oid lobjId);
El argumento lobjId especifica el OID del objeto grande a
eliminar. Devuelve 1 en caso de éxito, y -1 en caso de fallo.