¿Cómo insertar datos (archivos) en una columna Bytea de PostgreSQL?


38

Esta pregunta no se trata de bytea v. Oid v. Blobs v. Objetos grandes, etc.

Tengo una tabla que contiene un integercampo de clave principal y un byteacampo. Me gustaría ingresar datos en el byteacampo. Esto, presumiblemente, lo puede hacer uno de los PL/idiomas, y puedo considerar hacerlo PL/Pythonen el futuro.

Como todavía estoy probando y experimentando, simplemente me gustaría insertar datos de un archivo (en el servidor) usando declaraciones SQL "estándar". Soy consciente de que solo los administradores con permiso de escritura en el servidor podrán insertar datos de la manera que me gustaría. No estoy preocupado por eso en esta etapa ya que los usuarios no estarían insertando byteadatos en este momento. He buscado en varios sitios de StackExchange, los archivos PostgreSQL e Internet en general, pero no he podido encontrar una respuesta.

Editar: Esta discusión de 2008 implica que lo que quiero hacer no es posible. ¿Cómo se byteausan los campos entonces?

Editar: Esta pregunta similar de 2005 sigue sin respuesta.

Resuelto: Los detalles proporcionados aquí en el psycopgsitio web proporcionaron la base para una solución que he escrito en Python. También es posible insertar datos binarios en una byteacolumna usando PL/Python. No sé si esto es posible usando SQL "puro".


1
El enlace a los documentos de psycopg está roto y mi edición parece haber sido rechazada (!?). Aquí está la ubicación actual .
Aryeh Leib Taurog

@AryehLeibTaurog: Gracias. Rechacé la edición porque no estaba claro para mí que el texto modificado fuera un hipervínculo. Si desea volver a realizar la edición, lo aprobaré.
SabreWolfy

@Andriy_M ¿Por qué crees que "esta edición se desvía de la intención original de la publicación"? (¿La edición realizada por informatik01?)
miracle173

@ miracle173: Porque tuve la impresión de que algunas de las etiquetas sugeridas eran irrelevantes (bueno, solo una en realidad blob). Si eso fue un error, me disculpo sinceramente.
Andriy M

Respuestas:


27

como superusuario:

create or replace function bytea_import(p_path text, p_result out bytea) 
                   language plpgsql as $$
declare
  l_oid oid;
begin
  select lo_import(p_path) into l_oid;
  select lo_get(l_oid) INTO p_result;
  perform lo_unlink(l_oid);
end;$$;

lo_get se introdujo en 9.4, por lo que para versiones anteriores necesitaría:

create or replace function bytea_import(p_path text, p_result out bytea) 
                   language plpgsql as $$
declare
  l_oid oid;
  r record;
begin
  p_result := '';
  select lo_import(p_path) into l_oid;
  for r in ( select data 
             from pg_largeobject 
             where loid = l_oid 
             order by pageno ) loop
    p_result = p_result || r.data;
  end loop;
  perform lo_unlink(l_oid);
end;$$;

luego:

insert into my_table(bytea_data) select bytea_import('/my/file.name');

Para el proceso inverso, no he probado esto , pero si funciona, lo_export a ser todo lo que necesita
Jack Douglas


15

Esta solución no es exactamente eficiente en términos de tiempo de ejecución, pero es trivialmente fácil en comparación con hacer sus propios encabezados COPY BINARY. Además, no requiere ninguna biblioteca o lenguaje de script fuera de bash.

Primero, convierta el archivo en un hexdump, duplicando el tamaño del archivo. xxd -pnos acerca bastante, pero arroja algunas líneas molestas de las que tenemos que ocuparnos:

xxd -p /path/file.bin | tr -d '\n' > /path/file.hex

A continuación, importe los datos en PostgreSQL como un textcampo muy grande . Este tipo contiene hasta un GB por valor de campo, por lo que deberíamos estar bien para la mayoría de los propósitos:

CREATE TABLE hexdump (hex text); COPY hexdump FROM '/path/file.hex';

Ahora que nuestros datos son una cadena hexadecimal gratuita, utilizamos PostgresQL decodepara obtener un byteatipo:

CREATE TABLE bindump AS SELECT decode(hex, 'hex') FROM hexdump;

Sin embargo, esta solución da como resultado \ n caracteres que se eliminan del archivo.
SabreWolfy

2
SabreWolfy: No, no lo hace. El tr -d '\n'está operando en la salida de xxd, que codifica el contenido binario de la entrada como caracteres hexadecimales ASCII (0-9 y af). xxd también pasa a los saltos de línea de salida a intervalos regulares para que la salida sea legible para los humanos, pero en este caso queremos que se eliminen. Los avances de línea en los datos originales estarán en forma hexadecimal y no se verán afectados.
goodside

5

La respuesta con xxd es agradable y, para archivos pequeños, muy rápida. A continuación se muestra un script de ejemplo que estoy usando.

xxd  -p /home/user/myimage.png | tr -d '\n' > /tmp/image.hex
echo "
    -- CREATE TABLE hexdump (hex text);
    DELETE FROM hexdump;
    COPY hexdump FROM '/tmp/image.hex';

    -- CREATE TABLE bindump (binarydump bytea);
    DELETE FROM bindump;

    INSERT INTO bindump (binarydump)  
    (SELECT decode(hex, 'hex') FROM hexdump limit 1);

    UPDATE users 
    SET image= 
    (
        SELECT decode(hex, 'hex') 
        FROM hexdump LIMIT 1
    )  
    WHERE id=15489 ;
    " | psql mydatabase

1

Utilice la función BINARIO COPIA de Postgres . Esto es ampliamente equivalente a las tablas externas de Oracle .


Gracias. El enlace que proporcionó indica que los datos deben estar en formato de tabla binaria ASCII o PostgreSQL. Más abajo en la página, se menciona que el formato de tabla binaria se crea primero con un comando COPIAR A. ¿Alguno de estos enfoques me permitiría insertar un archivo binario (PDF, documento, hoja de cálculo) en una byteacolumna?
SabreWolfy

La documentación de PostgreSQL en COPY BINARY ( postgresql.org/docs/8.4/interactive/sql-copy.html ) indica que se requiere un encabezado de archivo especial al insertar datos binarios. ¿Necesito construir este encabezado y agregarlo a datos binarios? Eso parece algo complejo para simplemente almacenar una cadena de datos binarios.
SabreWolfy

Hmm, ahora que lo mencionas no estoy seguro, solo recordé el comando y asumí que haría eso. Quizás PL / lo que sea es la única forma de hacerlo.
Gaius
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.